diff --git a/layers/dot-cams/castle-rock/get_data.py b/layers/dot-cams/castle-rock/get_data.py
index 6a4111e..4d68eb9 100755
--- a/layers/dot-cams/castle-rock/get_data.py
+++ b/layers/dot-cams/castle-rock/get_data.py
@@ -10,8 +10,6 @@ with open('states.json') as f:
with open("query.graphql") as f:
QUERY = f.read()
-data = {}
-
for state, baseURL in states.items():
PAYLOAD = [
{
diff --git a/layers/dot-cams/index.js b/layers/dot-cams/index.js
index 7d16f40..736eac2 100644
--- a/layers/dot-cams/index.js
+++ b/layers/dot-cams/index.js
@@ -1,20 +1,18 @@
import al from './al/layer.js';
-import wi from './wi/layer.js';
+import wi from './travel-iq/index.js';
import castlerocklayers from './castle-rock/index.js';
+import travelIqLayers from './travel-iq/index.js';
const dot_cams = {
name: "State DOT Cameras",
layers: [
...castlerocklayers,
+ ...travelIqLayers,
{
name: "Alabama: ALDOT/ALGO",
layer: al,
},
- {
- name: "WisDOT/511WI",
- layer: wi,
- },
],
details: `Enable All`,
};
diff --git a/layers/dot-cams/travel-iq/get_data.py b/layers/dot-cams/travel-iq/get_data.py
new file mode 100755
index 0000000..bf66f2b
--- /dev/null
+++ b/layers/dot-cams/travel-iq/get_data.py
@@ -0,0 +1,92 @@
+#!/usr/bin/python3
+
+import requests
+import json
+
+with open('states.json') as f:
+ states = json.loads(f.read())
+
+for state, baseURL in states.items():
+ query={
+ "columns": [ # no clue what any of this is, so here it stays
+ {
+ "data": None,
+ "name": "",
+ },
+ {
+ "name": "sortId",
+ "s": True,
+ },
+ {
+ "name": "region",
+ "s": True,
+ },
+ {
+ "name": "county",
+ "s": True,
+ },
+ {
+ "name": "roadway",
+ "s": True,
+ },
+ {
+ "name": "description1",
+ },
+ {
+ "data": 6,
+ "name": "",
+ },
+ ],
+ "start": 0,
+ "length": 100,
+ }
+
+ cameras = []
+ available_cameras = 999_999 # lots
+
+ while len(cameras) < available_cameras:
+ res = requests.get(f"{baseURL}/List/GetData/Cameras", {
+ "query": json.dumps(query),
+ "lang": "en",
+ })
+ res.raise_for_status()
+ res = res.json()
+ available_cameras = res['recordsTotal']
+ for c in res['data']:
+ cameras.append({
+ "type": "Feature",
+ "geometry": {
+ "type": "Point",
+ "coordinates": [c['longitude'], c['latitude']], # yes, [lon, lat] since it's [x, y]
+ },
+ "properties": {
+ 'address': c['displayName'],
+ 'website': c['videoUrl'],
+ 'originalData': c,
+ },
+ })
+ query['start'] += 100
+
+ geojson = {
+ "type": "FeatureCollection",
+ "features": cameras,
+ }
+
+ with open(f"data/{state}.geojson", "w") as f:
+ f.write(json.dumps(geojson))
+
+ print(f"{len(cameras)} locations found for {state}")
+
+# hack hack hack
+#
+# If I write this to one big file, I can't take advantage of any lazy loading
+# for performance reasons, so I'm constrained to having a bunch of files. I
+# can't programmatically import those, since es6 imports don't allow for that.
+# So, codegen it is (and fairly gross codegen at that!).
+with open('data/states.js', 'w') as f:
+ for state in states:
+ f.write(f"import {state} from './{state}.geojson?url';\n")
+ f.write('\nexport default {\n')
+ for state in states:
+ f.write(f" {state}: {state},\n")
+ f.write("};\n")
diff --git a/layers/dot-cams/travel-iq/index.js b/layers/dot-cams/travel-iq/index.js
new file mode 100644
index 0000000..5fd807b
--- /dev/null
+++ b/layers/dot-cams/travel-iq/index.js
@@ -0,0 +1,60 @@
+import VectorLayer from 'ol/layer/Vector';
+import {Vector as VectorSource} from 'ol/source.js';
+import GeoJSON from 'ol/format/GeoJSON.js';
+
+import Hls from 'hls.js';
+
+import {Style} from 'ol/style.js';
+import Icon from 'ol/style/Icon.js';
+
+import states from './data/states.js';
+
+import pin from './pin.svg?url'; // TODO: remove `?url`?
+
+// https://en.wikipedia.org/wiki/Department_of_transportation#List_of_U.S._state_and_insular_area_departments_of_transportation
+const dot_names = {
+ wi: "WisDOT/511WI",
+};
+
+let vectorLayers = [];
+
+for (let [state, url] of Object.entries(states)) {
+ const vectorLayer = new VectorLayer({
+ source: new VectorSource({
+ url: url,
+ format: new GeoJSON,
+ }),
+ style: new Style({
+ image: new Icon({
+ anchor: [0.5, 1],
+ src: pin,
+ }),
+ }),
+ });
+
+ vectorLayer.customPopup = function(feature) {
+ return ``;
+ };
+
+ vectorLayer.customPopupCallback = function(feature) {
+
+ const video = document.getElementById('popupVideo');
+
+ const videoSrc = feature.values_.originalData.videoUrl;
+ if (Hls.isSupported()) {
+ var hls = new Hls();
+ hls.loadSource(videoSrc);
+ hls.attachMedia(video);
+ }
+ // iDevice support, untested (only works in Safari; required for iPhones)
+ else if (video.canPlayType('application/vnd.apple.mpegurl')) {
+ video.src = videoSrc;
+ }
+ }
+ vectorLayers.push({
+ name: dot_names[state] ?? state,
+ layer: vectorLayer,
+ });
+}
+
+export default vectorLayers;
diff --git a/layers/dot-cams/wi/pin.svg b/layers/dot-cams/travel-iq/pin.svg
similarity index 100%
rename from layers/dot-cams/wi/pin.svg
rename to layers/dot-cams/travel-iq/pin.svg
diff --git a/layers/dot-cams/travel-iq/states.json b/layers/dot-cams/travel-iq/states.json
new file mode 100644
index 0000000..154736e
--- /dev/null
+++ b/layers/dot-cams/travel-iq/states.json
@@ -0,0 +1,3 @@
+{
+ "wi": "https://511wi.gov/"
+}
diff --git a/layers/dot-cams/wi/get_data.py b/layers/dot-cams/wi/get_data.py
deleted file mode 100755
index c21fb45..0000000
--- a/layers/dot-cams/wi/get_data.py
+++ /dev/null
@@ -1,74 +0,0 @@
-#!/usr/bin/python3
-
-import requests
-import json
-
-query={
- "columns": [ # no clue what any of this is, so here it stays
- {
- "data": None,
- "name": "",
- },
- {
- "name": "sortId",
- "s": True,
- },
- {
- "name": "region",
- "s": True,
- },
- {
- "name": "county",
- "s": True,
- },
- {
- "name": "roadway",
- "s": True,
- },
- {
- "name": "description1",
- },
- {
- "data": 6,
- "name": "",
- },
- ],
- "start": 0,
- "length": 100,
-}
-
-cameras = []
-available_cameras = 999_999 # lots
-
-while len(cameras) < available_cameras:
- res = requests.get("https://511wi.gov/List/GetData/Cameras", {
- "query": json.dumps(query),
- "lang": "en",
- })
- res.raise_for_status()
- res = res.json()
- available_cameras = res['recordsTotal']
- for c in res['data']:
- cameras.append({
- "type": "Feature",
- "geometry": {
- "type": "Point",
- "coordinates": [c['longitude'], c['latitude']], # yes, [lon, lat] since it's [x, y]
- },
- "properties": {
- 'address': c['displayName'],
- 'website': c['videoUrl'],
- 'originalData': c,
- },
- })
- query['start'] += 100
-
-geojson = {
- "type": "FeatureCollection",
- "features": cameras,
-}
-
-with open("data.geojson", "w") as f:
- f.write(json.dumps(geojson))
-
-print(f"{len(cameras)} locations found")
diff --git a/layers/dot-cams/wi/layer.js b/layers/dot-cams/wi/layer.js
deleted file mode 100644
index 7a8a6e3..0000000
--- a/layers/dot-cams/wi/layer.js
+++ /dev/null
@@ -1,46 +0,0 @@
-import VectorLayer from 'ol/layer/Vector';
-import {Vector as VectorSource} from 'ol/source.js';
-import GeoJSON from 'ol/format/GeoJSON.js';
-
-import Hls from 'hls.js';
-
-import {Style} from 'ol/style.js';
-import Icon from 'ol/style/Icon.js';
-
-import url from './data.geojson?url'; // TODO: remove `?url`?
-import pin from './pin.svg?url'; // TODO: remove `?url`?
-
-const vectorLayer = new VectorLayer({
- source: new VectorSource({
- url: url,
- format: new GeoJSON,
- }),
- style: new Style({
- image: new Icon({
- anchor: [0.5, 1],
- src: pin,
- }),
- }),
-});
-
-vectorLayer.customPopup = function(feature) {
- return ``;
-};
-
-vectorLayer.customPopupCallback = function(feature) {
-
- const video = document.getElementById('popupVideo');
-
- const videoSrc = feature.values_.originalData.videoUrl;
- if (Hls.isSupported()) {
- var hls = new Hls();
- hls.loadSource(videoSrc);
- hls.attachMedia(video);
- }
- // iDevice support, untested (only works in Safari; required for iPhones)
- else if (video.canPlayType('application/vnd.apple.mpegurl')) {
- video.src = videoSrc;
- }
-}
-
-export default vectorLayer;