diff --git a/src/layer.js b/src/layer.js index 59c492d0a..cfb9629dc 100644 --- a/src/layer.js +++ b/src/layer.js @@ -108,7 +108,7 @@ export class MapLayer extends HTMLElement { this._createLayerControlHTML = M._createLayerControlHTML.bind(this); // this._opacity is used to record the current opacity value (with or without updates), // the initial value of this._opacity should be set as opacity attribute value, if exists, or the default value 1.0 - this._opacity = +(this.getAttribute('opacity') || 1.0); + this._opacity = this.opacity || 1.0; const doConnected = this._onAdd.bind(this); this.parentElement .whenReady() @@ -345,25 +345,20 @@ export class MapLayer extends HTMLElement { '_mapmlvectors', '_templatedLayer' ]; - if (layer.validProjection) { - for (let j = 0; j < layerTypes.length; j++) { - let type = layerTypes[j]; - if (this.checked) { - if (type === '_templatedLayer' && mapExtents.length > 0) { - for (let i = 0; i < mapExtents.length; i++) { - totalExtentCount++; - if (mapExtents[i]._validateDisabled()) disabledExtentCount++; - } - } else if (layer[type]) { - // not a templated layer + for (let j = 0; j < layerTypes.length; j++) { + let type = layerTypes[j]; + if (this.checked) { + if (type === '_templatedLayer' && mapExtents.length > 0) { + for (let i = 0; i < mapExtents.length; i++) { totalExtentCount++; - if (!layer[type].isVisible) disabledExtentCount++; + if (mapExtents[i]._validateDisabled()) disabledExtentCount++; } + } else if (layer[type]) { + // not a templated layer + totalExtentCount++; + if (!layer[type].isVisible) disabledExtentCount++; } } - } else { - disabledExtentCount = 1; - totalExtentCount = 1; } // if all extents are not visible / disabled, set layer to disabled if ( diff --git a/src/map-extent.js b/src/map-extent.js index 1bde6a396..9d52f64fe 100644 --- a/src/map-extent.js +++ b/src/map-extent.js @@ -168,9 +168,11 @@ export class MapExtent extends HTMLElement { ); this._changeHandler = this._handleChange.bind(this); this.parentLayer.addEventListener('map-change', this._changeHandler); + this.mapEl = this.parentLayer.closest('mapml-viewer,map[is=web-map]'); + this.mapEl.addEventListener('map-projectionchange', this._changeHandler); // this._opacity is used to record the current opacity value (with or without updates), // the initial value of this._opacity should be set as opacity attribute value, if exists, or the default value 1.0 - this._opacity = +(this.getAttribute('opacity') || 1.0); + this._opacity = this.opacity || 1.0; this._templatedLayer = M.templatedLayer(this._templateVars, { pane: this._layer._container, opacity: this.opacity, @@ -522,6 +524,7 @@ export class MapExtent extends HTMLElement { this._layerControlHTML.remove(); this._map.removeLayer(this._templatedLayer); this.parentLayer.removeEventListener('map-change', this._changeHandler); + this.mapEl.removeEventListener('map-projectionchange', this._changeHandler); delete this._templatedLayer; delete this.parentLayer.bounds; } diff --git a/src/mapml-viewer.js b/src/mapml-viewer.js index cdb0e0100..6eb7a2d63 100644 --- a/src/mapml-viewer.js +++ b/src/mapml-viewer.js @@ -377,9 +377,13 @@ export class MapViewer extends HTMLElement { this.zoomTo(lat, lon, zoom); if (M.options.announceMovement) this._map.announceMovement.enable(); - this.querySelectorAll('layer-').forEach((layer) => { - layer.dispatchEvent(new CustomEvent('map-change')); - }); + // required to delay until map-extent.disabled is correctly set + // which happens as a result of layer-._validateDisabled() + // which happens so much we have to delay until they calls are + // completed + setTimeout(() => { + this.dispatchEvent(new CustomEvent('map-projectionchange')); + }, 0); }); } }; diff --git a/src/mapml/handlers/ContextMenu.js b/src/mapml/handlers/ContextMenu.js index a316d9e4c..62e76bba1 100644 --- a/src/mapml/handlers/ContextMenu.js +++ b/src/mapml/handlers/ContextMenu.js @@ -798,7 +798,6 @@ export var ContextMenu = L.Handler.extend({ .closest('fieldset') .parentNode.parentNode.parentNode.querySelector('span') : elem.querySelector('span'); - if (!elem.layer.validProjection) return; this._layerClicked = elem; this._layerMenu.removeAttribute('hidden'); this._showAtPoint(e.containerPoint, e, this._layerMenu); diff --git a/src/mapml/layers/MapMLLayer.js b/src/mapml/layers/MapMLLayer.js index 809b76f62..670f5ca54 100644 --- a/src/mapml/layers/MapMLLayer.js +++ b/src/mapml/layers/MapMLLayer.js @@ -43,17 +43,6 @@ export var MapMLLayer = L.Layer.extend({ // OR use the extent of the content provided this._initialize(local ? layerEl : mapml); - - // a default extent can't be correctly set without the map to provide - // its bounds , projection, zoom range etc, so if that stuff's not - // established by metadata in the content, we should use map properties - // to set the extent, but the map won't be available until the - // element is attached to the element, wait for that to happen. - // weirdness. options is actually undefined here, despite the hardcoded - // options above. If you use this.options, you see the options defined - // above. Not going to change this, but failing to understand ATM. - // may revisit some time. - this.validProjection = true; }, setZIndex: function (zIndex) { this.options.zIndex = zIndex; @@ -98,11 +87,6 @@ export var MapMLLayer = L.Layer.extend({ }, onAdd: function (map) { - // probably don't need it except for layer context menu usage - if (this._properties && !this._validProjection(map)) { - this.validProjection = false; - return; - } this._map = map; if (this._mapmlvectors) map.addLayer(this._mapmlvectors); @@ -218,26 +202,6 @@ export var MapMLLayer = L.Layer.extend({ } }, - _validProjection: function (map) { - const mapExtents = this._layerEl.querySelectorAll('map-extent'); - let noLayer = false; - if (this._properties && mapExtents.length > 0) { - for (let i = 0; i < mapExtents.length; i++) { - if (mapExtents[i]._templateVars) { - for (let template of mapExtents[i]._templateVars) - if ( - !template.projectionMatch && - template.projection !== map.options.projection - ) { - noLayer = true; // if there's a single template where projections don't match, set noLayer to true - break; - } - } - } - } - return !(noLayer || this.getProjection() !== map.options.projection); - }, - addTo: function (map) { map.addLayer(this); return this; diff --git a/src/web-map.js b/src/web-map.js index 8ad2c1187..3c2bb4553 100644 --- a/src/web-map.js +++ b/src/web-map.js @@ -422,9 +422,13 @@ export class WebMap extends HTMLMapElement { this.zoomTo(lat, lon, zoom); if (M.options.announceMovement) this._map.announceMovement.enable(); - this.querySelectorAll('layer-').forEach((layer) => { - layer.dispatchEvent(new CustomEvent('map-change')); - }); + // required to delay until map-extent.disabled is correctly set + // which happens as a result of layer-._validateDisabled() + // which happens so much we have to delay until they calls are + // completed + setTimeout(() => { + this.dispatchEvent(new CustomEvent('map-projectionchange')); + }, 0); }); } }; diff --git a/test/e2e/api/events/map-projectionchange.html b/test/e2e/api/events/map-projectionchange.html new file mode 100644 index 000000000..3aa7365a9 --- /dev/null +++ b/test/e2e/api/events/map-projectionchange.html @@ -0,0 +1,38 @@ + + + + + map-projectionchange event + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/e2e/api/events/map-projectionchange.test.js b/test/e2e/api/events/map-projectionchange.test.js new file mode 100644 index 000000000..56ef4767e --- /dev/null +++ b/test/e2e/api/events/map-projectionchange.test.js @@ -0,0 +1,38 @@ +import { test, expect, chromium } from '@playwright/test'; + +test.describe('map-projectionchange test ', () => { + let page; + let context; + test.beforeAll(async () => { + context = await chromium.launchPersistentContext(''); + page = + context.pages().find((page) => page.url() === 'about:blank') || + (await context.newPage()); + await page.goto('events/map-projectionchange.html'); + }); + + test.afterAll(async function () { + await context.close(); + }); + + test('do something and test it', async () => { + const viewer = await page.locator('mapml-viewer'); + expect(await viewer.evaluate((v)=>v.projection)).toEqual('OSMTILE'); + expect(await viewer.evaluate((v)=>{ + return v.querySelector('map-extent[units=OSMTILE]').disabled; + })).toBe(false); + expect(await viewer.evaluate((v)=>{ + return v.querySelector('map-extent[units=CBMTILE]').disabled; + })).toBe(true); + await viewer.evaluate(()=> changeProjection()); + await page.waitForTimeout(500); + expect(await viewer.evaluate((v)=> v.projection)).toEqual('CBMTILE'); + expect(await viewer.evaluate((v)=>{ + return v.querySelector('map-extent[units=OSMTILE]').disabled; + })).toBe(true); + expect(await viewer.evaluate((v)=>{ + return v.querySelector('map-extent[units=CBMTILE]').disabled; + })).toBe(false); + + }); +}); diff --git a/test/e2e/layers/multipleExtents.test.js b/test/e2e/layers/multipleExtents.test.js index 0a3574896..c57fa3f84 100644 --- a/test/e2e/layers/multipleExtents.test.js +++ b/test/e2e/layers/multipleExtents.test.js @@ -352,7 +352,7 @@ test.describe('Multiple Extents Bounds Tests', () => { const alabamaExtentItem = page.getByText('alabama_feature'); await expect(alabamaExtentItem).toHaveCount(1); await expect(alabamaExtentItem).toHaveCSS('font-style', 'normal'); - + const alabamaMapExtent = page.locator('map-extent[label=alabama_feature]'); await expect(alabamaMapExtent).toHaveCount(1); await expect(alabamaMapExtent).not.toHaveAttribute('disabled'); diff --git a/test/e2e/mapml-viewer/customTCRS.test.js b/test/e2e/mapml-viewer/customTCRS.test.js index 32ba8a9d6..d3b4f7a07 100644 --- a/test/e2e/mapml-viewer/customTCRS.test.js +++ b/test/e2e/mapml-viewer/customTCRS.test.js @@ -17,7 +17,7 @@ test.describe('Playwright Custom TCRS Tests', () => { }); test('Simple Custom TCRS, tiles load, mismatched layer disabled', async () => { - await page.waitForTimeout(100); + await page.waitForTimeout(500); const misMatchedLayerDisabled = await page.$eval( 'body > mapml-viewer:nth-child(1)', (map) => map.querySelectorAll('layer-')[0].hasAttribute('disabled')