From e372cc424f61d62ec7b578dc65893f5e48334a66 Mon Sep 17 00:00:00 2001 From: prushfor Date: Fri, 10 Nov 2023 16:43:09 -0500 Subject: [PATCH 1/3] Add map-projectionchange event. Delete map projection attrChgCallbk from triggering map-change event. Allow map-extent to react to map-projectionchange event, enable/disable according to projection match. Change initialization logic for opacity, so that layer- and map-extent opacity value is maintained through map-projectionchange event. Remove MapMLLayer.validProjection attribute and flawed logic. Prettier formatting change only in multipleExtents.test.js Remove use of validProjection by layer context menu, was wrong anyway(?) Add waitfortimeout of 500ms in customTCRS.test.js (100ms was not enough) Add test for simple projection change. --- src/layer.js | 27 ++++++------- src/map-extent.js | 5 ++- src/mapml-viewer.js | 10 +++-- src/mapml/handlers/ContextMenu.js | 1 - src/mapml/layers/MapMLLayer.js | 36 ------------------ src/web-map.js | 10 +++-- test/e2e/api/events/map-projectionchange.html | 38 +++++++++++++++++++ .../api/events/map-projectionchange.test.js | 38 +++++++++++++++++++ test/e2e/layers/multipleExtents.test.js | 2 +- test/e2e/mapml-viewer/customTCRS.test.js | 2 +- 10 files changed, 107 insertions(+), 62 deletions(-) create mode 100644 test/e2e/api/events/map-projectionchange.html create mode 100644 test/e2e/api/events/map-projectionchange.test.js 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 @@ + + + + + Codestin Search App + + + + + + + + + + + + + + + + + + + + + + + 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') From df64f96ddcc9f75491b82c243dc616ef31eb848b Mon Sep 17 00:00:00 2001 From: Peter Rushforth Date: Mon, 13 Nov 2023 19:34:44 -0500 Subject: [PATCH 2/3] Add test for empty map history after map-projectionchange event --- .../api/events/map-projectionchange.test.js | 55 +++++++++++++------ 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/test/e2e/api/events/map-projectionchange.test.js b/test/e2e/api/events/map-projectionchange.test.js index 56ef4767e..ab4393cb6 100644 --- a/test/e2e/api/events/map-projectionchange.test.js +++ b/test/e2e/api/events/map-projectionchange.test.js @@ -8,6 +8,10 @@ test.describe('map-projectionchange test ', () => { page = context.pages().find((page) => page.url() === 'about:blank') || (await context.newPage()); + + }); + + test.beforeEach(async function() { await page.goto('events/map-projectionchange.html'); }); @@ -15,24 +19,41 @@ test.describe('map-projectionchange test ', () => { await context.close(); }); - test('do something and test it', async () => { + test('Multiple map-extents in different projections adapt to map-projectionchange', 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()); + 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); - + 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); + }); + test('History is empty after map-projectionchange', async () => { + const viewer = await page.locator('mapml-viewer'); + expect(await viewer.evaluate((v) => v.projection)).toEqual('OSMTILE'); + await viewer.evaluate(() => changeProjection()); + await page.waitForTimeout(1000); + expect(await viewer.evaluate((v) => v.projection)).toEqual('CBMTILE'); + const reload = await page.getByLabel('Reload'); + expect(await reload.evaluate((button)=>button.ariaDisabled)).toBe('true'); + }); }); From 809ab3af806f2770622ee9abcc5a8db7dbb964eb Mon Sep 17 00:00:00 2001 From: Peter Rushforth Date: Mon, 13 Nov 2023 19:46:34 -0500 Subject: [PATCH 3/3] Add test for opacity on layer and map-extent after map-projectionchange --- .../api/events/map-projectionchange.test.js | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/test/e2e/api/events/map-projectionchange.test.js b/test/e2e/api/events/map-projectionchange.test.js index ab4393cb6..55987bc07 100644 --- a/test/e2e/api/events/map-projectionchange.test.js +++ b/test/e2e/api/events/map-projectionchange.test.js @@ -8,10 +8,9 @@ test.describe('map-projectionchange test ', () => { page = context.pages().find((page) => page.url() === 'about:blank') || (await context.newPage()); - }); - - test.beforeEach(async function() { + + test.beforeEach(async function () { await page.goto('events/map-projectionchange.html'); }); @@ -50,10 +49,22 @@ test.describe('map-projectionchange test ', () => { const viewer = await page.locator('mapml-viewer'); expect(await viewer.evaluate((v) => v.projection)).toEqual('OSMTILE'); await viewer.evaluate(() => changeProjection()); - await page.waitForTimeout(1000); + await page.waitForTimeout(500); expect(await viewer.evaluate((v) => v.projection)).toEqual('CBMTILE'); const reload = await page.getByLabel('Reload'); - expect(await reload.evaluate((button)=>button.ariaDisabled)).toBe('true'); - + expect(await reload.evaluate((button) => button.ariaDisabled)).toBe('true'); + }); + test('Opacity is maintained on layer- and map-extent after map-projectionchange', async () => { + const layer = await page.locator('layer-'); + await layer.evaluate((l) => (l.opacity = 0.5)); + const osmtileExtent = await page.locator('map-extent[units=OSMTILE]'); + await osmtileExtent.evaluate((e) => (e.opacity = 0.4)); + const cbmtileExtent = await page.locator('map-extent[units=CBMTILE]'); + await cbmtileExtent.evaluate((e) => (e.opacity = 0.3)); + await page.evaluate(() => changeProjection()); + await page.waitForTimeout(500); + expect(await osmtileExtent.evaluate((e) => e.opacity)).toBe(0.4); + expect(await cbmtileExtent.evaluate((e) => e.opacity)).toBe(0.3); + expect(await layer.evaluate((l) => l.opacity)).toBe(0.5); }); });