Skip to content

Commit aae64e0

Browse files
authored
Merge branch 'master' into master
2 parents cc0cfd3 + 61e0459 commit aae64e0

File tree

7 files changed

+262
-15
lines changed

7 files changed

+262
-15
lines changed

package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/mapml/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,8 @@ window.M = M;
573573
});
574574
}());
575575

576+
M.convertPCRSBounds = Util.convertPCRSBounds;
577+
M.axisToXY = Util.axisToXY;
576578
M.csToAxes = Util.csToAxes;
577579
M.convertAndFormatPCRS = Util.convertAndFormatPCRS;
578580
M.axisToCS = Util.axisToCS;

src/mapml/layers/MapLayer.js

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ export var MapMLLayer = L.Layer.extend({
258258
},
259259
_onZoomAnim: function(e) {
260260
var toZoom = e.zoom,
261-
zoom = this._extent.querySelector("input[type=zoom]"),
261+
zoom = this._extent ? this._extent.querySelector("input[type=zoom]") : null,
262262
min = zoom && zoom.hasAttribute("min") ? parseInt(zoom.getAttribute("min")) : this._map.getMinZoom(),
263263
max = zoom && zoom.hasAttribute("max") ? parseInt(zoom.getAttribute("max")) : this._map.getMaxZoom(),
264264
canZoom = (toZoom < min && this._extent.zoomout) || (toZoom > max && this._extent.zoomin);
@@ -674,11 +674,16 @@ export var MapMLLayer = L.Layer.extend({
674674
if(mapml.querySelector('feature'))layer._content = mapml;
675675
if(!this.responseXML && this.responseText) mapml = new DOMParser().parseFromString(this.responseText,'text/xml');
676676
if (this.readyState === this.DONE && mapml.querySelector) {
677-
var serverExtent = mapml.querySelector('extent') || mapml.querySelector('meta[name=projection]'),
678-
projectionMatch = serverExtent && serverExtent.hasAttribute('units') &&
679-
serverExtent.getAttribute('units') === layer.options.mapprojection ||
680-
serverExtent && serverExtent.hasAttribute('content') &&
681-
M.metaContentToObject(serverExtent.getAttribute('content')).content === layer.options.mapprojection,
677+
var serverExtent = mapml.querySelector('extent') || mapml.querySelector('meta[name=projection]'), projection;
678+
679+
if (serverExtent.tagName.toLowerCase() === "extent" && serverExtent.hasAttribute('units')){
680+
projection = serverExtent.getAttribute("units");
681+
} else if (serverExtent.tagName.toLowerCase() === "meta" && serverExtent.hasAttribute('content')) {
682+
projection = M.metaContentToObject(serverExtent.getAttribute('content')).content;
683+
}
684+
685+
var projectionMatch = projection && projection === layer.options.mapprojection,
686+
metaExtent = mapml.querySelector('meta[name=extent]'),
682687
selectedAlternate = !projectionMatch && mapml.querySelector('head link[rel=alternate][projection='+layer.options.mapprojection+']'),
683688

684689
base =
@@ -702,7 +707,31 @@ export var MapMLLayer = L.Layer.extend({
702707
var tlist = serverExtent.querySelectorAll('link[rel=tile],link[rel=image],link[rel=features],link[rel=query]'),
703708
varNamesRe = (new RegExp('(?:\{)(.*?)(?:\})','g')),
704709
zoomInput = serverExtent.querySelector('input[type="zoom" i]'),
705-
includesZoom = false;
710+
includesZoom = false, extentFallback = {};
711+
712+
extentFallback.zoom = 0;
713+
if (metaExtent){
714+
let content = M.metaContentToObject(metaExtent.getAttribute("content")), cs;
715+
716+
extentFallback.zoom = content.zoom || extentFallback.zoom;
717+
718+
let metaKeys = Object.keys(content);
719+
for(let i =0;i<metaKeys.length;i++){
720+
if(!metaKeys[i].includes("zoom")){
721+
cs = M.axisToCS(metaKeys[i].split("-")[2]);
722+
break;
723+
}
724+
}
725+
let axes = M.csToAxes(cs);
726+
extentFallback.bounds = M.boundsToPCRSBounds(
727+
L.bounds(L.point(+content[`top-left-${axes[0]}`],+content[`top-left-${axes[1]}`]),
728+
L.point(+content[`bottom-right-${axes[0]}`],+content[`bottom-right-${axes[1]}`])),
729+
extentFallback.zoom, projection, cs);
730+
731+
} else {
732+
extentFallback.bounds = M[projection].options.crs.pcrs.bounds;
733+
}
734+
706735
for (var i=0;i< tlist.length;i++) {
707736
var t = tlist[i], template = t.getAttribute('tref');
708737
if(!template){
@@ -727,6 +756,16 @@ export var MapMLLayer = L.Layer.extend({
727756
var varName = v[1],
728757
inp = serverExtent.querySelector('input[name='+varName+'],select[name='+varName+']');
729758
if (inp) {
759+
760+
if ((inp.hasAttribute("type") && inp.getAttribute("type")==="location") && (!inp.hasAttribute("min" || !inp.hasAttribute("max")))){
761+
zoomInput.setAttribute("value", extentFallback.zoom);
762+
763+
let axis = inp.getAttribute("axis"),
764+
axisBounds = M.convertPCRSBounds(extentFallback.bounds, extentFallback.zoom, projection, M.axisToCS(axis));
765+
inp.setAttribute("min", axisBounds.min[M.axisToXY(axis)]);
766+
inp.setAttribute("max", axisBounds.max[M.axisToXY(axis)]);
767+
}
768+
730769
inputs.push(inp);
731770
includesZoom = includesZoom || inp.hasAttribute("type") && inp.getAttribute("type").toLowerCase() === "zoom";
732771
if (inp.hasAttribute('shard')) {

src/mapml/utils/Util.js

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ export var Util = {
55
if(!pcrsBounds || !map) return {};
66

77
let tcrsTopLeft = [], tcrsBottomRight = [],
8-
tileMatrixTopLeft = [], tileMatrixBottomRight = [];
8+
tileMatrixTopLeft = [], tileMatrixBottomRight = [],
9+
tileSize = map.options.crs.options.crs.tile.bounds.max.y;
910

1011
for(let i = 0;i<map.options.crs.options.resolutions.length;i++){
1112
let scale = map.options.crs.scale(i),
@@ -23,12 +24,12 @@ export var Util = {
2324

2425
//converts the tcrs values from earlier to tilematrix
2526
tileMatrixTopLeft.push({
26-
horizontal: tcrsTopLeft[i].horizontal / 256,
27-
vertical:tcrsTopLeft[i].vertical / 256,
27+
horizontal: tcrsTopLeft[i].horizontal / tileSize,
28+
vertical:tcrsTopLeft[i].vertical / tileSize,
2829
});
2930
tileMatrixBottomRight.push({
30-
horizontal: tcrsBottomRight[i].horizontal / 256,
31-
vertical: tcrsBottomRight[i].vertical / 256,
31+
horizontal: tcrsBottomRight[i].horizontal / tileSize,
32+
vertical: tcrsBottomRight[i].vertical / tileSize,
3233
});
3334
}
3435

@@ -176,6 +177,49 @@ export var Util = {
176177
} catch (e) {return undefined;}
177178
},
178179

180+
axisToXY: function(axis){
181+
try{
182+
switch(axis.toLowerCase()){
183+
case "i":
184+
case "column":
185+
case "longitude":
186+
case "x":
187+
case "easting":
188+
return "x";
189+
case "row":
190+
case "j":
191+
case "latitude":
192+
case "y":
193+
case "northing":
194+
return "y";
195+
196+
default:
197+
return undefined;
198+
}
199+
} catch (e) {return undefined;}
200+
},
201+
202+
convertPCRSBounds: function(pcrsBounds, zoom, projection, cs){
203+
if(!pcrsBounds || !zoom && +zoom !== 0 || !cs) return undefined;
204+
switch (cs.toLowerCase()) {
205+
case "pcrs":
206+
return pcrsBounds;
207+
case "tcrs":
208+
case "tilematrix":
209+
let minPixel = this[projection].transformation.transform(pcrsBounds.min, this[projection].scale(+zoom)),
210+
maxPixel = this[projection].transformation.transform(pcrsBounds.max, this[projection].scale(+zoom));
211+
if (cs.toLowerCase() === "tcrs") return L.bounds(minPixel, maxPixel);
212+
let tileSize = M[projection].options.crs.tile.bounds.max.x;
213+
return L.bounds(L.point(minPixel.x / tileSize, minPixel.y / tileSize), L.point(maxPixel.x / tileSize,maxPixel.y / tileSize));
214+
case "gcrs":
215+
let minGCRS = this[projection].unproject(pcrsBounds.min),
216+
maxGCRS = this[projection].unproject(pcrsBounds.max);
217+
return L.bounds(L.point(minGCRS.lng, minGCRS.lat), L.point(maxGCRS.lng, maxGCRS.lat));
218+
default:
219+
return undefined;
220+
}
221+
},
222+
179223
boundsToPCRSBounds: function(bounds, zoom, projection,cs){
180224
if(!bounds || !zoom && +zoom !== 0 || !cs) return undefined;
181225
let tileSize = M[projection].options.crs.tile.bounds.max.x;

test/e2e/core/metaDefault.html

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<html>
2+
3+
<head>
4+
<title>Missing Meta Parameters Test</title>
5+
<meta charset="UTF-8">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<script type="module" src="mapml-viewer.js"></script>
8+
<style>
9+
[is=web-map] {
10+
width: 100%;
11+
height: 400px;
12+
max-width: 100%;
13+
}
14+
15+
.transparency {
16+
opacity: 0.2;
17+
}
18+
</style>
19+
</head>
20+
21+
<body>
22+
<mapml-viewer style="width: 500px; height: 500px;" projection="CBMTILE" zoom="0" lat="45.5052040" lon="-75.2202344"
23+
controls>
24+
<layer- label="Map Layer" src="data/missing_min_max.mapml" checked></layer->
25+
26+
<layer- label="Toporama" checked>
27+
<meta name="zoom" content="min=4,max=5" />
28+
<meta name="extent"
29+
content="zoom=19,top-left-easting=-7786477.0,top-left-northing=-927808.0,bottom-right-easting=7148753.0,bottom-right-northing=7928344.0" />
30+
<extent units="CBMTILE">
31+
<input name="z" type="zoom" value="11" min="4" max="4" />
32+
<input name="w" type="width" />
33+
<input name="h" type="height" />
34+
<input name="xmin" type="location" units="pcrs" position="top-left" axis="easting" />
35+
<input name="ymin" type="location" units="pcrs" position="bottom-left" axis="northing" />
36+
<input name="xmax" type="location" units="pcrs" position="top-right" axis="easting" />
37+
<input name="ymax" type="location" units="pcrs" position="top-left" axis="northing" />
38+
<link rel="image"
39+
tref="http://wms.ess-ws.nrcan.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" />
40+
</extent>
41+
</layer->
42+
</mapml-viewer>
43+
44+
</body>
45+
46+
</html>

test/e2e/core/metaDefault.test.js

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
jest.setTimeout(50000);
2+
const playwright = require("playwright");
3+
4+
(async () => {
5+
6+
let expectedPCRSFirstLayer = {
7+
topLeft: {
8+
horizontal: -3263369.215138428,
9+
vertical: 4046262.80585894,
10+
},
11+
bottomRight: {
12+
horizontal: 3823752.959105924,
13+
vertical: -1554448.395563461,
14+
},
15+
}, expectedGCRSFirstLayer = {
16+
topLeft: {
17+
horizontal: -125.78104358919225,
18+
vertical: 56.11474703973131,
19+
},
20+
bottomRight: {
21+
horizontal: -5.116088318047697,
22+
vertical: 28.87016583287855,
23+
},
24+
};
25+
26+
let expectedPCRSSecondLayer = {
27+
topLeft: {
28+
horizontal: -7786477,
29+
vertical: 7928344,
30+
},
31+
bottomRight: {
32+
horizontal: 7148753,
33+
vertical: -927808,
34+
},
35+
}, expectedGCRSSecondLayer = {
36+
topLeft: {
37+
horizontal: -155.3514099767017,
38+
vertical: 22.2852694215843,
39+
},
40+
bottomRight: {
41+
horizontal: 32.23057852696884,
42+
vertical: 10.170068283825733,
43+
},
44+
};
45+
for (const browserType of BROWSER) {
46+
describe(
47+
"Playwright Missing Min Max Attribute, Meta Default Tests in " + browserType,
48+
() => {
49+
beforeAll(async () => {
50+
browser = await playwright[browserType].launch({
51+
headless: ISHEADLESS,
52+
});
53+
context = await browser.newContext();
54+
page = await context.newPage();
55+
if (browserType === "firefox") {
56+
await page.waitForNavigation();
57+
}
58+
await page.goto(PATH + "metaDefault.html");
59+
});
60+
61+
afterAll(async function () {
62+
await browser.close();
63+
});
64+
65+
test("[" + browserType + "]" + " Inline layer extent test", async () => {
66+
const extent = await page.$eval(
67+
"body > mapml-viewer > layer-:nth-child(1)",
68+
(layer) => layer.extent
69+
);
70+
expect(extent.hasOwnProperty("zoom")).toBeTruthy();
71+
expect(extent.hasOwnProperty("topLeft")).toBeTruthy();
72+
expect(extent.hasOwnProperty("bottomRight")).toBeTruthy();
73+
expect(extent.hasOwnProperty("projection")).toBeTruthy();
74+
expect(extent.topLeft.pcrs).toEqual(expectedPCRSFirstLayer.topLeft);
75+
expect(extent.bottomRight.pcrs).toEqual(expectedPCRSFirstLayer.bottomRight);
76+
expect(extent.topLeft.gcrs).toEqual(expectedGCRSFirstLayer.topLeft);
77+
expect(extent.bottomRight.gcrs).toEqual(expectedGCRSFirstLayer.bottomRight);
78+
});
79+
test("[" + browserType + "]" + " Fetched layer extent test", async () => {
80+
const extent = await page.$eval(
81+
"body > mapml-viewer > layer-:nth-child(2)",
82+
(layer) => layer.extent
83+
);
84+
85+
expect(extent.hasOwnProperty("zoom")).toBeTruthy();
86+
expect(extent.hasOwnProperty("topLeft")).toBeTruthy();
87+
expect(extent.hasOwnProperty("bottomRight")).toBeTruthy();
88+
expect(extent.hasOwnProperty("projection")).toBeTruthy();
89+
expect(extent.topLeft.pcrs).toEqual(expectedPCRSSecondLayer.topLeft);
90+
expect(extent.bottomRight.pcrs).toEqual(expectedPCRSSecondLayer.bottomRight);
91+
expect(extent.topLeft.gcrs).toEqual(expectedGCRSSecondLayer.topLeft);
92+
expect(extent.bottomRight.gcrs).toEqual(expectedGCRSSecondLayer.bottomRight);
93+
});
94+
}
95+
);
96+
}
97+
})();
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<mapml>
2+
<head>
3+
<title>Canada Base Map - Transportation (CBMT)</title>
4+
<meta http-equiv="Content-Type" content="text/mapml;projection=CBMTILE"/>
5+
<meta charset="utf-8"/>
6+
<base href=""/>
7+
<link rel="license" href="https://www.nrcan.gc.ca/earth-sciences/geography/topographic-information/free-data-geogratis/licence/17285" title="Canada Base Map © Natural Resources Canada"/>
8+
<link rel="zoomin" href="/mapml/en/cbmtile/cbmt/?z=18" type="text/mapml"/>
9+
<meta name="extent" content="zoom=17,top-left-row=29750,top-left-column=26484,bottom-right-row=34475,bottom-right-column=32463" />
10+
</head>
11+
<body>
12+
<extent units="CBMTILE">
13+
<input name="z" type="zoom" value="17" min="0" max="17"/>
14+
<input name="y" type="location" units="tilematrix" axis="row"/>
15+
<input name="x" type="location" units="tilematrix" axis="column"/>
16+
<link rel="tile" tref="cbmt/{z}/c{x}_r{y}.png" />
17+
</extent>
18+
</body>
19+
</mapml>

0 commit comments

Comments
 (0)