diff options
author | Guilhem Moulin <guilhem@fripost.org> | 2025-05-22 13:03:47 +0200 |
---|---|---|
committer | Guilhem Moulin <guilhem@fripost.org> | 2025-05-23 01:05:07 +0200 |
commit | bcc503ee14503e9bea3228e8c4138ead423f0f48 (patch) | |
tree | 589324fc086b841a78b5e0397e88af20faa0581f | |
parent | 8ca0f1d492a25932d8d2405a03e3754ca9721b7f (diff) |
Adjust to new MVT backend.
We now query a CGI to retrieve feature properties and full geometries
(as GeoJSON).
This partially reverts commit 1c0748176997d2e915faae3c6fcf5634f4fb0582.
-rw-r--r-- | main.js | 167 |
1 files changed, 69 insertions, 98 deletions
@@ -3215,78 +3215,56 @@ const styles = (function() { }, {}); })(); -const vectorLayers = {}; -const tileGrid = createXYZ({ - extent: extent, - tileSize: 1024, - maxResolution: 1024, /* = 1048576/1024 */ - minZoom: 0, - maxZoom: 9, -}); -function readLayerMap() { - fetch('/tiles/metadata.json', { - signal: AbortSignal.timeout(30000) - }).then((resp) => resp.json()) - .then((data) => { - const xyz = '/{z}/{x}/{y}.pbf'; - Object.entries(data.layermap).forEach(function([k, baseurl]) { - if (vectorLayers[k] !== undefined) { - const l = vectorLayers[k]; - if (l.baseurl !== baseurl) { - console.log(`Changing ${k}'s baseurl to ${baseurl} from ${l.baseurl}`); - l.baseurl = baseurl; - l.vectorLayer.getSource().setUrl(baseurl + xyz); +const vectorLayers = (function() { + const xyz = '/{z}/{x}/{y}.pbf'; + const tileGrid = createXYZ({ + extent: extent, + tileSize: 1024, + maxResolution: 1024, /* = 1048576/1024 */ + minZoom: 0, + maxZoom: 7, + }); + return Object.fromEntries( + ['mrr', 'nvr', 'ren', 'ri', 'sks', 'svk', 'vbk', 'misc'] + .map(function(k) { + let visible = false; + Object.keys(layers).forEach(function(lyr) { + if (lyr.startsWith(k + '_')) { + visible ||= styles[lyr] !== undefined; } - } else { - let visible = false; - Object.keys(layers).forEach(function(lyr) { - if (lyr.startsWith(k + '_')) { - visible ||= styles[lyr] !== undefined; + }); + const vectorLayer = new VectorTileLayer({ + source: new VectorTile({ + url: '/tiles/' + k + xyz, + format: new MVT(), + projection: projection, + wrapX: false, + transition: 0, + tileGrid: tileGrid, + }), + /* XXX switch to 'hybrid' if there are perf issues; but that seems to + * put lines above points regardless of their respective z-index */ + renderMode: 'hybrid', + declutter: false, + visible: visible, + style: function(feature, resolution) { + const style = styles[k + '_' + feature.getProperties().layer]; + if (!Array.isArray(style)) { + return style; + } else { + const maxi = style.length - 1; + const z = 10 /* Math.log2(maxResolution) */ - Math.log2(resolution); + /* use Math.floor() as VectorTile.js calls getZForResolution(resolution, 1) */ + const i = z <= 0 ? 0 : z >= maxi ? maxi : Math.floor(z); + // console.log(`resolution=${resolution}, z=${z}, i=${i}`); + return style[i]; } - }); - const vectorLayer = new VectorTileLayer({ - source: new VectorTile({ - url: baseurl + xyz, - format: new MVT(), - projection: projection, - wrapX: false, - transition: 0, - tileGrid: tileGrid, - }), - /* XXX switch to 'hybrid' if there are perf issues; but that seems to - * put lines above points regardless of their respective z-index */ - renderMode: 'hybrid', - declutter: false, - visible: visible, - style: function(feature, resolution) { - const style = styles[k + '_' + feature.getProperties().layer]; - if (!Array.isArray(style)) { - return style; - } else { - const maxi = style.length - 1; - const z = 10 /* Math.log2(maxResolution) */ - Math.log2(resolution); - /* use Math.floor() as VectorTile.js calls getZForResolution(resolution, 1) */ - const i = z <= 0 ? 0 : z >= maxi ? maxi : Math.floor(z); - // console.log(`resolution=${resolution}, z=${z}, i=${i}`); - return style[i]; - } - }, - }); - vectorLayer.set('layerGroup', k, true); - map.addLayer(vectorLayer); - vectorLayers[k] = { - baseurl: baseurl, - vectorLayer: vectorLayer, - }; - } - }); - }); -}; - -/* re-read after 6h so we don't miss updates; the interval should never - * be higher than the Cache-Control value on the tiles and metadata */ -readLayerMap(); -setInterval(readLayerMap, 21600000); + }}); + vectorLayer.set('layerGroup', k, true); + map.addLayer(vectorLayer); + return [k, vectorLayer]; + })); +})(); /* layer selection panel */ @@ -3350,7 +3328,7 @@ setInterval(readLayerMap, 21600000); const v = vectorLayers[lyr]; if (v !== undefined) { //console.log(lyr, visible); - v.vectorLayer.setVisible(visible); + v.setVisible(visible); } }); }; @@ -3377,7 +3355,7 @@ setInterval(readLayerMap, 21600000); layerList .map((l) => l.split('_', 2)[0]) .filter((v, i, arr) => arr.indexOf(v) === i) - .forEach((l) => vectorLayers[l].vectorLayer.getSource().changed()); + .forEach((l) => vectorLayers[l].getSource().changed()); searchParams.set('layers', layersParams.join(' ')); location.hash = '#' + searchParams.toString(); @@ -3748,41 +3726,34 @@ setInterval(readLayerMap, 21600000); map.forEachFeatureAtPixel(event.pixel, function(feature, layer) { const layerGroup = layer.get('layerGroup'); - let properties = feature.getProperties(); - const def = layers[layerGroup + '_' + properties.layer]; + const layerName = feature.getProperties().layer; + const def = layers[layerGroup + '_' + layerName]; if (def === undefined || def.popover === undefined) { /* skip layers which didn't opt-in for popover */ return; } - /* get filename and index of the original feature from the FID */ - const fid_dv = new DataView(new ArrayBuffer(4), 0); - fid_dv.setUint32(0, feature.getId(), false); - - const fid_idx = fid_dv.getUint16(2); - const buf = new Uint8Array(fid_dv.buffer.slice(0,2)) - const fid_p = buf.reduce((t, x) => t + x.toString(16).padStart(2, '0'), '') - if (features.length === 0) { document.body.classList.add('progress'); } - const url = vectorLayers[layerGroup].baseurl + '/attr/' + fid_p + '.json'; - fetch(url) - .then((resp) => resp.json()) + // TODO batch requests and use + // https://github.com/uhop/stream-json/wiki/StreamArray + fetch('/q', { + method: 'POST', + body: JSON.stringify({ + mvt: layerGroup, + layer: layerName, + fid: feature.getId() + }), + headers: { + 'Content-Type': 'application/json; charset=UTF-8' + } + }).then((resp) => resp.json()) .then((data) => { document.body.classList.remove('progress'); - properties = data[fid_idx] - //console.log(properties); - - /* build new feature from the metadata */ - const geojson = { id: feature.getId() } - geojson.properties = properties - const geom = properties['geom'] - delete properties['geom'] - geojson.geometry = geom - geojson.type = 'Feature' - const feature2 = new GeoJSON().readFeature(geojson); + const properties = data.properties || {}; + const feature0 = new GeoJSON().readFeature(data); /* turn the properties into a fine table */ const table = document.createElement('table'); @@ -3859,7 +3830,7 @@ setInterval(readLayerMap, 21600000); } content.appendChild(table); - features.push({feature: feature2, formattedContent: content}); + features.push({feature: feature0, formattedContent: content}); pageCount.innerHTML = features.length.toString(); if (features.length == 2) { @@ -3890,7 +3861,7 @@ setInterval(readLayerMap, 21600000); container: container0, }); popover.show(); - featureOverlaySource.addFeature(feature2); + featureOverlaySource.addFeature(feature0); } else if (popover.tip.classList.contains('popover-detached')) { refreshPopover(); |