@defra/interactive-map 0.0.14-alpha → 0.0.16-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/css/docusaurus.css +104 -0
- package/assets/images/favicon.svg +1 -0
- package/assets/images/hero.png +0 -0
- package/dist/css/index.css +1 -1
- package/dist/esm/im-core.js +1 -1
- package/dist/umd/im-core.js +1 -1
- package/dist/umd/index.js +1 -1
- package/docs/api/slot-map.svg +1 -0
- package/docs/api/slots.md +89 -6
- package/docs/api.md +1 -1
- package/docs/architecture.md +3 -1
- package/docs/{demo.mdx → examples.mdx} +1 -1
- package/docs/getting-started.md +1 -3
- package/docs/index.mdx +42 -0
- package/docs/plugins/interact.md +176 -55
- package/docs/plugins/map-styles.md +64 -7
- package/docs/plugins/search.md +207 -63
- package/docs/plugins.md +7 -15
- package/docusaurus.config.cjs +34 -34
- package/jest.setup.js +1 -1
- package/package.json +5 -4
- package/plugins/beta/datasets/dist/esm/im-datasets-plugin.js +1 -1
- package/plugins/beta/datasets/dist/umd/im-datasets-plugin.js +1 -1
- package/plugins/beta/datasets/src/DatasetsInit.jsx +1 -1
- package/plugins/beta/datasets/src/api/addDataset.js +1 -1
- package/plugins/beta/datasets/src/api/hideDataset.js +1 -1
- package/plugins/beta/datasets/src/api/hideFeatures.js +1 -1
- package/plugins/beta/datasets/src/api/removeDataset.js +1 -1
- package/plugins/beta/datasets/src/api/showDataset.js +1 -1
- package/plugins/beta/datasets/src/api/showFeatures.js +1 -1
- package/plugins/beta/datasets/src/datasets.js +4 -4
- package/plugins/beta/datasets/src/defaults.js +1 -1
- package/plugins/beta/datasets/src/fetch/createDynamicSource.js +5 -5
- package/plugins/beta/datasets/src/handleSetMapStyle.js +1 -1
- package/plugins/beta/datasets/src/manifest.js +7 -7
- package/plugins/beta/datasets/src/mapLayers.js +2 -3
- package/plugins/beta/datasets/src/panels/Key.jsx +31 -29
- package/plugins/beta/datasets/src/panels/Layers.jsx +8 -9
- package/plugins/beta/datasets/src/utils/bbox.js +4 -4
- package/plugins/beta/draw-es/dist/esm/im-draw-es-plugin.js +1 -1
- package/plugins/beta/draw-es/src/DrawInit.jsx +16 -16
- package/plugins/beta/draw-es/src/api/addFeature.js +3 -3
- package/plugins/beta/draw-es/src/api/deleteFeature.js +3 -3
- package/plugins/beta/draw-es/src/api/editFeature.js +3 -3
- package/plugins/beta/draw-es/src/api/newPolygon.js +3 -3
- package/plugins/beta/draw-es/src/events.js +52 -20
- package/plugins/beta/draw-es/src/events.test.js +301 -0
- package/plugins/beta/draw-es/src/graphic.js +1 -1
- package/plugins/beta/draw-es/src/manifest.js +4 -4
- package/plugins/beta/draw-es/src/reducer.js +1 -1
- package/plugins/beta/draw-es/src/sketchViewModel.js +1 -1
- package/plugins/beta/draw-ml/dist/esm/im-draw-ml-plugin.js +1 -1
- package/plugins/beta/draw-ml/dist/umd/im-draw-ml-plugin.js +1 -1
- package/plugins/beta/draw-ml/src/DrawInit.jsx +49 -52
- package/plugins/beta/draw-ml/src/api/deleteFeature.js +1 -1
- package/plugins/beta/draw-ml/src/api/editFeature.js +8 -5
- package/plugins/beta/draw-ml/src/api/newLine.js +0 -1
- package/plugins/beta/draw-ml/src/api/newPolygon.js +0 -1
- package/plugins/beta/draw-ml/src/api/split.js +4 -4
- package/plugins/beta/draw-ml/src/defaults.js +1 -1
- package/plugins/beta/draw-ml/src/events.js +8 -6
- package/plugins/beta/draw-ml/src/manifest.js +15 -15
- package/plugins/beta/draw-ml/src/mapboxDraw.js +1 -1
- package/plugins/beta/draw-ml/src/mapboxSnap.js +17 -18
- package/plugins/beta/draw-ml/src/modes/createDrawMode.js +31 -31
- package/plugins/beta/draw-ml/src/modes/disabledMode.js +1 -1
- package/plugins/beta/draw-ml/src/modes/editVertex/touchHandlers.js +11 -11
- package/plugins/beta/draw-ml/src/modes/editVertex/undoHandlers.js +7 -7
- package/plugins/beta/draw-ml/src/modes/editVertex/vertexOperations.js +8 -8
- package/plugins/beta/draw-ml/src/modes/editVertex/vertexQueries.js +7 -7
- package/plugins/beta/draw-ml/src/modes/editVertexMode.js +32 -24
- package/plugins/beta/draw-ml/src/reducer.js +1 -1
- package/plugins/beta/draw-ml/src/undoStack.js +4 -4
- package/plugins/beta/draw-ml/src/utils/snapHelpers.js +12 -12
- package/plugins/beta/draw-ml/src/utils/spatial.js +11 -11
- package/plugins/beta/frame/src/Frame.jsx +4 -4
- package/plugins/beta/frame/src/FrameInit.jsx +4 -4
- package/plugins/beta/frame/src/api/addFrame.js +1 -1
- package/plugins/beta/frame/src/api/editFeature.js +1 -1
- package/plugins/beta/frame/src/config.js +1 -1
- package/plugins/beta/frame/src/manifest.js +3 -3
- package/plugins/beta/frame/src/reducer.js +1 -1
- package/plugins/beta/frame/src/utils.js +1 -1
- package/plugins/beta/map-styles/dist/esm/im-map-styles-plugin.js +1 -1
- package/plugins/beta/map-styles/dist/umd/im-map-styles-plugin.js +1 -1
- package/plugins/beta/map-styles/src/MapStyles.jsx +18 -18
- package/plugins/beta/map-styles/src/manifest.js +2 -2
- package/plugins/beta/scale-bar/src/ScaleBar.jsx +5 -5
- package/plugins/beta/use-location/src/UseLocation.jsx +1 -1
- package/plugins/beta/use-location/src/defaults.js +1 -1
- package/plugins/beta/use-location/src/events.js +3 -3
- package/plugins/interact/src/InteractInit.jsx +1 -2
- package/plugins/interact/src/api/enable.js +8 -5
- package/plugins/interact/src/api/enable.test.js +2 -2
- package/plugins/interact/src/api/selectFeature.js +4 -4
- package/plugins/interact/src/api/unselectFeature.js +5 -5
- package/plugins/interact/src/defaults.js +0 -1
- package/plugins/interact/src/events.test.js +15 -15
- package/plugins/interact/src/hooks/useHighlightSync.js +1 -1
- package/plugins/interact/src/hooks/useInteractionHandlers.js +2 -2
- package/plugins/interact/src/hooks/useInteractionHandlers.test.js +5 -5
- package/plugins/interact/src/manifest.js +2 -2
- package/plugins/interact/src/manifest.test.js +3 -4
- package/plugins/interact/src/reducer.js +3 -3
- package/plugins/interact/src/reducer.test.js +0 -1
- package/plugins/interact/src/utils/spatial.js +10 -10
- package/plugins/interact/src/utils/spatial.test.js +14 -14
- package/plugins/search/dist/css/index.css +1 -1
- package/plugins/search/dist/esm/im-search-plugin.js +1 -1
- package/plugins/search/dist/esm/index.js +1 -1
- package/plugins/search/dist/umd/im-search-plugin.js +1 -1
- package/plugins/search/dist/umd/index.js +1 -1
- package/plugins/search/src/Search.jsx +7 -6
- package/plugins/search/src/Search.test.jsx +23 -23
- package/plugins/search/src/components/CloseButton/CloseButton.jsx +15 -15
- package/plugins/search/src/components/CloseButton/CloseButton.test.jsx +2 -2
- package/plugins/search/src/components/Form/Form.jsx +14 -14
- package/plugins/search/src/components/Form/Form.test.jsx +11 -11
- package/plugins/search/src/components/OpenButton/OpenButton.jsx +16 -15
- package/plugins/search/src/components/OpenButton/OpenButton.test.jsx +6 -2
- package/plugins/search/src/components/SubmitButton/SubmitButton.jsx +15 -15
- package/plugins/search/src/components/Suggestions/Suggestions.jsx +6 -6
- package/plugins/search/src/components/Suggestions/Suggestions.test.jsx +4 -4
- package/plugins/search/src/datasets.js +12 -13
- package/plugins/search/src/datasets.test.js +1 -1
- package/plugins/search/src/defaults.js +1 -1
- package/plugins/search/src/events/fetchSuggestions.js +4 -4
- package/plugins/search/src/events/fetchSuggestions.test.js +5 -5
- package/plugins/search/src/events/formHandlers.js +3 -3
- package/plugins/search/src/events/formHandlers.test.js +1 -1
- package/plugins/search/src/events/index.js +2 -2
- package/plugins/search/src/events/index.test.js +2 -2
- package/plugins/search/src/events/inputHandlers.js +4 -4
- package/plugins/search/src/events/inputHandlers.test.js +1 -1
- package/plugins/search/src/events/suggestionHandlers.js +2 -2
- package/plugins/search/src/events/suggestionHandlers.test.js +1 -1
- package/plugins/search/src/index.js +2 -1
- package/plugins/search/src/index.test.js +3 -3
- package/plugins/search/src/manifest.js +6 -4
- package/plugins/search/src/reducer.js +1 -2
- package/plugins/search/src/reducer.test.js +2 -2
- package/plugins/search/src/search.scss +18 -6
- package/plugins/search/src/utils/parseOsNamesResults.js +1 -2
- package/plugins/search/src/utils/parseOsNamesResults.test.js +2 -2
- package/plugins/search/src/utils/updateMap.js +1 -1
- package/plugins/search/src/utils/updateMap.test.js +5 -5
- package/providers/beta/esri/dist/esm/im-esri-provider.js +1 -1
- package/providers/beta/esri/src/esriProvider.js +5 -5
- package/providers/beta/esri/src/utils/coords.js +1 -1
- package/providers/beta/esri/src/utils/esriFixes.js +1 -1
- package/providers/beta/esri/src/utils/query.js +4 -4
- package/providers/beta/esri/src/utils/spatial.js +1 -2
- package/providers/beta/esri/src/utils/spatial.test.js +4 -1
- package/providers/beta/open-names/src/utils/mapToLocationModel.test.js +1 -1
- package/providers/maplibre/src/appEvents.test.js +1 -1
- package/providers/maplibre/src/index.js +1 -1
- package/providers/maplibre/src/index.test.js +3 -5
- package/providers/maplibre/src/mapEvents.test.js +15 -5
- package/providers/maplibre/src/maplibreProvider.test.js +6 -2
- package/providers/maplibre/src/utils/calculateLinearTextSize.js +4 -4
- package/providers/maplibre/src/utils/calculateLinearTextSize.test.js +3 -3
- package/providers/maplibre/src/utils/detectWebgl.test.js +1 -1
- package/providers/maplibre/src/utils/highlightFeatures.js +2 -2
- package/providers/maplibre/src/utils/highlightFeatures.test.js +12 -6
- package/providers/maplibre/src/utils/labels.js +19 -20
- package/providers/maplibre/src/utils/labels.test.js +15 -13
- package/providers/maplibre/src/utils/maplibreFixes.test.js +1 -1
- package/providers/maplibre/src/utils/queryFeatures.js +6 -6
- package/providers/maplibre/src/utils/queryFeatures.test.js +13 -13
- package/providers/maplibre/src/utils/spatial.js +0 -1
- package/providers/maplibre/src/utils/spatial.test.js +26 -27
- package/src/App/components/Panel/Panel.module.scss +1 -0
- package/src/App/hooks/useLayoutMeasurements.js +1 -10
- package/src/App/hooks/useLayoutMeasurements.test.js +2 -5
- package/src/App/hooks/useVisibleGeometry.js +7 -13
- package/src/App/hooks/useVisibleGeometry.test.js +72 -47
- package/src/App/layout/Layout.jsx +0 -3
- package/src/App/layout/Layout.test.jsx +0 -1
- package/src/App/layout/layout.module.scss +11 -77
- package/src/App/registry/pluginRegistry.js +17 -0
- package/src/App/registry/pluginRegistry.test.js +33 -0
- package/src/App/renderer/HtmlElementHost.jsx +0 -1
- package/src/App/renderer/HtmlElementHost.test.jsx +20 -11
- package/src/App/renderer/mapButtons.js +3 -2
- package/src/App/renderer/mapPanels.test.js +3 -3
- package/src/App/renderer/slotHelpers.js +2 -2
- package/src/App/renderer/slotHelpers.test.js +3 -3
- package/src/App/renderer/slots.js +0 -3
- package/src/App/store/AppProvider.jsx +0 -1
- package/src/App/store/appDispatchMiddleware.js +33 -1
- package/src/App/store/appDispatchMiddleware.test.js +250 -222
- package/src/config/appConfig.js +4 -4
- package/src/utils/getSafeZoneInset.js +139 -42
- package/src/utils/getSafeZoneInset.test.js +298 -122
- package/src/utils/logger.js +6 -0
- package/src/utils/logger.test.js +32 -0
- package/webpack.dev.mjs +22 -18
- package/docs/govuk-prototype.md +0 -23
- package/docs/index.md +0 -19
|
@@ -10,11 +10,11 @@ describe('updateMap', () => {
|
|
|
10
10
|
|
|
11
11
|
beforeEach(() => {
|
|
12
12
|
mapProvider = {
|
|
13
|
-
fitToBounds: jest.fn()
|
|
13
|
+
fitToBounds: jest.fn()
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
markers = {
|
|
17
|
-
add: jest.fn()
|
|
17
|
+
add: jest.fn()
|
|
18
18
|
}
|
|
19
19
|
})
|
|
20
20
|
|
|
@@ -25,7 +25,7 @@ describe('updateMap', () => {
|
|
|
25
25
|
point,
|
|
26
26
|
markers,
|
|
27
27
|
showMarker: true,
|
|
28
|
-
markerColor: 'red'
|
|
28
|
+
markerColor: 'red'
|
|
29
29
|
})
|
|
30
30
|
|
|
31
31
|
expect(mapProvider.fitToBounds).toHaveBeenCalledWith(bounds)
|
|
@@ -43,10 +43,10 @@ describe('updateMap', () => {
|
|
|
43
43
|
point,
|
|
44
44
|
markers,
|
|
45
45
|
showMarker: false,
|
|
46
|
-
markerColor: 'blue'
|
|
46
|
+
markerColor: 'blue'
|
|
47
47
|
})
|
|
48
48
|
|
|
49
49
|
expect(mapProvider.fitToBounds).toHaveBeenCalledWith(bounds)
|
|
50
50
|
expect(markers.add).not.toHaveBeenCalled()
|
|
51
51
|
})
|
|
52
|
-
})
|
|
52
|
+
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"@babel/runtime/helpers/defineProperty";import t from"@babel/runtime/helpers/
|
|
1
|
+
import e from"@babel/runtime/helpers/defineProperty";import t from"@babel/runtime/helpers/asyncToGenerator";import r from"@arcgis/core/config.js";import n from"@arcgis/core/layers/support/TileInfo.js";import o from"@arcgis/core/Map.js";import i from"@arcgis/core/views/MapView.js";import a from"@arcgis/core/layers/VectorTileLayer.js";import s from"@arcgis/core/geometry/Point.js";import{when as m,once as l,watch as u}from"@arcgis/core/core/reactiveUtils.js";import c from"@arcgis/core/geometry/Extent.js";var p={animationDuration:200},v=["showKeyboardHelp","selectControl","moveLarge","nudgeMap","zoomLarge","nudgeZoom"];var y=(e,t)=>{var r=null,n=function(){for(var n=arguments.length,o=new Array(n),i=0;i<n;i++)o[i]=arguments[i];clearTimeout(r),r=setTimeout(()=>{e(...o)},t)};return n.cancel=()=>{r&&(clearTimeout(r),r=null)},n};function h(e){var{mapProvider:t,view:r,baseTileLayer:n,events:o,eventBus:i,getZoom:a,getCenter:s,getBounds:c,getResolution:p}=e,v=!1,h=[],d=[],f=e=>{var t=(()=>{if(v||!r||r.destroyed||!r.extent)return null;var{maxZoom:e,minZoom:t}=r.constraints;return{center:s(),bounds:c(),resolution:p(),zoom:a(),isAtMaxZoom:r.zoom+.01>=e,isAtMinZoom:r.zoom-.01<=t}})();t&&i.emit(e,t)};m(()=>n.loaded&&r.resolution>0,()=>f(o.MAP_LOADED)),l(()=>r.ready).then(()=>{v||i.emit(o.MAP_READY,{map:t.map,view:t.view,mapStyleId:t.mapStyleId,mapSize:t.mapSize,crs:t.crs})}),l(()=>r.stationary).then(()=>f(o.MAP_FIRST_IDLE));var g=y(()=>f(o.MAP_MOVE_END),500);d.push(g),h.push(u(()=>[r.interacting,r.animation],e=>{var[t,r]=e;(t||r)&&i.emit(o.MAP_MOVE_START),t||r||g()}));var w,x,b,M=(w=()=>f(o.MAP_MOVE),x=10,b=0,function(){var e=Date.now();e-b>=x&&(b=e,w(...arguments))});d.push(M),h.push(u(()=>r.zoom,M)),h.push(u(()=>r.extent,()=>i.emit(o.MAP_RENDER),{initial:!1}));var E=y(()=>f(o.MAP_DATA_CHANGE),500);d.push(E),h.push(u(()=>r.updating,e=>!e&&E()));var A=null,T=null;return h.push(r.on("pointer-down",e=>{A=e.x,T=e.y})),h.push(r.on("pointer-up",e=>{var n;if(0===e.button&&!(Math.hypot(e.x-A,e.y-T)>6)&&"active"!==(null===(n=t.sketchViewModel)||void 0===n?void 0:n.state)){var a={x:e.x,y:e.y},s=r.toMap(a);s&&i.emit(o.MAP_CLICK,{point:a,coords:[s.x,s.y]})}})),{remove(){v=!0,d.forEach(e=>e.cancel()),h.forEach(e=>e.remove())}}}var d=e=>e?new c({xmin:e[0],ymin:e[1],xmax:e[2],ymax:e[3],spatialReference:{wkid:27700}}):void 0,f=e=>e?new s({x:e[0],y:e[1],spatialReference:{wkid:27700}}):void 0,g=(e,t)=>{if(e)if("FeatureCollection"===e.type)e.features.forEach(e=>g(e,t));else if("Feature"===e.type)g(e.geometry,t);else if("GeometryCollection"===e.type)e.geometries.forEach(e=>g(e,t));else{var r=e=>{Array.isArray(e)&&("number"==typeof e[0]?t.push(e):e.forEach(r))};r(e.coordinates)}},w=e=>{var t=[];g(e,t);var r=t.map(e=>e[0]),n=t.map(e=>e[1]);return d([Math.min(...r),Math.min(...n),Math.max(...r),Math.max(...n)])},x=e=>{var t=1609.344,r=e/t;if(r<.5/t)return"".concat(Math.round(e),"m");if(r<10){var n=Number.parseFloat(r.toFixed(1)),o=1===n?"mile":"miles";return"".concat(n," ").concat(o)}var i=Math.round(r),a=1===i?"mile":"miles";return"".concat(i," ").concat(a)};var b={top:0,right:0,bottom:0,left:0};function M(){return(M=t(function*(e,t){if(!e||!t)return[];var r=e.map.layers.filter(e=>e instanceof a);return r.length?(yield e.hitTest(t,{include:r.toArray()})).results.map(e=>({layerId:e.layer.id,layerTitle:e.layer.title||e.layer.id,type:e.layer.type,geometry:e.graphic.geometry,symbol:e.graphic.symbol})):[]})).apply(this,arguments)}function E(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),r.push.apply(r,n)}return r}function A(t){for(var r=1;r<arguments.length;r++){var n=null!=arguments[r]?arguments[r]:{};r%2?E(Object(n),!0).forEach(function(r){e(t,r,n[r])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(n)):E(Object(n)).forEach(function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(n,e))})}return t}class T{constructor(e){var{mapProviderConfig:t={},events:r,eventBus:n}=e;this.events=r,this.eventBus=n,this.capabilities={supportedShortcuts:v,supportsMapSizes:!1},Object.assign(this,t),this.mapEventHandles=[],this.appEventHandles=[]}initMap(e){var s=this;return t(function*(){var{container:t,padding:m,mapStyle:l,mapSize:u,maxExtent:c}=e;s.mapStyleId=null==l?void 0:l.id,s.mapSize=u;var{events:p,eventBus:v}=s;s.setupConfig&&(yield s.setupConfig(r));var y=new a({id:"baselayer",url:l.url,visible:!0}),g=new o({layers:[y]}),w=c?d(c):null,x=new i({spatialReference:27700,container:t,map:g,zoom:e.zoom,center:f(e.center),maxExtent:c,constraints:{lods:n.create({spatialReference:{wkid:27700}}).lods,snapToZoom:!1,minZoom:e.minZoom,maxZoom:e.maxZoom,maxScale:0,geometry:w,rotationEnabled:!1},ui:{components:[]},popupEnabled:!1});(e=>{if(e){var t=e.querySelector(".esri-view-surface");t.removeAttribute("role"),t.tabIndex=-1,t.style["outline-color"]="transparent",t.style.touchAction="none"}})(x.container),x.padding=m,e.bounds&&x.when(()=>x.goTo(d(e.bounds),{duration:0})),s.mapEventHandles=h({mapProvider:s,view:x,baseTileLayer:y,events:p,eventBus:v,getZoom:s.getZoom.bind(s),getCenter:s.getCenter.bind(s),getBounds:s.getBounds.bind(s),getResolution:s.getResolution.bind(s)}),s.appEventHandles=function(e){var{baseTileLayer:t,events:r,eventBus:n}=e,o=e=>{t.loadStyle(e.url).then(()=>{n.emit(r.MAP_STYLE_CHANGE,{mapStyleId:e.id})})};return n.on(r.MAP_SET_STYLE,o),{remove(){n.off(r.MAP_SET_STYLE,o)}}}({baseTileLayer:y,events:p,eventBus:v})||[],s.map=g,s.view=x,s.baseTileLayer=y})()}destroyMap(){var e,t;null===(e=this.mapEvents)||void 0===e||e.remove(),null===(t=this.appEvents)||void 0===t||t.remove(),this.mapEvents=null,this.appEvents=null,this.view&&(this.view.container=null,this.view.destroy(),this.view=null),this.map&&(this.map.removeAll(),this.map=null)}setView(e){var t,{center:r,zoom:n}=e;null===(t=this.view.animation)||void 0===t||t.destroy();var o={center:r?new s({x:r[0],y:r[1],spatialReference:{wkid:27700}}):this.view.center,zoom:null!=n?n:this.view.zoom};this.view.goTo(A(A({},o),{},{duration:p.animationDuration}))}zoomIn(e){var t;null===(t=this.view.animation)||void 0===t||t.destroy(),this.view.goTo({zoom:this.view.zoom+e,duration:p.animationDuration})}zoomOut(e){var t;null===(t=this.view.animation)||void 0===t||t.destroy(),this.view.goTo({zoom:this.view.zoom-e,duration:p.animationDuration})}panBy(e){var{x:t,y:r}=this.view.toScreen(this.view.center),n={x:t+e[0],y:r+e[1]},o=this.view.toMap(n);this.view.goTo({center:o,duration:p.animationDuration})}fitToBounds(e){var t=Array.isArray(e)?d(e):w(e);this.view.goTo(t,{duration:p.DELAY})}setPadding(e){this.view.padding=e}getCenter(){var e=this.view.center;return[e.x,e.y].map(e=>Math.round(100*e)/100)}getZoom(){return this.view.zoom}getBounds(){var{xmin:e,ymin:t,xmax:r,ymax:n}=this.view.extent;return[e,t,r,n].map(e=>Math.round(100*e)/100)}getFeaturesAtPoint(e,t){return function(e,t){return M.apply(this,arguments)}(this.view,e)}getAreaDimensions(){return(e=>{if(!(e&&e instanceof c))return"";var t=e.xmin,r=e.ymin,n=e.xmax,o=e.ymax-r,i=x(n-t),a=x(o);return"".concat(a," by ").concat(i)})(function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:b;if(!e.container)return null;var{width:r,height:n}=e.container.getBoundingClientRect(),o={x:t.left,y:n-t.bottom},i={x:r-t.right,y:t.top},a=e.toMap(o),s=e.toMap(i);return new c({xmin:a.x,ymin:a.y,xmax:s.x,ymax:s.y,spatialReference:a.spatialReference})}(this.view))}getCardinalMove(e,t){return function(e,t){var[r,n]=e,[o,i]=t,a=o-r,s=i-n,m=[];return Math.abs(s)>.1&&m.push("".concat(s>0?"north":"south"," ").concat(x(Math.abs(s)))),Math.abs(a)>.1&&m.push("".concat(a>0?"east":"west"," ").concat(x(Math.abs(a)))),m.join(", ")}(e,t)}getResolution(){return this.view.resolution}mapToScreen(e){var t=f(e),r=this.view.toScreen(t);return{x:r.x,y:r.y}}screenToMap(e){var t=this.view.toMap(e);return[t.x,t.y]}isGeometryObscured(e,t){return((e,t,r)=>{if(null==r||!r.container)return!1;var n=r.container.getBoundingClientRect(),o=w(e),i=[r.toScreen(new s({x:o.xmin,y:o.ymin,spatialReference:o.spatialReference})),r.toScreen(new s({x:o.xmin,y:o.ymax,spatialReference:o.spatialReference})),r.toScreen(new s({x:o.xmax,y:o.ymin,spatialReference:o.spatialReference})),r.toScreen(new s({x:o.xmax,y:o.ymax,spatialReference:o.spatialReference}))],a=Math.min(...i.map(e=>e.x)),m=Math.max(...i.map(e=>e.x)),l=Math.min(...i.map(e=>e.y)),u=Math.max(...i.map(e=>e.y)),c=t.left-n.left,p=t.top-n.top,v=t.right-n.left,y=t.bottom-n.top;return a<v&&m>c&&l<y&&u>p})(e,t,this.view)}}export{T as default};
|
|
@@ -30,7 +30,7 @@ export default class EsriProvider {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
async initMap (config) {
|
|
33
|
-
const { container, padding, mapStyle, mapSize, maxExtent
|
|
33
|
+
const { container, padding, mapStyle, mapSize, maxExtent } = config
|
|
34
34
|
this.mapStyleId = mapStyle?.id
|
|
35
35
|
this.mapSize = mapSize
|
|
36
36
|
const { events, eventBus } = this
|
|
@@ -49,7 +49,7 @@ export default class EsriProvider {
|
|
|
49
49
|
map,
|
|
50
50
|
zoom: config.zoom,
|
|
51
51
|
center: getPointFromFlatCoords(config.center),
|
|
52
|
-
maxExtent
|
|
52
|
+
maxExtent,
|
|
53
53
|
constraints: {
|
|
54
54
|
lods: TileInfo.create({ spatialReference: { wkid: 27700 } }).lods,
|
|
55
55
|
snapToZoom: false,
|
|
@@ -121,9 +121,9 @@ export default class EsriProvider {
|
|
|
121
121
|
// Side-effects
|
|
122
122
|
// ==========================
|
|
123
123
|
|
|
124
|
-
setView({ center, zoom }) {
|
|
124
|
+
setView ({ center, zoom }) {
|
|
125
125
|
this.view.animation?.destroy()
|
|
126
|
-
const point = center ? new Point({ x: center[0], y: center[1], spatialReference: { wkid: 27700 }}) : this.view.center
|
|
126
|
+
const point = center ? new Point({ x: center[0], y: center[1], spatialReference: { wkid: 27700 } }) : this.view.center
|
|
127
127
|
const target = { center: point, zoom: zoom ?? this.view.zoom }
|
|
128
128
|
this.view.goTo({ ...target, duration: defaults.animationDuration })
|
|
129
129
|
}
|
|
@@ -185,7 +185,7 @@ export default class EsriProvider {
|
|
|
185
185
|
// ==========================
|
|
186
186
|
// Spatial helpers
|
|
187
187
|
// ==========================
|
|
188
|
-
|
|
188
|
+
|
|
189
189
|
getAreaDimensions () {
|
|
190
190
|
return getAreaDimensions(getPaddedExtent(this.view))
|
|
191
191
|
}
|
|
@@ -6,7 +6,7 @@ import VectorTileLayer from '@arcgis/core/layers/VectorTileLayer.js'
|
|
|
6
6
|
* @param {{x: number, y: number}} screenPoint - pixel coordinates relative to the view container
|
|
7
7
|
* @returns {Promise<Array>} Array of objects with info about each vector tile layer hit
|
|
8
8
|
*/
|
|
9
|
-
export async function queryVectorTileFeatures(view, screenPoint) {
|
|
9
|
+
export async function queryVectorTileFeatures (view, screenPoint) {
|
|
10
10
|
if (!view || !screenPoint) {
|
|
11
11
|
return []
|
|
12
12
|
}
|
|
@@ -27,9 +27,9 @@ export async function queryVectorTileFeatures(view, screenPoint) {
|
|
|
27
27
|
return hitResults.results.map(result => ({
|
|
28
28
|
layerId: result.layer.id,
|
|
29
29
|
layerTitle: result.layer.title || result.layer.id,
|
|
30
|
-
type: result.layer.type,
|
|
30
|
+
type: result.layer.type, // 'vectortile'
|
|
31
31
|
geometry: result.graphic.geometry, // usually a point representing the symbol
|
|
32
|
-
symbol: result.graphic.symbol
|
|
32
|
+
symbol: result.graphic.symbol // symbol info (color, style, etc.)
|
|
33
33
|
// Note: feature attributes are not exposed by the Esri SDK
|
|
34
34
|
}))
|
|
35
|
-
}
|
|
35
|
+
}
|
|
@@ -69,7 +69,7 @@ const getAreaDimensions = (extent) => {
|
|
|
69
69
|
* @param {number[]} to - [easting, northing]
|
|
70
70
|
* @returns {string}
|
|
71
71
|
*/
|
|
72
|
-
function getCardinalMove(from, to) {
|
|
72
|
+
function getCardinalMove (from, to) {
|
|
73
73
|
const [x1, y1] = from
|
|
74
74
|
const [x2, y2] = to
|
|
75
75
|
|
|
@@ -125,7 +125,6 @@ const getPaddedExtent = (view, padding = DEFAULT_PADDING) => {
|
|
|
125
125
|
})
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
|
|
129
128
|
/**
|
|
130
129
|
* Returns true if the geometry's screen bounding box overlaps the given panel rectangle.
|
|
131
130
|
* Used to decide whether to pan/zoom when a panel opens over a visibleGeometry target.
|
|
@@ -10,7 +10,10 @@ jest.mock('@arcgis/core/geometry/Point.js', () =>
|
|
|
10
10
|
|
|
11
11
|
jest.mock('./coords.js', () => ({
|
|
12
12
|
getBboxFromGeoJSON: jest.fn(() => ({
|
|
13
|
-
xmin: 100,
|
|
13
|
+
xmin: 100,
|
|
14
|
+
ymin: 200,
|
|
15
|
+
xmax: 500,
|
|
16
|
+
ymax: 600,
|
|
14
17
|
spatialReference: { wkid: 27700 },
|
|
15
18
|
type: 'extent'
|
|
16
19
|
}))
|
|
@@ -14,7 +14,7 @@ import { getWebGL } from './utils/detectWebgl.js'
|
|
|
14
14
|
*
|
|
15
15
|
* @returns {boolean} true if modern syntax is supported, false otherwise
|
|
16
16
|
*/
|
|
17
|
-
function supportsModernMaplibre() {
|
|
17
|
+
function supportsModernMaplibre () {
|
|
18
18
|
return typeof ''.replaceAll === 'function'
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -6,12 +6,8 @@ jest.mock('maplibre-gl', () => ({ VERSION: '3.x' }))
|
|
|
6
6
|
jest.mock('./maplibreProvider.js', () => ({ default: class MockProvider {} }))
|
|
7
7
|
|
|
8
8
|
describe('createMapLibreProvider', () => {
|
|
9
|
-
|
|
10
9
|
beforeEach(() => {
|
|
11
10
|
getWebGL.mockReturnValue({ isEnabled: true, error: null })
|
|
12
|
-
|
|
13
|
-
// Ensure modern support by default
|
|
14
|
-
String.prototype.replaceAll = jest.fn()
|
|
15
11
|
})
|
|
16
12
|
|
|
17
13
|
afterEach(() => {
|
|
@@ -53,11 +49,13 @@ describe('createMapLibreProvider', () => {
|
|
|
53
49
|
})
|
|
54
50
|
|
|
55
51
|
test('checkDeviceCapabilities: no replaceAll support → isSupported false', () => {
|
|
52
|
+
const restoreReplaceAll = String.prototype.replaceAll
|
|
56
53
|
delete String.prototype.replaceAll
|
|
57
54
|
|
|
58
55
|
const result = createMapLibreProvider().checkDeviceCapabilities()
|
|
59
56
|
|
|
60
57
|
expect(result.isSupported).toBe(false)
|
|
58
|
+
String.prototype.replaceAll = restoreReplaceAll // eslint-disable-line
|
|
61
59
|
})
|
|
62
60
|
|
|
63
61
|
test('load returns MapProvider, mapFramework, and merged mapProviderConfig', async () => {
|
|
@@ -76,4 +74,4 @@ describe('createMapLibreProvider', () => {
|
|
|
76
74
|
|
|
77
75
|
expect(mapProviderConfig).toEqual({ crs: 'EPSG:4326' })
|
|
78
76
|
})
|
|
79
|
-
})
|
|
77
|
+
})
|
|
@@ -31,9 +31,15 @@ describe('attachMapEvents', () => {
|
|
|
31
31
|
}
|
|
32
32
|
eventBus = { emit: jest.fn() }
|
|
33
33
|
events = {
|
|
34
|
-
MAP_LOADED: 'loaded',
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
MAP_LOADED: 'loaded',
|
|
35
|
+
MAP_FIRST_IDLE: 'firstIdle',
|
|
36
|
+
MAP_MOVE_START: 'moveStart',
|
|
37
|
+
MAP_MOVE_END: 'moveEnd',
|
|
38
|
+
MAP_MOVE: 'move',
|
|
39
|
+
MAP_RENDER: 'render',
|
|
40
|
+
MAP_DATA_CHANGE: 'dataChange',
|
|
41
|
+
MAP_STYLE_CHANGE: 'styleChange',
|
|
42
|
+
MAP_CLICK: 'click'
|
|
37
43
|
}
|
|
38
44
|
getCenter = jest.fn(() => [0, 0])
|
|
39
45
|
getZoom = jest.fn(() => 10)
|
|
@@ -62,8 +68,12 @@ describe('attachMapEvents', () => {
|
|
|
62
68
|
|
|
63
69
|
test('stateful events emit map state', () => {
|
|
64
70
|
const state = {
|
|
65
|
-
center: [0, 0],
|
|
66
|
-
|
|
71
|
+
center: [0, 0],
|
|
72
|
+
bounds: [[0, 0], [1, 1]],
|
|
73
|
+
resolution: 100,
|
|
74
|
+
zoom: 10,
|
|
75
|
+
isAtMaxZoom: false,
|
|
76
|
+
isAtMinZoom: false
|
|
67
77
|
}
|
|
68
78
|
map.once.mock.calls.find(([e]) => e === 'idle')[1]()
|
|
69
79
|
expect(eventBus.emit).toHaveBeenCalledWith(events.MAP_FIRST_IDLE, state)
|
|
@@ -67,8 +67,12 @@ describe('MapLibreProvider', () => {
|
|
|
67
67
|
})
|
|
68
68
|
|
|
69
69
|
const doInitMap = (p, extra = {}) => p.initMap({
|
|
70
|
-
container: 'div',
|
|
71
|
-
|
|
70
|
+
container: 'div',
|
|
71
|
+
padding: {},
|
|
72
|
+
mapStyle: { url: 'style.json', mapColorScheme: 'dark' },
|
|
73
|
+
center: [0, 0],
|
|
74
|
+
zoom: 5,
|
|
75
|
+
...extra
|
|
72
76
|
})
|
|
73
77
|
|
|
74
78
|
test('constructor spreads mapProviderConfig and sets capabilities', () => {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* @param {number} zoom - The current map zoom level.
|
|
6
6
|
* @returns {number} The interpolated size value.
|
|
7
7
|
*/
|
|
8
|
-
export function calculateLinearTextSize(expression, zoom) {
|
|
8
|
+
export function calculateLinearTextSize (expression, zoom) {
|
|
9
9
|
const { stops } = expression
|
|
10
10
|
|
|
11
11
|
if (stops.length < 2) {
|
|
@@ -40,10 +40,10 @@ export function calculateLinearTextSize(expression, zoom) {
|
|
|
40
40
|
|
|
41
41
|
// 3. Perform Simple Linear Interpolation (LERP)
|
|
42
42
|
// t is the proportion of the distance between Z0 and Z1 that 'zoom' has traveled.
|
|
43
|
-
const t = (zoom - Z0) / (Z1 - Z0)
|
|
44
|
-
|
|
43
|
+
const t = (zoom - Z0) / (Z1 - Z0)
|
|
44
|
+
|
|
45
45
|
// S0 + (S1 - S0) * t
|
|
46
46
|
const interpolatedSize = S0 + (S1 - S0) * t
|
|
47
47
|
|
|
48
48
|
return interpolatedSize
|
|
49
|
-
}
|
|
49
|
+
}
|
|
@@ -23,9 +23,9 @@ describe('calculateLinearTextSize', () => {
|
|
|
23
23
|
|
|
24
24
|
it('works with multiple stops', () => {
|
|
25
25
|
const expr = { stops: [[0, 5], [5, 15], [10, 25]] }
|
|
26
|
-
expect(calculateLinearTextSize(expr, -1)).toBe(5)
|
|
27
|
-
expect(calculateLinearTextSize(expr, 12)).toBe(25)
|
|
26
|
+
expect(calculateLinearTextSize(expr, -1)).toBe(5) // below first
|
|
27
|
+
expect(calculateLinearTextSize(expr, 12)).toBe(25) // above last
|
|
28
28
|
expect(calculateLinearTextSize(expr, 2.5)).toBe(10) // between first two
|
|
29
29
|
expect(calculateLinearTextSize(expr, 7.5)).toBe(20) // between last two
|
|
30
30
|
})
|
|
31
|
-
})
|
|
31
|
+
})
|
|
@@ -68,7 +68,7 @@ const calculateBounds = (LngLatBounds, renderedFeatures) => {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
const bounds = new LngLatBounds()
|
|
71
|
-
|
|
71
|
+
|
|
72
72
|
renderedFeatures.forEach(f => {
|
|
73
73
|
const add = (c) => typeof c[0] === 'number' ? bounds.extend(c) : c.forEach(add)
|
|
74
74
|
add(f.geometry.coordinates)
|
|
@@ -81,7 +81,7 @@ const calculateBounds = (LngLatBounds, renderedFeatures) => {
|
|
|
81
81
|
* Update highlighted features using pure filters.
|
|
82
82
|
* Supports fill + line geometry, multi-source, cleanup, and bounds.
|
|
83
83
|
*/
|
|
84
|
-
export function updateHighlightedFeatures({ LngLatBounds, map, selectedFeatures, stylesMap }) {
|
|
84
|
+
export function updateHighlightedFeatures ({ LngLatBounds, map, selectedFeatures, stylesMap }) {
|
|
85
85
|
if (!map) {
|
|
86
86
|
return null
|
|
87
87
|
}
|
|
@@ -2,7 +2,7 @@ import { updateHighlightedFeatures } from './highlightFeatures.js'
|
|
|
2
2
|
|
|
3
3
|
describe('Highlighting Utils', () => {
|
|
4
4
|
let map
|
|
5
|
-
const LngLatBounds = function() {
|
|
5
|
+
const LngLatBounds = function () {
|
|
6
6
|
this.coords = []
|
|
7
7
|
this.extend = (c) => this.coords.push(c)
|
|
8
8
|
this.getWest = () => Math.min(...this.coords.map(c => c[0]))
|
|
@@ -60,7 +60,7 @@ describe('Highlighting Utils', () => {
|
|
|
60
60
|
// Line 13 verify: map.getLayer returned null and function returned early
|
|
61
61
|
// Line 49-50 verify: Stale sources filtered out
|
|
62
62
|
expect(map.setFilter).toHaveBeenCalledWith('highlight-stale-fill', ['==', 'id', ''])
|
|
63
|
-
|
|
63
|
+
|
|
64
64
|
// Line 124 verify: Clear fill highlight when switching to line geometry
|
|
65
65
|
expect(map.setFilter).toHaveBeenCalledWith('highlight-s2-fill', ['==', 'id', ''])
|
|
66
66
|
|
|
@@ -76,7 +76,9 @@ describe('Highlighting Utils', () => {
|
|
|
76
76
|
map._highlightedSources = undefined
|
|
77
77
|
map.getLayer.mockImplementation(id => id === 'l1' ? { source: 's1', type: 'line' } : null)
|
|
78
78
|
map.queryRenderedFeatures.mockReturnValue([])
|
|
79
|
-
updateHighlightedFeatures({
|
|
79
|
+
updateHighlightedFeatures({
|
|
80
|
+
LngLatBounds,
|
|
81
|
+
map,
|
|
80
82
|
selectedFeatures: [{ featureId: 1, layerId: 'l1' }],
|
|
81
83
|
stylesMap: { l1: { stroke: 'red' } }
|
|
82
84
|
})
|
|
@@ -88,7 +90,9 @@ describe('Highlighting Utils', () => {
|
|
|
88
90
|
map._highlightedSources = new Set(['stale', 's1'])
|
|
89
91
|
map.getLayer.mockImplementation(id => id === 'l1' ? { source: 's1', type: 'line' } : null)
|
|
90
92
|
map.queryRenderedFeatures.mockReturnValue([])
|
|
91
|
-
updateHighlightedFeatures({
|
|
93
|
+
updateHighlightedFeatures({
|
|
94
|
+
LngLatBounds,
|
|
95
|
+
map,
|
|
92
96
|
selectedFeatures: [{ featureId: 1, layerId: 'l1' }],
|
|
93
97
|
stylesMap: { l1: { stroke: 'red' } }
|
|
94
98
|
})
|
|
@@ -105,7 +109,9 @@ describe('Highlighting Utils', () => {
|
|
|
105
109
|
return null
|
|
106
110
|
})
|
|
107
111
|
map.queryRenderedFeatures.mockReturnValue([])
|
|
108
|
-
updateHighlightedFeatures({
|
|
112
|
+
updateHighlightedFeatures({
|
|
113
|
+
LngLatBounds,
|
|
114
|
+
map,
|
|
109
115
|
selectedFeatures: [
|
|
110
116
|
{ featureId: 1, layerId: 'l1' },
|
|
111
117
|
{ featureId: 2, layerId: 'l2' }
|
|
@@ -123,4 +129,4 @@ describe('Highlighting Utils', () => {
|
|
|
123
129
|
const res = updateHighlightedFeatures({ LngLatBounds, map, selectedFeatures: [], stylesMap: {} })
|
|
124
130
|
expect(res).toBeNull()
|
|
125
131
|
})
|
|
126
|
-
})
|
|
132
|
+
})
|
|
@@ -4,7 +4,7 @@ import { calculateLinearTextSize } from './calculateLinearTextSize.js'
|
|
|
4
4
|
const HIGHLIGHT_SCALE_FACTOR = 1.5
|
|
5
5
|
const HIGHLIGHT_LABEL_SOURCE = 'highlighted-label'
|
|
6
6
|
|
|
7
|
-
export function getGeometryCenter(geometry) {
|
|
7
|
+
export function getGeometryCenter (geometry) {
|
|
8
8
|
const { type, coordinates } = geometry
|
|
9
9
|
if (type === 'Point') {
|
|
10
10
|
return coordinates
|
|
@@ -24,7 +24,7 @@ export function getGeometryCenter(geometry) {
|
|
|
24
24
|
return null
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export function evalInterpolate(expr, zoom) {
|
|
27
|
+
export function evalInterpolate (expr, zoom) {
|
|
28
28
|
if (typeof expr === 'number') {
|
|
29
29
|
return expr
|
|
30
30
|
}
|
|
@@ -50,14 +50,14 @@ export function evalInterpolate(expr, zoom) {
|
|
|
50
50
|
return stops[stops.length - 1]
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
export function getHighlightColors(isDarkStyle) {
|
|
53
|
+
export function getHighlightColors (isDarkStyle) {
|
|
54
54
|
if (isDarkStyle) {
|
|
55
55
|
return { text: '#ffffff', halo: '#000000' }
|
|
56
56
|
}
|
|
57
57
|
return { text: '#000000', halo: '#ffffff' }
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
export function extractTextPropertyName(textField) {
|
|
60
|
+
export function extractTextPropertyName (textField) {
|
|
61
61
|
if (typeof textField === 'string') {
|
|
62
62
|
return /^{(.+)}$/.exec(textField)?.[1]
|
|
63
63
|
}
|
|
@@ -67,7 +67,7 @@ export function extractTextPropertyName(textField) {
|
|
|
67
67
|
return null
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
export function buildLabelFromFeature(feature, layer, propName, map) {
|
|
70
|
+
export function buildLabelFromFeature (feature, layer, propName, map) {
|
|
71
71
|
const center = getGeometryCenter(feature.geometry)
|
|
72
72
|
if (!center) {
|
|
73
73
|
return null
|
|
@@ -76,7 +76,7 @@ export function buildLabelFromFeature(feature, layer, propName, map) {
|
|
|
76
76
|
return { text: feature.properties[propName], x: projected.x, y: projected.y, feature, layer }
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
export function buildLabelsFromLayers(map, symbolLayers, features) {
|
|
79
|
+
export function buildLabelsFromLayers (map, symbolLayers, features) {
|
|
80
80
|
return symbolLayers.flatMap(layer => {
|
|
81
81
|
const textField = layer.layout?.['text-field']
|
|
82
82
|
const propName = extractTextPropertyName(textField)
|
|
@@ -90,7 +90,7 @@ export function buildLabelsFromLayers(map, symbolLayers, features) {
|
|
|
90
90
|
})
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
export function findClosestLabel(labels, centerPoint) {
|
|
93
|
+
export function findClosestLabel (labels, centerPoint) {
|
|
94
94
|
return labels.reduce((best, label) => {
|
|
95
95
|
const dist = (label.x - centerPoint.x) ** 2 + (label.y - centerPoint.y) ** 2
|
|
96
96
|
if (!best || dist < best.dist) {
|
|
@@ -100,7 +100,7 @@ export function findClosestLabel(labels, centerPoint) {
|
|
|
100
100
|
}, null)?.label
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
export function createHighlightLayerConfig(sourceLayer, highlightSize, colors) {
|
|
103
|
+
export function createHighlightLayerConfig (sourceLayer, highlightSize, colors) {
|
|
104
104
|
return {
|
|
105
105
|
id: `highlight-${sourceLayer.id}`,
|
|
106
106
|
type: sourceLayer.type,
|
|
@@ -123,18 +123,17 @@ export function createHighlightLayerConfig(sourceLayer, highlightSize, colors) {
|
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
export function removeHighlightLayer(map, state) {
|
|
126
|
+
export function removeHighlightLayer (map, state) {
|
|
127
127
|
if (state.highlightLayerId && map.getLayer(state.highlightLayerId)) {
|
|
128
128
|
try {
|
|
129
129
|
map.removeLayer(state.highlightLayerId)
|
|
130
|
-
}
|
|
131
|
-
catch {}
|
|
130
|
+
} catch {}
|
|
132
131
|
state.highlightLayerId = null
|
|
133
132
|
state.highlightedExpr = null
|
|
134
133
|
}
|
|
135
134
|
}
|
|
136
135
|
|
|
137
|
-
export function applyHighlight(map, labelData, state) {
|
|
136
|
+
export function applyHighlight (map, labelData, state) {
|
|
138
137
|
if (!labelData?.feature?.layer) {
|
|
139
138
|
return
|
|
140
139
|
}
|
|
@@ -156,7 +155,7 @@ export function applyHighlight(map, labelData, state) {
|
|
|
156
155
|
map.moveLayer(state.highlightLayerId)
|
|
157
156
|
}
|
|
158
157
|
|
|
159
|
-
export function navigateToNextLabel(direction, state) {
|
|
158
|
+
export function navigateToNextLabel (direction, state) {
|
|
160
159
|
if (!state.currentPixel) {
|
|
161
160
|
return null
|
|
162
161
|
}
|
|
@@ -174,19 +173,19 @@ export function navigateToNextLabel(direction, state) {
|
|
|
174
173
|
return state.labels[filtered[nextFilteredIndex].index]
|
|
175
174
|
}
|
|
176
175
|
|
|
177
|
-
function initLabelSource(map) {
|
|
176
|
+
function initLabelSource (map) {
|
|
178
177
|
if (!map.getSource(HIGHLIGHT_LABEL_SOURCE)) {
|
|
179
178
|
map.addSource(HIGHLIGHT_LABEL_SOURCE, { type: 'geojson', data: { type: 'FeatureCollection', features: [] } })
|
|
180
179
|
}
|
|
181
180
|
}
|
|
182
181
|
|
|
183
|
-
function setLineCenterPlacement(map) {
|
|
182
|
+
function setLineCenterPlacement (map) {
|
|
184
183
|
map.getStyle().layers
|
|
185
184
|
.filter(l => l.layout?.['symbol-placement'] === 'line')
|
|
186
185
|
.forEach(l => map.setLayoutProperty(l.id, 'symbol-placement', 'line-center'))
|
|
187
186
|
}
|
|
188
187
|
|
|
189
|
-
function setSymbolTextOpacity(map) {
|
|
188
|
+
function setSymbolTextOpacity (map) {
|
|
190
189
|
map.getStyle().layers
|
|
191
190
|
.filter(l => l.type === 'symbol')
|
|
192
191
|
.forEach(layer => {
|
|
@@ -194,7 +193,7 @@ function setSymbolTextOpacity(map) {
|
|
|
194
193
|
})
|
|
195
194
|
}
|
|
196
195
|
|
|
197
|
-
export function createMapLabelNavigator(map, mapColorScheme, events, eventBus) {
|
|
196
|
+
export function createMapLabelNavigator (map, mapColorScheme, events, eventBus) {
|
|
198
197
|
const state = {
|
|
199
198
|
isDarkStyle: mapColorScheme === 'dark',
|
|
200
199
|
labels: [],
|
|
@@ -221,13 +220,13 @@ export function createMapLabelNavigator(map, mapColorScheme, events, eventBus) {
|
|
|
221
220
|
}
|
|
222
221
|
})
|
|
223
222
|
|
|
224
|
-
function refreshLabels() {
|
|
223
|
+
function refreshLabels () {
|
|
225
224
|
const symbolLayers = map.getStyle().layers.filter(l => l.type === 'symbol')
|
|
226
225
|
const features = map.queryRenderedFeatures({ layers: symbolLayers.map(l => l.id) })
|
|
227
226
|
state.labels = buildLabelsFromLayers(map, symbolLayers, features)
|
|
228
227
|
}
|
|
229
228
|
|
|
230
|
-
function highlightCenter() {
|
|
229
|
+
function highlightCenter () {
|
|
231
230
|
refreshLabels()
|
|
232
231
|
if (!state.labels.length) {
|
|
233
232
|
return null
|
|
@@ -239,7 +238,7 @@ export function createMapLabelNavigator(map, mapColorScheme, events, eventBus) {
|
|
|
239
238
|
return `${closest.text} (${closest.layer.id})`
|
|
240
239
|
}
|
|
241
240
|
|
|
242
|
-
function highlightNext(direction) {
|
|
241
|
+
function highlightNext (direction) {
|
|
243
242
|
refreshLabels()
|
|
244
243
|
if (!state.labels.length) {
|
|
245
244
|
return null
|
|
@@ -5,14 +5,13 @@ import {
|
|
|
5
5
|
navigateToNextLabel, createMapLabelNavigator
|
|
6
6
|
} from './labels.js'
|
|
7
7
|
|
|
8
|
-
jest.mock('./spatial.js', () => ({ spatialNavigate: jest.fn() }))
|
|
9
|
-
jest.mock('./calculateLinearTextSize.js', () => ({ calculateLinearTextSize: jest.fn(() => 12) }))
|
|
10
|
-
|
|
11
8
|
import { spatialNavigate } from './spatial.js'
|
|
12
9
|
import { calculateLinearTextSize } from './calculateLinearTextSize.js'
|
|
13
10
|
|
|
14
|
-
|
|
11
|
+
jest.mock('./spatial.js', () => ({ spatialNavigate: jest.fn() }))
|
|
12
|
+
jest.mock('./calculateLinearTextSize.js', () => ({ calculateLinearTextSize: jest.fn(() => 12) }))
|
|
15
13
|
|
|
14
|
+
describe('labels utils', () => {
|
|
16
15
|
test('getGeometryCenter all geometry types', () => {
|
|
17
16
|
expect(getGeometryCenter({ type: 'Point', coordinates: [1, 2] })).toEqual([1, 2])
|
|
18
17
|
expect(getGeometryCenter({ type: 'MultiPoint', coordinates: [[3, 4]] })).toEqual([3, 4])
|
|
@@ -30,9 +29,9 @@ describe('labels utils', () => {
|
|
|
30
29
|
expect(evalInterpolate(['literal', 'x'], 10)).toBe(12)
|
|
31
30
|
expect(() => evalInterpolate(['interpolate', ['linear'], ['get', 'p'], 5, 10], 10)).toThrow()
|
|
32
31
|
const expr = ['interpolate', ['linear'], ['zoom'], 5, 10, 10, 20]
|
|
33
|
-
expect(evalInterpolate(expr, 3)).toBe(10)
|
|
34
|
-
expect(evalInterpolate(expr, 7.5)).toBe(15)
|
|
35
|
-
expect(evalInterpolate(expr, 15)).toBe(20)
|
|
32
|
+
expect(evalInterpolate(expr, 3)).toBe(10) // zoom <= z0
|
|
33
|
+
expect(evalInterpolate(expr, 7.5)).toBe(15) // interpolated
|
|
34
|
+
expect(evalInterpolate(expr, 15)).toBe(20) // beyond last stop
|
|
36
35
|
})
|
|
37
36
|
|
|
38
37
|
test('getHighlightColors', () => {
|
|
@@ -77,7 +76,7 @@ describe('labels utils', () => {
|
|
|
77
76
|
|
|
78
77
|
test('findClosestLabel: empty → undefined; returns closest; skips farther', () => {
|
|
79
78
|
expect(findClosestLabel([], { x: 0, y: 0 })).toBeUndefined()
|
|
80
|
-
const labels = [{ x: 2, y: 0 }, { x: 10, y: 0 }]
|
|
79
|
+
const labels = [{ x: 2, y: 0 }, { x: 10, y: 0 }] // closer first → second hits false branch
|
|
81
80
|
expect(findClosestLabel(labels, { x: 0, y: 0 })).toBe(labels[0])
|
|
82
81
|
})
|
|
83
82
|
|
|
@@ -109,9 +108,12 @@ describe('labels utils', () => {
|
|
|
109
108
|
|
|
110
109
|
test('applyHighlight: early returns without feature.layer; applies otherwise', () => {
|
|
111
110
|
const map = {
|
|
112
|
-
getLayer: jest.fn(),
|
|
111
|
+
getLayer: jest.fn(),
|
|
112
|
+
removeLayer: jest.fn(),
|
|
113
113
|
getSource: jest.fn(() => ({ setData: jest.fn() })),
|
|
114
|
-
getZoom: jest.fn(() => 10),
|
|
114
|
+
getZoom: jest.fn(() => 10),
|
|
115
|
+
addLayer: jest.fn(),
|
|
116
|
+
moveLayer: jest.fn()
|
|
115
117
|
}
|
|
116
118
|
const state = { highlightLayerId: null, highlightedExpr: null, isDarkStyle: false }
|
|
117
119
|
applyHighlight(map, null, state)
|
|
@@ -132,9 +134,9 @@ describe('labels utils', () => {
|
|
|
132
134
|
currentPixel: { x: 1, y: 1 }, labels: [{ x: 1, y: 1 }]
|
|
133
135
|
})).toBeNull()
|
|
134
136
|
const state = { currentPixel: { x: 0, y: 0 }, labels: [{ x: 0, y: 0 }, { x: 5, y: 5 }] }
|
|
135
|
-
spatialNavigate.mockReturnValue(-1)
|
|
137
|
+
spatialNavigate.mockReturnValue(-1) // out of range → use 0
|
|
136
138
|
expect(navigateToNextLabel('ArrowRight', state)).toBe(state.labels[1])
|
|
137
|
-
spatialNavigate.mockReturnValue(0)
|
|
139
|
+
spatialNavigate.mockReturnValue(0) // valid index
|
|
138
140
|
expect(navigateToNextLabel('ArrowRight', state)).toBe(state.labels[1])
|
|
139
141
|
})
|
|
140
142
|
|
|
@@ -212,7 +214,7 @@ describe('labels utils', () => {
|
|
|
212
214
|
})
|
|
213
215
|
|
|
214
216
|
test('initLabelSource skips addSource when source exists; MAP_SET_STYLE triggers re-init', () => {
|
|
215
|
-
map.getSource.mockReset().mockReturnValue({ setData: jest.fn() })
|
|
217
|
+
map.getSource.mockReset().mockReturnValue({ setData: jest.fn() }) // source always exists
|
|
216
218
|
const eventBus = { on: jest.fn() }
|
|
217
219
|
createMapLabelNavigator(map, 'light', { MAP_SET_STYLE: 'set-style' }, eventBus)
|
|
218
220
|
expect(map.addSource).not.toHaveBeenCalled()
|