Skip to content

Commit 930b852

Browse files
yhy0217prushforprushforthAliyanH
authored
Develop <map-feature> custom element (#801)
* map-feature development * add comments for intended zoom attribute behaviors * fix bug of the click() method * handle focus, modify default click() and focus() methods and tests * fix bugs, make layer element reload if the src attribute is changed * small fix, make focus not toggled and remove the current focus state when other element is set to focused * Change context menu to copy location as a map-feature. Change Util._pasteLayer to sniff for <map-feature, paste as a visible layer. * make elements in mapml file migrate at loading stage * small fix, add comments * fix issue 803 * map-feature development * add comments for intended zoom attribute behaviors * fix bug of the click() method * handle focus, modify default click() and focus() methods and tests * fix bugs, make layer element reload if the src attribute is changed * small fix, make focus not toggled and remove the current focus state when other element is set to focused * make elements in mapml file migrate at loading stage * small fix, add comments * fix issue 803 * Add states and cors support for development needs * fix bug: err is thrown if making changes on <map-feature> when templated features exist in <layer- > * fix bug when projection is changed: XHR twice and multiple copies of mapml is attached to shadow * make map-properties can be interactively removed and added, change geojson format and rename the method * modify tests * rename get geojson method for consistency, add tests * simplify focus method * Revert "Add states and cors support for development needs" This reverts commit 6afc79d. * Revert "Change context menu to copy location as a map-feature. Change Util._pasteLayer to sniff for <map-feature, paste as a visible layer." This reverts commit 99963c5. * rename _featureLayer to _featureGroup for consistency * create private methods that imply layer- element is removed and connected to DOM * continue renaming * add getMaxZoom() method * zoomTo, paste, remove feature * add support for setting event handlers via HTML and Script * small fix * Update src/map-feature.js Co-authored-by: Aliyan Haq <[email protected]> * Update src/map-feature.js Co-authored-by: Aliyan Haq <[email protected]> * bug fixing, refactoring, support for mapFeature.addEventListener * fix bug that map-coordinates cannot be changed twice * add zoom to link in popup, make a connection that allows the Leaflet layer to reference the corresponding Map feature element, and some small fix * resolve failing tests * zoomTo link bug fixing 1 * add min and max attributes, modify zoomTo method * add 'options' parameter to focus() method * close 821, localize zoom to here link in popup * Add Man With Two Hats to index.html * update outdated comment for mapml2geojson method * bug fixing, add comments * make _handlefocus only handle keyboardEvent Co-authored-by: Aliyan Haq <[email protected]> * make _handlefocus only handle keyboardEvent, cont. Co-authored-by: Aliyan Haq <[email protected]> * remove unnecessary _clampZoom in FeatureLayer.js --------- Co-authored-by: prushfor <[email protected]> Co-authored-by: Peter Rushforth <[email protected]> Co-authored-by: Aliyan Haq <[email protected]> Co-authored-by: AliyanH <[email protected]>
1 parent fc0c8da commit 930b852

18 files changed

+2403
-123
lines changed

Gruntfile.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ module.exports = function(grunt) {
2727
'dist/mapml-viewer.js': ['src/mapml-viewer.js'],
2828
'dist/DOMTokenList.js': ['src/mapml/utils/DOMTokenList.js'],
2929
'dist/map-caption.js': ['src/map-caption.js'],
30+
'dist/map-feature.js': ['src/map-feature.js'],
3031
'dist/map-area.js': ['src/map-area.js'],
3132
'dist/layer.js': ['src/layer.js'],
3233
'dist/leaflet.js': ['dist/leaflet-src.js',

index.html

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,55 @@
7575
<mapml-viewer projection="CBMTILE" zoom="2" lat="45" lon="-90" controls controlslist="geolocation">
7676
<map-caption>A pleasing map of Canada</map-caption>
7777
<layer- label="CBMT" src="https://geogratis.gc.ca/mapml/en/cbmtile/cbmt/" checked></layer->
78+
<layer- label="Hat Guy" checked>
79+
<map-meta name="projection" content="CBMTILE"></map-meta>
80+
<map-feature id="twohats" zoom="15" class="twohats">
81+
<map-properties>
82+
<table>
83+
<tr>
84+
<th>code</th>
85+
<td>1200020</td>
86+
</tr>
87+
<tr>
88+
<th>accuracy</th>
89+
<td>26</td>
90+
</tr>
91+
<tr>
92+
<th>valdate</th>
93+
<td>1995</td>
94+
</tr>
95+
<tr>
96+
<th>image</th>
97+
<td><a href="https://www.veterans.gc.ca/eng/remembrance/memorials/national-inventory-canadian-memorials/details/9304">
98+
<img src="https://www.veterans.gc.ca/images/remembrance/memorials/national-inventory-canadian-memorials/mem/35059-173a.jpg" width="60" height="60"/>
99+
</a>
100+
</td>
101+
</tr>
102+
<tr>
103+
<th>theme</th>
104+
<td>FO</td>
105+
</tr>
106+
<tr>
107+
<th>type</th>
108+
<td>2</td>
109+
</tr>
110+
<tr>
111+
<th>elevation</th>
112+
<td>61</td>
113+
</tr>
114+
<tr>
115+
<th>altiaccu</th>
116+
<td>5</td>
117+
</tr>
118+
</table>
119+
</map-properties>
120+
<map-geometry cs="gcrs">
121+
<map-point>
122+
<map-coordinates>-75.705278 45.397778</map-coordinates>
123+
</map-point>
124+
</map-geometry>
125+
</map-feature>
126+
</layer->
78127
</mapml-viewer>
79128
</body>
80129
</html>

src/layer.js

Lines changed: 55 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,6 @@ export class MapLayer extends HTMLElement {
1212
set src(val) {
1313
if (val) {
1414
this.setAttribute('src', val);
15-
if (this._layer) {
16-
let oldOpacity = this.opacity;
17-
// go through the same sequence as if the layer had been removed from
18-
// the DOM and re-attached with a new URL source.
19-
this.disconnectedCallback();
20-
var base = this.baseURI ? this.baseURI : document.baseURI;
21-
this._layer = M.mapMLLayer(val ? (new URL(val, base)).href: null, this);
22-
this._layer.on('extentload', this._onLayerExtentLoad, this);
23-
this._setUpEvents();
24-
if (this.parentNode) {
25-
this.connectedCallback();
26-
}
27-
this.opacity = oldOpacity;
28-
}
2915
}
3016
}
3117
get label() {
@@ -82,6 +68,10 @@ export class MapLayer extends HTMLElement {
8268
// to the layer being removed with the _onLayerChange execution
8369
// that is set up in _attached:
8470
if(this.hasAttribute("data-moving")) return;
71+
this._onRemove();
72+
}
73+
74+
_onRemove() {
8575
this._removeEvents();
8676
if (this._layer._map) {
8777
this._layer._map.removeLayer(this._layer);
@@ -90,11 +80,23 @@ export class MapLayer extends HTMLElement {
9080
if (this._layerControl && !this.hidden) {
9181
this._layerControl.removeLayer(this._layer);
9282
}
83+
84+
if (this.shadowRoot) {
85+
this.shadowRoot.innerHTML = '';
86+
}
9387
}
88+
9489
connectedCallback() {
9590
//creates listener that waits for createmap event, this allows for delayed builds of maps
9691
//this allows a safeguard for the case where loading a custom TCRS takes longer than loading mapml-viewer.js/web-map.js
9792
if(this.hasAttribute("data-moving")) return;
93+
this._onAdd();
94+
}
95+
96+
_onAdd() {
97+
if(this.getAttribute('src') && !this.shadowRoot) {
98+
this.attachShadow({mode: 'open'});
99+
}
98100
this.parentNode.addEventListener('createmap', ()=>{
99101
this._ready();
100102
// if the map has been attached, set this layer up wrt Leaflet map
@@ -108,6 +110,7 @@ export class MapLayer extends HTMLElement {
108110
//if map is already created then dispatch createmap event, allowing layer to be built
109111
if(this.parentNode._map)this.parentNode.dispatchEvent(new CustomEvent('createmap'));
110112
}
113+
111114
adoptedCallback() {
112115
// console.log('Custom map element moved to new page.');
113116
}
@@ -148,7 +151,24 @@ export class MapLayer extends HTMLElement {
148151
this.opacity = newValue;
149152
}
150153
break;
154+
case 'src':
155+
if (oldValue !== newValue && this._layer) {
156+
this._reload();
157+
// the original inline content will not be removed
158+
// but has NO EFFECT and works as a fallback
159+
}
160+
}
161+
}
162+
// re-load the layer element when the src attribute is changed
163+
_reload() {
164+
let oldOpacity = this.opacity;
165+
// go through the same sequence as if the layer had been removed from
166+
// the DOM and re-attached with a new URL source.
167+
this._onRemove();
168+
if (this.isConnected) {
169+
this._onAdd();
151170
}
171+
this.opacity = oldOpacity;
152172
}
153173
_onLayerExtentLoad(e) {
154174
// the mapml document associated to this layer can in theory contain many
@@ -327,46 +347,30 @@ export class MapLayer extends HTMLElement {
327347
zoomTo() {
328348
if(!this.extent) return;
329349
let map = this._layer._map,
330-
tL = this.extent.topLeft.pcrs,
331-
bR = this.extent.bottomRight.pcrs,
332-
layerBounds = L.bounds(L.point(tL.horizontal, tL.vertical), L.point(bR.horizontal, bR.vertical)),
333-
center = map.options.crs.unproject(layerBounds.getCenter(true)),
334-
newZoom = map.getZoom();
350+
tL = this.extent.topLeft.pcrs,
351+
bR = this.extent.bottomRight.pcrs,
352+
layerBounds = L.bounds(L.point(tL.horizontal, tL.vertical), L.point(bR.horizontal, bR.vertical)),
353+
center = map.options.crs.unproject(layerBounds.getCenter(true));
335354

336-
let maxZoom = this.extent.zoom.maxZoom, minZoom = this.extent.zoom.minZoom;
337-
338-
let scale = map.options.crs.scale(newZoom),
339-
mapCenterTCRS = map.options.crs.transformation.transform(layerBounds.getCenter(true), scale);
340-
341-
let mapHalf = map.getSize().divideBy(2),
342-
mapTlNew = mapCenterTCRS.subtract(mapHalf).round(),
343-
mapBrNew = mapCenterTCRS.add(mapHalf).round();
344-
345-
let mapTlPCRSNew = M.pixelToPCRSPoint(mapTlNew, newZoom, map.options.projection),
346-
mapBrPCRSNew = M.pixelToPCRSPoint(mapBrNew, newZoom, map.options.projection);
347-
348-
let mapPCRS = L.bounds(mapTlPCRSNew, mapBrPCRSNew);
349-
350-
let zOffset = mapPCRS.contains(layerBounds) ? 1 : -1;
351-
352-
while((zOffset === -1 && !(mapPCRS.contains(layerBounds)) && (newZoom - 1) >= minZoom) ||
353-
(zOffset === 1 && mapPCRS.contains(layerBounds) && (newZoom + 1) <= maxZoom)) {
354-
newZoom += zOffset;
355-
356-
scale = map.options.crs.scale(newZoom);
357-
mapCenterTCRS = map.options.crs.transformation.transform(layerBounds.getCenter(true), scale);
358-
359-
mapTlNew = mapCenterTCRS.subtract(mapHalf).round();
360-
mapBrNew = mapCenterTCRS.add(mapHalf).round();
361-
mapTlPCRSNew = M.pixelToPCRSPoint(mapTlNew, newZoom, map.options.projection);
362-
mapBrPCRSNew = M.pixelToPCRSPoint(mapBrNew, newZoom, map.options.projection);
363-
364-
mapPCRS = L.bounds(mapTlPCRSNew, mapBrPCRSNew);
365-
}
366-
if(zOffset === 1 && newZoom - 1 >= 0) newZoom--;
367-
map.setView(center, newZoom, {animate: false});
355+
let maxZoom = this.extent.zoom.maxZoom,
356+
minZoom = this.extent.zoom.minZoom;
357+
map.setView(center, M.getMaxZoom(layerBounds, map, minZoom, maxZoom), {animate: false});
368358
}
369359
mapml2geojson(options = {}){
370360
return M.mapml2geojson(this, options);
371361
}
362+
pasteFeature(feature) {
363+
switch(typeof feature) {
364+
case "string":
365+
feature.trim();
366+
if (feature.slice(0,12) === "<map-feature" && feature.slice(-14) === "</map-feature>") {
367+
this.insertAdjacentHTML("beforeend", feature);
368+
}
369+
break;
370+
case "object":
371+
if (feature.nodeName.toUpperCase() === 'MAP-FEATURE') {
372+
this.appendChild(feature);
373+
}
374+
}
375+
}
372376
}

0 commit comments

Comments
 (0)