about summary refs log tree commit diff
path: root/map/main.js
diff options
context:
space:
mode:
Diffstat (limited to 'map/main.js')
-rw-r--r--map/main.js284
1 files changed, 284 insertions, 0 deletions
diff --git a/map/main.js b/map/main.js
new file mode 100644
index 0000000..5340ca1
--- /dev/null
+++ b/map/main.js
@@ -0,0 +1,284 @@
+import * as MaplibreGL from 'https://cdn.skypack.dev/maplibre-gl?min';
+import * as Diplomat from 'https://cdn.skypack.dev/@americana/diplomat?min';
+import * as PMTiles from 'https://cdn.skypack.dev/pmtiles?min';
+import * as D3 from 'https://cdn.skypack.dev/d3?min';
+import turf from 'https://cdn.skypack.dev/turf?min';
+
+
+// local imports
+import {
+    CustomControl,
+} from './controls.js';
+
+// add the PMTiles plugin to the maplibregl global.
+const pmproto = new PMTiles.Protocol();
+MaplibreGL.addProtocol('pmtiles', pmproto.tile);
+
+// globals
+export const map = initMap();
+export const urlState = initUrlState();
+
+
+function initUrlState() {
+    const params = new URLSearchParams(window.location.search);
+
+    if (params.has('show')) {
+        const show = params.get('show');
+        const vals = show.split(',');
+        if (vals.includes('japan')) {
+            loadJapan();
+        }
+    }
+
+    return params;
+}
+
+function initMap() {
+    const map = new MaplibreGL.Map({
+        container: 'map',
+        style: 'https://tiles.openfreemap.org/styles/positron',
+    });
+
+    // overwrite basemap style
+    const style = D3.json('https://tiles.openfreemap.org/styles/positron')
+    style.then((data) => {
+        data.layers = data.layers.map((l) => {
+            if (l.id === "boundary_2") {
+                l.paint["line-color"] = "red";
+            }
+            if (l.id === "boundary_3") {
+                l.minzoom = 4;
+                l.paint["line-color"] = "orange";
+            }
+            if (l.id === "label_state") {
+                l.minzoom = 4;
+                l.paint["text-color"] = "orange";
+            }
+            if (l.id === "label_other") {
+                l.minzoom = 4;
+                l.paint["text-color"] = "orange";
+            }
+            return l;
+        });
+        map.setStyle(data);
+    });
+
+    map.addControl(new MaplibreGL.FullscreenControl());
+
+    map.addControl(new MaplibreGL.NavigationControl({
+        showZoom: true,
+        showCompass: true,
+        visualizeRoll: true,
+        visualizePitch: true,
+    }));
+
+    map.addControl(new MaplibreGL.GlobeControl());
+
+    map.addControl(new MaplibreGL.GeolocateControl({
+        positionOptions: {
+            enableHighAccuracy: true
+        },
+    }));
+
+    map.addControl(new CustomControl({
+        label: 'Japan',
+        icon: '🇯🇵',
+        onclick: () => {
+            loadJapan();
+        },
+    }));
+    map.addControl(new CustomControl({
+        label: 'Raw',
+        icon: 'R',
+        onclick: () => {
+            loadRaw();
+        },
+    }));
+    map.addControl(new CustomControl({
+        label: 'Visited',
+        icon: 'V',
+        onclick: () => {
+            loadVisited();
+        },
+    }));
+
+    // https://github.com/osm-americana/diplomat/
+    map.once("styledata", (event) => {
+      Diplomat.localizeStyle(map);
+    });
+
+    return map;
+}
+
+
+function loadRaw() {
+    const raw = D3.json('export-data/data.geojson');
+    raw.then((data) => {
+        if (map.getSource('raw') === undefined) {
+            map.addSource('raw', {
+                type: 'geojson',
+                data: data,
+            });
+            map.addLayer({
+                id: 'raw',
+                source: 'raw',
+                type: 'heatmap',
+                paint: {
+                    // Increase the heatmap weight based on frequency and property magnitude
+                    'heatmap-weight': [
+                        'interpolate',
+                        ['linear'],
+                        ['get', 'mag'],
+                        0,
+                        0,
+                        6,
+                        1
+                    ],
+                    // Increase the heatmap color weight weight by zoom level
+                    // heatmap-intensity is a multiplier on top of heatmap-weight
+                    'heatmap-intensity': [
+                        'interpolate',
+                        ['linear'],
+                        ['zoom'],
+                        0,
+                        1,
+                        9,
+                        3
+                    ],
+                    // Color ramp for heatmap.  Domain is 0 (low) to 1 (high).
+                    // Begin color ramp at 0-stop with a 0-transparency color
+                    // to create a blur-like effect.
+                    'heatmap-color': [
+                        'interpolate',
+                        ['linear'],
+                        ['heatmap-density'],
+                        0,
+                        'rgba(33,102,172,0)',
+                        0.2,
+                        'rgb(103,169,207)',
+                        0.4,
+                        'rgb(209,229,240)',
+                        0.6,
+                        'rgb(253,219,199)',
+                        0.8,
+                        'rgb(239,138,98)',
+                        1,
+                        'rgb(178,24,43)'
+                    ],
+                    // Adjust the heatmap radius by zoom level
+                    'heatmap-radius': [
+                        'interpolate',
+                        ['linear'],
+                        ['zoom'],
+                        0,
+                        2,
+                        9,
+                        20
+                    ],
+                },
+            });
+        }
+        map.fitBounds(turf.bbox(data), {
+            padding: 50,
+        });
+    })
+}
+
+function loadVisited() {
+    // add data
+    const vis = D3.json('export-data/visited.geojson');
+    vis.then((data) => {
+        if (map.getSource('visited') === undefined) {
+            map.addSource('visited', {
+                type: 'geojson',
+                data: data,
+            });
+            // boundaries
+            map.addLayer({
+                id: 'visited-bounds',
+                type: 'fill',
+                source: 'visited',
+                layout: {},
+                paint: {
+                    'fill-color': 'hotpink',
+                    'fill-opacity': 0.6,
+                },
+                filter: ['==', '$type', 'Polygon'],
+            });
+            // labels
+            map.addLayer({
+                id: 'visited-labels',
+                type: 'symbol',
+                source: 'visited',
+                layout: {
+                    'text-field': '{iso3166}\n{timestamp}',
+                    'text-font': ['Noto Sans Regular'],
+                    'text-size': 12,
+                    'text-variable-anchor': ['top', 'bottom', 'left', 'right'],
+                    'text-radial-offset': 0.3,
+                    'text-justify': 'auto',
+                },
+                paint: {
+                    'text-color': 'black',
+                    'text-opacity': 1.0,
+                },
+                filter: ['==', '$type', 'Polygon'],
+            });
+        }
+        map.fitBounds(turf.bbox(data), {
+            padding: 50,
+        });
+    });
+}
+
+function loadJapan() {
+    function normalizeLocation() {
+        let addr = window.location.toString();
+        let idx = addr.lastIndexOf("/");
+        return addr.slice(0, idx);
+    }
+
+    const jpn_url = 'export-data/japan-admin_level=4.pmtiles'
+    const jpn = new PMTiles.PMTiles(jpn_url);
+    pmproto.add(jpn);
+    jpn.getHeader().then(hdr => {
+        map.fitBounds([[hdr.minLon, hdr.minLat],[hdr.maxLon, hdr.maxLat]], {
+            padding: 1,
+        });
+    //     map.addSource('jpn', {
+    //         type: 'vector',
+    //         url: `pmtiles://${normalizeLocation()}/${jpn_url}`,
+    //         attribution: '© <a href="https://osm-boundaries.com/about">OSM-Boundaries</a>'
+    //     });
+    //     map.addLayer({
+    //         id: 'jpn-bounds',
+    //         source: 'jpn',
+    //         'source-layer': 'japan-bounds',
+    //         type: 'line',
+    //         layout: {},
+    //         paint: {
+    //             'line-color': 'orange',
+    //             'line-width': 2,
+    //             'line-opacity': 0.5,
+    //         },
+    //     });
+    //     map.addLayer({
+    //         id: 'jpn-labels',
+    //         source: 'jpn',
+    //         'source-layer': 'japan-labels',
+    //         type: 'symbol',
+    //         layout: {
+    //             'text-field': '{name_en}',
+    //             'text-font': ['Noto Sans Regular'],
+    //             'text-size': 12,
+    //             'text-variable-anchor': ['top', 'bottom', 'left', 'right'],
+    //             'text-radial-offset': 0.2,
+    //             'text-justify': 'auto',
+    //         },
+    //         paint: {
+    //             'text-color': 'black',
+    //             'text-opacity': 1.0,
+    //         },
+    //     });
+    });
+}