Skip to content

Commit c039076

Browse files
AliyanHprushforth
authored andcommitted
Add default projection (OSMTILE) + remove use of 'createmap' events
1 parent b48d26d commit c039076

File tree

9 files changed

+134
-73
lines changed

9 files changed

+134
-73
lines changed

src/layer.js

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -95,25 +95,11 @@ export class MapLayer extends HTMLElement {
9595
if (this.getAttribute('src') && !this.shadowRoot) {
9696
this.attachShadow({ mode: 'open' });
9797
}
98-
//creates listener that waits for createmap event, this allows for delayed builds of maps
99-
//this allows a safeguard for the case where loading a custom TCRS takes longer than loading mapml-viewer.js/web-map.js
100-
this.parentNode.addEventListener(
101-
'createmap',
102-
() => {
103-
this._ready();
104-
// if the map has been attached, set this layer up wrt Leaflet map
105-
if (this.parentNode._map) {
106-
this._attachedToMap();
107-
}
108-
if (this._layerControl && !this.hidden) {
109-
this._layerControl.addOrUpdateOverlay(this._layer, this.label);
110-
}
111-
},
112-
{ once: true }
113-
); //listener stops listening after event occurs once
114-
//if map is already created then dispatch createmap event, allowing layer to be built
115-
if (this.parentNode._map)
116-
this.parentNode.dispatchEvent(new CustomEvent('createmap'));
98+
this._ready();
99+
this._attachedToMap();
100+
if (this._layerControl && !this.hidden) {
101+
this._layerControl.addOrUpdateOverlay(this._layer, this.label);
102+
}
117103
}
118104

119105
adoptedCallback() {

src/map-extent.js

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -78,17 +78,7 @@ export class MapExtent extends HTMLElement {
7878
this.parentNode.nodeName.toUpperCase() === 'LAYER-'
7979
? this.parentNode
8080
: this.parentNode.host;
81-
if (!parentLayer._layer) {
82-
// for custom projection cases, the MapMLLayer has not yet created and binded with the layer- at this point,
83-
// because the "createMap" event of mapml-viewer has not yet been dispatched, the map has not yet been created
84-
// the event will be dispatched after defineCustomProjection > projection setter
85-
// should wait until MapMLLayer is built
86-
parentLayer.parentNode.addEventListener('createmap', (e) => {
87-
this._layer = parentLayer._layer;
88-
});
89-
} else {
90-
this._layer = parentLayer._layer;
91-
}
81+
this._layer = parentLayer._layer;
9282
}
9383
disconnectedCallback() {}
9484
}

src/map-feature.js

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -220,23 +220,12 @@ export class MapFeature extends HTMLElement {
220220
}
221221
};
222222

223-
if (!this._parentEl._layer) {
224-
// for custom projection cases, the MapMLLayer has not yet created and binded with the layer- at this point,
225-
// because the "createMap" event of mapml-viewer has not yet been dispatched, the map has not yet been created
226-
// the event will be dispatched after defineCustomProjection > projection setter
227-
// should wait until MapMLLayer is built
228-
let parentLayer =
229-
this._parentEl.nodeName.toUpperCase() === 'LAYER-'
230-
? this._parentEl
231-
: this._parentEl.parentElement || this._parentEl.parentNode.host;
232-
parentLayer.parentNode.addEventListener('createmap', (e) => {
233-
this._layer = parentLayer._layer;
234-
_attachedToMap();
235-
});
236-
} else {
237-
this._layer = this._parentEl._layer;
238-
_attachedToMap();
239-
}
223+
let parentLayer =
224+
parentEl.nodeName.toUpperCase() === 'LAYER-'
225+
? parentEl
226+
: parentEl.parentElement || parentEl.parentNode.host;
227+
this._layer = parentLayer._layer;
228+
_attachedToMap();
240229
}
241230

242231
_updateFeature() {

src/mapml-viewer.js

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -74,23 +74,13 @@ export class MapViewer extends HTMLElement {
7474
}
7575
}
7676
get projection() {
77-
return this.hasAttribute('projection')
77+
return this.hasAttribute('projection') && M[this.getAttribute('projection')]
7878
? this.getAttribute('projection')
79-
: '';
79+
: 'OSMTILE';
8080
}
8181
set projection(val) {
8282
if (val && M[val]) {
8383
this.setAttribute('projection', val);
84-
if (this._map && this._map.options.projection !== val) {
85-
this._map.options.crs = M[val];
86-
this._map.options.projection = val;
87-
for (let layer of this.querySelectorAll('layer-')) {
88-
layer.removeAttribute('disabled');
89-
let reAttach = this.removeChild(layer);
90-
this.appendChild(reAttach);
91-
}
92-
if (this._debug) for (let i = 0; i < 2; i++) this.toggleDebug();
93-
} else this.dispatchEvent(new CustomEvent('createmap'));
9484
} else throw new Error('Undefined Projection');
9585
}
9686
get zoom() {
@@ -176,7 +166,6 @@ export class MapViewer extends HTMLElement {
176166
// is because the mapml-viewer element has / can have a size of 0 up until after
177167
// something that happens between this point and the event handler executing
178168
// perhaps a browser rendering cycle??
179-
this.addEventListener('createmap', this._createMap);
180169

181170
let custom = !['CBMTILE', 'APSTILE', 'OSMTILE', 'WGS84'].includes(
182171
this.projection
@@ -185,9 +174,8 @@ export class MapViewer extends HTMLElement {
185174
// https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent
186175
// In particular:
187176
// "All applicable event handlers are called and return before dispatchEvent() returns."
188-
if (!custom) {
189-
this.dispatchEvent(new CustomEvent('createmap'));
190-
}
177+
this._createMap();
178+
191179
// https://github.com/Maps4HTML/Web-Map-Custom-Element/issues/274
192180
this.setAttribute('role', 'application');
193181
this._toggleStatic();
@@ -362,6 +350,22 @@ export class MapViewer extends HTMLElement {
362350
case 'static':
363351
this._toggleStatic();
364352
break;
353+
case 'projection':
354+
if (newValue && M[newValue]) {
355+
if (this._map && this._map.options.projection !== newValue) {
356+
this._map.options.crs = M[newValue];
357+
this._map.options.projection = newValue;
358+
for (let layer of this.querySelectorAll('layer-')) {
359+
layer.removeAttribute('disabled');
360+
let reAttach = this.removeChild(layer);
361+
this.appendChild(reAttach);
362+
}
363+
if (this._debug) for (let i = 0; i < 2; i++) this.toggleDebug();
364+
this.zoomTo(this.lat, this.lon, this.zoom);
365+
//this.dispatchEvent(new CustomEvent('projectionchange'));
366+
}
367+
}
368+
break;
365369
}
366370
}
367371

@@ -815,7 +819,7 @@ export class MapViewer extends HTMLElement {
815819
this._updateMapCenter();
816820
this._addToHistory();
817821
this.dispatchEvent(
818-
new CustomEvent('moveend', { detail: { target: this } })
822+
new CustomEvent('map-moveend', { detail: { target: this } })
819823
);
820824
},
821825
this

src/mapml/handlers/AnnounceMovement.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ export var AnnounceMovement = L.Handler.extend({
55
layerremove: this.totalBounds
66
});
77

8-
this._map.options.mapEl.addEventListener('moveend', this.announceBounds);
8+
this._map.options.mapEl.addEventListener(
9+
'map-moveend',
10+
this.announceBounds
11+
);
912
this._map.dragging._draggable.addEventListener('dragstart', this.dragged);
1013
this._map.options.mapEl.addEventListener(
1114
'mapfocused',
@@ -18,7 +21,10 @@ export var AnnounceMovement = L.Handler.extend({
1821
layerremove: this.totalBounds
1922
});
2023

21-
this._map.options.mapEl.removeEventListener('moveend', this.announceBounds);
24+
this._map.options.mapEl.removeEventListener(
25+
'map-moveend',
26+
this.announceBounds
27+
);
2228
this._map.dragging._draggable.removeEventListener(
2329
'dragstart',
2430
this.dragged

src/mapml/layers/MapMLLayer.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1260,7 +1260,10 @@ export var MapMLLayer = L.Layer.extend({
12601260
cs
12611261
);
12621262
} else {
1263-
extentFallback.bounds = M[projection].options.crs.pcrs.bounds;
1263+
// for custom projections, M[projection] may not be loaded, so uses M['OSMTILE'] as backup, this code will need to get rerun once projection is changed and M[projection] is available
1264+
// TODO: This is a temporary fix, _initTemplateVars (or processinitialextent) should not be called when projection of the layer and map do not match, this should be called/reinitialized once the layer projection matches with the map projection
1265+
let fallbackProjection = M[projection] || M.OSMTILE;
1266+
extentFallback.bounds = fallbackProjection.options.crs.pcrs.bounds;
12641267
}
12651268

12661269
for (var i = 0; i < tlist.length; i++) {
@@ -1491,6 +1494,7 @@ export var MapMLLayer = L.Layer.extend({
14911494
);
14921495
return;
14931496
} else if (
1497+
// when there is only one layer with different projection from the map, change's map's projection to match layer
14941498
!projectionMatch &&
14951499
layer._map &&
14961500
layer._map.options.mapEl.querySelectorAll('layer-').length === 1

test/e2e/core/projectionDefault.html

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<script type="module" src="mapml-viewer.js"></script>
8+
<title>Default Projection</title>
9+
</head>
10+
<body>
11+
<mapml-viewer>
12+
<layer- label="Rectangle" checked>
13+
<map-feature>
14+
<map-featurecaption>Rectangle</map-featurecaption>
15+
<map-geometry>
16+
<map-polygon>
17+
<map-coordinates>-123.216259390223 55.90361621419453 -123.216259390223 -0.5886925650467134 78.15130158758717 -0.5886925650467134 78.15130158758717 55.90361621419453 -123.216259390223 55.90361621419453
18+
</map-coordinates>
19+
</map-polygon>
20+
</map-geometry>
21+
<map-properties>Rectangle</map-properties>
22+
</map-feature>
23+
</layer->
24+
</mapml-viewer>
25+
</body>
26+
</html>
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { test, expect, chromium } from '@playwright/test';
2+
3+
test.describe('Playwright Viewer Default Projection', () => {
4+
let page;
5+
let context;
6+
test.beforeAll(async () => {
7+
context = await chromium.launchPersistentContext('');
8+
page =
9+
context.pages().find((page) => page.url() === 'about:blank') ||
10+
(await context.newPage());
11+
await page.goto('projectionDefault.html');
12+
});
13+
14+
test.afterAll(async function () {
15+
await context.close();
16+
});
17+
18+
test.describe('Viewer with no projection attribute', () => {
19+
test('Viewer defaults to OSMTILE', async () => {
20+
const mapProjection = await page.$eval(
21+
'body > mapml-viewer',
22+
(map) => map.projection
23+
);
24+
const leafletProjection = await page.$eval(
25+
'body > mapml-viewer',
26+
(map) => map._map.options.projection
27+
);
28+
const leafletProjection1 = await page.$eval(
29+
'body > mapml-viewer',
30+
(map) => map._map.options.crs.code
31+
);
32+
const projectionAttribute = await page.$eval(
33+
'body > mapml-viewer',
34+
(map) => map.getAttribute('projection')
35+
);
36+
expect(mapProjection).toEqual('OSMTILE');
37+
expect(leafletProjection).toEqual('OSMTILE');
38+
expect(leafletProjection1).toEqual('EPSG:3857');
39+
expect(projectionAttribute).toEqual(null);
40+
});
41+
42+
test('layer renders', async () => {
43+
const featureSVG = await page.$eval(
44+
'body > mapml-viewer > layer- > map-feature',
45+
(feature) => feature._groupEl.firstChild.getAttribute('d')
46+
);
47+
expect(featureSVG).toEqual('M62 27L62 75L206 75L206 27L62 27z');
48+
});
49+
});
50+
});

test/e2e/mapml-viewer/customTCRS.test.js

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,13 @@ test.describe('Playwright Custom TCRS Tests', () => {
1818

1919
test('Simple Custom TCRS, tiles load, mismatched layer disabled', async () => {
2020
const misMatchedLayerDisabled = await page.$eval(
21-
'body > mapml-viewer:nth-child(1) > layer-:nth-child(1)',
22-
(layer) => layer.hasAttribute('disabled')
21+
'body > mapml-viewer:nth-child(1)',
22+
(map) => map.querySelectorAll('layer-')[0].hasAttribute('disabled')
23+
);
24+
25+
const matchedLayerEnabled = await page.$eval(
26+
'body > mapml-viewer:nth-child(1)',
27+
(map) => map.querySelectorAll('layer-')[1].hasAttribute('disabled')
2328
);
2429

2530
const tilesLoaded = await page.$eval(
@@ -29,6 +34,7 @@ test.describe('Playwright Custom TCRS Tests', () => {
2934

3035
expect(tilesLoaded).toEqual(2);
3136
expect(misMatchedLayerDisabled).toEqual(true);
37+
expect(matchedLayerEnabled).toEqual(false);
3238
});
3339
test('A projection name containing a colon is invalid', async () => {
3440
const message = await page.$eval(
@@ -39,13 +45,13 @@ test.describe('Playwright Custom TCRS Tests', () => {
3945
});
4046
test('Complex Custom TCRS, static features loaded, templated features loaded', async () => {
4147
const staticFeatures = await page.$eval(
42-
'body > mapml-viewer:nth-child(3) > layer-:nth-child(1)',
43-
(layer) => layer.hasAttribute('disabled')
48+
'body > mapml-viewer:nth-child(3)',
49+
(map) => map.querySelectorAll('layer-')[0].hasAttribute('disabled')
4450
);
4551

4652
const templatedFeatures = await page.$eval(
47-
'body > mapml-viewer:nth-child(3) > layer-:nth-child(2)',
48-
(layer) => layer.hasAttribute('disabled')
53+
'body > mapml-viewer:nth-child(3)',
54+
(map) => map.querySelectorAll('layer-')[1].hasAttribute('disabled')
4955
);
5056

5157
const featureOne = await page.$eval(

0 commit comments

Comments
 (0)