diff --git a/package-lock.json b/package-lock.json index 0917392..415ef88 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ "@suid/vite-plugin": "^0.1.0", "isomorphic-xml2js": "^0.1.3", "lodash": "^4.17.21", + "memoizee": "^0.4.15", "ol": "^7.1.0", "pouchdb": "^7.3.1", "pouchdb-browser": "^7.3.1", @@ -31,6 +32,7 @@ "devDependencies": { "@capacitor/cli": "^3.4.3", "@testing-library/jest-dom": "^5.16.2", + "@types/memoizee": "^0.4.8", "jsdom": ">19.0.0", "solid-testing-library": ">0.3.0", "typescript": "^4.6.2", @@ -1314,6 +1316,12 @@ "pretty-format": "^29.0.0" } }, + "node_modules/@types/memoizee": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/@types/memoizee/-/memoizee-0.4.8.tgz", + "integrity": "sha512-qDpXKGgwKywnQt/64fH1O0LiPA++QGIYeykEUiZ51HymKVRLnUSGcRuF60IfpPeeXiuRwiR/W4y7S5VzbrgLCA==", + "dev": true + }, "node_modules/@types/node": { "version": "18.11.9", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", @@ -1884,6 +1892,15 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" }, + "node_modules/d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dependencies": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, "node_modules/data-urls": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", @@ -2135,6 +2152,50 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es5-ext": { + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "hasInstallScript": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dependencies": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, "node_modules/esbuild": { "version": "0.15.15", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.15.tgz", @@ -2547,6 +2608,15 @@ "node": ">=0.10.0" } }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, "node_modules/event-target-shim": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", @@ -2571,6 +2641,19 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/ext/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==" + }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", @@ -3079,6 +3162,11 @@ "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" + }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -3645,6 +3733,14 @@ "node": ">=10" } }, + "node_modules/lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", + "dependencies": { + "es5-ext": "~0.10.2" + } + }, "node_modules/ltgt": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz", @@ -3672,6 +3768,21 @@ "resolved": "https://registry.npmjs.org/mapbox-to-css-font/-/mapbox-to-css-font-2.4.1.tgz", "integrity": "sha512-QQ/iKiM43DM9+aujTL45Iz5o7gDeSFmy4LPl3HZmNcwCE++NxGazf+yFpY+wCb+YS23sDa1ghpo3zrNFOcHlow==" }, + "node_modules/memoizee": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", + "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.53", + "es6-weak-map": "^2.0.3", + "event-emitter": "^0.3.5", + "is-promise": "^2.2.2", + "lru-queue": "^0.1.0", + "next-tick": "^1.1.0", + "timers-ext": "^0.1.7" + } + }, "node_modules/merge-anything": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/merge-anything/-/merge-anything-5.1.3.tgz", @@ -3821,6 +3932,11 @@ "node": ">=12.13.0" } }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" + }, "node_modules/node-fetch": { "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", @@ -4900,6 +5016,15 @@ "readable-stream": "3" } }, + "node_modules/timers-ext": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", + "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", + "dependencies": { + "es5-ext": "~0.10.46", + "next-tick": "1" + } + }, "node_modules/tinybench": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.3.1.tgz", @@ -4992,6 +5117,11 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" }, + "node_modules/type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" + }, "node_modules/type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", diff --git a/package.json b/package.json index be198cc..bd6f40d 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "devDependencies": { "@capacitor/cli": "^3.4.3", "@testing-library/jest-dom": "^5.16.2", + "@types/memoizee": "^0.4.8", "jsdom": ">19.0.0", "solid-testing-library": ">0.3.0", "typescript": "^4.6.2", @@ -35,6 +36,7 @@ "@suid/vite-plugin": "^0.1.0", "isomorphic-xml2js": "^0.1.3", "lodash": "^4.17.21", + "memoizee": "^0.4.15", "ol": "^7.1.0", "pouchdb": "^7.3.1", "pouchdb-browser": "^7.3.1", diff --git a/src/components/gpx/styles.ts b/src/components/gpx/styles.ts index 9bb5889..087fac3 100644 --- a/src/components/gpx/styles.ts +++ b/src/components/gpx/styles.ts @@ -1,35 +1,14 @@ -import { Circle, Fill, Text, Icon, Stroke, Style } from 'ol/style'; +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-red.svg'; import { Feature } from 'ol'; +import memoize from 'memoizee'; -const trackStrokeStyle = new Stroke({ - color: 'blue', - width: 3, - -}); - -const trtksegStartImageStyle = new Icon({ - src: startIcon, - scale: 0.2, - opacity: 0.6, - anchor: [0.5, 1], -}); - -const trtksegFinishImageStyle = new Icon({ - src: finishIcon, - scale: 0.2, - opacity: 0.6, - anchor: [0.5, 1], -}); - -const wptImageStyle = new Icon({ - src: wptIcon, - scale: 0.1, - opacity: 0.9, - anchor: [0.5, 1], -}); +interface StyleParameters { + type: string; + isSelected: boolean; +} const textStroke = new Stroke({ color: '#fff', @@ -39,36 +18,105 @@ const textFill = new Fill({ color: '#000', }); -const wptTextStyle = (feature: Feature) => - new Text({ - font: '16px Calibri,sans-serif', - text: feature.get('name'), - fill: textFill, - stroke: textStroke, - offsetY: -40, - }); +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: new Icon({ + src: wptIcon, + 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: textFill, + stroke: textStroke, + offsetY: -40, + }), + }, + }, + selected: { + trkseg: { + stroke: new Stroke({ + color: 'red', + width: 3, + }), + }, + }, +}; -const trtksegStyle = new Style({ stroke: trackStrokeStyle }); -const trtksegStartStyle = new Style({ image: trtksegStartImageStyle }); -const trtksegFinishStyle = new Style({ image: trtksegFinishImageStyle }); +const styleRequiresFeature = memoize((type: keyof typeof styles.default) => { + const defaults = styles.default[type]; + const selected = styles.selected[type]; + const all = { ...defaults, ...selected }; + for (const key of Object.keys(all)) { + if (all[key] instanceof Function) { + return true; + } + } + return false; +}); -const wptStyle = (feature: Feature) => - new Style({ image: wptImageStyle, text: wptTextStyle(feature) }); +const getStyle = memoize( + ( + type: keyof typeof styles.default, + isSelected: boolean = false, + params: 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](params); + } + } + return new Style(all); + }, + { length: 3, max: 1024 } +); export const style = (feature: Feature, resolution: number) => { const type = feature.get('type'); - if (type === 'trkseg') { - return trtksegStyle; - } - if (type === 'trkseg-start') { - return trtksegStartStyle; - } - if (type === 'trkseg-finish') { - return trtksegFinishStyle; - } - if (type === 'wpt') { - return wptStyle(feature); + const isSelected = feature.get('isSelected') === true; + console.log({ caller: 'style', type, isSelected }); + if (styleRequiresFeature(type)) { + return getStyle(type, isSelected, feature); } + return getStyle(type, isSelected, null); }; export default style;