diff --git a/src/components/map/Map.tsx b/src/components/map/Map.tsx index 8e89261..db20031 100644 --- a/src/components/map/Map.tsx +++ b/src/components/map/Map.tsx @@ -17,7 +17,7 @@ import 'ol/ol.css'; import './Map.css'; import { Collection, VectorTile } from 'ol'; import { Point } from 'ol/geom'; -import { Style, Icon } from 'ol/style'; +import { Style, Icon, Circle, Fill } from 'ol/style'; import GetLocation, { getCurrentLocation } from '../get-location'; import ShowLocationIcon from '../get-location/ShowLocationIcon.svg'; import { Back, Forward } from '../back-forward'; @@ -32,12 +32,14 @@ import PinchZoom from 'ol/interaction/PinchZoom'; import KeyboardPan from 'ol/interaction/KeyboardPan'; import KeyboardZoom from 'ol/interaction/KeyboardZoom'; import MouseWheelZoom from 'ol/interaction/MouseWheelZoom'; +import Cluster from 'ol/source/Cluster.js'; +import * as olExtent from 'ol/extent'; import DragZoom from 'ol/interaction/DragZoom'; import Infos, { clickHandler } from '../infos'; import GpxDialog from '../gpx-dialog'; import GpxRecord from '../gpx-record'; import dispatch from '../../workers/dispatcher-main'; -import { debounce } from 'lodash'; +import { debounce, floor } from 'lodash'; import { AndroidFullScreen } from '@awesome-cordova-plugins/android-full-screen'; import Account from '../account'; @@ -235,34 +237,25 @@ const Map: Component = () => { zIndex: Infinity, }); - const vectorTileSource1 = new VectorTileSource({ + const vectorTileSource = new VectorTileSource({ format: new MVT({ featureClass: Feature }), url: 'https://geo.dyomedea.com/services/spain/tiles/{z}/{x}/{y}.pbf', maxZoom: 14, }); - const vectorTileLayer1 = new VectorTileLayer({ - source: vectorTileSource1, - style: style, + const vectorTileLayer = new VectorTileLayer({ + source: vectorTileSource, + style: [], declutter: false, }); - const vectorTileSource2 = new VectorTileSource({ - format: new MVT(), - url: 'http://localhost:8080/geoserver/gwc/service/tms/1.0.0/dyomedea%3Ahiking_routes@EPSG%3A900913@pbf/{z}/{x}/{-y}.pbf', - }); - - const vectorTileLayer2 = new VectorTileLayer({ - source: vectorTileSource2, - }); - const olMap = new OlMap({ view: new View({ center: [+getState().lon, +getState().lat], zoom: +getState().zoom, rotation: +getState().rotation, }), - layers: [tileLayer, vectorTileLayer1, vectorLayer], + layers: [tileLayer, vectorTileLayer, vectorLayer], target: target, controls: new Collection([ new Attribution({ collapsible: true }), @@ -285,6 +278,92 @@ const Map: Component = () => { olMap.on(['moveend'], changeListener); olMap.on(['singleclick'], clickHandler); + // cf https://stackoverflow.com/questions/55161380/openlayers-cluster-with-mvt-vectortilesource-impossible + + const vectorTileMirrorSource = new VectorSource(); + let featuresForZ: Feature[] = []; + let viewZ: number = floor(+getState().zoom) - 1; + + const vectorMirrorRefresh = () => { + console.log({ + caller: 'Map / Cluster / vectorMirrorRefresh', + olMap, + vectorMirrorLayer, + viewZ, + featuresForZ, + }); + vectorTileMirrorSource.clear(); + if (featuresForZ[viewZ]) { + vectorTileMirrorSource.addFeatures(featuresForZ[viewZ]); + } + }; + + vectorTileLayer.getSource()?.on('tileloadend', (evt) => { + const z = evt.tile.getTileCoord()[0]; + const features = evt.tile.getFeatures(); + features.forEach((feature: Feature) => { + feature.setId(undefined); + }); + if (!Array.isArray(featuresForZ[z])) { + featuresForZ[z] = []; + } + featuresForZ[z] = featuresForZ[z].concat(features); + if (z === viewZ) { + vectorMirrorRefresh(); + } + console.log({ + caller: 'Map / Cluster / on tileloadend', + olMap, + z, + viewZ, + features, + vectorMirrorLayer, + featuresForZ, + }); + }); + + olMap.getView().on('change:resolution', function () { + // use VT features from the tile z level corresponding to view resolution + const newZ = vectorTileLayer + .getSource() + .getTileGrid() + .getZForResolution(olMap.getView().getResolution()); + console.log({ + caller: 'Map / Cluster / on change:resolution', + olMap, + newZ, + viewZ, + vectorMirrorLayer, + featuresForZ, + }); + if (newZ !== viewZ) { + viewZ = newZ; + vectorMirrorRefresh(); + } + }); + + let vectorMirrorLayer = new VectorLayer({ + source: new Cluster({ + source: vectorTileMirrorSource, + geometryFunction: function (feature: Feature) { + // test data is linestrings + return new Point( + olExtent.getCenter(feature.getGeometry().getExtent()) + ); + }, + }), + style, + // style: function (feature) { + // return new Style({ + // image: new Circle({ + // radius: feature.get('features').length * 5, + // fill: new Fill({ color: 'black' }), + // }), + // }); + // }, + }); + olMap.addLayer(vectorMirrorLayer); + setMap(olMap); });