From 36337623ca6d61bbc3c00f3b7b428933a65ac0b7 Mon Sep 17 00:00:00 2001 From: evlist Date: Sat, 21 Jan 2023 21:22:36 +0100 Subject: [PATCH] Refactoring and implementing the actual selection of features to display. --- src/components/gpx/styles.ts | 10 +- .../map-tile-provider/MapTileProvider.tsx | 25 ++++- src/components/map-tile-provider/index.ts | 8 +- src/components/map/Map.tsx | 60 +----------- src/components/map/Overlays.tsx | 98 +++++++++++++++++++ 5 files changed, 137 insertions(+), 64 deletions(-) create mode 100644 src/components/map/Overlays.tsx diff --git a/src/components/gpx/styles.ts b/src/components/gpx/styles.ts index 85a7b43..ae7ab94 100644 --- a/src/components/gpx/styles.ts +++ b/src/components/gpx/styles.ts @@ -23,6 +23,7 @@ import { createDefaultStyle } from 'ol/style/Style'; import osmIcons, { highlight } from './osm-icons'; import { indexOf } from 'lodash'; import { getZoomInteger } from '../map/Map'; +import { isHighlighted } from '../map-tile-provider'; interface StyleParameters { type: string; @@ -327,17 +328,16 @@ const styles = { poi: { getParameters: (feature: Feature) => { const klass: string = feature.get('class'); - const isHighlighted = highlight.hasOwnProperty(klass); + const isHighlightedFeature = isHighlighted(feature); return { - isSelected: feature.get('isSelected') ?? false, name: feature.get('name'), klass, - isHighlighted, + isHighlighted: isHighlightedFeature, isTextHidden: getZoomInteger() < 19, // isHidden: !isHighlighted && getZoomInteger() < 16, isHidden: - (feature.get('sub-type') === 'tourism' && getZoomInteger() < 14) || - (feature.get('sub-type') !== 'tourism' && getZoomInteger() < 16), + (isHighlightedFeature && getZoomInteger() < 14) || + (!isHighlightedFeature && getZoomInteger() < 16), }; }, getStyle: memoize((params: any) => { diff --git a/src/components/map-tile-provider/MapTileProvider.tsx b/src/components/map-tile-provider/MapTileProvider.tsx index 5c4f6f0..9b96731 100644 --- a/src/components/map-tile-provider/MapTileProvider.tsx +++ b/src/components/map-tile-provider/MapTileProvider.tsx @@ -22,6 +22,7 @@ import Tree from '../tree'; import { createCachedSignal } from '../../workers/cached-signals'; import dispatch from '../../workers/dispatcher-main'; import getUri from '../../lib/ids'; +import { Feature } from 'ol'; const id = getUri('overlays', undefined); @@ -176,13 +177,35 @@ const currentOverlayKey = () => const currentOverlay = () => getOverlays() ? getOverlays()[currentOverlayKey()] : {}; -const currentOverlayDefinition = () => overlayDefinitions[currentOverlayKey()]; +export const currentOverlayDefinition = () => + overlayDefinitions[currentOverlayKey()]; const currentOverlayHighlightedKey = () => currentOverlay() && currentOverlay().highlighted ? Object.keys(currentOverlay().highlighted)[0] : 'none'; +export const currentOverlayHighlightedDefinition = () => + currentOverlayDefinition()[currentOverlayHighlightedKey()]; + +export const isHighlighted = (feature: Feature) => { + const type = feature.get('sub-type'); + const subType = feature.get('class'); + const highlightedType = currentOverlayHighlightedDefinition()[type]; + if (!highlightedType) { + return false; + } + // console.log({ + // caller: 'Overlays / isHighlighted', + // feature, + // type, + // subType, + // currentOverlayHighlightedDefinition: currentOverlayHighlightedDefinition(), + // highlightedType, + // }); + return highlightedType === '*' || highlightedType.includes(subType); +}; + const MapTilesProvider: Component<{}> = (props) => { const [open, setOpen] = createSignal(false); diff --git a/src/components/map-tile-provider/index.ts b/src/components/map-tile-provider/index.ts index 071bcef..7708f35 100644 --- a/src/components/map-tile-provider/index.ts +++ b/src/components/map-tile-provider/index.ts @@ -1 +1,7 @@ -export { default, mapTileProviders } from './MapTileProvider'; +export { + default, + mapTileProviders, + currentOverlayDefinition, + currentOverlayHighlightedDefinition, + isHighlighted, +} from './MapTileProvider'; diff --git a/src/components/map/Map.tsx b/src/components/map/Map.tsx index e3e709d..9337e84 100644 --- a/src/components/map/Map.tsx +++ b/src/components/map/Map.tsx @@ -49,6 +49,7 @@ import VectorTileSource from 'ol/source/VectorTile.js'; import MVT from 'ol/format/MVT.js'; import style from '../gpx/styles'; import ClusterableVectorTileSourceProxy from '../../lib/ClusterableVectorTileSourceProxy'; +import { Overlays } from './Overlays'; const [getState, setState] = createSignal({ lon: 0, @@ -277,69 +278,14 @@ const Map: Component = () => { olMap.on(['moveend'], changeListener); olMap.on(['singleclick'], clickHandler); - // // cf https://stackoverflow.com/questions/55161380/openlayers-cluster-with-mvt-vectortilesource-impossible - - const vectorTileSource = new VectorTileSource({ - url: 'https://geo.dyomedea.com/services/spain/tiles/{z}/{x}/{y}.pbf', - format: new MVT({ featureClass: Feature }), - maxZoom: 14, - }); - - const vectorTileLayer = new VectorTileLayer({ - source: vectorTileSource, - style, - declutter: false, - }); - - const clusterableVectorTileSource = new ClusterableVectorTileSourceProxy({ - source: vectorTileSource, - }); - - const clusterSource = new Cluster({ - source: clusterableVectorTileSource, - distance: 30, - minDistance: 10, - geometryFunction: (feature: Feature) => { - // console.log({ - // caller: 'Map / Cluster / geometryFunction', - // feature, - // }); - if (getZoomInteger() < 14 && feature.get('sub-type') === 'tourism') { - return feature.getGeometry(); - } - return null; - }, - createCluster: (point: Point, features: Feature[]) => { - // console.log({ - // caller: 'Map / Cluster / createCluster', - // point, - // features, - // }); - - return new Feature({ - geometry: point, - features: features, - type: 'cluster', - }); - }, - }); - - let clusterLayer = new VectorLayer({ - source: clusterSource, - zIndex: Infinity, - style, - }); - - olMap.addLayer(vectorTileLayer); - olMap.addLayer(clusterLayer); - setMap(olMap); }); return ( + // // @ts-ignore
- + diff --git a/src/components/map/Overlays.tsx b/src/components/map/Overlays.tsx new file mode 100644 index 0000000..edbc96e --- /dev/null +++ b/src/components/map/Overlays.tsx @@ -0,0 +1,98 @@ +import { Component, createEffect, onMount } from 'solid-js'; +import OlMap from 'ol/Map'; + +import { + currentOverlayDefinition, + currentOverlayHighlightedDefinition, + isHighlighted, +} from '../map-tile-provider'; +import { Feature } from 'ol'; +import MVT from 'ol/format/MVT'; +import { Point } from 'ol/geom'; +import VectorLayer from 'ol/layer/Vector'; +import VectorTileLayer from 'ol/layer/VectorTile'; +import VectorTileSource from 'ol/source/VectorTile.js'; +import Cluster from 'ol/source/Cluster'; +import { style } from '../gpx/styles'; +import ClusterableVectorTileSourceProxy from '../../lib/ClusterableVectorTileSourceProxy'; +import { getMap, getZoomInteger } from './Map'; + +interface Props { + map: () => OlMap | null; +} + +let clusterLayer: VectorLayer; +let vectorTileLayer: VectorTileLayer; + +export const Overlays: Component = ({ map }) => { + onMount(() => { + const vectorTileSource = new VectorTileSource({ + url: 'https://geo.dyomedea.com/services/spain/tiles/{z}/{x}/{y}.pbf', + format: new MVT({ featureClass: Feature }), + maxZoom: 14, + }); + + vectorTileLayer = new VectorTileLayer({ + source: vectorTileSource, + style, + declutter: false, + }); + + const clusterableVectorTileSource = new ClusterableVectorTileSourceProxy({ + source: vectorTileSource, + }); + + const clusterSource = new Cluster({ + source: clusterableVectorTileSource, + distance: 30, + minDistance: 10, + geometryFunction: (feature: Feature) => { + // console.log({ + // caller: 'Map / Cluster / geometryFunction', + // feature, + // }); + if (getZoomInteger() < 14 && isHighlighted(feature)) { + return feature.getGeometry(); + } + return null; + }, + createCluster: (point: Point, features: Feature[]) => { + // console.log({ + // caller: 'Map / Cluster / createCluster', + // point, + // features, + // }); + + return new Feature({ + geometry: point, + features: features, + type: 'cluster', + }); + }, + }); + + clusterLayer = new VectorLayer({ + source: clusterSource, + zIndex: Infinity, + style, + }); + }); + + createEffect(() => { + const overlayDefinition = currentOverlayDefinition(); + const overlayHighlightedDefinition = currentOverlayHighlightedDefinition(); + const olMap = getMap(); + if (olMap) { + olMap.removeLayer(clusterLayer); + olMap.removeLayer(vectorTileLayer); + if (Object.keys(overlayDefinition).length > 0) { + vectorTileLayer.changed(); + clusterLayer.changed(); + olMap.addLayer(vectorTileLayer); + olMap.addLayer(clusterLayer); + } + } + }); + + return <>; +};