diff --git a/lib/markerLayerFactory.ts b/lib/markerLayerFactory.ts index bf0aba1a..54ffcb5e 100644 --- a/lib/markerLayerFactory.ts +++ b/lib/markerLayerFactory.ts @@ -1,5 +1,6 @@ import type { FitBoundsOptions, + GeoJSONSource, LayerSpecification, LngLatBounds, Map, @@ -112,105 +113,96 @@ export function updateMarkers( const markerIdPrevious = Object.keys(markers) const markerIdcurrent: string[] = [] - const features = map.querySourceFeatures(src) + const features = map.querySourceFeatures(src).filter(feature => feature.geometry.type === 'Point') // for every cluster on the screen, create an HTML marker for it (if we didn't yet), // and add it to the map if it's not there already - features - .filter(feature => feature.geometry.type === 'Point') - .forEach((feature) => { - const coords = (feature.geometry as GeoJSON.Point).coordinates as [ - number, - number, - ] - const props = feature.properties - if (props?.cluster) { - const id = `c${props.cluster_id}` - markerIdcurrent.push(id) - if (!markers[id]) { - const { - cluster: _a, - cluster_id: _b, - point_count, - _c: _d, - point_count_abbreviated: _e, - ...countPercolor - } = props - const element = createMarkerDonutChart(countPercolor, point_count) - - markers[id] = createMarker(coords, { element }) - markers[id].addTo(map) - - element.addEventListener('click', (e) => { - e.stopPropagation() - const source = map.getSource(src) - - if (source && 'getClusterLeaves' in source) { - // @ts-expect-error: getClusterLeaves is for GeoJSONSource but source is Source type - source.getClusterLeaves( - props.cluster_id, - 100, - 0, - (error: any, features: GeoJSON.Feature[]) => { - if (!error && map) { - const bounds = getBBoxFeatures(features) - if (bounds) - fitBounds(bounds, {}) - } - }, - ) + for (let i = 0; i < features.length; i++) { + const coords = (features[i].geometry as GeoJSON.Point).coordinates as [ + number, + number, + ] + const props = features[i].properties + if (props?.cluster) { + const id = `c${props.cluster_id}` + markerIdcurrent.push(id) + if (!markers[id]) { + const { + cluster: _a, + cluster_id: _b, + point_count, + _c: _d, + point_count_abbreviated: _e, + ...countPercolor + } = props + const element = createMarkerDonutChart(countPercolor, point_count) + + markers[id] = createMarker(coords, { element }) + markers[id].addTo(map) + + element.addEventListener('click', async (e) => { + e.stopPropagation() + const source = map.getSource(src) as GeoJSONSource + + if (source && 'getClusterLeaves' in source) { + const leaves = await source.getClusterLeaves(props.cluster_id, props.point_count, 0) + if (leaves.length) { + const bounds = getBBoxFeatures(leaves) + if (bounds) + fitBounds(bounds, {}) } - }) - } + } + }) } - else if (props?.metadata) { - if (typeof props.metadata === 'string') - props.metadata = JSON.parse(props.metadata) - - const id = `m${feature.id}` - markerIdcurrent.push(id) - - // Workaround to correct shifting POI markers after zoom-in - if (!markers[id] || (markers[id] && (markers[id]?.getLngLat().lat !== (feature.geometry as GeoJSON.Point).coordinates[1]))) { - if (markers[id]) - markers[id].remove() - - const markerCoords - = feature.geometry.type === 'Point' - && (feature.geometry.coordinates as TupleLatLng) - if (markerCoords) { - if (typeof props.display === 'string') - props.display = JSON.parse(props.display) - - if (typeof props.editorial === 'string') - props.editorial = JSON.parse(props.editorial) - - // Marker - markers[id] = makerHtmlFactory( - id, - markerCoords, // Using this to avoid misplaced marker - props.display?.color_fill || '#000000', - props.display?.icon || '#000000', - props['image:thumbnail'], - null, - props.display?.text, - ) - - // Click handler - if (markerClickCallBack && props.editorial?.popup_fields) { - const el = markers[id].getElement() - - el.addEventListener('click', (e: MouseEvent) => { - e.stopPropagation() - const pinMarker = createMarker(markerCoords) - - markerClickCallBack(feature as unknown as ApiPoi, pinMarker) - }) - } - markers[id].addTo(map) + } + else if (props?.metadata) { + if (typeof props.metadata === 'string') + props.metadata = JSON.parse(props.metadata) + + const id = `m${features[i].id}` + markerIdcurrent.push(id) + + // Workaround to correct shifting POI markers after zoom-in + if (!markers[id] || (markers[id] && (markers[id]?.getLngLat().lat !== (features[i].geometry as GeoJSON.Point).coordinates[1]))) { + if (markers[id]) + markers[id].remove() + + const markerCoords + = features[i].geometry.type === 'Point' + && ((features[i].geometry as GeoJSON.Point).coordinates as TupleLatLng) + if (markerCoords) { + if (typeof props.display === 'string') + props.display = JSON.parse(props.display) + + if (typeof props.editorial === 'string') + props.editorial = JSON.parse(props.editorial) + + // Marker + markers[id] = makerHtmlFactory( + id, + markerCoords, // Using this to avoid misplaced marker + props.display?.color_fill || '#000000', + props.display?.icon || '#000000', + props['image:thumbnail'], + null, + props.display?.text, + ) + + // Click handler + if (markerClickCallBack && props.editorial?.popup_fields) { + const el = markers[id].getElement() + + el.addEventListener('click', (e: MouseEvent) => { + e.stopPropagation() + const pinMarker = createMarker(markerCoords) + + markerClickCallBack(features[i] as unknown as ApiPoi, pinMarker) + }) } + markers[id].addTo(map) } } - }) + } + } // for every marker we've added previously, remove those that are no longer visible const markerIdcurrentSet = new Set(markerIdcurrent) diff --git a/package.json b/package.json index b2a17ac0..ac7f357e 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "lodash.uniq": "^4.5.0", "lodash.uniqby": "^4.7.0", "lodash.without": "^4.4.0", - "maplibre-gl": "^3.6.2", + "maplibre-gl": "4.0.0", "opening_hours": "^3.8.0", "pinia": "^2.0.33", "pinia-shared-state": "0.5.1", diff --git a/yarn.lock b/yarn.lock index 0a353503..4af73fa1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1952,21 +1952,23 @@ __metadata: languageName: node linkType: hard -"@maplibre/maplibre-gl-style-spec@npm:^19.3.3": - version: 19.3.3 - resolution: "@maplibre/maplibre-gl-style-spec@npm:19.3.3" +"@maplibre/maplibre-gl-style-spec@npm:^20.1.0": + version: 20.3.0 + resolution: "@maplibre/maplibre-gl-style-spec@npm:20.3.0" dependencies: "@mapbox/jsonlint-lines-primitives": "npm:~2.0.2" "@mapbox/unitbezier": "npm:^0.0.1" - json-stringify-pretty-compact: "npm:^3.0.0" + json-stringify-pretty-compact: "npm:^4.0.0" minimist: "npm:^1.2.8" + quickselect: "npm:^2.0.0" rw: "npm:^1.3.3" sort-object: "npm:^3.0.3" + tinyqueue: "npm:^2.0.3" bin: gl-style-format: dist/gl-style-format.mjs gl-style-migrate: dist/gl-style-migrate.mjs gl-style-validate: dist/gl-style-validate.mjs - checksum: 10c0/ef315bf9c4e5ebce0d76a7722e53c3e4192b92ea405c95392f61655f551a112bbc17fd00c7c62a16eeb57cdb79a2145e385c4eaf2ca7f50222d2540c9e7e0a7a + checksum: 10c0/86c55a71b58a3895e56070e8a912449d6cfec25e2b4a1a9847a51bf5abd666416ecd8515ebf07557a07f51af1ae4b19e3b1247a105368141f4982cefe067105e languageName: node linkType: hard @@ -3563,7 +3565,7 @@ __metadata: lodash.uniq: "npm:^4.5.0" lodash.uniqby: "npm:^4.7.0" lodash.without: "npm:^4.4.0" - maplibre-gl: "npm:^3.6.2" + maplibre-gl: "npm:4.0.0" msw: "npm:^1.2.2" nuxt: "npm:3.8.0" nuxt-simple-sitemap: "npm:^2.7.0" @@ -3929,6 +3931,15 @@ __metadata: languageName: node linkType: hard +"@types/geojson-vt@npm:3.2.5": + version: 3.2.5 + resolution: "@types/geojson-vt@npm:3.2.5" + dependencies: + "@types/geojson": "npm:*" + checksum: 10c0/bfd9157c7d0441dc4b420e0c6df65b4e4b29f3d33cc77667b3dc5acd68ba6326bfbfd867642645357382e3374ceebfb9c5d15f2b2c0ee3e3c492e0b5a2bb71be + languageName: node + linkType: hard + "@types/geojson@npm:*, @types/geojson@npm:^7946.0.10, @types/geojson@npm:^7946.0.13": version: 7946.0.14 resolution: "@types/geojson@npm:7946.0.14" @@ -10519,10 +10530,10 @@ __metadata: languageName: node linkType: hard -"json-stringify-pretty-compact@npm:^3.0.0": - version: 3.0.0 - resolution: "json-stringify-pretty-compact@npm:3.0.0" - checksum: 10c0/fc522c25047bd96d72ded77af4002e7f12e9ba9f4b7e7e12a9316aee166f1b8f9c7b0d0d989a8494e3fdd804a23819f411479f68f2ef10b2f7a144581b2c68f4 +"json-stringify-pretty-compact@npm:^4.0.0": + version: 4.0.0 + resolution: "json-stringify-pretty-compact@npm:4.0.0" + checksum: 10c0/505781b4be7c72047ae8dfa667b520d20461ceac451b6516cb8ac5e12a758fbd7491d99d5e3f7e60423ce9d26ed4e4bcaccab3420bf651298901635c849017cf languageName: node linkType: hard @@ -11107,9 +11118,9 @@ __metadata: languageName: node linkType: hard -"maplibre-gl@npm:^3.6.2": - version: 3.6.2 - resolution: "maplibre-gl@npm:3.6.2" +"maplibre-gl@npm:4.0.0": + version: 4.0.0 + resolution: "maplibre-gl@npm:4.0.0" dependencies: "@mapbox/geojson-rewind": "npm:^0.5.2" "@mapbox/jsonlint-lines-primitives": "npm:^2.0.2" @@ -11118,8 +11129,9 @@ __metadata: "@mapbox/unitbezier": "npm:^0.0.1" "@mapbox/vector-tile": "npm:^1.3.1" "@mapbox/whoots-js": "npm:^3.1.0" - "@maplibre/maplibre-gl-style-spec": "npm:^19.3.3" + "@maplibre/maplibre-gl-style-spec": "npm:^20.1.0" "@types/geojson": "npm:^7946.0.13" + "@types/geojson-vt": "npm:3.2.5" "@types/mapbox__point-geometry": "npm:^0.1.4" "@types/mapbox__vector-tile": "npm:^1.3.4" "@types/pbf": "npm:^3.0.5" @@ -11136,7 +11148,7 @@ __metadata: supercluster: "npm:^8.0.1" tinyqueue: "npm:^2.0.3" vt-pbf: "npm:^3.1.3" - checksum: 10c0/51245b634087dd5f2a971b1dfa4170b98e10472e0d00859774d2ab1bd646de9a78342616862f4a66e932d0a75a6a5695258ce044f128a26e77d2f6b9efe7dafe + checksum: 10c0/a501283283f67bd4673b922974cda4579756996a2c4f971e0a6c2976df80e7567c2fa5de0f763f9bb394b5ebffd7ed58747fe34dc0f36179bb41b0ce18393458 languageName: node linkType: hard