diff --git a/index.html b/index.html
index ddfa9d00d..320c86c74 100644
--- a/index.html
+++ b/index.html
@@ -76,7 +76,6 @@
A pleasing map of Canada
-
-
+
-75.705278 45.397778
diff --git a/src/map-feature.js b/src/map-feature.js
index 075a36633..f54d94f5a 100644
--- a/src/map-feature.js
+++ b/src/map-feature.js
@@ -291,14 +291,32 @@ export class MapFeature extends HTMLElement {
_getNativeZoomAndCS(content) {
// content: referred to if the has inline , or
// referred to remote mapml if the has a src attribute, and the fetched mapml contains
+ // referred to [map-meta, ...] if it is query
// referred to null otherwise (i.e. has fetched in shadow, the attaches to 's shadow)
let nativeZoom, nativeCS;
if (this._extentEl) {
// feature attaches to extent's shadow
if (this._extentEl.querySelector('map-link[rel=query]')) {
// for query, fallback zoom is the current map zoom level that the query is returned
- nativeZoom = this._map.getZoom();
- nativeCS = 'pcrs';
+ let metaZoom, metaCS;
+ if (content) {
+ metaZoom = M._metaContentToObject(
+ Array.prototype.filter
+ .call(content, function (elem) {
+ return elem.matches('map-meta[name=zoom]');
+ })[0]
+ ?.getAttribute('content')
+ ).content;
+ metaCS = M._metaContentToObject(
+ Array.prototype.filter
+ .call(content, function (elem) {
+ return elem.matches('map-meta[name=cs]');
+ })[0]
+ ?.getAttribute('content')
+ ).content;
+ }
+ nativeZoom = metaZoom || this._map.getZoom();
+ nativeCS = metaCS || 'gcrs';
} else if (this._extentEl.querySelector('map-link[rel=features]')) {
// for templated feature, read fallback from the fetched mapml's map-meta[name=zoom / cs]
nativeZoom = this._extentEl._nativeZoom;
@@ -326,7 +344,7 @@ export class MapFeature extends HTMLElement {
csLength = csMeta?.length;
nativeCS = csLength
? csMeta[csLength - 1].getAttribute('content')
- : 'pcrs';
+ : 'gcrs';
return { zoom: nativeZoom, cs: nativeCS };
}
}
@@ -347,7 +365,9 @@ export class MapFeature extends HTMLElement {
// calculate feature extent
let map = this._map,
geometry = this.querySelector('map-geometry'),
- native = this._getNativeZoomAndCS(this._layer._content),
+ native = this._getNativeZoomAndCS(
+ this._layer._content || this._layer.metas
+ ),
cs = geometry.getAttribute('cs') || native.cs,
// zoom level that the feature rendered at
zoom = this.zoom || native.zoom,
diff --git a/src/mapml/handlers/QueryHandler.js b/src/mapml/handlers/QueryHandler.js
index 666a563c5..b0a494503 100644
--- a/src/mapml/handlers/QueryHandler.js
+++ b/src/mapml/handlers/QueryHandler.js
@@ -109,6 +109,12 @@ export var QueryHandler = L.Handler.extend({
features = Array.prototype.slice.call(
mapmldoc.querySelectorAll('map-feature')
);
+ // elements
+ layer.metas = Array.prototype.slice.call(
+ mapmldoc.querySelectorAll(
+ 'map-meta[name=cs], map-meta[name=zoom], map-meta[name=projection]'
+ )
+ );
if (features.length)
layer._mapmlFeatures = layer._mapmlFeatures.concat(features);
} else {
@@ -246,6 +252,7 @@ export var QueryHandler = L.Handler.extend({
}
}
function displayFeaturesPopup(features, loc) {
+ if (features.length === 0) return;
let f = M.featureLayer(features, {
// pass the vector layer a renderer of its own, otherwise leaflet
// puts everything into the overlayPane
@@ -279,7 +286,7 @@ export var QueryHandler = L.Handler.extend({
layer.on('popupclose', function () {
map.removeLayer(f);
});
- f.showPaginationFeature({ i: 0, popup: layer._popup });
+ f.showPaginationFeature({ i: 0, popup: layer._popup, meta: layer.metas });
}
}
});
diff --git a/src/mapml/layers/FeatureLayer.js b/src/mapml/layers/FeatureLayer.js
index 8fee20358..0a0956683 100644
--- a/src/mapml/layers/FeatureLayer.js
+++ b/src/mapml/layers/FeatureLayer.js
@@ -88,14 +88,26 @@ export var FeatureLayer = L.FeatureGroup.extend({
showPaginationFeature: function (e) {
if (this.options.query && this._mapmlFeatures[e.i]) {
let feature = this._mapmlFeatures[e.i];
- // remove the prev / next one from shadow if there is any
- feature._extentEl.shadowRoot.firstChild?.remove();
+ if (e.type === 'featurepagination') {
+ // remove map-feature only (keep meta's) when paginating
+ feature._extentEl.shadowRoot.querySelector('map-feature')?.remove();
+ } else {
+ // empty the map-extent shadowRoot
+ // remove the prev / next one and 's from shadow if there is any
+ feature._extentEl.shadowRoot.replaceChildren();
+ }
this.clearLayers();
feature._featureGroup = this.addData(
feature,
this.options.nativeCS,
this.options.nativeZoom
);
+ // append all map-meta from mapml document
+ if (e.meta) {
+ for (let i = 0; i < e.meta.length; i++) {
+ feature._extentEl.shadowRoot.appendChild(e.meta[i]);
+ }
+ }
feature._extentEl.shadowRoot.appendChild(feature);
e.popup._navigationBar.querySelector('p').innerText =
e.i + 1 + '/' + this.options._leafletLayer._totalFeatureCount;
@@ -116,21 +128,51 @@ export var FeatureLayer = L.FeatureGroup.extend({
}
},
+ // _getNativeVariables: returns an object with the native zoom and CS,
+ // based on the map-metas that are available within
+ // the layer or the fallback default values.
+ // _getNativeVariables: mapml-||layer-||null||[map-feature,...] -> {zoom: _, val: _}
+ // mapml can be a mapml- element, layer- element, null, or an array of map-features
_getNativeVariables: function (mapml) {
- let nativeZoom =
- (mapml.querySelector &&
- mapml.querySelector('map-meta[name=zoom]') &&
- +M._metaContentToObject(
- mapml.querySelector('map-meta[name=zoom]').getAttribute('content')
- ).value) ||
- 0;
- let nativeCS =
- (mapml.querySelector &&
- mapml.querySelector('map-meta[name=cs]') &&
- M._metaContentToObject(
- mapml.querySelector('map-meta[name=cs]').getAttribute('content')
- ).content) ||
- 'PCRS';
+ let nativeZoom, nativeCS;
+ // when mapml is an array of features provided by the query
+ if (
+ mapml.length &&
+ mapml[0].parentElement.parentElement &&
+ mapml[0].parentElement.parentElement.tagName === 'mapml-'
+ ) {
+ let mapmlEl = mapml[0].parentElement.parentElement;
+ nativeZoom =
+ (mapmlEl.querySelector &&
+ mapmlEl.querySelector('map-meta[name=zoom]') &&
+ +M._metaContentToObject(
+ mapmlEl.querySelector('map-meta[name=zoom]').getAttribute('content')
+ ).value) ||
+ 0;
+ nativeCS =
+ (mapmlEl.querySelector &&
+ mapmlEl.querySelector('map-meta[name=cs]') &&
+ M._metaContentToObject(
+ mapmlEl.querySelector('map-meta[name=cs]').getAttribute('content')
+ ).content) ||
+ 'GCRS';
+ } else {
+ // when mapml is null or a layer-/mapml- element
+ nativeZoom =
+ (mapml.querySelector &&
+ mapml.querySelector('map-meta[name=zoom]') &&
+ +M._metaContentToObject(
+ mapml.querySelector('map-meta[name=zoom]').getAttribute('content')
+ ).value) ||
+ 0;
+ nativeCS =
+ (mapml.querySelector &&
+ mapml.querySelector('map-meta[name=cs]') &&
+ M._metaContentToObject(
+ mapml.querySelector('map-meta[name=cs]').getAttribute('content')
+ ).content) ||
+ 'GCRS';
+ }
return { zoom: nativeZoom, cs: nativeCS };
},
diff --git a/src/mapml/layers/MapMLLayer.js b/src/mapml/layers/MapMLLayer.js
index 2d49c14b8..48cfaa398 100644
--- a/src/mapml/layers/MapMLLayer.js
+++ b/src/mapml/layers/MapMLLayer.js
@@ -1401,11 +1401,21 @@ export var MapMLLayer = L.Layer.extend({
layer._content = mapml;
if (!this.responseXML && this.responseText)
mapml = new DOMParser().parseFromString(this.responseText, 'text/xml');
+
+ // if everything is ok, continue with the processing
if (
this.readyState === this.DONE &&
mapml.querySelector &&
!mapml.querySelector('parsererror')
) {
+ // Get layer's title/label
+ if (mapml.querySelector('map-title')) {
+ layer._title = mapml.querySelector('map-title').textContent.trim();
+ layer._titleIsReadOnly = true;
+ } else if (mapml instanceof Element && mapml.hasAttribute('label')) {
+ layer._title = mapml.getAttribute('label').trim();
+ }
+
var serverExtent = mapml.querySelectorAll('map-extent'),
projection,
projectionMatch,
@@ -1441,6 +1451,15 @@ export var MapMLLayer = L.Layer.extend({
projectionMatch =
projection && projection === layer.options.mapprojection;
}
+ } else {
+ // default projection set to parent projection when no map-meta projection element present
+ projection = layer.options.mapprojection;
+ projectionMatch = true;
+ serverMeta = projection;
+ console.log(
+ `A projection was not assigned to the '${layer._title}' Layer. Please specify a projection for that layer using a map-meta element. See more here - https://maps4html.org/web-map-doc/docs/elements/meta/`
+ );
+ // TODO: Add a more obvious warning.
}
var metaExtent = mapml.querySelector('map-meta[name=extent]'),
@@ -1509,7 +1528,13 @@ export var MapMLLayer = L.Layer.extend({
}
}
} else {
- layer._extent = serverMeta;
+ if (typeof serverMeta === 'string') {
+ // when map-meta projection not present for layer
+ layer._extent = { serverMeta };
+ } else {
+ // when map-meta projection present for layer
+ layer._extent = serverMeta;
+ }
}
layer._parseLicenseAndLegend(mapml, layer, projection);
@@ -1626,12 +1651,6 @@ export var MapMLLayer = L.Layer.extend({
layer._styles = stylesControl;
}
- if (mapml.querySelector('map-title')) {
- layer._title = mapml.querySelector('map-title').textContent.trim();
- layer._titleIsReadOnly = true;
- } else if (mapml instanceof Element && mapml.hasAttribute('label')) {
- layer._title = mapml.getAttribute('label').trim();
- }
if (layer._map) {
layer._validateExtent();
// if the layer is checked in the layer control, force the addition
@@ -1742,7 +1761,7 @@ export var MapMLLayer = L.Layer.extend({
let extent = this._extent._mapExtents
? this._extent._mapExtents[0]
: this._extent; // the projections for each extent eould be the same (as) validated in _validProjection, so can use mapExtents[0]
- if (!extent) return FALLBACK_PROJECTION;
+ if (extent.serverMeta) return extent.serverMeta;
switch (extent.tagName.toUpperCase()) {
case 'MAP-EXTENT':
if (extent.hasAttribute('units'))
diff --git a/src/mapml/layers/TemplatedFeaturesLayer.js b/src/mapml/layers/TemplatedFeaturesLayer.js
index 54e160ee2..2f2e3c3c1 100644
--- a/src/mapml/layers/TemplatedFeaturesLayer.js
+++ b/src/mapml/layers/TemplatedFeaturesLayer.js
@@ -159,7 +159,7 @@ export var TemplatedFeaturesLayer = L.Layer.extend({
.querySelector('map-meta[name=cs]')
.getAttribute('content')
).content) ||
- 'PCRS');
+ 'GCRS');
features.addData(mapml, nativeCS, nativeZoom);
// "migrate" to extent's shadow
// make a clone, prevent the elements from being removed from mapml file
diff --git a/test/e2e/core/metaDefault.html b/test/e2e/core/metaDefault.html
index 3996838c6..81e240a2c 100644
--- a/test/e2e/core/metaDefault.html
+++ b/test/e2e/core/metaDefault.html
@@ -34,6 +34,16 @@
tref="http://maps.geogratis.gc.ca/wms/toporama_en?SERVICE=WMS&REQUEST=GetMap&FORMAT=image/jpeg&TRANSPARENT=FALSE&STYLES=&VERSION=1.3.0&LAYERS=WMS-Toporama&WIDTH={w}&HEIGHT={h}&CRS=EPSG:3978&BBOX={xmin},{ymin},{xmax},{ymax}&m4h=t" >
+
+
+
+
+ -79.477626 43.764814
+
+
+
+
+