Skip to content

Commit 5bc36bf

Browse files
authored
Merge pull request #231 from ahmadayubi/clientTile
Programmatic way to allow a JavaScript client to render tiles
2 parents 882365f + 93cd485 commit 5bc36bf

File tree

8 files changed

+230
-15
lines changed

8 files changed

+230
-15
lines changed

debug/clientTile.html

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<!DOCTYPE html>
2+
<html>
3+
4+
<head>
5+
<title>Client Tiles</title>
6+
<meta charset="UTF-8">
7+
<script type="module" src="../dist/mapml-viewer.js"></script>
8+
<style>
9+
html {
10+
height: 100%
11+
}
12+
13+
body,
14+
map {
15+
height: inherit
16+
}
17+
18+
* {
19+
margin: 0;
20+
padding: 0;
21+
}
22+
</style>
23+
</head>
24+
25+
<body>
26+
<mapml-viewer style="width: 500px;height: 500px;" projection="WGS84" zoom="1" lat="59.87304909" lon="-53.22587225"
27+
width="900" height="400" controls>
28+
29+
<layer- label="Inline Templated Tile" checked>
30+
<meta name="zoom" content="min=0,max=5" />
31+
<extent units="WGS84">
32+
<input name="zoomLevel" type="zoom" min="1" max="1" value="0" />
33+
34+
<input name="row" type="location" axis="row" units="tilematrix" min="0" max="1" />
35+
<input name="col" type="location" axis="column" units="tilematrix" min="0" max="1" />
36+
37+
<link rel='tile' type='text/mapml' title='Tiles for ne_10m_admin_0_countries (as MapML)' />
38+
39+
</extent>
40+
</layer->
41+
</mapml-viewer>
42+
<script>
43+
let layer = document.querySelector("body > mapml-viewer > layer- > extent > link");
44+
layer.addEventListener("tileloadstart", (e) => {
45+
//let cust = document.createElement("IMG")
46+
//cust.src = "https://1000logos.net/wp-content/uploads/2018/11/GitHub-logo-500x452.png";
47+
//cust.width = 50;
48+
//cust.height = 50;
49+
let cust = document.createElement("IFRAME");
50+
cust.src = "https://www.youtube.com/embed/yI2oS2hoL0k?autoplay=1&mute=1";
51+
cust.width = 256;
52+
cust.height = 256;
53+
e.detail.appendTile(cust);
54+
});
55+
</script>
56+
</body>
57+
58+
</html>

src/mapml/layers/MapLayer.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { FALLBACK_PROJECTION } from '../utils/Constants';
1+
import { FALLBACK_PROJECTION, BLANK_TT_TREF } from '../utils/Constants';
22

33
export var MapMLLayer = L.Layer.extend({
44
// zIndex has to be set, for the case where the layer is added to the
@@ -648,8 +648,16 @@ export var MapMLLayer = L.Layer.extend({
648648
zoomInput = serverExtent.querySelector('input[type="zoom" i]'),
649649
includesZoom = false;
650650
for (var i=0;i< tlist.length;i++) {
651-
var t = tlist[i],
652-
template = t.getAttribute('tref'), v,
651+
var t = tlist[i], template = t.getAttribute('tref');
652+
if(!template){
653+
template = BLANK_TT_TREF;
654+
let blankInputs = mapml.querySelectorAll('input');
655+
for (let i of blankInputs){
656+
template += `{${i.getAttribute("name")}}`;
657+
}
658+
}
659+
660+
var v,
653661
title = t.hasAttribute('title') ? t.getAttribute('title') : 'Query this layer',
654662
vcount=template.match(varNamesRe),
655663
trel = (!t.hasAttribute('rel') || t.getAttribute('rel').toLowerCase() === 'tile') ? 'tile' : t.getAttribute('rel').toLowerCase(),
@@ -704,7 +712,7 @@ export var MapMLLayer = L.Layer.extend({
704712
break;
705713
}
706714
}
707-
if (template && vcount.length === inputs.length) {
715+
if (template && vcount.length === inputs.length || template === BLANK_TT_TREF) {
708716
if (trel === 'query') {
709717
layer.queryable = true;
710718
}
@@ -714,6 +722,7 @@ export var MapMLLayer = L.Layer.extend({
714722
// template has a matching input for every variable reference {varref}
715723
layer._templateVars.push({
716724
template:decodeURI(new URL(template, base)),
725+
linkEl: t,
717726
title:title,
718727
rel: trel,
719728
type: ttype,

src/mapml/layers/TemplatedTileLayer.js

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { BLANK_TT_TREF } from '../utils/Constants';
2+
13
export var TemplatedTileLayer = L.TileLayer.extend({
24
// a TemplateTileLayer is similar to a L.TileLayer except its templates are
35
// defined by the <extent><template/></extent>
@@ -59,22 +61,38 @@ export var TemplatedTileLayer = L.TileLayer.extend({
5961
this._parentOnMoveEnd();
6062
},
6163
createTile: function (coords) {
62-
let tileSize = this._map.options.crs.options.crs.tile.bounds.max.x;
64+
let tileGroup = document.createElement("DIV"),
65+
tileSize = this._map.options.crs.options.crs.tile.bounds.max.x;
66+
L.DomUtil.addClass(tileGroup, "mapml-tile-group");
67+
L.DomUtil.addClass(tileGroup, "leaflet-tile");
68+
69+
tileGroup.setAttribute("width", `${tileSize}`);
70+
tileGroup.setAttribute("height", `${tileSize}`);
71+
72+
this._template.linkEl.dispatchEvent(new CustomEvent('tileloadstart', {
73+
detail:{
74+
x:coords.x,
75+
y:coords.y,
76+
zoom:coords.z,
77+
appendTile: (elem)=>{tileGroup.appendChild(elem);},
78+
},
79+
}));
80+
6381
if (this._template.type.startsWith('image/')) {
64-
return L.TileLayer.prototype.createTile.call(this, coords, function(){});
65-
} else {
82+
tileGroup.appendChild(L.TileLayer.prototype.createTile.call(this, coords, function(){}));
83+
} else if(!this._url.includes(BLANK_TT_TREF)) {
6684
// tiles of type="text/mapml" will have to fetch content while creating
6785
// the tile here, unless there can be a callback associated to the element
6886
// that will render the content in the alread-placed tile
6987
// var tile = L.DomUtil.create('canvas', 'leaflet-tile');
7088
var tile = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
89+
this._fetchTile(coords, tile);
7190
tile.setAttribute("width", `${tileSize}`);
7291
tile.setAttribute("height", `${tileSize}`);
73-
// tile.style.outline="1px solid red";
7492
L.DomUtil.addClass(tile, "leaflet-tile");
75-
this._fetchTile(coords, tile);
76-
return tile;
93+
tileGroup.appendChild(tile);
7794
}
95+
return tileGroup;
7896
},
7997
_mapmlTileReady: function(tile) {
8098
L.DomUtil.addClass(tile,'leaflet-tile-loaded');

src/mapml/utils/Constants.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export const TILE_SIZE = 256;
22
export const FALLBACK_PROJECTION = "OSMTILE";
3-
export const FALLBACK_CS = "TILEMATRIX";
3+
export const FALLBACK_CS = "TILEMATRIX";
4+
export const BLANK_TT_TREF = "mapmltemplatedtileplaceholder";

test/e2e/core/styleParsing.test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,15 @@ jest.setTimeout(50000);
7575
//testing done on 2nd map in the page
7676
test("[" + browserType + "]" + " CSS from a retrieved MapML file added inorder inside svg within templated-tile-container", async () => {
7777
const firstStyle = await page.$eval(
78-
"xpath=//html/body/map[2]/div >> css=div > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-overlay-pane > div > div.leaflet-layer.mapml-templatedlayer-container > div > div > svg:nth-child(1) > style:nth-child(1)",
78+
"xpath=//html/body/map[2]/div >> css=div > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-overlay-pane > div > div.leaflet-layer.mapml-templatedlayer-container > div > div > div > svg:nth-child(1) > style:nth-child(1)",
7979
(styleE) => styleE.innerHTML
8080
);
8181
const secondStyle = await page.$eval(
82-
"xpath=//html/body/map[2]/div >> css=div > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-overlay-pane > div > div.leaflet-layer.mapml-templatedlayer-container > div > div > svg:nth-child(1) > style:nth-child(2)",
82+
"xpath=//html/body/map[2]/div >> css=div > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-overlay-pane > div > div.leaflet-layer.mapml-templatedlayer-container > div > div > div > svg:nth-child(1) > style:nth-child(2)",
8383
(styleE) => styleE.innerHTML
8484
);
8585
const foundStyleLink = await page.$(
86-
"xpath=//html/body/map[2]/div >> css=div > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-overlay-pane > div > div.leaflet-layer.mapml-templatedlayer-container > div > div > svg:nth-child(1) > link"
86+
"xpath=//html/body/map[2]/div >> css=div > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-overlay-pane > div > div.leaflet-layer.mapml-templatedlayer-container > div > div > div > svg:nth-child(1) > link"
8787
);
8888
expect(firstStyle).toMatch("refStyleOne");
8989
expect(secondStyle).toMatch("refStyleTwo");

test/e2e/core/tms.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jest.setTimeout(50000);
2626
let tileOrder = ["1/0/1", "1/0/0", "1/1/1", "1/1/0"]
2727
for (let i = 0; i < 4; i++) {
2828
const feature = await page.$eval(
29-
`xpath=//html/body/mapml-viewer >> css=div > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-overlay-pane > div > div.leaflet-layer.mapml-templatedlayer-container > div > div > img:nth-child(${i + 1})`,
29+
`xpath=//html/body/mapml-viewer >> css=div > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-overlay-pane > div > div.leaflet-layer.mapml-templatedlayer-container > div > div > div:nth-child(${i + 1}) > img`,
3030
(tile) => tile.getAttribute("src")
3131
);
3232
expect(feature).toEqual(`https://maps4html.org/TiledArt-Rousseau/TheBanksOfTheBièvreNearBicêtre/${tileOrder[i]}.png`);
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<html>
2+
3+
<head>
4+
<title>Client Tiles</title>
5+
<meta charset="UTF-8">
6+
<script type="module" src="mapml-viewer.js"></script>
7+
<style>
8+
html {
9+
height: 100%
10+
}
11+
12+
body,
13+
map {
14+
height: inherit
15+
}
16+
17+
* {
18+
margin: 0;
19+
padding: 0;
20+
}
21+
</style>
22+
</head>
23+
24+
<body>
25+
<mapml-viewer style="width: 500px;height: 500px;" projection="WGS84" zoom="0" lat="59.87304909" lon="-53.22587225"
26+
width="900" height="400" controls>
27+
28+
<layer- label="Inline Templated Tile" checked>
29+
<meta name="zoom" content="min=0,max=5" />
30+
<extent units="WGS84">
31+
<input name="zoomLevel" type="zoom" min="1" max="1" value="0" />
32+
33+
<input name="row" type="location" axis="row" units="tilematrix" min="0" max="1" />
34+
<input name="col" type="location" axis="column" units="tilematrix" min="0" max="1" />
35+
36+
<link rel='tile' type='text/mapml' title='Tiles for ne_10m_admin_0_countries (as MapML)' />
37+
38+
</extent>
39+
</layer->
40+
</mapml-viewer>
41+
<script>
42+
let layer = document.querySelector("body > mapml-viewer > layer- > extent > link");
43+
layer.addEventListener("tileloadstart", (e) => {
44+
//let cust = document.createElement("IMG")
45+
//cust.src = "https://1000logos.net/wp-content/uploads/2018/11/GitHub-logo-500x452.png";
46+
//cust.width = 50;
47+
//cust.height = 50;
48+
let cust = document.createElement("P");
49+
cust.textContent = `${e.detail.x}${e.detail.y}${e.detail.zoom}`;
50+
e.detail.appendTile(cust);
51+
});
52+
</script>
53+
</body>
54+
55+
</html>
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
const playwright = require("playwright");
2+
3+
jest.setTimeout(50000);
4+
(async () => {
5+
6+
for (const browserType of BROWSER) {
7+
let page, browser, context;
8+
describe(
9+
"Playwright Client Tile Tests in " + browserType,
10+
() => {
11+
beforeAll(async () => {
12+
browser = await playwright[browserType].launch({
13+
headless: ISHEADLESS,
14+
slowMo: 50,
15+
});
16+
context = await browser.newContext();
17+
page = await context.newPage();
18+
if (browserType === "firefox") {
19+
await page.waitForNavigation();
20+
}
21+
await page.goto(PATH + "clientTemplatedTileLayer.html");
22+
});
23+
24+
afterAll(async function () {
25+
await browser.close();
26+
});
27+
28+
test("[" + browserType + "]" + " Custom Tiles Loaded In, Accurate Coordinates", async () => {
29+
const one = await page.$eval(
30+
"xpath=//html/body/mapml-viewer >> css=div > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-overlay-pane > div > div.leaflet-layer.mapml-templatedlayer-container > div > div > div:nth-child(1) > p",
31+
(tile) => tile.textContent
32+
);
33+
const two = await page.$eval(
34+
"xpath=//html/body/mapml-viewer >> css=div > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-overlay-pane > div > div.leaflet-layer.mapml-templatedlayer-container > div > div > div:nth-child(2) > p",
35+
(tile) => tile.textContent
36+
);
37+
const three = await page.$eval(
38+
"xpath=//html/body/mapml-viewer >> css=div > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-overlay-pane > div > div.leaflet-layer.mapml-templatedlayer-container > div > div > div:nth-child(3) > p",
39+
(tile) => tile.textContent
40+
);
41+
const four = await page.$eval(
42+
"xpath=//html/body/mapml-viewer >> css=div > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-overlay-pane > div > div.leaflet-layer.mapml-templatedlayer-container > div > div > div:nth-child(4) > p",
43+
(tile) => tile.textContent
44+
);
45+
const five = await page.$eval(
46+
"xpath=//html/body/mapml-viewer >> css=div > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-overlay-pane > div > div.leaflet-layer.mapml-templatedlayer-container > div > div > div:nth-child(5) > p",
47+
(tile) => tile.textContent
48+
);
49+
const six = await page.$eval(
50+
"xpath=//html/body/mapml-viewer >> css=div > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-overlay-pane > div > div.leaflet-layer.mapml-templatedlayer-container > div > div > div:nth-child(6) > p",
51+
(tile) => tile.textContent
52+
);
53+
const seven = await page.$eval(
54+
"xpath=//html/body/mapml-viewer >> css=div > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-overlay-pane > div > div.leaflet-layer.mapml-templatedlayer-container > div > div > div:nth-child(7) > p",
55+
(tile) => tile.textContent
56+
);
57+
const eight = await page.$eval(
58+
"xpath=//html/body/mapml-viewer >> css=div > div.leaflet-pane.leaflet-map-pane > div.leaflet-pane.leaflet-overlay-pane > div > div.leaflet-layer.mapml-templatedlayer-container > div > div > div:nth-child(8) > p",
59+
(tile) => tile.textContent
60+
);
61+
62+
expect(one).toEqual("101");
63+
expect(two).toEqual("001");
64+
expect(three).toEqual("201");
65+
expect(four).toEqual("111");
66+
expect(five).toEqual("011");
67+
expect(six).toEqual("211");
68+
expect(seven).toEqual("301");
69+
expect(eight).toEqual("311");
70+
71+
});
72+
});
73+
}
74+
})();

0 commit comments

Comments
 (0)