From 10a5f2fb185b014012a7d56f9e419286ebea9efb Mon Sep 17 00:00:00 2001 From: evlist Date: Tue, 24 Jan 2023 10:37:03 +0100 Subject: [PATCH] Huge and dirty refactoring of the vector tile stuff. --- src/components/gpx/styles.ts | 44 +-- src/components/infos/Infos.tsx | 11 + .../map-tile-provider/MapTileProvider.tsx | 259 +++++++++++++----- src/components/map-tile-provider/index.ts | 2 +- src/components/map/Map.tsx | 2 +- src/components/{map => overlays}/Overlays.tsx | 19 +- src/components/overlays/index.ts | 1 + .../overlays/overlay-definitions.ts | 107 ++++++++ 8 files changed, 355 insertions(+), 90 deletions(-) rename src/components/{map => overlays}/Overlays.tsx (85%) create mode 100644 src/components/overlays/index.ts create mode 100644 src/components/overlays/overlay-definitions.ts diff --git a/src/components/gpx/styles.ts b/src/components/gpx/styles.ts index ae7ab94..d076d32 100644 --- a/src/components/gpx/styles.ts +++ b/src/components/gpx/styles.ts @@ -24,6 +24,11 @@ import osmIcons, { highlight } from './osm-icons'; import { indexOf } from 'lodash'; import { getZoomInteger } from '../map/Map'; import { isHighlighted } from '../map-tile-provider'; +import { + getHighlightedTagValue, + getTagValue, +} from '../map-tile-provider/MapTileProvider'; +import { getCenter } from 'ol/extent'; interface StyleParameters { type: string; @@ -327,27 +332,35 @@ const styles = { }, poi: { getParameters: (feature: Feature) => { - const klass: string = feature.get('class'); - const isHighlightedFeature = isHighlighted(feature); + if (feature.getGeometryName() !== 'Point') { + feature.setGeometry( + new Point(getCenter(feature.getGeometry().getExtent())) + ); + } + if (getZoomInteger() < 14) { + return null; + } + const highlightedTagValue = getHighlightedTagValue(feature); + const isHighlightedFeature = !!highlightedTagValue; + if ( + (isHighlightedFeature && getZoomInteger() < 14) || + (!isHighlightedFeature && getZoomInteger() < 16) + ) { + return null; + } return { name: feature.get('name'), - klass, + poiType: isHighlightedFeature + ? highlightedTagValue + : getTagValue(feature), isHighlighted: isHighlightedFeature, isTextHidden: getZoomInteger() < 19, - // isHidden: !isHighlighted && getZoomInteger() < 16, - isHidden: - (isHighlightedFeature && getZoomInteger() < 14) || - (!isHighlightedFeature && getZoomInteger() < 16), }; }, getStyle: memoize((params: any) => { // console.log({ caller: 'getStyle', params }); - const { isSelected, name, klass, isHidden, isTextHidden, isHighlighted } = - params; - if (isHidden) { - return null; - } - const icon = osmIcons[klass]; + const { name, poiType, isTextHidden, isHighlighted } = params; + const icon = osmIcons[poiType]; if (icon === undefined) { return undefined; } @@ -389,10 +402,9 @@ const styles = { cluster: { getParameters: (feature: Feature) => { const nbFeatures = feature.get('features').length; - // console.log({ caller: 'cluster / getParameters', feature, nbFeatures }); + // console.log({ caller: 'cluster / getParameters', feature, nbFeatures }); return { nbFeatures, - subFeature: nbFeatures === 1 ? feature.get('features')[0] : undefined, }; }, getStyle: memoize((params: any) => { @@ -427,7 +439,7 @@ export const style = (feature: Feature, resolution: number) => { return createDefaultStyle(feature, resolution)[0]; } const params = styles[type].getParameters(feature); - if (params?.isHidden) { + if (params === null || params?.isHidden) { return null; } // if (params.subFeature) { diff --git a/src/components/infos/Infos.tsx b/src/components/infos/Infos.tsx index 4a1aa4f..311d472 100644 --- a/src/components/infos/Infos.tsx +++ b/src/components/infos/Infos.tsx @@ -15,6 +15,12 @@ import Dialog from '../dialog'; import Tree from '../tree'; import { GpxViewer } from '../gpx'; import { Browser } from '@capacitor/browser'; +import { isHighlighted } from '../map-tile-provider'; +import { + getHighlightedTagValue, + getTagValue, +} from '../map-tile-provider/MapTileProvider'; +import style from '../gpx/styles'; const Item = styled(Paper)(({ theme }) => ({ ...theme.typography.body2, @@ -198,7 +204,12 @@ const Infos: Component<{}> = (props) => { <> {console.log({ caller: 'Infos / vector layer feature', + highlightedTagValue: + getHighlightedTagValue(feature), + isHighlighted: isHighlighted(feature), + tagValue: getTagValue(feature), properties: feature.getProperties(), + style: style(feature), })} diff --git a/src/components/map-tile-provider/MapTileProvider.tsx b/src/components/map-tile-provider/MapTileProvider.tsx index 9b96731..2836bf1 100644 --- a/src/components/map-tile-provider/MapTileProvider.tsx +++ b/src/components/map-tile-provider/MapTileProvider.tsx @@ -24,6 +24,11 @@ import dispatch from '../../workers/dispatcher-main'; import getUri from '../../lib/ids'; import { Feature } from 'ol'; +import { + overlayCategories, + overlayDefinitions, +} from '../overlays/overlay-definitions'; + const id = getUri('overlays', undefined); interface TileProvider { @@ -119,49 +124,64 @@ const defaultOverlays: Overlays = { }, }; -type OverlayDefinition = Record; -type OverlayDefinitions = Record; +// type OverlayDefinition = Record; +// type OverlayDefinitions = Record; -export const overlayDefinitions: OverlayDefinitions = { - none: {}, - hiking: { - none: {}, - sleeping: { - tourism: '*', - }, - drinking: { - amenity: ['bar', 'cafe', 'pub', 'drinking_water', 'water_point'], - }, - eating: { - amenity: ['fast_food', 'pub', 'restaurant'], - shop: [ - 'bakery', - 'butcher', - 'cheese', - 'chocolate', - 'convenience', - 'dairy', - 'farm', - 'greengrocer', - 'health_food', - 'pastry', - 'seafood', - 'department_store', - 'supermarket', - ], - }, - health: { - amenity: ['doctors', 'hospital', 'pharmacy'], - }, - security: { - amenity: ['police', 'fire_station'], - }, - dayToDay: { - amenity: ['waste_basket', 'waste_disposal'], - shop: ['laundry'], - }, - }, -}; +// export const overlayDefinitions: OverlayDefinitions = { +// none: {}, +// hiking: { +// none: {}, +// sleeping: { +// tourism: [ +// 'hotel', +// 'alpine_hut', +// 'apartment', +// 'camp_site', +// 'chalet', +// 'guest_house', +// 'hostel', +// 'motel', +// 'wilderness_hut', +// ], +// }, +// drinking: { +// amenity: ['bar', 'cafe', 'pub', 'drinking_water', 'water_point'], +// natural: ['spring'], +// }, +// eating: { +// amenity: ['fast_food', 'pub', 'restaurant'], +// shop: [ +// 'bakery', +// 'butcher', +// 'cheese', +// 'chocolate', +// 'convenience', +// 'dairy', +// 'farm', +// 'greengrocer', +// 'health_food', +// 'pastry', +// 'seafood', +// 'department_store', +// 'supermarket', +// ], +// }, +// health: { +// amenity: ['doctors', 'hospital', 'pharmacy'], +// }, +// security: { +// amenity: ['police', 'fire_station'], +// }, +// dayToday: { +// amenity: ['waste_basket', 'waste_disposal'], +// shop: ['laundry'], +// }, +// naturalSites: { +// tourism: ['viewpoint'], +// natural: '*', +// }, +// }, +// }; const getOverlays = createCachedSignal({ id, @@ -177,33 +197,144 @@ const currentOverlayKey = () => const currentOverlay = () => getOverlays() ? getOverlays()[currentOverlayKey()] : {}; -export const currentOverlayDefinition = () => - overlayDefinitions[currentOverlayKey()]; +const overlayCategoriesPlusNone = { none: [], ...overlayCategories }; + +export const currentCategory = () => + currentOverlayKey() === 'none' + ? [] + : ['none', ...overlayCategoriesPlusNone[currentOverlayKey()]]; const currentOverlayHighlightedKey = () => currentOverlay() && currentOverlay().highlighted - ? Object.keys(currentOverlay().highlighted)[0] + ? currentOverlay().highlighted : 'none'; export const currentOverlayHighlightedDefinition = () => - currentOverlayDefinition()[currentOverlayHighlightedKey()]; + currentCategory()[currentOverlayHighlightedKey()]; + +export const highlightedTags = () => { + let result = {}; + Object.keys(overlayDefinitions).forEach((tagName) => { + let tagValues = []; + const tag = overlayDefinitions[tagName]; + Object.keys(tag).forEach((tagValue) => { + const catDef = tag[tagValue]; + Object.keys(catDef).forEach((catName) => { + if (catName === currentOverlayKey()) { + const catValue = catDef[catName]; + if (catValue[currentOverlay()?.highlighted]) { + tagValues = [...tagValues, tagValue]; + } + } + }); + }); + if (tagValues.length > 0) { + result[tagName] = tagValues; + } + }); + + // console.log({ + // caller: 'MapTileProviders / highlightedTags', + // result, + // currentOverlayKey: currentOverlayKey(), + // currentOverlay: currentOverlay(), + // }); + return result; +}; + +// createEffect(() => { +// highlightedTags = {}; +// Object.keys(overlayDefinitions).forEach((tagName) => { +// let tagValues = []; +// const tag = overlayDefinitions[tagName]; +// Object.keys(tag).forEach((tagValue) => { +// const catDef = tag[tagValue]; +// Object.keys(catDef).forEach((catName) => { +// if (catName === currentOverlayKey()) { +// const catValue = catDef[catName]; +// if (catValue[currentOverlay()?.highlighted]) { +// tagValues = [...tagValues, tagValue]; +// } +// } +// }); +// }); +// if (tagValues.length > 0) { +// highlightedTags[tagName] = tagValues; +// } +// }); + +// console.log({ +// caller: 'MapTileProviders / createEffect', +// highlightedTags, +// currentOverlayKey: currentOverlayKey(), +// currentOverlay: currentOverlay(), +// }); +// }); + +export const getHighlightedTagValue = (feature: Feature) => { + let result = false; + + Object.keys(highlightedTags()).every((tagName) => { + const value = feature.get(tagName); + const highlightedValues = highlightedTags()[tagName]; + // console.log({ + // caller: 'MapTileProviders / highlightedTag / found', + // feature, + // feature_values: feature.values_, + // highlightedTags, + // tagName, + // tag_value: value, + // highlightedValues, + // }); + + if (value !== undefined && highlightedValues.includes(value)) { + result = value; + return false; + } + return true; + }); + // console.log({ + // caller: 'MapTileProviders / highlightedTag / result', + // feature, + // feature_values: feature.values_, + // highlightedTags, + // result, + // }); + return result; +}; export const isHighlighted = (feature: Feature) => { - const type = feature.get('sub-type'); - const subType = feature.get('class'); - const highlightedType = currentOverlayHighlightedDefinition()[type]; - if (!highlightedType) { - return false; - } + return !!getHighlightedTagValue(feature); +}; + +export const getTagValue = (feature: Feature) => { + let result = false; + Object.keys(overlayDefinitions).every((tagName) => { + const value = feature.get(tagName); + const tagValues = overlayDefinitions[tagName]; + + if (value !== undefined && Object.keys(tagValues).includes(value)) { + // console.log({ + // caller: 'MapTileProviders / tagValue / found', + // feature, + // feature_values: feature.values_, + // highlightedTags, + // tagName, + // tag_value: value, + // highlightedValues, + // }); + result = value; + return false; + } + return true; + }); // console.log({ - // caller: 'Overlays / isHighlighted', + // caller: 'MapTileProviders / isHighlighted / false', // feature, - // type, - // subType, - // currentOverlayHighlightedDefinition: currentOverlayHighlightedDefinition(), - // highlightedType, + // feature_values: feature.values_, + // highlightedTags, // }); - return highlightedType === '*' || highlightedType.includes(subType); + return result; }; const MapTilesProvider: Component<{}> = (props) => { @@ -235,7 +366,7 @@ const MapTilesProvider: Component<{}> = (props) => { overlays: getOverlays(), currentOverlayKey: currentOverlayKey(), currentOverlay: currentOverlay(), - currentOverlayDefinition: currentOverlayDefinition(), + currentOverlayDefinition: currentCategory(), currentOverlayHighlightedKey: currentOverlayHighlightedKey(), }); }); @@ -265,8 +396,7 @@ const MapTilesProvider: Component<{}> = (props) => { value, }); const newOverlays = getOverlays(); - newOverlays[currentOverlayKey()].highlighted = {}; - newOverlays[currentOverlayKey()].highlighted[value] = []; + newOverlays[currentOverlayKey()].highlighted = value; dispatch({ action: 'putOverlays', params: { id, overlays: newOverlays }, @@ -293,21 +423,20 @@ const MapTilesProvider: Component<{}> = (props) => { defaultValue={currentOverlayKey()} onChange={handleOverlayChange} > - + {(p: string) => ( } label={p} /> )} - 0}> - {' '} + 0}>
---
Highlight
- + {(p: string) => ( OlMap | null; @@ -47,12 +48,16 @@ export const Overlays: Component = ({ map }) => { distance: 30, minDistance: 10, geometryFunction: (feature: Feature) => { - // console.log({ - // caller: 'Map / Cluster / geometryFunction', - // feature, - // }); - if (getZoomInteger() < 14 && isHighlighted(feature)) { - return feature.getGeometry(); + if ( + getZoomInteger() < 14 && + feature.get('type') === 'poi' && + isHighlighted(feature) + ) { + // console.log({ + // caller: 'Map / Cluster / geometryFunction / true', + // feature, + // }); + return new Point(getCenter(feature.getGeometry().getExtent())); } return null; }, diff --git a/src/components/overlays/index.ts b/src/components/overlays/index.ts new file mode 100644 index 0000000..898bd3a --- /dev/null +++ b/src/components/overlays/index.ts @@ -0,0 +1 @@ +import { overlayDefinitions, overlayCategories } from './overlay-definitions'; diff --git a/src/components/overlays/overlay-definitions.ts b/src/components/overlays/overlay-definitions.ts new file mode 100644 index 0000000..f2f22a2 --- /dev/null +++ b/src/components/overlays/overlay-definitions.ts @@ -0,0 +1,107 @@ +import { indexOf } from 'lodash'; + +export const overlayDefinitions = { + amenity: { + bar: { hiking: { drinking: true } }, + fast_food: { hiking: { eating: true } }, + food_court: { hiking: { eating: true } }, + pub: { hiking: { eating: true } }, + restaurant: { hiking: { eating: true } }, + cafe: { hiking: { drinking: true } }, + atm: { hiking: { money: true, dayToDay: true } }, + bank: { hiking: { money: true, dayToDay: true } }, + doctors: { hiking: { health: true } }, + hospital: { hiking: { health: true } }, + pharmacy: { hiking: { health: true } }, + police: { hiking: { security: true } }, + fire_station: { hiking: { security: true } }, + drinking_water: { hiking: { drinking: true } }, + water_point: { hiking: { drinking: true } }, + waste_basket: { hiking: { dayToDay: true } }, + waste_disposal: { hiking: { dayToDay: true } }, + vending_machine: { hiking: { dayToDay: true } }, + }, + shop: { + bakery: { hiking: { eating: true } }, + butcher: { hiking: { eating: true } }, + cheese: { hiking: { eating: true } }, + chocolate: { hiking: { eating: true } }, + convenience: { hiking: { eating: true } }, + dairy: { hiking: { eating: true } }, + farm: { hiking: { eating: true } }, + greengrocer: { hiking: { eating: true } }, + health_food: { hiking: { eating: true } }, + pasta: { hiking: { eating: true } }, + pastry: { hiking: { eating: true } }, + seafood: { hiking: { eating: true } }, + water: { hiking: { drinking: true } }, + department_store: { hiking: { dayToDay: true } }, + general: { hiking: { dayToDay: true } }, + mall: { hiking: { dayToDay: true } }, + supermarket: { hiking: { eating: true } }, + wholesale: { hiking: { eating: true } }, + outdoor: { hiking: { material: true } }, + laundry: { hiking: { dayToDay: true } }, + }, + tourism: { + hotel: { hiking: { sleeping: true } }, + alpine_hut: { hiking: { sleeping: true } }, + apartment: { hiking: { sleeping: true } }, + camp_site: { hiking: { sleeping: true } }, + chalet: { hiking: { sleeping: true } }, + guest_house: { hiking: { sleeping: true } }, + hostel: { hiking: { sleeping: true } }, + motel: { hiking: { sleeping: true } }, + wilderness_hut: { hiking: { sleeping: true } }, + viewpoint: { hiking: { naturalSites: true } }, + }, + waterway: { waterfall: { hiking: { naturalSites: true } } }, + natural: { + peak: { hiking: { naturalSites: true } }, + cave_entrance: { hiking: { naturalSites: true } }, + volcano: { hiking: { naturalSites: true } }, + arch: { hiking: { naturalSites: true } }, + arete: { hiking: { naturalSites: true } }, + fumarole: { hiking: { naturalSites: true } }, + rock: { hiking: { naturalSites: true } }, + saddle: { hiking: { naturalSites: true } }, + sinkhole: { hiking: { naturalSites: true } }, + stone: { hiking: { naturalSites: true } }, + glacier: { hiking: { naturalSites: true } }, + spring: { hiking: { naturalSites: true } }, + hot_spring: { hiking: { naturalSites: true } }, + geyser: { hiking: { naturalSites: true } }, + }, +}; + +let _flat: any = []; +Object.values(overlayDefinitions).forEach((category) => { + Object.values(category).forEach((subCategory) => { + _flat = [..._flat, subCategory]; + }); +}); + +type Categories = { string: Set }; + +export let overlayCategories: Categories = {}; + +_flat.forEach((obj: any) => { + Object.keys(obj).forEach((catName: string) => { + const catValue = obj[catName]; + const previous = + overlayCategories[catName] === undefined + ? [] + : overlayCategories[catName]; + overlayCategories[catName] = new Set([ + ...previous, + ...Object.keys(catValue), + ]); + }); +}); + +console.log({ + caller: 'overlay-definitions', + overlayDefinitions, + _flat, + overlayCategories, +});