Skip to content

Commit 750ca7d

Browse files
committed
Add Legend in layer control settings
1 parent b0a44a2 commit 750ca7d

4 files changed

Lines changed: 196 additions & 4 deletions

File tree

src/mapml.css

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,19 @@ the browser)' */
9595
color: revert;
9696
}
9797

98+
.mapml-layer-item-legend-link {
99+
display: inline-block;
100+
margin-block-start: .25rem;
101+
}
102+
103+
.mapml-layer-item-legend-image {
104+
display: block;
105+
max-width: min(100%, 16rem);
106+
height: auto;
107+
border: 1px solid #e3e3e3;
108+
border-radius: 2px;
109+
}
110+
98111
.leaflet-top .leaflet-control {
99112
margin-top: 5px;
100113
}
@@ -801,7 +814,7 @@ label.mapml-layer-item-toggle {
801814
padding-block-start: .25rem;
802815
padding-block-end: .25rem;
803816
padding-inline-start: .25rem;
804-
padding-inline-end: 1rem;
817+
display: inline-block;
805818
}
806819

807820
.mapml-layer-item-settings > * {

src/mapml/elementSupport/layers/createLayerControlForLayer.js

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,12 +139,38 @@ export var createLayerControlHTML = async function () {
139139
};
140140
input.addEventListener('change', changeCheck.bind(this));
141141
if (this._layer._legendUrl) {
142-
var legendLink = document.createElement('a');
143-
legendLink.text = ' ' + this._layer._title;
142+
layerItemName.innerText = this._layer._title;
143+
144+
let legendControl = DomUtil.create(
145+
'details',
146+
'mapml-layer-item-legend mapml-control-layers',
147+
layerItemSettings
148+
),
149+
legendSummary = DomUtil.create('summary'),
150+
legendLink = document.createElement('a'),
151+
legendImage = document.createElement('img');
152+
153+
legendSummary.innerText = mapEl.locale.lmLegend;
154+
legendControl.appendChild(legendSummary);
155+
144156
legendLink.href = this._layer._legendUrl;
145157
legendLink.target = '_blank';
158+
legendLink.rel = 'noopener noreferrer';
146159
legendLink.draggable = false;
147-
layerItemName.appendChild(legendLink);
160+
legendLink.className = 'mapml-layer-item-legend-link';
161+
162+
legendImage.src = this._layer._legendUrl;
163+
legendImage.alt = `${this._layer._title} legend`;
164+
legendImage.loading = 'lazy';
165+
legendImage.decoding = 'async';
166+
legendImage.className = 'mapml-layer-item-legend-image';
167+
legendImage.addEventListener('error', () => {
168+
legendLink.textContent = mapEl.locale.lmOpenInNewTab;
169+
legendImage.remove();
170+
});
171+
172+
legendLink.appendChild(legendImage);
173+
legendControl.appendChild(legendLink);
148174
} else {
149175
layerItemName.innerHTML = this._layer._title;
150176
}

test/e2e/layers/layerLegend.html

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<title>Layer Legend Control Tests</title>
6+
<meta charset="UTF-8">
7+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
8+
<script type="module" src="mapml.js"></script>
9+
<style>
10+
html,
11+
body {
12+
height: 100%;
13+
}
14+
15+
* {
16+
margin: 0;
17+
padding: 0;
18+
}
19+
20+
mapml-viewer:defined {
21+
max-width: 100%;
22+
width: 100%;
23+
height: 100%;
24+
}
25+
26+
mapml-viewer:not(:defined) > * {
27+
display: none;
28+
}
29+
30+
map-layer {
31+
display: none;
32+
}
33+
</style>
34+
</head>
35+
36+
<body>
37+
<mapml-viewer projection="CBMTILE" zoom="2" lat="45" lon="-95" controls>
38+
<map-layer label="Toporama" src="data/templatedImage.mapml" checked></map-layer>
39+
40+
<map-layer label="Inline No Legend" checked>
41+
<map-meta name="zoom" content="min=0,max=3,value=2"></map-meta>
42+
<map-meta name="projection" content="CBMTILE"></map-meta>
43+
<map-tile zoom="2" row="10" col="11" src="data/cbmt/2/c11_r10.png"></map-tile>
44+
</map-layer>
45+
46+
<map-layer label="html legend" checked>
47+
<map-meta name="zoom" content="min=0,max=3,value=2"></map-meta>
48+
<map-meta name="projection" content="CBMTILE"></map-meta>
49+
<map-link rel="legend" href="https://maps4html.org/web-map-doc/"></map-link>
50+
<map-feature>
51+
<map-geometry cs="gcrs">
52+
<map-point class="ottawa">
53+
<map-coordinates>-75.697193 45.421530</map-coordinates>
54+
</map-point>
55+
</map-geometry>
56+
</map-feature>
57+
</mapml-viewer>
58+
</body>
59+
60+
</html>
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import { test, expect, chromium } from '@playwright/test';
2+
3+
test.describe('Layer legend tests', () => {
4+
let page;
5+
let context;
6+
7+
test.beforeAll(async () => {
8+
context = await chromium.launchPersistentContext('', { slowMo: 250 });
9+
page = await context.newPage();
10+
await page.goto('layerLegend.html');
11+
await page.locator('mapml-viewer').hover();
12+
});
13+
14+
test.afterAll(async () => {
15+
await context.close();
16+
});
17+
18+
test('Legend layer has legend details in layer settings', async () => {
19+
// Get the first layer in the overlay list (the one with an img legend)
20+
const layer = page
21+
.locator('.leaflet-control-layers-overlays > fieldset')
22+
.first();
23+
24+
// Open the settings for that layer and check that the legend details are present
25+
const settings = layer.locator('.mapml-layer-item-settings');
26+
27+
// Check that the legend details, name, and link are present and correct
28+
const legendDetails = settings.locator('details.mapml-layer-item-legend');
29+
await expect(legendDetails).toHaveCount(1);
30+
await expect(legendDetails.locator('summary')).toHaveText('Legend');
31+
await expect(
32+
legendDetails.locator('a.mapml-layer-item-legend-link')
33+
).toHaveAttribute(
34+
'href',
35+
'http://maps.geogratis.gc.ca/wms/toporama_en?SERVICE=WMS&REQUEST=GetLegendGraphic&LAYER=WMS-Toporama&VERSION=1.1&FORMAT=image/png'
36+
);
37+
await expect(
38+
legendDetails.locator('img.mapml-layer-item-legend-image')
39+
).toHaveAttribute(
40+
'src',
41+
'http://maps.geogratis.gc.ca/wms/toporama_en?SERVICE=WMS&REQUEST=GetLegendGraphic&LAYER=WMS-Toporama&VERSION=1.1&FORMAT=image/png'
42+
);
43+
44+
// check that the legend details are the second details element in the settings
45+
const secondDetails = settings.locator('> details').nth(1);
46+
await expect(secondDetails).toHaveClass(
47+
'mapml-layer-item-legend mapml-control-layers'
48+
);
49+
});
50+
51+
test('Layer without legend does not render legend details in settings', async () => {
52+
// Get the second layer in the overlay list (the one without a legend)
53+
const layer = page
54+
.locator('.leaflet-control-layers-overlays > fieldset')
55+
.nth(1);
56+
57+
// check that the settings for that layer do not contain any legend details
58+
const settings = layer.locator('.mapml-layer-item-settings');
59+
await expect(
60+
settings.locator('details.mapml-layer-item-legend')
61+
).toHaveCount(0);
62+
});
63+
64+
test('Layer with a non img legend renders a legend link', async () => {
65+
// Get the third layer in the overlay list (the one with a non img legend)
66+
const layer = page
67+
.locator('.leaflet-control-layers-overlays > fieldset')
68+
.nth(2);
69+
70+
// check that the settings for that layer contain a legend link
71+
const settings = layer.locator('.mapml-layer-item-settings');
72+
73+
// Check that the legend details, name, and link are present and correct
74+
const legendDetails = settings.locator('details.mapml-layer-item-legend');
75+
await expect(legendDetails).toHaveCount(1);
76+
await expect(legendDetails.locator('summary')).toHaveText('Legend');
77+
await expect(
78+
legendDetails.locator('a.mapml-layer-item-legend-link')
79+
).toHaveAttribute('href', 'https://maps4html.org/web-map-doc/');
80+
81+
// not working, need to manually open the legend for it to update.
82+
/*await expect(
83+
legendDetails.locator('a.mapml-layer-item-legend-link')
84+
).toHaveText("Open Legend");
85+
*/
86+
87+
// check that the legend details are the second details element in the settings
88+
const secondDetails = settings.locator('> details').nth(1);
89+
await expect(secondDetails).toHaveClass(
90+
'mapml-layer-item-legend mapml-control-layers'
91+
);
92+
});
93+
});

0 commit comments

Comments
 (0)