import { Fill, Text, Icon, Stroke, Style } from 'ol/style'; import startIcon from '../../icons/flag-start-b-svgrepo-com-green.svg'; import finishIcon from '../../icons/flag-finish-b-o-svgrepo-com-red.svg'; import wptIcon from '../../icons/location-pin-svgrepo-com-green.svg'; import houseIcon from '../../icons/house-svgrepo-com.svg'; import houseFlatIcon from '../../icons/houseFlat-svgrepo-com.svg'; import campingIcon from '../../icons/camping-14-svgrepo-com.svg'; import farmPigIcon from '../../icons/farm-pig-svgrepo-com.svg'; import cheeseIcon from '../../icons/cheese-svgrepo-com.svg'; import trainIcon from '../../icons/train-svgrepo-com.svg'; import picnicIcon from '../../icons/picnic-svgrepo-com.svg'; import caveIcon from '../../icons/cave-entrance-svgrepo-com.svg'; import wptIconSel from '../../icons/location-pin-svgrepo-com-red.svg'; import { Feature } from 'ol'; import memoize from 'memoizee'; import { getState } from '../map'; interface StyleParameters { type: string; isSelected: boolean; } const icons = { house: { src: houseIcon, scale: 1 / 15, opacity: 0.9, anchor: [0.5, 1], }, houseFlat: { src: houseFlatIcon, scale: 1 / 15, opacity: 0.9, anchor: [0.5, 1], }, camping: { src: campingIcon, scale: 2, opacity: 0.9, anchor: [0.5, 1], }, farmPig: { src: farmPigIcon, scale: 1 / 12, opacity: 0.9, anchor: [0.5, 1], }, cheese: { src: cheeseIcon, scale: 3 / 4, opacity: 0.9, anchor: [0.5, 1], }, train: { src: trainIcon, scale: 1 / 10, opacity: 0.9, anchor: [0.5, 1], }, picnic: { src: picnicIcon, scale: 1 / 15, opacity: 0.9, anchor: [0.5, 1], }, cave: { src: caveIcon, scale: 1 / 7, opacity: 0.9, anchor: [0.5, 1], }, }; const wptIconObj = { src: wptIcon, scale: 0.1, opacity: 0.9, anchor: [0.5, 1], }; const textStroke = new Stroke({ color: '#fff', width: 3, }); const textFill = new Fill({ color: '#000', }); const textFillSel = new Fill({ color: 'red', }); const styles = { default: { trkseg: { stroke: new Stroke({ color: 'blue', width: 3, }), }, 'trkseg-start': { image: new Icon({ src: startIcon, scale: 0.2, opacity: 0.6, anchor: [0.5, 1], }), }, 'trkseg-finish': { image: new Icon({ src: finishIcon, scale: 0.2, opacity: 0.6, anchor: [0.5, 1], }), }, wpt: { image: (feature: Feature, zoom: number) => { const minZoom = feature.get('extensions')?.['dyo:minZoom']; if (minZoom && zoom < minZoom) { return null; } const customIcon = icons[feature.get('sym') as keyof typeof icons]; const icon = customIcon ?? wptIconObj; return new Icon(icon); }, text: (feature: Feature, zoom: number) => { const minZoom = feature.get('extensions')?.['dyo:minZoom']; if (minZoom && zoom < minZoom) { return null; } return new Text({ font: '16px Calibri,sans-serif', text: feature.get('name'), fill: textFill, stroke: textStroke, offsetY: -40, }); }, }, }, selected: { trkseg: { stroke: new Stroke({ color: 'red', width: 3, }), }, wpt: { image: new Icon({ src: wptIconSel, scale: 0.1, opacity: 0.9, anchor: [0.5, 1], }), text: (feature: Feature) => new Text({ font: '16px Calibri,sans-serif', text: feature.get('name'), fill: textFillSel, stroke: textStroke, offsetY: -40, }), }, }, }; const styleRequiresFeatureAndZoom = memoize( (type: keyof typeof styles.default) => { const defaults = styles.default[type]; const selected = styles.selected[type]; const all = { ...selected, ...defaults }; for (const key of Object.keys(all)) { if (all[key] instanceof Function && all[key].length > 1) { return true; } } return false; } ); const styleRequiresFeature = memoize((type: keyof typeof styles.default) => { const defaults = styles.default[type]; const selected = styles.selected[type]; const all = { ...selected, ...defaults }; for (const key of Object.keys(all)) { if (all[key] instanceof Function) { return true; } } return false; }); const getStyle = memoize( ( type: keyof typeof styles.default, isSelected: boolean = false, feature: any, zoom: any ) => { const defaults = styles.default[type]; const selected = styles.selected[type]; const all = isSelected ? { ...defaults, ...selected } : { ...defaults }; // console.log({ // caller: 'style / getStyle', // type, // isSelected, // params, // defaults, // selected, // all, // }); for (const key of Object.keys(all)) { if (all[key] instanceof Function) { all[key] = all[key](feature, zoom); } } return new Style(all); }, { length: 4, max: 1024 } ); export const style = (feature: Feature) => { const type = feature.get('type'); const isSelected = feature.get('isSelected') === true; // console.log({ caller: 'style', type, isSelected }); if (styleRequiresFeatureAndZoom(type)) { const zoom = Math.floor(getState().zoom); return getStyle(type, isSelected, feature, zoom); } if (styleRequiresFeature(type)) { return getStyle(type, isSelected, feature, null); } return getStyle(type, isSelected, null, null); }; export default style;