@defra/interactive-map 0.0.24-alpha → 0.0.26-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/dist/css/index.css +1 -1
- package/docs/api/map-style-config.md +69 -2
- package/package.json +4 -3
- package/plugins/beta/draw-ml/dist/css/index.css +21 -1
- package/plugins/beta/scale-bar/dist/css/index.css +31 -1
- package/plugins/search/dist/css/index.css +250 -1
- package/providers/beta/openlayers/dist/esm/im-openlayers-provider.js +1 -1
- package/providers/beta/openlayers/dist/umd/im-openlayers-provider.js +1 -1
- package/providers/beta/openlayers/dist/umd/index.js +1 -1
- package/providers/beta/openlayers/src/appEvents.js +25 -36
- package/providers/beta/openlayers/src/appEvents.test.js +99 -121
- package/providers/beta/openlayers/src/mapEvents.js +2 -4
- package/providers/beta/openlayers/src/mapEvents.test.js +27 -0
- package/providers/beta/openlayers/src/openlayersProvider.js +23 -8
- package/providers/beta/openlayers/src/openlayersProvider.test.js +60 -5
- package/providers/beta/openlayers/src/utils/spatial.js +18 -14
- package/providers/beta/openlayers/src/utils/spatial.test.js +4 -2
- package/providers/beta/openlayers/src/utils/tileLayers.js +133 -0
- package/providers/beta/openlayers/src/utils/tileLayers.test.js +256 -0
- package/providers/maplibre/dist/esm/im-maplibre-provider.js +1 -1
- package/providers/maplibre/dist/umd/im-maplibre-provider.js +1 -1
- package/providers/maplibre/src/utils/maplibreFixes.js +1 -1
- package/src/App/layout/layout.module.scss +1 -0
- package/src/types.js +11 -1
- package/webpack.dev.mjs +8 -4
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! For license information please see index.js.LICENSE.txt */
|
|
2
|
-
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("defra",[],t):"object"==typeof exports?exports.defra=t():(e.defra=e.defra||{},e.defra.openLayersProvider=t())}(this,()=>(()=>{"use strict";var e,t,r={},n={};function o(e){var t=n[e];if(void 0!==t)return t.exports;var i=n[e]={exports:{}};return r[e](i,i.exports,o),i.exports}o.m=r,o.d=(e,t)=>{for(var r in t)o.o(t,r)&&!o.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce((t,r)=>(o.f[r](e,t),t),[])),o.u=e=>"im-openlayers-provider.js",o.miniCssF=e=>{},o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),e={},t="defra.openLayersProvider:",o.l=(r,n,i,a)=>{if(e[r])e[r].push(n);else{var u,c;if(void 0!==i)for(var f=document.getElementsByTagName("script"),p=0;p<f.length;p++){var s=f[p];if(s.getAttribute("src")==r||s.getAttribute("data-webpack")==t+i){u=s;break}}u||(c=!0,(u=document.createElement("script")).charset="utf-8",o.nc&&u.setAttribute("nonce",o.nc),u.setAttribute("data-webpack",t+i),u.src=r),e[r]=[n];var l=(t,n)=>{u.onerror=u.onload=null,clearTimeout(d);var o=e[r];if(delete e[r],u.parentNode&&u.parentNode.removeChild(u),o&&o.forEach(e=>e(n)),t)return t(n)},d=setTimeout(l.bind(null,void 0,{type:"timeout",target:u}),12e4);u.onerror=l.bind(null,u.onerror),u.onload=l.bind(null,u.onload),c&&document.head.appendChild(u)}},o.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{var e;o.g.importScripts&&(e=o.g.location+"");var t=o.g.document;if(!e&&t&&(t.currentScript&&"SCRIPT"===t.currentScript.tagName.toUpperCase()&&(e=t.currentScript.src),!e)){var r=t.getElementsByTagName("script");if(r.length)for(var n=r.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=r[n--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),o.p=e})(),(()=>{var e={57:0};o.f.j=(t,r)=>{var n=o.o(e,t)?e[t]:void 0;if(0!==n)if(n)r.push(n[2]);else{var i=new Promise((r,o)=>n=e[t]=[r,o]);r.push(n[2]=i);var a=o.p+o.u(t),u=new Error;o.l(a,r=>{if(o.o(e,t)&&(0!==(n=e[t])&&(e[t]=void 0),n)){var i=r&&("load"===r.type?"missing":r.type),a=r&&r.target&&r.target.src;u.message="Loading chunk "+t+" failed.\n("+i+": "+a+")",u.name="ChunkLoadError",u.type=i,u.request=a,n[1](u)}},"chunk-"+t,t)}};var t=(t,r)=>{var n,i,[a,u,c]=r,f=0;if(a.some(t=>0!==e[t])){for(n in u)o.o(u,n)&&(o.m[n]=u[n]);c&&c(o)}for(t&&t(r);f<a.length;f++)i=a[f],o.o(e,i)&&e[i]&&e[i][0](),e[i]=0},r=this.webpackChunkdefra_DefraMap=this.webpackChunkdefra_DefraMap||[];r.forEach(t.bind(null,0)),r.push=t.bind(null,r.push.bind(r))})();var i={};function a(){var e,t,r="function"==typeof Symbol?Symbol:{},n=r.iterator||"@@iterator",o=r.toStringTag||"@@toStringTag";function i(r,n,o,i){var a=n&&n.prototype instanceof f?n:f,p=Object.create(a.prototype);return u(p,"_invoke",function(r,n,o){var i,a,u,f=0,p=o||[],s=!1,l={p:0,n:0,v:e,a:d,f:d.bind(e,4),d:function(t,r){return i=t,a=0,u=e,l.n=r,c}};function d(r,n){for(a=r,u=n,t=0;!s&&f&&!o&&t<p.length;t++){var o,i=p[t],d=l.p,v=i[2];r>3?(o=v===n)&&(u=i[(a=i[4])?5:(a=3,3)],i[4]=i[5]=e):i[0]<=d&&((o=r<2&&d<i[1])?(a=0,l.v=n,l.n=i[1]):d<v&&(o=r<3||i[0]>n||n>v)&&(i[4]=r,i[5]=n,l.n=v,a=0))}if(o||r>1)return c;throw s=!0,n}return function(o,p,v){if(f>1)throw TypeError("Generator is already running");for(s&&1===p&&d(p,v),a=p,u=v;(t=a<2?e:u)||!s;){i||(a?a<3?(a>1&&(l.n=-1),d(a,u)):l.n=u:l.v=u);try{if(f=2,i){if(a||(o="next"),t=i[o]){if(!(t=t.call(i,u)))throw TypeError("iterator result is not an object");if(!t.done)return t;u=t.value,a<2&&(a=0)}else 1===a&&(t=i.return)&&t.call(i),a<2&&(u=TypeError("The iterator does not provide a '"+o+"' method"),a=1);i=e}else if((t=(s=l.n<0)?u:r.call(n,l))!==c)break}catch(t){i=e,a=1,u=t}finally{f=1}}return{value:t,done:s}}}(r,o,i),!0),p}var c={};function f(){}function p(){}function s(){}t=Object.getPrototypeOf;var l=[][n]?t(t([][n]())):(u(t={},n,function(){return this}),t),d=s.prototype=f.prototype=Object.create(l);function v(e){return Object.setPrototypeOf?Object.setPrototypeOf(e,s):(e.__proto__=s,u(e,o,"GeneratorFunction")),e.prototype=Object.create(d),e}return p.prototype=s,u(d,"constructor",s),u(s,"constructor",p),p.displayName="GeneratorFunction",u(s,o,"GeneratorFunction"),u(d),u(d,o,"Generator"),u(d,n,function(){return this}),u(d,"toString",function(){return"[object Generator]"}),(a=function(){return{w:i,m:v}})()}function u(e,t,r,n){var o=Object.defineProperty;try{o({},"",{})}catch(e){o=0}u=function(e,t,r,n){function i(t,r){u(e,t,function(e){return this._invoke(t,r,e)})}t?o?o(e,t,{value:r,enumerable:!n,configurable:!n,writable:!n}):e[t]=r:(i("next",0),i("throw",1),i("return",2))},u(e,t,r,n)}function c(e,t,r,n,o,i,a){try{var u=e[i](a),c=u.value}catch(e){return void r(e)}u.done?t(c):Promise.resolve(c).then(n,o)}function f(){var e,t,r=(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}).zoomAlignment;return{checkDeviceCapabilities:function(){return{isSupported:!!document.createElement("canvas").getContext,error:"Canvas is not supported in this browser"}},load:(e=a().m(function e(){var t,n;return a().w(function(e){for(;;)switch(e.n){case 0:return e.n=1,o.e(142).then(o.bind(o,
|
|
2
|
+
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("defra",[],t):"object"==typeof exports?exports.defra=t():(e.defra=e.defra||{},e.defra.openLayersProvider=t())}(this,()=>(()=>{"use strict";var e,t,r={},n={};function o(e){var t=n[e];if(void 0!==t)return t.exports;var i=n[e]={exports:{}};return r[e](i,i.exports,o),i.exports}o.m=r,o.d=(e,t)=>{for(var r in t)o.o(t,r)&&!o.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce((t,r)=>(o.f[r](e,t),t),[])),o.u=e=>"im-openlayers-provider.js",o.miniCssF=e=>{},o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),o.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),e={},t="defra.openLayersProvider:",o.l=(r,n,i,a)=>{if(e[r])e[r].push(n);else{var u,c;if(void 0!==i)for(var f=document.getElementsByTagName("script"),p=0;p<f.length;p++){var s=f[p];if(s.getAttribute("src")==r||s.getAttribute("data-webpack")==t+i){u=s;break}}u||(c=!0,(u=document.createElement("script")).charset="utf-8",o.nc&&u.setAttribute("nonce",o.nc),u.setAttribute("data-webpack",t+i),u.src=r),e[r]=[n];var l=(t,n)=>{u.onerror=u.onload=null,clearTimeout(d);var o=e[r];if(delete e[r],u.parentNode&&u.parentNode.removeChild(u),o&&o.forEach(e=>e(n)),t)return t(n)},d=setTimeout(l.bind(null,void 0,{type:"timeout",target:u}),12e4);u.onerror=l.bind(null,u.onerror),u.onload=l.bind(null,u.onload),c&&document.head.appendChild(u)}},o.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{var e;o.g.importScripts&&(e=o.g.location+"");var t=o.g.document;if(!e&&t&&(t.currentScript&&"SCRIPT"===t.currentScript.tagName.toUpperCase()&&(e=t.currentScript.src),!e)){var r=t.getElementsByTagName("script");if(r.length)for(var n=r.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=r[n--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),o.p=e})(),(()=>{var e={57:0};o.f.j=(t,r)=>{var n=o.o(e,t)?e[t]:void 0;if(0!==n)if(n)r.push(n[2]);else{var i=new Promise((r,o)=>n=e[t]=[r,o]);r.push(n[2]=i);var a=o.p+o.u(t),u=new Error;o.l(a,r=>{if(o.o(e,t)&&(0!==(n=e[t])&&(e[t]=void 0),n)){var i=r&&("load"===r.type?"missing":r.type),a=r&&r.target&&r.target.src;u.message="Loading chunk "+t+" failed.\n("+i+": "+a+")",u.name="ChunkLoadError",u.type=i,u.request=a,n[1](u)}},"chunk-"+t,t)}};var t=(t,r)=>{var n,i,[a,u,c]=r,f=0;if(a.some(t=>0!==e[t])){for(n in u)o.o(u,n)&&(o.m[n]=u[n]);c&&c(o)}for(t&&t(r);f<a.length;f++)i=a[f],o.o(e,i)&&e[i]&&e[i][0](),e[i]=0},r=this.webpackChunkdefra_DefraMap=this.webpackChunkdefra_DefraMap||[];r.forEach(t.bind(null,0)),r.push=t.bind(null,r.push.bind(r))})();var i={};function a(){var e,t,r="function"==typeof Symbol?Symbol:{},n=r.iterator||"@@iterator",o=r.toStringTag||"@@toStringTag";function i(r,n,o,i){var a=n&&n.prototype instanceof f?n:f,p=Object.create(a.prototype);return u(p,"_invoke",function(r,n,o){var i,a,u,f=0,p=o||[],s=!1,l={p:0,n:0,v:e,a:d,f:d.bind(e,4),d:function(t,r){return i=t,a=0,u=e,l.n=r,c}};function d(r,n){for(a=r,u=n,t=0;!s&&f&&!o&&t<p.length;t++){var o,i=p[t],d=l.p,v=i[2];r>3?(o=v===n)&&(u=i[(a=i[4])?5:(a=3,3)],i[4]=i[5]=e):i[0]<=d&&((o=r<2&&d<i[1])?(a=0,l.v=n,l.n=i[1]):d<v&&(o=r<3||i[0]>n||n>v)&&(i[4]=r,i[5]=n,l.n=v,a=0))}if(o||r>1)return c;throw s=!0,n}return function(o,p,v){if(f>1)throw TypeError("Generator is already running");for(s&&1===p&&d(p,v),a=p,u=v;(t=a<2?e:u)||!s;){i||(a?a<3?(a>1&&(l.n=-1),d(a,u)):l.n=u:l.v=u);try{if(f=2,i){if(a||(o="next"),t=i[o]){if(!(t=t.call(i,u)))throw TypeError("iterator result is not an object");if(!t.done)return t;u=t.value,a<2&&(a=0)}else 1===a&&(t=i.return)&&t.call(i),a<2&&(u=TypeError("The iterator does not provide a '"+o+"' method"),a=1);i=e}else if((t=(s=l.n<0)?u:r.call(n,l))!==c)break}catch(t){i=e,a=1,u=t}finally{f=1}}return{value:t,done:s}}}(r,o,i),!0),p}var c={};function f(){}function p(){}function s(){}t=Object.getPrototypeOf;var l=[][n]?t(t([][n]())):(u(t={},n,function(){return this}),t),d=s.prototype=f.prototype=Object.create(l);function v(e){return Object.setPrototypeOf?Object.setPrototypeOf(e,s):(e.__proto__=s,u(e,o,"GeneratorFunction")),e.prototype=Object.create(d),e}return p.prototype=s,u(d,"constructor",s),u(s,"constructor",p),p.displayName="GeneratorFunction",u(s,o,"GeneratorFunction"),u(d),u(d,o,"Generator"),u(d,n,function(){return this}),u(d,"toString",function(){return"[object Generator]"}),(a=function(){return{w:i,m:v}})()}function u(e,t,r,n){var o=Object.defineProperty;try{o({},"",{})}catch(e){o=0}u=function(e,t,r,n){function i(t,r){u(e,t,function(e){return this._invoke(t,r,e)})}t?o?o(e,t,{value:r,enumerable:!n,configurable:!n,writable:!n}):e[t]=r:(i("next",0),i("throw",1),i("return",2))},u(e,t,r,n)}function c(e,t,r,n,o,i,a){try{var u=e[i](a),c=u.value}catch(e){return void r(e)}u.done?t(c):Promise.resolve(c).then(n,o)}function f(){var e,t,r=(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}).zoomAlignment;return{checkDeviceCapabilities:function(){return{isSupported:!!document.createElement("canvas").getContext,error:"Canvas is not supported in this browser"}},load:(e=a().m(function e(){var t,n;return a().w(function(e){for(;;)switch(e.n){case 0:return e.n=1,o.e(142).then(o.bind(o,272));case 1:return t=e.v.default,n={zoomAlignment:r,crs:"EPSG:27700"},e.a(2,{MapProvider:t,mapProviderConfig:n})}},e)}),t=function(){var t=this,r=arguments;return new Promise(function(n,o){var i=e.apply(t,r);function a(e){c(i,n,o,a,u,"next",e)}function u(e){c(i,n,o,a,u,"throw",e)}a(void 0)})},function(){return t.apply(this,arguments)})}}return o.d(i,{default:()=>f}),i.default})());
|
|
@@ -1,50 +1,39 @@
|
|
|
1
|
-
import
|
|
2
|
-
import TileGrid from 'ol/tilegrid/TileGrid.js'
|
|
3
|
-
import TileState from 'ol/TileState.js'
|
|
4
|
-
import { TILE_GRID_RESOLUTIONS, TILE_GRID_ORIGIN, TILE_SIZE } from './defaults.js'
|
|
1
|
+
import { createTileSource, createVectorTileLayer, createOGCVectorTileLayer } from './utils/tileLayers.js'
|
|
5
2
|
|
|
6
|
-
|
|
7
|
-
const result = transformRequest(src, 'Tile') || {}
|
|
8
|
-
const url = result.url || src
|
|
9
|
-
const headers = result.headers || {}
|
|
10
|
-
fetch(url, { headers })
|
|
11
|
-
.then(r => r.blob())
|
|
12
|
-
.then(blob => { tile.getImage().src = URL.createObjectURL(blob) })
|
|
13
|
-
.catch(() => tile.setState(TileState.ERROR))
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function createTileSource (url, transformRequest) {
|
|
17
|
-
const tileGrid = new TileGrid({
|
|
18
|
-
resolutions: TILE_GRID_RESOLUTIONS,
|
|
19
|
-
origin: TILE_GRID_ORIGIN,
|
|
20
|
-
tileSize: TILE_SIZE
|
|
21
|
-
})
|
|
3
|
+
export { createTileSource, createVectorTileLayer, createOGCVectorTileLayer }
|
|
22
4
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
5
|
+
export function attachAppEvents ({ mapProvider, layer, layerType, transformRequest, events, eventBus, map }) {
|
|
6
|
+
const handleSetMapStyle = async (mapStyle) => {
|
|
7
|
+
if (layerType === 'raster') {
|
|
8
|
+
const source = createTileSource(mapStyle.url, transformRequest)
|
|
9
|
+
layer.setSource(source)
|
|
10
|
+
} else if (mapStyle.type === 'ogc-vt') {
|
|
11
|
+
const { layer: newLayer } = await createOGCVectorTileLayer(mapStyle.url, transformRequest, mapStyle)
|
|
12
|
+
map.getLayers().setAt(0, newLayer)
|
|
13
|
+
} else {
|
|
14
|
+
const { layer: newLayer } = await createVectorTileLayer(mapStyle.url, transformRequest, mapStyle)
|
|
15
|
+
map.getLayers().setAt(0, newLayer)
|
|
16
|
+
}
|
|
17
|
+
eventBus.emit(events.MAP_STYLE_CHANGE, { mapStyleId: mapStyle.id })
|
|
18
|
+
}
|
|
27
19
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
tileUrlFunction,
|
|
32
|
-
tileLoadFunction: transformRequest ? createTileLoadFunction(transformRequest) : undefined
|
|
33
|
-
})
|
|
34
|
-
}
|
|
20
|
+
const handleSetPixelRatio = (pixelRatio) => {
|
|
21
|
+
map.setPixelRatio(pixelRatio)
|
|
22
|
+
}
|
|
35
23
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const source = createTileSource(mapStyle.url, transformRequest)
|
|
39
|
-
tileLayer.setSource(source)
|
|
40
|
-
eventBus.emit(events.MAP_STYLE_CHANGE, { mapStyleId: mapStyle.id })
|
|
24
|
+
const handleSizeChange = ({ mapSize }) => {
|
|
25
|
+
mapProvider.mapSize = mapSize
|
|
41
26
|
}
|
|
42
27
|
|
|
43
28
|
eventBus.on(events.MAP_SET_STYLE, handleSetMapStyle)
|
|
29
|
+
eventBus.on(events.MAP_SET_PIXEL_RATIO, handleSetPixelRatio)
|
|
30
|
+
eventBus.on(events.MAP_SIZE_CHANGE, handleSizeChange)
|
|
44
31
|
|
|
45
32
|
return {
|
|
46
33
|
remove () {
|
|
47
34
|
eventBus.off(events.MAP_SET_STYLE, handleSetMapStyle)
|
|
35
|
+
eventBus.off(events.MAP_SET_PIXEL_RATIO, handleSetPixelRatio)
|
|
36
|
+
eventBus.off(events.MAP_SIZE_CHANGE, handleSizeChange)
|
|
48
37
|
}
|
|
49
38
|
}
|
|
50
39
|
}
|
|
@@ -1,140 +1,118 @@
|
|
|
1
|
-
import
|
|
2
|
-
import TileGrid from 'ol/tilegrid/TileGrid.js'
|
|
3
|
-
import { createTileSource, attachAppEvents } from './appEvents.js'
|
|
4
|
-
import { TILE_GRID_RESOLUTIONS, TILE_GRID_ORIGIN, TILE_SIZE } from './defaults.js'
|
|
1
|
+
import { attachAppEvents } from './appEvents.js'
|
|
5
2
|
|
|
6
|
-
|
|
7
|
-
const mockSourceInstance = {}
|
|
8
|
-
|
|
9
|
-
jest.mock('ol/source/XYZ.js', () => ({ __esModule: true, default: jest.fn(() => mockSourceInstance) }))
|
|
10
|
-
jest.mock('ol/tilegrid/TileGrid.js', () => ({ __esModule: true, default: jest.fn(() => mockTileGridInstance) }))
|
|
11
|
-
jest.mock('ol/TileState.js', () => ({ __esModule: true, default: { ERROR: 'error' } }))
|
|
3
|
+
import { createTileSource, createVectorTileLayer } from './utils/tileLayers.js'
|
|
12
4
|
|
|
13
|
-
const
|
|
5
|
+
const mockSourceInstance = {}
|
|
6
|
+
const mockVectorTileLayerInstance = {}
|
|
14
7
|
|
|
15
|
-
|
|
16
|
-
|
|
8
|
+
jest.mock('./utils/tileLayers.js', () => ({
|
|
9
|
+
__esModule: true,
|
|
10
|
+
createTileSource: jest.fn(() => mockSourceInstance),
|
|
11
|
+
createVectorTileLayer: jest.fn(async () => ({ layer: mockVectorTileLayerInstance, source: {} }))
|
|
12
|
+
}))
|
|
17
13
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
})
|
|
25
|
-
})
|
|
14
|
+
const events = {
|
|
15
|
+
MAP_SET_STYLE: 'map:setstyle',
|
|
16
|
+
MAP_STYLE_CHANGE: 'map:stylechange',
|
|
17
|
+
MAP_SET_PIXEL_RATIO: 'map:setpixelratio',
|
|
18
|
+
MAP_SIZE_CHANGE: 'map:sizechange'
|
|
19
|
+
}
|
|
26
20
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
})
|
|
21
|
+
function makeMap () {
|
|
22
|
+
return { getLayers: jest.fn(() => ({ setAt: jest.fn() })), setPixelRatio: jest.fn() }
|
|
23
|
+
}
|
|
31
24
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
expect(tileUrlFunction([7, 3, 5])).toBe('https://tiles.example.com/7/3/5')
|
|
36
|
-
})
|
|
25
|
+
function makeProvider () {
|
|
26
|
+
return { mapSize: 'small' }
|
|
27
|
+
}
|
|
37
28
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const mockImg = { src: null }
|
|
54
|
-
const mockTile = { getImage: () => mockImg, setState: jest.fn() }
|
|
55
|
-
|
|
56
|
-
beforeEach(() => {
|
|
57
|
-
jest.clearAllMocks()
|
|
58
|
-
mockImg.src = null
|
|
59
|
-
global.URL.createObjectURL = jest.fn(() => 'blob:test')
|
|
60
|
-
global.fetch = jest.fn().mockResolvedValue({
|
|
61
|
-
blob: () => Promise.resolve(new Blob())
|
|
29
|
+
describe('attachAppEvents', () => {
|
|
30
|
+
describe('raster', () => {
|
|
31
|
+
function makeSetup () {
|
|
32
|
+
jest.clearAllMocks()
|
|
33
|
+
const layer = { setSource: jest.fn() }
|
|
34
|
+
const eventBus = { on: jest.fn(), off: jest.fn(), emit: jest.fn() }
|
|
35
|
+
const mapProvider = makeProvider()
|
|
36
|
+
const handles = attachAppEvents({ mapProvider, layer, layerType: 'raster', transformRequest: null, events, eventBus, map: makeMap() })
|
|
37
|
+
const handlerFor = (event) => eventBus.on.mock.calls.find(c => c[0] === event)[1]
|
|
38
|
+
return { layer, eventBus, handles, handlerFor, mapProvider }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
it('subscribes to MAP_SET_STYLE on the event bus', () => {
|
|
42
|
+
const { eventBus } = makeSetup()
|
|
43
|
+
expect(eventBus.on).toHaveBeenCalledWith(events.MAP_SET_STYLE, expect.any(Function))
|
|
62
44
|
})
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
function getTileLoadFn (transformRequest) {
|
|
66
|
-
createTileSource('https://tiles.example.com/{z}/{x}/{y}', transformRequest)
|
|
67
|
-
return XYZ.mock.calls[0][0].tileLoadFunction
|
|
68
|
-
}
|
|
69
45
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
it('uses url and headers from transformRequest result', async () => {
|
|
78
|
-
const transformRequest = jest.fn(() => ({ url: 'https://proxied.example.com/tile', headers: { Authorization: 'Bearer abc' } }))
|
|
79
|
-
const fn = getTileLoadFn(transformRequest)
|
|
80
|
-
fn(mockTile, url)
|
|
81
|
-
await flushPromises()
|
|
82
|
-
expect(fetch).toHaveBeenCalledWith('https://proxied.example.com/tile', { headers: { Authorization: 'Bearer abc' } })
|
|
83
|
-
})
|
|
46
|
+
it('on MAP_SET_STYLE: creates a tile source and sets it on the layer', async () => {
|
|
47
|
+
const { layer, handlerFor } = makeSetup()
|
|
48
|
+
await handlerFor(events.MAP_SET_STYLE)({ url: 'https://new.tiles.com/{z}/{x}/{y}', id: 'newStyle' })
|
|
49
|
+
expect(createTileSource).toHaveBeenCalledWith('https://new.tiles.com/{z}/{x}/{y}', null)
|
|
50
|
+
expect(layer.setSource).toHaveBeenCalledWith(mockSourceInstance)
|
|
51
|
+
})
|
|
84
52
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
})
|
|
53
|
+
it('on MAP_SET_STYLE: emits MAP_STYLE_CHANGE with the new style id', async () => {
|
|
54
|
+
const { eventBus, handlerFor } = makeSetup()
|
|
55
|
+
await handlerFor(events.MAP_SET_STYLE)({ url: 'https://new.tiles.com/{z}/{x}/{y}', id: 'newStyle' })
|
|
56
|
+
expect(eventBus.emit).toHaveBeenCalledWith(events.MAP_STYLE_CHANGE, { mapStyleId: 'newStyle' })
|
|
57
|
+
})
|
|
91
58
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
59
|
+
it('remove() unsubscribes all handlers', () => {
|
|
60
|
+
const { eventBus, handles, handlerFor } = makeSetup()
|
|
61
|
+
handles.remove()
|
|
62
|
+
expect(eventBus.off).toHaveBeenCalledWith(events.MAP_SET_STYLE, handlerFor(events.MAP_SET_STYLE))
|
|
63
|
+
expect(eventBus.off).toHaveBeenCalledWith(events.MAP_SET_PIXEL_RATIO, handlerFor(events.MAP_SET_PIXEL_RATIO))
|
|
64
|
+
expect(eventBus.off).toHaveBeenCalledWith(events.MAP_SIZE_CHANGE, handlerFor(events.MAP_SIZE_CHANGE))
|
|
65
|
+
})
|
|
97
66
|
})
|
|
98
67
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
})
|
|
68
|
+
describe('vector', () => {
|
|
69
|
+
function makeSetup () {
|
|
70
|
+
jest.clearAllMocks()
|
|
71
|
+
const setAt = jest.fn()
|
|
72
|
+
const map = { getLayers: jest.fn(() => ({ setAt })), setPixelRatio: jest.fn() }
|
|
73
|
+
const eventBus = { on: jest.fn(), off: jest.fn(), emit: jest.fn() }
|
|
74
|
+
const mapProvider = makeProvider()
|
|
75
|
+
const handles = attachAppEvents({ mapProvider, layer: {}, layerType: 'vector', transformRequest: null, events, eventBus, map })
|
|
76
|
+
const handlerFor = (event) => eventBus.on.mock.calls.find(c => c[0] === event)[1]
|
|
77
|
+
return { map, setAt, eventBus, handles, handlerFor, mapProvider }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
it('on MAP_SET_STYLE: creates a vector tile layer and places it at index 0', async () => {
|
|
81
|
+
const { setAt, handlerFor } = makeSetup()
|
|
82
|
+
const mapStyle = { url: 'https://example.com/styles', id: 'newVts' }
|
|
83
|
+
await handlerFor(events.MAP_SET_STYLE)(mapStyle)
|
|
84
|
+
expect(createVectorTileLayer).toHaveBeenCalledWith(mapStyle.url, null, mapStyle)
|
|
85
|
+
expect(setAt).toHaveBeenCalledWith(0, mockVectorTileLayerInstance)
|
|
86
|
+
})
|
|
107
87
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
function makeSetup () {
|
|
115
|
-
jest.clearAllMocks()
|
|
116
|
-
const tileLayer = { setSource: jest.fn() }
|
|
117
|
-
const eventBus = { on: jest.fn(), off: jest.fn(), emit: jest.fn() }
|
|
118
|
-
const handles = attachAppEvents({ tileLayer, transformRequest: null, events, eventBus })
|
|
119
|
-
const styleHandler = eventBus.on.mock.calls[0][1]
|
|
120
|
-
return { tileLayer, eventBus, handles, styleHandler }
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
it('subscribes to MAP_SET_STYLE on the event bus', () => {
|
|
124
|
-
const { eventBus } = makeSetup()
|
|
125
|
-
expect(eventBus.on).toHaveBeenCalledWith(events.MAP_SET_STYLE, expect.any(Function))
|
|
88
|
+
it('on MAP_SET_STYLE: emits MAP_STYLE_CHANGE with the new style id', async () => {
|
|
89
|
+
const { eventBus, handlerFor } = makeSetup()
|
|
90
|
+
await handlerFor(events.MAP_SET_STYLE)({ url: 'https://example.com/styles', id: 'newVts' })
|
|
91
|
+
expect(eventBus.emit).toHaveBeenCalledWith(events.MAP_STYLE_CHANGE, { mapStyleId: 'newVts' })
|
|
92
|
+
})
|
|
126
93
|
})
|
|
127
94
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
95
|
+
describe('pixel ratio and map size', () => {
|
|
96
|
+
function makeSetup () {
|
|
97
|
+
jest.clearAllMocks()
|
|
98
|
+
const map = makeMap()
|
|
99
|
+
const eventBus = { on: jest.fn(), off: jest.fn(), emit: jest.fn() }
|
|
100
|
+
const mapProvider = makeProvider()
|
|
101
|
+
attachAppEvents({ mapProvider, layer: {}, layerType: 'vector', transformRequest: null, events, eventBus, map })
|
|
102
|
+
const handlerFor = (event) => eventBus.on.mock.calls.find(c => c[0] === event)[1]
|
|
103
|
+
return { map, mapProvider, handlerFor }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
it('on MAP_SET_PIXEL_RATIO: calls map.setPixelRatio with the new ratio', () => {
|
|
107
|
+
const { map, handlerFor } = makeSetup()
|
|
108
|
+
handlerFor(events.MAP_SET_PIXEL_RATIO)(3)
|
|
109
|
+
expect(map.setPixelRatio).toHaveBeenCalledWith(3)
|
|
110
|
+
})
|
|
134
111
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
112
|
+
it('on MAP_SIZE_CHANGE: updates mapProvider.mapSize', () => {
|
|
113
|
+
const { mapProvider, handlerFor } = makeSetup()
|
|
114
|
+
handlerFor(events.MAP_SIZE_CHANGE)({ mapSize: 'large' })
|
|
115
|
+
expect(mapProvider.mapSize).toBe('large')
|
|
116
|
+
})
|
|
139
117
|
})
|
|
140
118
|
})
|
|
@@ -82,8 +82,6 @@ export function attachMapEvents ({
|
|
|
82
82
|
const debouncers = []
|
|
83
83
|
|
|
84
84
|
const view = map.getView()
|
|
85
|
-
const viewMinZoom = view.getMinZoom()
|
|
86
|
-
const viewMaxZoom = view.getMaxZoom()
|
|
87
85
|
|
|
88
86
|
const getMapState = () => {
|
|
89
87
|
if (destroyed) {
|
|
@@ -95,8 +93,8 @@ export function attachMapEvents ({
|
|
|
95
93
|
bounds: getBounds(),
|
|
96
94
|
resolution: getResolution(),
|
|
97
95
|
zoom,
|
|
98
|
-
isAtMaxZoom: zoom + ZOOM_TOLERANCE >=
|
|
99
|
-
isAtMinZoom: zoom - ZOOM_TOLERANCE <=
|
|
96
|
+
isAtMaxZoom: zoom + ZOOM_TOLERANCE >= view.getMaxZoom(),
|
|
97
|
+
isAtMinZoom: zoom - ZOOM_TOLERANCE <= view.getMinZoom()
|
|
100
98
|
}
|
|
101
99
|
}
|
|
102
100
|
|
|
@@ -51,6 +51,7 @@ function setup () {
|
|
|
51
51
|
map.getView = jest.fn(() => view)
|
|
52
52
|
|
|
53
53
|
const source = makeTarget()
|
|
54
|
+
source.changed = jest.fn()
|
|
54
55
|
const eventBus = { emit: jest.fn() }
|
|
55
56
|
|
|
56
57
|
const getZoom = jest.fn(() => 7)
|
|
@@ -172,6 +173,32 @@ describe('attachMapEvents — render and data events', () => {
|
|
|
172
173
|
})
|
|
173
174
|
})
|
|
174
175
|
|
|
176
|
+
describe('attachMapEvents — dynamic zoom bounds', () => {
|
|
177
|
+
it('isAtMaxZoom is updated in emitted event when view max zoom changes', () => {
|
|
178
|
+
const { view, eventBus } = setup()
|
|
179
|
+
view.trigger('change')
|
|
180
|
+
mockDebounceFns[0].fn()
|
|
181
|
+
expect(eventBus.emit).toHaveBeenCalledWith(events.MAP_MOVE_END, expect.objectContaining({ isAtMaxZoom: false }))
|
|
182
|
+
|
|
183
|
+
eventBus.emit.mockClear()
|
|
184
|
+
view.getMaxZoom.mockReturnValue(7)
|
|
185
|
+
mockDebounceFns[0].fn()
|
|
186
|
+
expect(eventBus.emit).toHaveBeenCalledWith(events.MAP_MOVE_END, expect.objectContaining({ isAtMaxZoom: true }))
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
it('isAtMinZoom is updated in emitted event when view min zoom changes', () => {
|
|
190
|
+
const { view, eventBus } = setup()
|
|
191
|
+
view.trigger('change')
|
|
192
|
+
mockDebounceFns[0].fn()
|
|
193
|
+
expect(eventBus.emit).toHaveBeenCalledWith(events.MAP_MOVE_END, expect.objectContaining({ isAtMinZoom: false }))
|
|
194
|
+
|
|
195
|
+
eventBus.emit.mockClear()
|
|
196
|
+
view.getMinZoom.mockReturnValue(7)
|
|
197
|
+
mockDebounceFns[0].fn()
|
|
198
|
+
expect(eventBus.emit).toHaveBeenCalledWith(events.MAP_MOVE_END, expect.objectContaining({ isAtMinZoom: true }))
|
|
199
|
+
})
|
|
200
|
+
})
|
|
201
|
+
|
|
175
202
|
describe('attachMapEvents — remove', () => {
|
|
176
203
|
it('calls cancel on all debouncers', () => {
|
|
177
204
|
const { handles } = setup()
|
|
@@ -7,7 +7,7 @@ import { register } from 'ol/proj/proj4.js'
|
|
|
7
7
|
import { supportedShortcuts, DEFAULTS } from './defaults.js'
|
|
8
8
|
import { getViewResolutionConfig, ZOOM_ALIGNMENT } from './utils/zoom.js'
|
|
9
9
|
import { attachMapEvents } from './mapEvents.js'
|
|
10
|
-
import { attachAppEvents, createTileSource } from './appEvents.js'
|
|
10
|
+
import { attachAppEvents, createTileSource, createVectorTileLayer, createOGCVectorTileLayer } from './appEvents.js'
|
|
11
11
|
import { getAreaDimensions, getCardinalMove, getExtentFromGeoJSON, getPaddedExtent, isGeometryObscured } from './utils/spatial.js'
|
|
12
12
|
|
|
13
13
|
const CRS = 'EPSG:27700'
|
|
@@ -31,19 +31,30 @@ export default class OpenLayersProvider {
|
|
|
31
31
|
this.eventBus = eventBus
|
|
32
32
|
this.capabilities = {
|
|
33
33
|
supportedShortcuts,
|
|
34
|
-
supportsMapSizes:
|
|
34
|
+
supportsMapSizes: true
|
|
35
35
|
}
|
|
36
36
|
Object.assign(this, mapProviderConfig)
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
async initMap (config) {
|
|
40
|
-
const { container, padding, mapStyle, mapSize, center, zoom, bounds, minZoom, maxZoom, transformRequest } = config
|
|
40
|
+
const { container, padding, mapStyle, mapSize, center, zoom, bounds, minZoom, maxZoom, transformRequest, pixelRatio } = config
|
|
41
41
|
this.mapStyleId = mapStyle?.id
|
|
42
42
|
this.mapSize = mapSize
|
|
43
43
|
const { events, eventBus } = this
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
let tileLayer, source
|
|
46
|
+
if (mapStyle.type === 'raster') {
|
|
47
|
+
source = createTileSource(mapStyle.url, transformRequest)
|
|
48
|
+
tileLayer = new TileLayer({ source })
|
|
49
|
+
} else if (mapStyle.type === 'ogc-vt') {
|
|
50
|
+
const vectorTile = await createOGCVectorTileLayer(mapStyle.url, transformRequest, mapStyle)
|
|
51
|
+
tileLayer = vectorTile.layer
|
|
52
|
+
source = vectorTile.source
|
|
53
|
+
} else {
|
|
54
|
+
const vectorTile = await createVectorTileLayer(mapStyle.url, transformRequest, mapStyle)
|
|
55
|
+
tileLayer = vectorTile.layer
|
|
56
|
+
source = vectorTile.source
|
|
57
|
+
}
|
|
47
58
|
|
|
48
59
|
const viewResolutions = getViewResolutionConfig(this.zoomAlignment ?? ZOOM_ALIGNMENT.UK)
|
|
49
60
|
|
|
@@ -63,7 +74,8 @@ export default class OpenLayersProvider {
|
|
|
63
74
|
layers: [tileLayer],
|
|
64
75
|
view,
|
|
65
76
|
controls: [],
|
|
66
|
-
interactions: defaultInteractions({ doubleClickZoom: false })
|
|
77
|
+
interactions: defaultInteractions({ doubleClickZoom: false }),
|
|
78
|
+
pixelRatio
|
|
67
79
|
})
|
|
68
80
|
|
|
69
81
|
if (bounds) {
|
|
@@ -84,10 +96,13 @@ export default class OpenLayersProvider {
|
|
|
84
96
|
})
|
|
85
97
|
|
|
86
98
|
this.appEventHandles = attachAppEvents({
|
|
87
|
-
|
|
99
|
+
mapProvider: this,
|
|
100
|
+
layer: tileLayer,
|
|
101
|
+
layerType: mapStyle.type ?? 'vector',
|
|
88
102
|
transformRequest,
|
|
89
103
|
events,
|
|
90
|
-
eventBus
|
|
104
|
+
eventBus,
|
|
105
|
+
map
|
|
91
106
|
}) || []
|
|
92
107
|
|
|
93
108
|
this.map = map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Mock-prefixed variables are allowed in jest.mock factories by babel-plugin-jest-hoist
|
|
2
2
|
import OpenLayersProvider from './openlayersProvider.js'
|
|
3
3
|
import { attachMapEvents } from './mapEvents.js'
|
|
4
|
-
import { attachAppEvents, createTileSource } from './appEvents.js'
|
|
4
|
+
import { attachAppEvents, createTileSource, createVectorTileLayer } from './appEvents.js'
|
|
5
5
|
import { getExtentFromGeoJSON, isGeometryObscured } from './utils/spatial.js'
|
|
6
6
|
|
|
7
7
|
const mockAnimate = jest.fn()
|
|
@@ -36,6 +36,7 @@ const mockMapInstance = {
|
|
|
36
36
|
|
|
37
37
|
const mockSource = {}
|
|
38
38
|
const mockTileLayer = { setSource: jest.fn() }
|
|
39
|
+
const mockVectorTileLayer = {}
|
|
39
40
|
const mockMapEventHandlesRemove = jest.fn()
|
|
40
41
|
const mockAppEventHandlesRemove = jest.fn()
|
|
41
42
|
|
|
@@ -56,6 +57,7 @@ jest.mock('./mapEvents.js', () => ({
|
|
|
56
57
|
jest.mock('./appEvents.js', () => ({
|
|
57
58
|
__esModule: true,
|
|
58
59
|
createTileSource: jest.fn(() => mockSource),
|
|
60
|
+
createVectorTileLayer: jest.fn(async () => ({ layer: mockVectorTileLayer, source: mockSource })),
|
|
59
61
|
attachAppEvents: jest.fn(() => ({ remove: mockAppEventHandlesRemove }))
|
|
60
62
|
}))
|
|
61
63
|
jest.mock('./utils/spatial.js', () => ({
|
|
@@ -106,9 +108,9 @@ describe('OpenLayersProvider', () => {
|
|
|
106
108
|
expect(provider.eventBus).toBe(eventBus)
|
|
107
109
|
})
|
|
108
110
|
|
|
109
|
-
it('sets capabilities with supportsMapSizes
|
|
111
|
+
it('sets capabilities with supportsMapSizes true and supportedShortcuts array', () => {
|
|
110
112
|
const { provider } = makeProvider()
|
|
111
|
-
expect(provider.capabilities.supportsMapSizes).toBe(
|
|
113
|
+
expect(provider.capabilities.supportsMapSizes).toBe(true)
|
|
112
114
|
expect(Array.isArray(provider.capabilities.supportedShortcuts)).toBe(true)
|
|
113
115
|
})
|
|
114
116
|
|
|
@@ -120,10 +122,10 @@ describe('OpenLayersProvider', () => {
|
|
|
120
122
|
})
|
|
121
123
|
|
|
122
124
|
describe('initMap', () => {
|
|
123
|
-
it('creates tile
|
|
125
|
+
it('creates vector tile layer, OL objects, and emits MAP_READY by default', async () => {
|
|
124
126
|
const { provider, eventBus } = makeProvider()
|
|
125
127
|
await provider.initMap(defaultInitConfig)
|
|
126
|
-
expect(
|
|
128
|
+
expect(createVectorTileLayer).toHaveBeenCalledWith(defaultInitConfig.mapStyle.url, null, defaultInitConfig.mapStyle)
|
|
127
129
|
expect(attachMapEvents).toHaveBeenCalled()
|
|
128
130
|
expect(attachAppEvents).toHaveBeenCalled()
|
|
129
131
|
expect(eventBus.emit).toHaveBeenCalledWith(events.MAP_READY, expect.objectContaining({
|
|
@@ -148,6 +150,59 @@ describe('OpenLayersProvider', () => {
|
|
|
148
150
|
await provider.initMap(defaultInitConfig)
|
|
149
151
|
expect(mockMapOnce).not.toHaveBeenCalled()
|
|
150
152
|
})
|
|
153
|
+
|
|
154
|
+
it('calls createVectorTileLayer and skips createTileSource when mapStyle has no type', async () => {
|
|
155
|
+
const { provider } = makeProvider()
|
|
156
|
+
await provider.initMap(defaultInitConfig)
|
|
157
|
+
expect(createVectorTileLayer).toHaveBeenCalled()
|
|
158
|
+
expect(createTileSource).not.toHaveBeenCalled()
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
it('calls createTileSource and skips createVectorTileLayer when mapStyle.type is "raster"', async () => {
|
|
162
|
+
const { provider, eventBus } = makeProvider()
|
|
163
|
+
const rasterConfig = {
|
|
164
|
+
...defaultInitConfig,
|
|
165
|
+
mapStyle: { id: 'myStyle', url: 'https://tiles.example.com/{z}/{x}/{y}', type: 'raster' }
|
|
166
|
+
}
|
|
167
|
+
await provider.initMap(rasterConfig)
|
|
168
|
+
expect(createTileSource).toHaveBeenCalledWith('https://tiles.example.com/{z}/{x}/{y}', null)
|
|
169
|
+
expect(createVectorTileLayer).not.toHaveBeenCalled()
|
|
170
|
+
expect(eventBus.emit).toHaveBeenCalledWith(events.MAP_READY, expect.objectContaining({ mapStyleId: 'myStyle' }))
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
it('passes layerType "vector" and map to attachAppEvents by default', async () => {
|
|
174
|
+
const { provider } = makeProvider()
|
|
175
|
+
await provider.initMap(defaultInitConfig)
|
|
176
|
+
expect(attachAppEvents).toHaveBeenCalledWith(expect.objectContaining({
|
|
177
|
+
layerType: 'vector',
|
|
178
|
+
map: mockMapInstance
|
|
179
|
+
}))
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
it('passes layerType "raster" to attachAppEvents when mapStyle.type is "raster"', async () => {
|
|
183
|
+
const { provider } = makeProvider()
|
|
184
|
+
const rasterConfig = {
|
|
185
|
+
...defaultInitConfig,
|
|
186
|
+
mapStyle: { id: 'myStyle', url: 'https://tiles.example.com/{z}/{x}/{y}', type: 'raster' }
|
|
187
|
+
}
|
|
188
|
+
await provider.initMap(rasterConfig)
|
|
189
|
+
expect(attachAppEvents).toHaveBeenCalledWith(expect.objectContaining({
|
|
190
|
+
layerType: 'raster'
|
|
191
|
+
}))
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
it('passes pixelRatio to OlMap constructor', async () => {
|
|
195
|
+
const OlMap = require('ol/Map.js').default
|
|
196
|
+
const { provider } = makeProvider()
|
|
197
|
+
await provider.initMap({ ...defaultInitConfig, pixelRatio: 2 })
|
|
198
|
+
expect(OlMap).toHaveBeenCalledWith(expect.objectContaining({ pixelRatio: 2 }))
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
it('passes mapProvider to attachAppEvents', async () => {
|
|
202
|
+
const { provider } = makeProvider()
|
|
203
|
+
await provider.initMap(defaultInitConfig)
|
|
204
|
+
expect(attachAppEvents).toHaveBeenCalledWith(expect.objectContaining({ mapProvider: provider }))
|
|
205
|
+
})
|
|
151
206
|
})
|
|
152
207
|
|
|
153
208
|
describe('destroyMap', () => {
|
|
@@ -99,10 +99,19 @@ const getPaddedExtent = (map) => {
|
|
|
99
99
|
|
|
100
100
|
/**
|
|
101
101
|
* Returns true if the geometry's screen bounding box overlaps the given panel rectangle.
|
|
102
|
-
*
|
|
102
|
+
* getPixelFromCoordinate returns layout-space pixels (unscaled canvas), so we convert them
|
|
103
|
+
* to screen space using the ratio between the viewport's visual size and the canvas size.
|
|
104
|
+
* This accounts for the CSS scale transform applied on medium/large mapSize.
|
|
103
105
|
*/
|
|
104
106
|
const isGeometryObscured = (geojson, panelRect, map) => {
|
|
105
107
|
const containerRect = map.getTargetElement().getBoundingClientRect()
|
|
108
|
+
if (!containerRect.width || !containerRect.height) {
|
|
109
|
+
return false
|
|
110
|
+
}
|
|
111
|
+
const viewportRect = map.getViewport().getBoundingClientRect()
|
|
112
|
+
const scaleX = viewportRect.width / containerRect.width
|
|
113
|
+
const scaleY = viewportRect.height / containerRect.height
|
|
114
|
+
|
|
106
115
|
const [west, south, east, north] = getBboxFromGeoJSON(geojson)
|
|
107
116
|
|
|
108
117
|
const corners = [[west, south], [west, north], [east, south], [east, north]].map(coord => {
|
|
@@ -113,21 +122,16 @@ const isGeometryObscured = (geojson, panelRect, map) => {
|
|
|
113
122
|
return false
|
|
114
123
|
}
|
|
115
124
|
|
|
116
|
-
const screenMinX = Math.min(...corners.map(c => c[0]))
|
|
117
|
-
const screenMaxX = Math.max(...corners.map(c => c[0]))
|
|
118
|
-
const screenMinY = Math.min(...corners.map(c => c[1]))
|
|
119
|
-
const screenMaxY = Math.max(...corners.map(c => c[1]))
|
|
120
|
-
|
|
121
|
-
const panelLeft = panelRect.left - containerRect.left
|
|
122
|
-
const panelTop = panelRect.top - containerRect.top
|
|
123
|
-
const panelRight = panelRect.right - containerRect.left
|
|
124
|
-
const panelBottom = panelRect.bottom - containerRect.top
|
|
125
|
+
const screenMinX = containerRect.left + Math.min(...corners.map(c => c[0])) * scaleX
|
|
126
|
+
const screenMaxX = containerRect.left + Math.max(...corners.map(c => c[0])) * scaleX
|
|
127
|
+
const screenMinY = containerRect.top + Math.min(...corners.map(c => c[1])) * scaleY
|
|
128
|
+
const screenMaxY = containerRect.top + Math.max(...corners.map(c => c[1])) * scaleY
|
|
125
129
|
|
|
126
130
|
return (
|
|
127
|
-
screenMinX <
|
|
128
|
-
screenMaxX >
|
|
129
|
-
screenMinY <
|
|
130
|
-
screenMaxY >
|
|
131
|
+
screenMinX < panelRect.right &&
|
|
132
|
+
screenMaxX > panelRect.left &&
|
|
133
|
+
screenMinY < panelRect.bottom &&
|
|
134
|
+
screenMaxY > panelRect.top
|
|
131
135
|
)
|
|
132
136
|
}
|
|
133
137
|
|