Skip to content

Commit db0ee63

Browse files
author
Peter Rushforth
committed
Add calculatePosition function to be shared by
map-extent, -tile, -feature to determine zIndex positioning in parent based on how Leaflet layers are created and shared among sibling elements in a sequence Add red/green/blue-tile.png Add setZIndex function to MapFeatureLayer, MapTileLayer, copied from MapExtentLayer. Update MapFeatureLayer, MapExtentLayer, MapTileLayer initialize constructors to set the zIndex if there's an option present for it
1 parent d071ae2 commit db0ee63

File tree

12 files changed

+262
-11
lines changed

12 files changed

+262
-11
lines changed

src/map-extent.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { bounds as Lbounds, point as Lpoint } from 'leaflet';
33
import { Util } from './mapml/utils/Util.js';
44
import { mapExtentLayer } from './mapml/layers/MapExtentLayer.js';
55
import { createLayerControlExtentHTML } from './mapml/elementSupport/extents/createLayerControlForExtent.js';
6+
import { calculatePosition } from './mapml/elementSupport/layers/calculatePosition.js';
67

78
/* global M */
89
export class HTMLExtentElement extends HTMLElement {
@@ -77,6 +78,9 @@ export class HTMLExtentElement extends HTMLElement {
7778
? getExtent(this)
7879
: getCalculatedExtent(this);
7980
}
81+
get position() {
82+
return calculatePosition(this);
83+
}
8084

8185
getOuterHTML() {
8286
let tempElement = this.cloneNode(true);
@@ -263,14 +267,11 @@ export class HTMLExtentElement extends HTMLElement {
263267
// this._opacity is used to record the current opacity value (with or without updates),
264268
// the initial value of this._opacity should be set as opacity attribute value, if exists, or the default value 1.0
265269
this._opacity = this.opacity || 1.0;
270+
console.log(this.label + ' extent position: ' + this.position);
266271
this._extentLayer = mapExtentLayer({
267272
opacity: this.opacity,
268273
crs: M[this.units],
269-
extentZIndex: Array.from(
270-
this.parentLayer.src
271-
? this.parentLayer.shadowRoot.querySelectorAll(':host > map-extent')
272-
: this.parentLayer.querySelectorAll(':scope > map-extent')
273-
).indexOf(this),
274+
zIndex: this.position,
274275
extentEl: this
275276
});
276277
// this._layerControlHTML is the fieldset for the extent in the LayerControl

src/map-feature.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { MapFeatureLayer } from './mapml/layers/MapFeatureLayer.js';
44
import { featureRenderer } from './mapml/features/featureRenderer.js';
55
import { Util } from './mapml/utils/Util.js';
66
import proj4 from 'proj4';
7+
import { calculatePosition } from './mapml/elementSupport/layers/calculatePosition.js';
78

89
export class HTMLFeatureElement extends HTMLElement {
910
static get observedAttributes() {
@@ -138,6 +139,9 @@ export class HTMLFeatureElement extends HTMLElement {
138139
return this._getFeatureExtent();
139140
}
140141
}
142+
get position() {
143+
return calculatePosition(this);
144+
}
141145
getMapEl() {
142146
return Util.getClosest(this, 'mapml-viewer,map[is=web-map]');
143147
}
@@ -162,6 +166,7 @@ export class HTMLFeatureElement extends HTMLElement {
162166
constructor() {
163167
// Always call super first in constructor
164168
super();
169+
this._calculatePosition = calculatePosition.bind(this);
165170
}
166171

167172
connectedCallback() {
@@ -324,6 +329,7 @@ export class HTMLFeatureElement extends HTMLElement {
324329
: {}),
325330
...(isMapLink ? { zoomBounds: this._getZoomBounds() } : {}),
326331
...(isMapLink ? {} : { _leafletLayer: parentElement._layer }),
332+
zIndex: this.position,
327333
projection: map.options.projection,
328334
mapEl: parentElement.getMapEl(),
329335
onEachFeature: function (properties, geometry) {

src/map-tile.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { bounds as Lbounds, point as Lpoint } from 'leaflet';
22

33
import { Util } from './mapml/utils/Util.js';
44
import { mapTileLayer } from './mapml/layers/MapTileLayer.js';
5+
import { calculatePosition } from './mapml/elementSupport/layers/calculatePosition.js';
56

67
/* global M */
78

@@ -76,6 +77,9 @@ export class HTMLTileElement extends HTMLElement {
7677
}
7778
return this._extent;
7879
}
80+
get position() {
81+
return calculatePosition(this);
82+
}
7983
constructor() {
8084
// Always call super first in constructor
8185
super();
@@ -217,7 +221,8 @@ export class HTMLTileElement extends HTMLElement {
217221
// used by map-link and map-layer, both have containers
218222
pane:
219223
parentElement._templatedLayer?.getContainer() ||
220-
parentElement._layer.getContainer()
224+
parentElement._layer.getContainer(),
225+
zIndex: this.position
221226
});
222227
this._tileLayer.addMapTile(this);
223228

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/**
2+
* Calculate the sequence position for map elements based on their position in a
3+
* sequence of target elements (map-tile, map-feature, map-extent).
4+
* - map-extent: Each element gets its own unique position (each is its own MapExtentLayer)
5+
* - map-tile/map-feature: Adjacent elements of same type share the same position (they share a MapTileLayer/MapFeatureLayer)
6+
* - used to set the zIndex for the LayerGroup's _container (rendering).
7+
*
8+
* @param {HTMLElement} element - The element to calculate position for (map-tile, map-extent, or map-feature)
9+
* @returns {number} The position of this element's LayerGroup
10+
*/
11+
export function calculatePosition(element) {
12+
const tagName = element.tagName.toLowerCase();
13+
const validTags = ['map-tile', 'map-extent', 'map-feature'];
14+
15+
// Validate element type
16+
if (!validTags.includes(tagName)) {
17+
console.warn(`calculatePosition: Invalid element type ${tagName}`);
18+
return 0;
19+
}
20+
21+
const parent = element.parentElement;
22+
if (!parent) return 1;
23+
24+
let position = 0;
25+
let lastTag = null;
26+
let foundTarget = false;
27+
28+
// Iterate through all child elements
29+
for (const child of parent.children) {
30+
const childTag = child.tagName.toLowerCase();
31+
32+
// Skip non-map elements
33+
if (!validTags.includes(childTag)) continue;
34+
35+
// Check if we've reached our target element
36+
if (child === element) {
37+
foundTarget = true;
38+
39+
// map-extent always needs a new position
40+
if (childTag === 'map-extent') {
41+
position++;
42+
return position;
43+
}
44+
45+
// For map-tile and map-feature:
46+
// If this element continues a sequence of the same type, return the current position
47+
if (lastTag === childTag) {
48+
return position;
49+
}
50+
51+
// This element starts a new layer group
52+
position++;
53+
return position;
54+
}
55+
56+
// Before reaching target, count layer group transitions
57+
if (!foundTarget) {
58+
if (childTag === 'map-extent') {
59+
// Each map-extent increments position
60+
position++;
61+
} else if (lastTag !== null && lastTag !== childTag) {
62+
// Transition between different types (excluding map-extent)
63+
position++;
64+
} else if (lastTag === null) {
65+
// First valid element starts at position 1
66+
position = 1;
67+
}
68+
69+
lastTag = childTag;
70+
}
71+
}
72+
// Element not found (shouldn't happen in normal usage)
73+
return 0;
74+
}

src/mapml/layers/MapExtentLayer.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ export var MapExtentLayer = LayerGroup.extend({
3434
// Call LayerGroup's initialize to trigger Leaflet's setup
3535
LayerGroup.prototype.initialize.call(this, null, options);
3636
this._container = DomUtil.create('div', 'leaflet-layer');
37+
if (options.zIndex) {
38+
this._container.style.zIndex = options.zIndex;
39+
}
3740
this._extentEl = this.options.extentEl;
3841
this.changeOpacity(this.options.opacity);
3942
// Add class to the container
@@ -60,11 +63,6 @@ export var MapExtentLayer = LayerGroup.extend({
6063
layer.redraw();
6164
});
6265
},
63-
//addTo: function(map) {
64-
//for(let i = 0; i < this._templates.length; i++){
65-
// this._templates[0].layer.addTo(map);
66-
//}
67-
//},
6866
setZIndex: function (zIndex) {
6967
this.options.zIndex = zIndex;
7068
this._updateZIndex();

src/mapml/layers/MapFeatureLayer.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ export var MapFeatureLayer = FeatureGroup.extend({
8484
this._container = this.options.pane;
8585
DomUtil.addClass(this._container, 'leaflet-pane mapml-vector-container');
8686
}
87+
if (this.options.zIndex) {
88+
this._container.style.zIndex = this.options.zIndex;
89+
}
8790

8891
this.options.renderer.options.pane = this._container;
8992
},
@@ -116,7 +119,21 @@ export var MapFeatureLayer = FeatureGroup.extend({
116119
get _staticFeature() {
117120
return this._context === 'static';
118121
},
122+
setZIndex: function (zIndex) {
123+
this.options.zIndex = zIndex;
124+
this._updateZIndex();
119125

126+
return this;
127+
},
128+
_updateZIndex: function () {
129+
if (
130+
this._container &&
131+
this.options.zIndex !== undefined &&
132+
this.options.zIndex !== null
133+
) {
134+
this._container.style.zIndex = this.options.zIndex;
135+
}
136+
},
120137
isVisible: function () {
121138
let map = this.options.mapEl._map;
122139
// if query, isVisible is unconditionally true

src/mapml/layers/MapTileLayer.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ export var MapTileLayer = GridLayer.extend({
3131
this._pendingTiles = {};
3232
this._buildTileMap();
3333
this._container = DomUtil.create('div', 'leaflet-layer');
34+
if (options.zIndex) {
35+
this._container.style.zIndex = options.zIndex;
36+
}
3437
DomUtil.addClass(this._container, 'mapml-static-tile-container');
3538
// Store bounds for visibility checks
3639
// this.layerBounds = this._computeLayerBounds();
@@ -58,6 +61,21 @@ export var MapTileLayer = GridLayer.extend({
5861
// remove _container from the dom, but don't delete it
5962
DomUtil.remove(this._container);
6063
},
64+
setZIndex: function (zIndex) {
65+
this.options.zIndex = zIndex;
66+
this._updateZIndex();
67+
68+
return this;
69+
},
70+
_updateZIndex: function () {
71+
if (
72+
this._container &&
73+
this.options.zIndex !== undefined &&
74+
this.options.zIndex !== null
75+
) {
76+
this._container.style.zIndex = this.options.zIndex;
77+
}
78+
},
6179

6280
_handleZoomChange: function () {
6381
// this is necessary for CBMTILE in particular, I think because

test/e2e/data/tiles/blue-tile.png

3.45 KB
Loading

test/e2e/data/tiles/green-tile.png

3.43 KB
Loading

test/e2e/data/tiles/red-tile.png

3.46 KB
Loading

0 commit comments

Comments
 (0)