From 408f0e28dbaefee5e3b957d4460f24d1d284189f Mon Sep 17 00:00:00 2001 From: Ahmad Ayubi Date: Wed, 24 Nov 2021 14:32:40 -0500 Subject: [PATCH 01/11] Tab order based on distance from center --- src/mapml/features/feature.js | 4 +++ src/mapml/features/featureRenderer.js | 46 +++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/mapml/features/feature.js b/src/mapml/features/feature.js index 8e6083736..234313bab 100644 --- a/src/mapml/features/feature.js +++ b/src/mapml/features/feature.js @@ -339,6 +339,10 @@ export var Feature = L.Path.extend({ if (!this._bounds) return null; return this._map.options.crs.unproject(this._bounds.getCenter()); }, + + getPCRSCenter: function () { + return this._bounds.getCenter(); + }, }); /** diff --git a/src/mapml/features/featureRenderer.js b/src/mapml/features/featureRenderer.js index 7ec5cde7c..724fb0288 100644 --- a/src/mapml/features/featureRenderer.js +++ b/src/mapml/features/featureRenderer.js @@ -4,7 +4,40 @@ * @returns {*} */ export var FeatureRenderer = L.SVG.extend({ - + + _indexOrder: [], + + _addToIndex: function (layer, updateIndex) { + let scale = this._map.options.crs.scale(this._map.getZoom()); + let mc = this._map.options.crs.transformation.untransform(this._map.getPixelBounds().getCenter(),scale); + let lc = layer.getPCRSCenter(); + let dist = Math.sqrt(Math.pow(lc.x - mc.x, 2) + Math.pow(lc.y - mc.y, 2)) + + this._indexOrder.push({layer: layer, dist: dist, updateIndex: updateIndex}); + for (let i = this._indexOrder.length - 1; i > 0 && this._indexOrder[i].dist < this._indexOrder[i-1].dist; i--) { + let tmp = this._indexOrder[i]; + this._indexOrder[i] = this._indexOrder[i-1]; + this._indexOrder[i].updateIndex(i); + tmp.updateIndex(i-1); + this._indexOrder[i-1] = tmp; + } + }, + + _sortIndex: function () { + let scale = this._map.options.crs.scale(this._map.getZoom()); + let mc = this._map.options.crs.transformation.untransform(this._map.getPixelBounds().getCenter(),scale); + this._indexOrder.sort(function(a, b) { + let ac = a.layer.getPCRSCenter(); + let bc = b.layer.getPCRSCenter(); + a.dist = Math.sqrt(Math.pow(ac.x - mc.x, 2) + Math.pow(ac.y - mc.y, 2)); + b.dist = Math.sqrt(Math.pow(bc.x - mc.x, 2) + Math.pow(bc.y - mc.y, 2)); + return a.dist - b.dist; + }); + + this._indexOrder.forEach(function (l, i) { + l.updateIndex(i + 1); + }); + }, /** * Override method of same name from L.SVG, use the this._container property @@ -21,6 +54,7 @@ export var FeatureRenderer = L.SVG.extend({ // access it and set the role="none presetation" which suppresses the // announcement of "Graphic" on each feature focus. this._container.setAttribute('role', 'none presentation'); + this._map.on("moveend", this._sortIndex, this); }, /** @@ -43,13 +77,21 @@ export var FeatureRenderer = L.SVG.extend({ for (let p of layer._parts) { if (p.rings){ this._createPath(p, layer.options.className, layer.featureAttributes['aria-label'], layer.options.interactive, layer.featureAttributes); + if(layer.options.interactive) { + this._addToIndex(layer, function (val) { + p.path.setAttribute("tabindex", val); + }); + } if(layer.outlinePath) p.path.style.stroke = "none"; } if (p.subrings) { for (let r of p.subrings) { this._createPath(r, layer.options.className, r.attr['aria-label'], (r.link !== undefined), r.attr); if(r.attr && r.attr.tabindex){ - p.path.setAttribute('tabindex', r.attr.tabindex || '0'); + this._addToIndex(layer, function (val) { + r.path.setAttribute("tabindex", val); + }); + //p.path.setAttribute('tabindex', r.attr.tabindex || '0'); } } } From d2373fadab995761a47053a6f22f7e147dc9d562 Mon Sep 17 00:00:00 2001 From: Ahmad Ayubi Date: Sat, 27 Nov 2021 14:42:16 -0500 Subject: [PATCH 02/11] Use global sorting, handle tabbing using event handlers rather than tabindex --- src/mapml-viewer.js | 35 ++++++++++++++++++++ src/mapml/features/featureGroup.js | 36 ++++++++++++++++++++- src/mapml/features/featureRenderer.js | 46 +-------------------------- src/mapml/layers/Crosshair.js | 1 + src/web-map.js | 35 ++++++++++++++++++++ 5 files changed, 107 insertions(+), 46 deletions(-) diff --git a/src/mapml-viewer.js b/src/mapml-viewer.js index 66c247738..ca5e4a93c 100644 --- a/src/mapml-viewer.js +++ b/src/mapml-viewer.js @@ -152,6 +152,40 @@ export class MapViewer extends HTMLElement { }); }); this.controlsListObserver.observe(this, {attributes:true}); + this._featureIndexOrder = []; + this._currFeatureIndex = 0; + } + + _addToIndex(layer, path) { + let scale = this._map.options.crs.scale(this._map.getZoom()); + let mc = this._map.options.crs.transformation.untransform(this._map.getPixelBounds().getCenter(),scale); + let lc = layer.getPCRSCenter(); + let dist = Math.sqrt(Math.pow(lc.x - mc.x, 2) + Math.pow(lc.y - mc.y, 2)); + let index = this._map.options.mapEl._featureIndexOrder; + + let elem = {path: path, layer: layer, dist: dist}; + path.setAttribute("tabindex", -1); + index.push(elem); + for (let i = index.length - 1; i > 0 && index[i].dist < index[i-1].dist; i--) { + let tmp = index[i]; + index[i] = index[i-1]; + index[i-1] = tmp; + } + } + + _sortIndex() { + let scale = this._map.options.crs.scale(this._map.getZoom()); + let mc = this._map.options.crs.transformation.untransform(this._map.getPixelBounds().getCenter(),scale); + let index = this._map.options.mapEl._featureIndexOrder; + index[0].path.setAttribute("tabindex", -1); + index.sort(function(a, b) { + let ac = a.layer.getPCRSCenter(); + let bc = b.layer.getPCRSCenter(); + a.dist = Math.sqrt(Math.pow(ac.x - mc.x, 2) + Math.pow(ac.y - mc.y, 2)); + b.dist = Math.sqrt(Math.pow(bc.x - mc.x, 2) + Math.pow(bc.y - mc.y, 2)); + return a.dist - b.dist; + }); + index[0].path.setAttribute("tabindex", 0); } connectedCallback() { if (this.isConnected) { @@ -375,6 +409,7 @@ export class MapViewer extends HTMLElement { {target: this}})); } }); + this._map.on('mapfocused', () => this._sortIndex()); this._map.on('load', function () { this.dispatchEvent(new CustomEvent('load', {detail: {target: this}})); diff --git a/src/mapml/features/featureGroup.js b/src/mapml/features/featureGroup.js index bcf3688ee..faa6218c2 100644 --- a/src/mapml/features/featureGroup.js +++ b/src/mapml/features/featureGroup.js @@ -12,7 +12,6 @@ export var FeatureGroup = L.FeatureGroup.extend({ L.LayerGroup.prototype.initialize.call(this, layers, options); if((this.options.onEachFeature && this.options.properties) || this.options.link) { - this.options.group.setAttribute('tabindex', '0'); L.DomUtil.addClass(this.options.group, "leaflet-interactive"); L.DomEvent.on(this.options.group, "keyup keydown mousedown", this._handleFocus, this); let firstLayer = layers[Object.keys(layers)[0]]; @@ -26,6 +25,7 @@ export var FeatureGroup = L.FeatureGroup.extend({ this.options.onEachFeature(this.options.properties, this); this.off("click", this._openPopup); } + this.options._leafletLayer._map.options.mapEl._addToIndex(this, this.options.group); } this.options.group.setAttribute('aria-label', this.options.accessibleTitle); @@ -39,6 +39,27 @@ export var FeatureGroup = L.FeatureGroup.extend({ */ _handleFocus: function(e) { if(e.target.tagName.toUpperCase() !== "G") return; + if((e.keyCode === 9 || e.keyCode === 16) && e.type === "keydown"){ + let index = this.options._leafletLayer._map.options.mapEl._currFeatureIndex; + if(e.keyCode === 9 && e.shiftKey) { + if(index !== 0){ + L.DomEvent.stop(e); + this.options._leafletLayer._map.options.mapEl._featureIndexOrder[index - 1].path.focus(); + this.options._leafletLayer._map.options.mapEl._currFeatureIndex--; + } + } else if (e.keyCode === 9) { + if(index !== this.options._leafletLayer._map.options.mapEl._featureIndexOrder.length - 1) { + L.DomEvent.stop(e); + this.options._leafletLayer._map.options.mapEl._featureIndexOrder[index + 1].path.focus(); + this.options._leafletLayer._map.options.mapEl._currFeatureIndex++; + } else { + this.options._leafletLayer._map.options.mapEl._featureIndexOrder[0].path.setAttribute("tabindex", -1); + this.options._leafletLayer._map.options.mapEl._featureIndexOrder[index].path.setAttribute("tabindex", 0); + } + } + } else if (!(e.keyCode === 9 || e.keyCode === 16)){ + this.options._leafletLayer._map.options.mapEl._currFeatureIndex = 0; + } if((e.keyCode === 9 || e.keyCode === 16 || e.keyCode === 13) && e.type === "keyup") { this.openTooltip(); } else if (e.keyCode === 13 || e.keyCode === 32){ @@ -108,6 +129,19 @@ export var FeatureGroup = L.FeatureGroup.extend({ group.focus(); this._map.closePopup(); }, + + getPCRSCenter: function () { + let bounds; + for(let l in this._layers){ + let layer = this._layers[l]; + if (!bounds) { + bounds = L.bounds(layer.getPCRSCenter(), layer.getPCRSCenter()); + } else { + bounds.extend(layer.getPCRSCenter()); + } + } + return bounds.getCenter(); + }, }); /** diff --git a/src/mapml/features/featureRenderer.js b/src/mapml/features/featureRenderer.js index 724fb0288..b2551937c 100644 --- a/src/mapml/features/featureRenderer.js +++ b/src/mapml/features/featureRenderer.js @@ -4,41 +4,6 @@ * @returns {*} */ export var FeatureRenderer = L.SVG.extend({ - - _indexOrder: [], - - _addToIndex: function (layer, updateIndex) { - let scale = this._map.options.crs.scale(this._map.getZoom()); - let mc = this._map.options.crs.transformation.untransform(this._map.getPixelBounds().getCenter(),scale); - let lc = layer.getPCRSCenter(); - let dist = Math.sqrt(Math.pow(lc.x - mc.x, 2) + Math.pow(lc.y - mc.y, 2)) - - this._indexOrder.push({layer: layer, dist: dist, updateIndex: updateIndex}); - for (let i = this._indexOrder.length - 1; i > 0 && this._indexOrder[i].dist < this._indexOrder[i-1].dist; i--) { - let tmp = this._indexOrder[i]; - this._indexOrder[i] = this._indexOrder[i-1]; - this._indexOrder[i].updateIndex(i); - tmp.updateIndex(i-1); - this._indexOrder[i-1] = tmp; - } - }, - - _sortIndex: function () { - let scale = this._map.options.crs.scale(this._map.getZoom()); - let mc = this._map.options.crs.transformation.untransform(this._map.getPixelBounds().getCenter(),scale); - this._indexOrder.sort(function(a, b) { - let ac = a.layer.getPCRSCenter(); - let bc = b.layer.getPCRSCenter(); - a.dist = Math.sqrt(Math.pow(ac.x - mc.x, 2) + Math.pow(ac.y - mc.y, 2)); - b.dist = Math.sqrt(Math.pow(bc.x - mc.x, 2) + Math.pow(bc.y - mc.y, 2)); - return a.dist - b.dist; - }); - - this._indexOrder.forEach(function (l, i) { - l.updateIndex(i + 1); - }); - }, - /** * Override method of same name from L.SVG, use the this._container property * to set up the role="none presentation" on featureGroupu container, @@ -54,7 +19,6 @@ export var FeatureRenderer = L.SVG.extend({ // access it and set the role="none presetation" which suppresses the // announcement of "Graphic" on each feature focus. this._container.setAttribute('role', 'none presentation'); - this._map.on("moveend", this._sortIndex, this); }, /** @@ -77,21 +41,13 @@ export var FeatureRenderer = L.SVG.extend({ for (let p of layer._parts) { if (p.rings){ this._createPath(p, layer.options.className, layer.featureAttributes['aria-label'], layer.options.interactive, layer.featureAttributes); - if(layer.options.interactive) { - this._addToIndex(layer, function (val) { - p.path.setAttribute("tabindex", val); - }); - } if(layer.outlinePath) p.path.style.stroke = "none"; } if (p.subrings) { for (let r of p.subrings) { this._createPath(r, layer.options.className, r.attr['aria-label'], (r.link !== undefined), r.attr); if(r.attr && r.attr.tabindex){ - this._addToIndex(layer, function (val) { - r.path.setAttribute("tabindex", val); - }); - //p.path.setAttribute('tabindex', r.attr.tabindex || '0'); + this._map.options.mapEl._addToIndex(layer, r.path); } } } diff --git a/src/mapml/layers/Crosshair.js b/src/mapml/layers/Crosshair.js index b63ae5a54..4d8902097 100644 --- a/src/mapml/layers/Crosshair.js +++ b/src/mapml/layers/Crosshair.js @@ -96,6 +96,7 @@ export var Crosshair = L.Layer.extend({ this._map.isFocused = false; } else this._map.isFocused = isLeafletContainer && ["keyup", "keydown"].includes(e.type); + if(this._map.isFocused) this._map.fire("mapfocused"); this._addOrRemoveMapOutline(); this._addOrRemoveCrosshair(); }, diff --git a/src/web-map.js b/src/web-map.js index 850355f98..af3533aed 100644 --- a/src/web-map.js +++ b/src/web-map.js @@ -168,6 +168,40 @@ export class WebMap extends HTMLMapElement { }); }); this.controlsListObserver.observe(this, {attributes:true}); + this._featureIndexOrder = []; + this._currFeatureIndex = 0; + } + + _addToIndex(layer, path) { + let scale = this._map.options.crs.scale(this._map.getZoom()); + let mc = this._map.options.crs.transformation.untransform(this._map.getPixelBounds().getCenter(),scale); + let lc = layer.getPCRSCenter(); + let dist = Math.sqrt(Math.pow(lc.x - mc.x, 2) + Math.pow(lc.y - mc.y, 2)); + let index = this._map.options.mapEl._featureIndexOrder; + + let elem = {path: path, layer: layer, dist: dist}; + path.setAttribute("tabindex", -1); + index.push(elem); + for (let i = index.length - 1; i > 0 && index[i].dist < index[i-1].dist; i--) { + let tmp = index[i]; + index[i] = index[i-1]; + index[i-1] = tmp; + } + } + + _sortIndex() { + let scale = this._map.options.crs.scale(this._map.getZoom()); + let mc = this._map.options.crs.transformation.untransform(this._map.getPixelBounds().getCenter(),scale); + let index = this._map.options.mapEl._featureIndexOrder; + index[0].path.setAttribute("tabindex", -1); + index.sort(function(a, b) { + let ac = a.layer.getPCRSCenter(); + let bc = b.layer.getPCRSCenter(); + a.dist = Math.sqrt(Math.pow(ac.x - mc.x, 2) + Math.pow(ac.y - mc.y, 2)); + b.dist = Math.sqrt(Math.pow(bc.x - mc.x, 2) + Math.pow(bc.y - mc.y, 2)); + return a.dist - b.dist; + }); + index[0].path.setAttribute("tabindex", 0); } connectedCallback() { if (this.isConnected) { @@ -413,6 +447,7 @@ export class WebMap extends HTMLMapElement { {target: this}})); } }); + this._map.on('mapfocused', () => this._sortIndex()); this._map.on('load', function () { this.dispatchEvent(new CustomEvent('load', {detail: {target: this}})); From 9417a78ab1816359875b52ff6036f3ddd810714f Mon Sep 17 00:00:00 2001 From: Ahmad Ayubi Date: Sat, 4 Dec 2021 17:39:22 -0500 Subject: [PATCH 03/11] Fix feature order --- src/mapml-viewer.js | 30 ++++++++++++++++++--------- src/mapml/features/feature.js | 11 ++++++++-- src/mapml/features/featureGroup.js | 9 +++++++- src/mapml/features/featureRenderer.js | 4 +--- src/mapml/layers/FeatureLayer.js | 4 ++++ src/web-map.js | 30 ++++++++++++++++++--------- 6 files changed, 62 insertions(+), 26 deletions(-) diff --git a/src/mapml-viewer.js b/src/mapml-viewer.js index ca5e4a93c..4e4082d65 100644 --- a/src/mapml-viewer.js +++ b/src/mapml-viewer.js @@ -156,14 +156,13 @@ export class MapViewer extends HTMLElement { this._currFeatureIndex = 0; } - _addToIndex(layer, path) { + _addToIndex(layer, lc, path) { let scale = this._map.options.crs.scale(this._map.getZoom()); let mc = this._map.options.crs.transformation.untransform(this._map.getPixelBounds().getCenter(),scale); - let lc = layer.getPCRSCenter(); let dist = Math.sqrt(Math.pow(lc.x - mc.x, 2) + Math.pow(lc.y - mc.y, 2)); let index = this._map.options.mapEl._featureIndexOrder; - let elem = {path: path, layer: layer, dist: dist}; + let elem = {path: path, layer: layer, center: lc, dist: dist}; path.setAttribute("tabindex", -1); index.push(elem); for (let i = index.length - 1; i > 0 && index[i].dist < index[i-1].dist; i--) { @@ -173,20 +172,31 @@ export class MapViewer extends HTMLElement { } } + _cleanIndex() { + this._currFeatureIndex = 0; + this._featureIndexOrder = this._featureIndexOrder.filter((elem) => { + return elem.layer._map; + }); + } + _sortIndex() { + this._cleanIndex(); + if(this._featureIndexOrder.length === 0) return; + let scale = this._map.options.crs.scale(this._map.getZoom()); - let mc = this._map.options.crs.transformation.untransform(this._map.getPixelBounds().getCenter(),scale); - let index = this._map.options.mapEl._featureIndexOrder; - index[0].path.setAttribute("tabindex", -1); - index.sort(function(a, b) { - let ac = a.layer.getPCRSCenter(); - let bc = b.layer.getPCRSCenter(); + let mc = this._map.options.crs.transformation.untransform(this._map.getPixelBounds().getCenter(), scale); + this._featureIndexOrder.sort(function(a, b) { + let ac = a.center; + let bc = b.center; + a.path.setAttribute("tabindex", -1); + b.path.setAttribute("tabindex", -1); a.dist = Math.sqrt(Math.pow(ac.x - mc.x, 2) + Math.pow(ac.y - mc.y, 2)); b.dist = Math.sqrt(Math.pow(bc.x - mc.x, 2) + Math.pow(bc.y - mc.y, 2)); return a.dist - b.dist; }); - index[0].path.setAttribute("tabindex", 0); + this._featureIndexOrder[0].path.setAttribute("tabindex", 0); } + connectedCallback() { if (this.isConnected) { diff --git a/src/mapml/features/feature.js b/src/mapml/features/feature.js index 234313bab..60ba12936 100644 --- a/src/mapml/features/feature.js +++ b/src/mapml/features/feature.js @@ -284,13 +284,19 @@ export var Feature = L.Path.extend({ this._coordinateToArrays(span, main, subParts, false, span.getAttribute("class"), parents.concat([span])); } let noSpan = coords.textContent.replace(/(<([^>]+)>)/ig, ''), - pairs = noSpan.match(/(\S+\s+\S+)/gim), local = []; + pairs = noSpan.match(/(\S+\s+\S+)/gim), local = [], bounds; for (let p of pairs) { let numPair = []; p.split(/\s+/gim).forEach(M.parseNumber, numPair); let point = M.pointToPCRSPoint(L.point(numPair), this.options.zoom, this.options.projection, this.options.nativeCS); local.push(point); - this._bounds = this._bounds ? this._bounds.extend(point) : L.bounds(point, point); + bounds = bounds ? bounds.extend(point) : L.bounds(point, point); + } + if (this._bounds) { + this._bounds.extend(bounds.min); + this._bounds.extend(bounds.max); + } else { + this._bounds = bounds; } if (isFirst) { main.push({ points: local }); @@ -303,6 +309,7 @@ export var Feature = L.Path.extend({ } subParts.unshift({ points: local, + center: bounds.getCenter(), cls: `${cls || ""} ${wrapperAttr.className || ""}`.trim(), attr: attrMap, link: wrapperAttr.link, diff --git a/src/mapml/features/featureGroup.js b/src/mapml/features/featureGroup.js index faa6218c2..2114366ee 100644 --- a/src/mapml/features/featureGroup.js +++ b/src/mapml/features/featureGroup.js @@ -25,13 +25,17 @@ export var FeatureGroup = L.FeatureGroup.extend({ this.options.onEachFeature(this.options.properties, this); this.off("click", this._openPopup); } - this.options._leafletLayer._map.options.mapEl._addToIndex(this, this.options.group); } this.options.group.setAttribute('aria-label', this.options.accessibleTitle); if(this.options.featureID) this.options.group.setAttribute("data-fid", this.options.featureID); }, + _updateInteraction: function () { + if((this.options.onEachFeature && this.options.properties) || this.options.link) + this.options._leafletLayer._map.options.mapEl._addToIndex(this, this.getPCRSCenter(), this.options.group); + }, + /** * Handler for focus events * @param {L.DOMEvent} e - Event that occurred @@ -42,6 +46,8 @@ export var FeatureGroup = L.FeatureGroup.extend({ if((e.keyCode === 9 || e.keyCode === 16) && e.type === "keydown"){ let index = this.options._leafletLayer._map.options.mapEl._currFeatureIndex; if(e.keyCode === 9 && e.shiftKey) { + if(index === this.options._leafletLayer._map.options.mapEl._featureIndexOrder.length - 1) + this.options._leafletLayer._map.options.mapEl._featureIndexOrder[index].path.setAttribute("tabindex", -1); if(index !== 0){ L.DomEvent.stop(e); this.options._leafletLayer._map.options.mapEl._featureIndexOrder[index - 1].path.focus(); @@ -59,6 +65,7 @@ export var FeatureGroup = L.FeatureGroup.extend({ } } else if (!(e.keyCode === 9 || e.keyCode === 16)){ this.options._leafletLayer._map.options.mapEl._currFeatureIndex = 0; + this.options._leafletLayer._map.options.mapEl._featureIndexOrder[0].path.focus(); } if((e.keyCode === 9 || e.keyCode === 16 || e.keyCode === 13) && e.type === "keyup") { this.openTooltip(); diff --git a/src/mapml/features/featureRenderer.js b/src/mapml/features/featureRenderer.js index b2551937c..0968ed00d 100644 --- a/src/mapml/features/featureRenderer.js +++ b/src/mapml/features/featureRenderer.js @@ -46,9 +46,7 @@ export var FeatureRenderer = L.SVG.extend({ if (p.subrings) { for (let r of p.subrings) { this._createPath(r, layer.options.className, r.attr['aria-label'], (r.link !== undefined), r.attr); - if(r.attr && r.attr.tabindex){ - this._map.options.mapEl._addToIndex(layer, r.path); - } + if(r.attr && r.attr.tabindex) this._map.options.mapEl._addToIndex(layer, r.center, r.path); } } this._updateStyle(layer); diff --git a/src/mapml/layers/FeatureLayer.js b/src/mapml/layers/FeatureLayer.js index e3a012a03..72cbff54f 100644 --- a/src/mapml/layers/FeatureLayer.js +++ b/src/mapml/layers/FeatureLayer.js @@ -72,6 +72,9 @@ export var MapMLFeatures = L.FeatureGroup.extend({ onAdd: function(map){ L.FeatureGroup.prototype.onAdd.call(this, map); + this.eachLayer(function (layer) { + layer._updateInteraction(); + }); if(this._mapmlFeatures)map.on("featurepagination", this.showPaginationFeature, this); }, @@ -82,6 +85,7 @@ export var MapMLFeatures = L.FeatureGroup.extend({ L.DomUtil.remove(this._container); } L.FeatureGroup.prototype.onRemove.call(this, map); + this._map.options.mapEl._cleanIndex(); }, getEvents: function(){ diff --git a/src/web-map.js b/src/web-map.js index af3533aed..63ad92575 100644 --- a/src/web-map.js +++ b/src/web-map.js @@ -172,14 +172,13 @@ export class WebMap extends HTMLMapElement { this._currFeatureIndex = 0; } - _addToIndex(layer, path) { + _addToIndex(layer, lc, path) { let scale = this._map.options.crs.scale(this._map.getZoom()); let mc = this._map.options.crs.transformation.untransform(this._map.getPixelBounds().getCenter(),scale); - let lc = layer.getPCRSCenter(); let dist = Math.sqrt(Math.pow(lc.x - mc.x, 2) + Math.pow(lc.y - mc.y, 2)); let index = this._map.options.mapEl._featureIndexOrder; - let elem = {path: path, layer: layer, dist: dist}; + let elem = {path: path, layer: layer, center: lc, dist: dist}; path.setAttribute("tabindex", -1); index.push(elem); for (let i = index.length - 1; i > 0 && index[i].dist < index[i-1].dist; i--) { @@ -189,20 +188,31 @@ export class WebMap extends HTMLMapElement { } } + _cleanIndex() { + this._currFeatureIndex = 0; + this._featureIndexOrder = this._featureIndexOrder.filter((elem) => { + return elem.layer._map; + }); + } + _sortIndex() { + this._cleanIndex(); + if(this._featureIndexOrder.length === 0) return; + let scale = this._map.options.crs.scale(this._map.getZoom()); - let mc = this._map.options.crs.transformation.untransform(this._map.getPixelBounds().getCenter(),scale); - let index = this._map.options.mapEl._featureIndexOrder; - index[0].path.setAttribute("tabindex", -1); - index.sort(function(a, b) { - let ac = a.layer.getPCRSCenter(); - let bc = b.layer.getPCRSCenter(); + let mc = this._map.options.crs.transformation.untransform(this._map.getPixelBounds().getCenter(), scale); + this._featureIndexOrder.sort(function(a, b) { + let ac = a.center; + let bc = b.center; + a.path.setAttribute("tabindex", -1); + b.path.setAttribute("tabindex", -1); a.dist = Math.sqrt(Math.pow(ac.x - mc.x, 2) + Math.pow(ac.y - mc.y, 2)); b.dist = Math.sqrt(Math.pow(bc.x - mc.x, 2) + Math.pow(bc.y - mc.y, 2)); return a.dist - b.dist; }); - index[0].path.setAttribute("tabindex", 0); + this._featureIndexOrder[0].path.setAttribute("tabindex", 0); } + connectedCallback() { if (this.isConnected) { From bfc0c460e520d42ed847070f972810ce4027e3fd Mon Sep 17 00:00:00 2001 From: Ahmad Ayubi Date: Sat, 4 Dec 2021 18:21:13 -0500 Subject: [PATCH 04/11] Update popup navigation button function --- src/mapml/features/featureGroup.js | 38 +++++++----------------------- src/mapml/layers/MapLayer.js | 23 +++++++++--------- 2 files changed, 21 insertions(+), 40 deletions(-) diff --git a/src/mapml/features/featureGroup.js b/src/mapml/features/featureGroup.js index 2114366ee..475af8a32 100644 --- a/src/mapml/features/featureGroup.js +++ b/src/mapml/features/featureGroup.js @@ -63,7 +63,7 @@ export var FeatureGroup = L.FeatureGroup.extend({ this.options._leafletLayer._map.options.mapEl._featureIndexOrder[index].path.setAttribute("tabindex", 0); } } - } else if (!(e.keyCode === 9 || e.keyCode === 16)){ + } else if (!(e.keyCode === 9 || e.keyCode === 16 || e.keyCode === 13)){ this.options._leafletLayer._map.options.mapEl._currFeatureIndex = 0; this.options._leafletLayer._map.options.mapEl._featureIndexOrder[0].path.focus(); } @@ -97,22 +97,10 @@ export var FeatureGroup = L.FeatureGroup.extend({ * @private */ _previousFeature: function(e){ - let group = this._source.group.previousSibling; - if(!group){ - let currentIndex = this._source.group.closest("div.mapml-layer").style.zIndex; - let overlays = this._map.getPane("overlayPane").children; - for(let i = overlays.length - 1; i >= 0; i--){ - let layer = overlays[i]; - if(layer.style.zIndex >= currentIndex) continue; - group = layer.querySelector("g.leaflet-interactive"); - if(group){ - group = group.parentNode.lastChild; - break; - } - } - if (!group) group = this._source.group; - } - group.focus(); + L.DomEvent.stop(e); + this._map.options.mapEl._currFeatureIndex = Math.max(this._map.options.mapEl._currFeatureIndex - 1, 0); + let prevFocus = this._map.options.mapEl._featureIndexOrder[this._map.options.mapEl._currFeatureIndex]; + prevFocus.path.focus(); this._map.closePopup(); }, @@ -122,18 +110,10 @@ export var FeatureGroup = L.FeatureGroup.extend({ * @private */ _nextFeature: function(e){ - let group = this._source.group.nextSibling; - if(!group){ - let currentIndex = this._source.group.closest("div.mapml-layer").style.zIndex; - - for(let layer of this._map.getPane("overlayPane").children){ - if(layer.style.zIndex <= currentIndex) continue; - group = layer.querySelectorAll("g.leaflet-interactive"); - if(group.length > 0)break; - } - group = group && group.length > 0 ? group[0] : this._source.group; - } - group.focus(); + L.DomEvent.stop(e); + this._map.options.mapEl._currFeatureIndex = Math.min(this._map.options.mapEl._currFeatureIndex + 1, this._map.options.mapEl._featureIndexOrder.length - 1); + let nextFocus = this._map.options.mapEl._featureIndexOrder[this._map.options.mapEl._currFeatureIndex]; + nextFocus.path.focus(); this._map.closePopup(); }, diff --git a/src/mapml/layers/MapLayer.js b/src/mapml/layers/MapLayer.js index 11777521e..ccbd3363d 100644 --- a/src/mapml/layers/MapLayer.js +++ b/src/mapml/layers/MapLayer.js @@ -1168,9 +1168,9 @@ export var MapMLLayer = L.Layer.extend({ mapFocusButton.type = "button"; mapFocusButton.title = "Focus Map"; mapFocusButton.innerHTML = ""; - L.DomEvent.disableClickPropagation(mapFocusButton); - L.DomEvent.on(mapFocusButton, 'click', L.DomEvent.stop); L.DomEvent.on(mapFocusButton, 'click', (e)=>{ + L.DomEvent.stop(e); + map.options.mapEl._sortIndex(); map.closePopup(); map._container.focus(); }, popup); @@ -1180,8 +1180,6 @@ export var MapMLLayer = L.Layer.extend({ previousButton.type = "button"; previousButton.title = "Previous Feature"; previousButton.innerHTML = ""; - L.DomEvent.disableClickPropagation(previousButton); - L.DomEvent.on(previousButton, 'click', L.DomEvent.stop); L.DomEvent.on(previousButton, 'click', layer._previousFeature, popup); // static feature counter that 1/1 @@ -1194,8 +1192,6 @@ export var MapMLLayer = L.Layer.extend({ nextButton.type = "button"; nextButton.title = "Next Feature"; nextButton.innerHTML = ""; - L.DomEvent.disableClickPropagation(nextButton); - L.DomEvent.on(nextButton, 'click', L.DomEvent.stop); L.DomEvent.on(nextButton, 'click', layer._nextFeature, popup); // creates >| button, focuses map controls @@ -1203,9 +1199,12 @@ export var MapMLLayer = L.Layer.extend({ controlFocusButton.type = "button"; controlFocusButton.title = "Focus Controls"; controlFocusButton.innerHTML = ""; - L.DomEvent.disableClickPropagation(controlFocusButton); - L.DomEvent.on(controlFocusButton, 'click', L.DomEvent.stop); L.DomEvent.on(controlFocusButton, 'click', (e) => { + map.options.mapEl._sortIndex(); + map.options.mapEl._currFeatureIndex = map.options.mapEl._featureIndexOrder.length - 1; + map.options.mapEl._featureIndexOrder[0].path.setAttribute("tabindex", -1); + map.options.mapEl._featureIndexOrder[map.options.mapEl._currFeatureIndex].path.setAttribute("tabindex", 0); + L.DomEvent.stop(e); map.closePopup(); map._controlContainer.querySelector("A").focus(); }, popup); @@ -1232,9 +1231,11 @@ export var MapMLLayer = L.Layer.extend({ let isTab = focusEvent.originalEvent.keyCode === 9, shiftPressed = focusEvent.originalEvent.shiftKey; if((path[0].classList.contains("leaflet-popup-close-button") && isTab && !shiftPressed) || focusEvent.originalEvent.keyCode === 27){ - L.DomEvent.stop(focusEvent); - map.closePopup(popup); - group.focus(); + setTimeout(() => { + L.DomEvent.stop(focusEvent); + map.closePopup(popup); + group.focus(); + }, 0); } else if ((path[0].title==="Focus Map" || path[0].classList.contains("mapml-popup-content")) && isTab && shiftPressed){ setTimeout(() => { //timeout needed so focus of the feature is done even after the keypressup event occurs L.DomEvent.stop(focusEvent); From 9c29869634705263412eaf113b2af1ff3d28f1b9 Mon Sep 17 00:00:00 2001 From: Ahmad Ayubi Date: Fri, 10 Dec 2021 15:24:16 -0500 Subject: [PATCH 05/11] Refactor, only tab features within map bounds --- src/mapml-viewer.js | 45 +------------- src/mapml/features/featureGroup.js | 26 ++++---- src/mapml/features/featureRenderer.js | 2 +- src/mapml/handlers/FeatureIndex.js | 90 +++++++++++++++++++++++++++ src/mapml/index.js | 3 + src/mapml/layers/FeatureLayer.js | 2 +- src/web-map.js | 45 +------------- 7 files changed, 110 insertions(+), 103 deletions(-) create mode 100644 src/mapml/handlers/FeatureIndex.js diff --git a/src/mapml-viewer.js b/src/mapml-viewer.js index 4e4082d65..0f47f3ac3 100644 --- a/src/mapml-viewer.js +++ b/src/mapml-viewer.js @@ -152,49 +152,6 @@ export class MapViewer extends HTMLElement { }); }); this.controlsListObserver.observe(this, {attributes:true}); - this._featureIndexOrder = []; - this._currFeatureIndex = 0; - } - - _addToIndex(layer, lc, path) { - let scale = this._map.options.crs.scale(this._map.getZoom()); - let mc = this._map.options.crs.transformation.untransform(this._map.getPixelBounds().getCenter(),scale); - let dist = Math.sqrt(Math.pow(lc.x - mc.x, 2) + Math.pow(lc.y - mc.y, 2)); - let index = this._map.options.mapEl._featureIndexOrder; - - let elem = {path: path, layer: layer, center: lc, dist: dist}; - path.setAttribute("tabindex", -1); - index.push(elem); - for (let i = index.length - 1; i > 0 && index[i].dist < index[i-1].dist; i--) { - let tmp = index[i]; - index[i] = index[i-1]; - index[i-1] = tmp; - } - } - - _cleanIndex() { - this._currFeatureIndex = 0; - this._featureIndexOrder = this._featureIndexOrder.filter((elem) => { - return elem.layer._map; - }); - } - - _sortIndex() { - this._cleanIndex(); - if(this._featureIndexOrder.length === 0) return; - - let scale = this._map.options.crs.scale(this._map.getZoom()); - let mc = this._map.options.crs.transformation.untransform(this._map.getPixelBounds().getCenter(), scale); - this._featureIndexOrder.sort(function(a, b) { - let ac = a.center; - let bc = b.center; - a.path.setAttribute("tabindex", -1); - b.path.setAttribute("tabindex", -1); - a.dist = Math.sqrt(Math.pow(ac.x - mc.x, 2) + Math.pow(ac.y - mc.y, 2)); - b.dist = Math.sqrt(Math.pow(bc.x - mc.x, 2) + Math.pow(bc.y - mc.y, 2)); - return a.dist - b.dist; - }); - this._featureIndexOrder[0].path.setAttribute("tabindex", 0); } connectedCallback() { @@ -243,6 +200,7 @@ export class MapViewer extends HTMLElement { query: true, contextMenu: true, announceMovement: M.options.announceMovement, + featureIndex: true, mapEl: this, crs: M[this.projection], zoom: this.zoom, @@ -419,7 +377,6 @@ export class MapViewer extends HTMLElement { {target: this}})); } }); - this._map.on('mapfocused', () => this._sortIndex()); this._map.on('load', function () { this.dispatchEvent(new CustomEvent('load', {detail: {target: this}})); diff --git a/src/mapml/features/featureGroup.js b/src/mapml/features/featureGroup.js index 475af8a32..7d5091c67 100644 --- a/src/mapml/features/featureGroup.js +++ b/src/mapml/features/featureGroup.js @@ -33,7 +33,7 @@ export var FeatureGroup = L.FeatureGroup.extend({ _updateInteraction: function () { if((this.options.onEachFeature && this.options.properties) || this.options.link) - this.options._leafletLayer._map.options.mapEl._addToIndex(this, this.getPCRSCenter(), this.options.group); + this._map.featureIndex.addToIndex(this, this.getPCRSCenter(), this.options.group); }, /** @@ -44,28 +44,28 @@ export var FeatureGroup = L.FeatureGroup.extend({ _handleFocus: function(e) { if(e.target.tagName.toUpperCase() !== "G") return; if((e.keyCode === 9 || e.keyCode === 16) && e.type === "keydown"){ - let index = this.options._leafletLayer._map.options.mapEl._currFeatureIndex; + let index = this._map.featureIndex.currentIndex; if(e.keyCode === 9 && e.shiftKey) { - if(index === this.options._leafletLayer._map.options.mapEl._featureIndexOrder.length - 1) - this.options._leafletLayer._map.options.mapEl._featureIndexOrder[index].path.setAttribute("tabindex", -1); + if(index === this._map.featureIndex.inBoundFeatures.length - 1) + this._map.featureIndex.inBoundFeatures[index].path.setAttribute("tabindex", -1); if(index !== 0){ L.DomEvent.stop(e); - this.options._leafletLayer._map.options.mapEl._featureIndexOrder[index - 1].path.focus(); - this.options._leafletLayer._map.options.mapEl._currFeatureIndex--; + this._map.featureIndex.inBoundFeatures[index - 1].path.focus(); + this._map.featureIndex.currentIndex--; } } else if (e.keyCode === 9) { - if(index !== this.options._leafletLayer._map.options.mapEl._featureIndexOrder.length - 1) { + if(index !== this._map.featureIndex.inBoundFeatures.length - 1) { L.DomEvent.stop(e); - this.options._leafletLayer._map.options.mapEl._featureIndexOrder[index + 1].path.focus(); - this.options._leafletLayer._map.options.mapEl._currFeatureIndex++; + this._map.featureIndex.inBoundFeatures[index + 1].path.focus(); + this._map.featureIndex.currentIndex++; } else { - this.options._leafletLayer._map.options.mapEl._featureIndexOrder[0].path.setAttribute("tabindex", -1); - this.options._leafletLayer._map.options.mapEl._featureIndexOrder[index].path.setAttribute("tabindex", 0); + this._map.featureIndex.inBoundFeatures[0].path.setAttribute("tabindex", -1); + this._map.featureIndex.inBoundFeatures[index].path.setAttribute("tabindex", 0); } } } else if (!(e.keyCode === 9 || e.keyCode === 16 || e.keyCode === 13)){ - this.options._leafletLayer._map.options.mapEl._currFeatureIndex = 0; - this.options._leafletLayer._map.options.mapEl._featureIndexOrder[0].path.focus(); + this._map.featureIndex.currentIndex = 0; + this._map.featureIndex.inBoundFeatures[0].path.focus(); } if((e.keyCode === 9 || e.keyCode === 16 || e.keyCode === 13) && e.type === "keyup") { this.openTooltip(); diff --git a/src/mapml/features/featureRenderer.js b/src/mapml/features/featureRenderer.js index 0968ed00d..27682d399 100644 --- a/src/mapml/features/featureRenderer.js +++ b/src/mapml/features/featureRenderer.js @@ -46,7 +46,7 @@ export var FeatureRenderer = L.SVG.extend({ if (p.subrings) { for (let r of p.subrings) { this._createPath(r, layer.options.className, r.attr['aria-label'], (r.link !== undefined), r.attr); - if(r.attr && r.attr.tabindex) this._map.options.mapEl._addToIndex(layer, r.center, r.path); + if(r.attr && r.attr.tabindex) this._map.featureIndex.addToIndex(layer, r.center, r.path); } } this._updateStyle(layer); diff --git a/src/mapml/handlers/FeatureIndex.js b/src/mapml/handlers/FeatureIndex.js new file mode 100644 index 000000000..90606d313 --- /dev/null +++ b/src/mapml/handlers/FeatureIndex.js @@ -0,0 +1,90 @@ +export var FeatureIndex = L.Handler.extend({ + initialize: function (map) { + L.Handler.prototype.initialize.call(this, map); + this.inBoundFeatures = []; + this.outBoundFeatures = []; + this.currentIndex = 0; + this.mapPCRSBounds = M.pixelToPCRSBounds( + map.getPixelBounds(), + map.getZoom(), + map.options.projection); + }, + + addHooks: function () { + this._map.on("moveend", this._updateMapBounds, this); + this._map.on('mapfocused', this._sortIndex, this); + }, + + removeHooks: function () { + this._map.off("moveend", this._updateMapBounds); + this._map.off('mapfocused', this._sortIndex); + }, + + addToIndex: function (layer, lc, path) { + let scale = this._map.options.crs.scale(this._map.getZoom()); + let mc = this._map.options.crs.transformation.untransform(this._map.getPixelBounds().getCenter(),scale); + let dist = Math.sqrt(Math.pow(lc.x - mc.x, 2) + Math.pow(lc.y - mc.y, 2)); + let index = this.mapPCRSBounds.contains(lc) ? this.inBoundFeatures : this.outBoundFeatures; + + let elem = {path: path, layer: layer, center: lc, dist: dist}; + path.setAttribute("tabindex", -1); + + index.push(elem); + for (let i = index.length - 1; i > 0 && index[i].dist < index[i-1].dist; i--) { + let tmp = index[i]; + index[i] = index[i-1]; + index[i-1] = tmp; + } + + if (this.mapPCRSBounds.contains(lc)) + this.inBoundFeatures = index; + else + this.outBoundFeatures = index; + }, + + cleanIndex: function() { + this.currentIndex = 0; + this.inBoundFeatures = this.inBoundFeatures.filter((elem) => { + let inbound = this.mapPCRSBounds.contains(elem.center); + if (elem.layer._map && !inbound) { + this.outBoundFeatures.push(elem); + } + return elem.layer._map && inbound; + }); + this.outBoundFeatures = this.outBoundFeatures.filter((elem) => { + let inbound = this.mapPCRSBounds.contains(elem.center); + if (elem.layer._map && inbound) { + this.inBoundFeatures.push(elem); + } + return elem.layer._map && !inbound; + }); + }, + + _sortIndex: function() { + this.cleanIndex(); + if(this.inBoundFeatures.concat(this.outBoundFeatures).length === 0) return; + + let scale = this._map.options.crs.scale(this._map.getZoom()); + let mc = this._map.options.crs.transformation.untransform(this._map.getPixelBounds().getCenter(), scale); + + this.inBoundFeatures.sort(function(a, b) { + let ac = a.center; + let bc = b.center; + a.path.setAttribute("tabindex", -1); + b.path.setAttribute("tabindex", -1); + a.dist = Math.sqrt(Math.pow(ac.x - mc.x, 2) + Math.pow(ac.y - mc.y, 2)); + b.dist = Math.sqrt(Math.pow(bc.x - mc.x, 2) + Math.pow(bc.y - mc.y, 2)); + return a.dist - b.dist; + }); + + this.inBoundFeatures[0].path.setAttribute("tabindex", 0); + }, + + _updateMapBounds: function (e) { + this.mapPCRSBounds = M.pixelToPCRSBounds( + this._map.getPixelBounds(), + this._map.getZoom(), + this._map.options.projection); + }, +}); + diff --git a/src/mapml/index.js b/src/mapml/index.js index c29c5aee9..6d587d814 100644 --- a/src/mapml/index.js +++ b/src/mapml/index.js @@ -58,6 +58,7 @@ import { Feature, feature } from "./features/feature"; import { FeatureRenderer, featureRenderer } from './features/featureRenderer'; import { FeatureGroup, featureGroup} from './features/featureGroup'; import {AnnounceMovement} from "./handlers/AnnounceMovement"; +import { FeatureIndex } from "./handlers/FeatureIndex"; import { Options } from "./options"; import "./keyboard"; @@ -607,11 +608,13 @@ M.gcrsToTileMatrix = Util.gcrsToTileMatrix; M.QueryHandler = QueryHandler; M.ContextMenu = ContextMenu; M.AnnounceMovement = AnnounceMovement; +M.FeatureIndex = FeatureIndex; // see https://leafletjs.com/examples/extending/extending-3-controls.html#handlers L.Map.addInitHook('addHandler', 'query', M.QueryHandler); L.Map.addInitHook('addHandler', 'contextMenu', M.ContextMenu); L.Map.addInitHook('addHandler', 'announceMovement', M.AnnounceMovement); +L.Map.addInitHook('addHandler', 'featureIndex', M.FeatureIndex); M.MapMLLayer = MapMLLayer; M.mapMLLayer = mapMLLayer; diff --git a/src/mapml/layers/FeatureLayer.js b/src/mapml/layers/FeatureLayer.js index 72cbff54f..419cdabf7 100644 --- a/src/mapml/layers/FeatureLayer.js +++ b/src/mapml/layers/FeatureLayer.js @@ -85,7 +85,7 @@ export var MapMLFeatures = L.FeatureGroup.extend({ L.DomUtil.remove(this._container); } L.FeatureGroup.prototype.onRemove.call(this, map); - this._map.options.mapEl._cleanIndex(); + this._map.featureIndex.cleanIndex(); }, getEvents: function(){ diff --git a/src/web-map.js b/src/web-map.js index 63ad92575..8f08b7050 100644 --- a/src/web-map.js +++ b/src/web-map.js @@ -168,49 +168,6 @@ export class WebMap extends HTMLMapElement { }); }); this.controlsListObserver.observe(this, {attributes:true}); - this._featureIndexOrder = []; - this._currFeatureIndex = 0; - } - - _addToIndex(layer, lc, path) { - let scale = this._map.options.crs.scale(this._map.getZoom()); - let mc = this._map.options.crs.transformation.untransform(this._map.getPixelBounds().getCenter(),scale); - let dist = Math.sqrt(Math.pow(lc.x - mc.x, 2) + Math.pow(lc.y - mc.y, 2)); - let index = this._map.options.mapEl._featureIndexOrder; - - let elem = {path: path, layer: layer, center: lc, dist: dist}; - path.setAttribute("tabindex", -1); - index.push(elem); - for (let i = index.length - 1; i > 0 && index[i].dist < index[i-1].dist; i--) { - let tmp = index[i]; - index[i] = index[i-1]; - index[i-1] = tmp; - } - } - - _cleanIndex() { - this._currFeatureIndex = 0; - this._featureIndexOrder = this._featureIndexOrder.filter((elem) => { - return elem.layer._map; - }); - } - - _sortIndex() { - this._cleanIndex(); - if(this._featureIndexOrder.length === 0) return; - - let scale = this._map.options.crs.scale(this._map.getZoom()); - let mc = this._map.options.crs.transformation.untransform(this._map.getPixelBounds().getCenter(), scale); - this._featureIndexOrder.sort(function(a, b) { - let ac = a.center; - let bc = b.center; - a.path.setAttribute("tabindex", -1); - b.path.setAttribute("tabindex", -1); - a.dist = Math.sqrt(Math.pow(ac.x - mc.x, 2) + Math.pow(ac.y - mc.y, 2)); - b.dist = Math.sqrt(Math.pow(bc.x - mc.x, 2) + Math.pow(bc.y - mc.y, 2)); - return a.dist - b.dist; - }); - this._featureIndexOrder[0].path.setAttribute("tabindex", 0); } connectedCallback() { @@ -257,6 +214,7 @@ export class WebMap extends HTMLMapElement { query: true, contextMenu: true, announceMovement: M.options.announceMovement, + featureIndex: true, mapEl: this, crs: M[this.projection], zoom: this.zoom, @@ -457,7 +415,6 @@ export class WebMap extends HTMLMapElement { {target: this}})); } }); - this._map.on('mapfocused', () => this._sortIndex()); this._map.on('load', function () { this.dispatchEvent(new CustomEvent('load', {detail: {target: this}})); From 060bab8ba44e446b923fd9cf953ddf30442a91cf Mon Sep 17 00:00:00 2001 From: Ahmad Ayubi Date: Fri, 10 Dec 2021 16:53:29 -0500 Subject: [PATCH 06/11] Fix link tabbing --- src/mapml/features/featureGroup.js | 24 ++++++++++++++++++++--- src/mapml/features/featureRenderer.js | 3 +-- src/mapml/handlers/FeatureIndex.js | 28 +++++++++++++-------------- src/mapml/layers/FeatureLayer.js | 3 --- 4 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/mapml/features/featureGroup.js b/src/mapml/features/featureGroup.js index 7d5091c67..cd839276d 100644 --- a/src/mapml/features/featureGroup.js +++ b/src/mapml/features/featureGroup.js @@ -31,9 +31,26 @@ export var FeatureGroup = L.FeatureGroup.extend({ if(this.options.featureID) this.options.group.setAttribute("data-fid", this.options.featureID); }, - _updateInteraction: function () { + onAdd: function (map) { + L.LayerGroup.prototype.onAdd.call(this, map); + this.updateInteraction(); + }, + + updateInteraction: function () { + let map = this.options._leafletLayer._map || this._map; if((this.options.onEachFeature && this.options.properties) || this.options.link) - this._map.featureIndex.addToIndex(this, this.getPCRSCenter(), this.options.group); + map.featureIndex.addToIndex(this, this.getPCRSCenter(), this.options.group); + + for (let layerID in this._layers) { + let layer = this._layers[layerID]; + for(let part of layer._parts){ + if(layer.featureAttributes && layer.featureAttributes.tabindex) + map.featureIndex.addToIndex(layer, layer.getPCRSCenter(), part.path); + for(let subPart of part.subrings) { + if(subPart.attr && subPart.attr.tabindex) map.featureIndex.addToIndex(layer, subPart.center, subPart.path); + } + } + } }, /** @@ -42,7 +59,6 @@ export var FeatureGroup = L.FeatureGroup.extend({ * @private */ _handleFocus: function(e) { - if(e.target.tagName.toUpperCase() !== "G") return; if((e.keyCode === 9 || e.keyCode === 16) && e.type === "keydown"){ let index = this._map.featureIndex.currentIndex; if(e.keyCode === 9 && e.shiftKey) { @@ -67,6 +83,8 @@ export var FeatureGroup = L.FeatureGroup.extend({ this._map.featureIndex.currentIndex = 0; this._map.featureIndex.inBoundFeatures[0].path.focus(); } + + if(e.target.tagName.toUpperCase() !== "G") return; if((e.keyCode === 9 || e.keyCode === 16 || e.keyCode === 13) && e.type === "keyup") { this.openTooltip(); } else if (e.keyCode === 13 || e.keyCode === 32){ diff --git a/src/mapml/features/featureRenderer.js b/src/mapml/features/featureRenderer.js index 27682d399..89a428648 100644 --- a/src/mapml/features/featureRenderer.js +++ b/src/mapml/features/featureRenderer.js @@ -46,7 +46,6 @@ export var FeatureRenderer = L.SVG.extend({ if (p.subrings) { for (let r of p.subrings) { this._createPath(r, layer.options.className, r.attr['aria-label'], (r.link !== undefined), r.attr); - if(r.attr && r.attr.tabindex) this._map.featureIndex.addToIndex(layer, r.center, r.path); } } this._updateStyle(layer); @@ -73,7 +72,7 @@ export var FeatureRenderer = L.SVG.extend({ if (title) p.setAttribute('aria-label', title); } else { for(let [name, value] of Object.entries(attr)){ - if(name === "id") continue; + if(name === "id" || name === "tabindex") continue; p.setAttribute(name, value); } } diff --git a/src/mapml/handlers/FeatureIndex.js b/src/mapml/handlers/FeatureIndex.js index 90606d313..e71d6114c 100644 --- a/src/mapml/handlers/FeatureIndex.js +++ b/src/mapml/handlers/FeatureIndex.js @@ -4,27 +4,26 @@ export var FeatureIndex = L.Handler.extend({ this.inBoundFeatures = []; this.outBoundFeatures = []; this.currentIndex = 0; - this.mapPCRSBounds = M.pixelToPCRSBounds( + this._mapPCRSBounds = M.pixelToPCRSBounds( map.getPixelBounds(), map.getZoom(), map.options.projection); }, addHooks: function () { - this._map.on("moveend", this._updateMapBounds, this); + this._map.on("mapfocused", this._updateMapBounds, this); this._map.on('mapfocused', this._sortIndex, this); }, removeHooks: function () { - this._map.off("moveend", this._updateMapBounds); + this._map.off("mapfocused", this._updateMapBounds); this._map.off('mapfocused', this._sortIndex); }, addToIndex: function (layer, lc, path) { - let scale = this._map.options.crs.scale(this._map.getZoom()); - let mc = this._map.options.crs.transformation.untransform(this._map.getPixelBounds().getCenter(),scale); + let mc = this._mapPCRSBounds.getCenter(); let dist = Math.sqrt(Math.pow(lc.x - mc.x, 2) + Math.pow(lc.y - mc.y, 2)); - let index = this.mapPCRSBounds.contains(lc) ? this.inBoundFeatures : this.outBoundFeatures; + let index = this._mapPCRSBounds.contains(lc) ? this.inBoundFeatures : this.outBoundFeatures; let elem = {path: path, layer: layer, center: lc, dist: dist}; path.setAttribute("tabindex", -1); @@ -36,7 +35,7 @@ export var FeatureIndex = L.Handler.extend({ index[i-1] = tmp; } - if (this.mapPCRSBounds.contains(lc)) + if (this._mapPCRSBounds.contains(lc)) this.inBoundFeatures = index; else this.outBoundFeatures = index; @@ -45,14 +44,16 @@ export var FeatureIndex = L.Handler.extend({ cleanIndex: function() { this.currentIndex = 0; this.inBoundFeatures = this.inBoundFeatures.filter((elem) => { - let inbound = this.mapPCRSBounds.contains(elem.center); + let inbound = this._mapPCRSBounds.contains(elem.center); + elem.path.setAttribute("tabindex", -1); if (elem.layer._map && !inbound) { this.outBoundFeatures.push(elem); } return elem.layer._map && inbound; }); this.outBoundFeatures = this.outBoundFeatures.filter((elem) => { - let inbound = this.mapPCRSBounds.contains(elem.center); + let inbound = this._mapPCRSBounds.contains(elem.center); + elem.path.setAttribute("tabindex", -1); if (elem.layer._map && inbound) { this.inBoundFeatures.push(elem); } @@ -62,16 +63,13 @@ export var FeatureIndex = L.Handler.extend({ _sortIndex: function() { this.cleanIndex(); - if(this.inBoundFeatures.concat(this.outBoundFeatures).length === 0) return; + if(this.inBoundFeatures.length === 0) return; - let scale = this._map.options.crs.scale(this._map.getZoom()); - let mc = this._map.options.crs.transformation.untransform(this._map.getPixelBounds().getCenter(), scale); + let mc = this._mapPCRSBounds.getCenter(); this.inBoundFeatures.sort(function(a, b) { let ac = a.center; let bc = b.center; - a.path.setAttribute("tabindex", -1); - b.path.setAttribute("tabindex", -1); a.dist = Math.sqrt(Math.pow(ac.x - mc.x, 2) + Math.pow(ac.y - mc.y, 2)); b.dist = Math.sqrt(Math.pow(bc.x - mc.x, 2) + Math.pow(bc.y - mc.y, 2)); return a.dist - b.dist; @@ -81,7 +79,7 @@ export var FeatureIndex = L.Handler.extend({ }, _updateMapBounds: function (e) { - this.mapPCRSBounds = M.pixelToPCRSBounds( + this._mapPCRSBounds = M.pixelToPCRSBounds( this._map.getPixelBounds(), this._map.getZoom(), this._map.options.projection); diff --git a/src/mapml/layers/FeatureLayer.js b/src/mapml/layers/FeatureLayer.js index 419cdabf7..d61cb2d8c 100644 --- a/src/mapml/layers/FeatureLayer.js +++ b/src/mapml/layers/FeatureLayer.js @@ -72,9 +72,6 @@ export var MapMLFeatures = L.FeatureGroup.extend({ onAdd: function(map){ L.FeatureGroup.prototype.onAdd.call(this, map); - this.eachLayer(function (layer) { - layer._updateInteraction(); - }); if(this._mapmlFeatures)map.on("featurepagination", this.showPaginationFeature, this); }, From ac31ee46bb4d5e92da2ea31bcf5572173daf28bd Mon Sep 17 00:00:00 2001 From: Ahmad Ayubi Date: Fri, 10 Dec 2021 17:01:50 -0500 Subject: [PATCH 07/11] Fix feature button navigation --- src/mapml-viewer.js | 1 - src/mapml/features/featureGroup.js | 8 ++++---- src/mapml/layers/MapLayer.js | 10 +++++----- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/mapml-viewer.js b/src/mapml-viewer.js index 0f47f3ac3..ba89ab5ba 100644 --- a/src/mapml-viewer.js +++ b/src/mapml-viewer.js @@ -153,7 +153,6 @@ export class MapViewer extends HTMLElement { }); this.controlsListObserver.observe(this, {attributes:true}); } - connectedCallback() { if (this.isConnected) { diff --git a/src/mapml/features/featureGroup.js b/src/mapml/features/featureGroup.js index cd839276d..b40bfc2e9 100644 --- a/src/mapml/features/featureGroup.js +++ b/src/mapml/features/featureGroup.js @@ -116,8 +116,8 @@ export var FeatureGroup = L.FeatureGroup.extend({ */ _previousFeature: function(e){ L.DomEvent.stop(e); - this._map.options.mapEl._currFeatureIndex = Math.max(this._map.options.mapEl._currFeatureIndex - 1, 0); - let prevFocus = this._map.options.mapEl._featureIndexOrder[this._map.options.mapEl._currFeatureIndex]; + this._map.featureIndex.currentIndex = Math.max(this._map.featureIndex.currentIndex - 1, 0); + let prevFocus = this._map.featureIndex.inBoundFeatures[this._map.featureIndex.currentIndex]; prevFocus.path.focus(); this._map.closePopup(); }, @@ -129,8 +129,8 @@ export var FeatureGroup = L.FeatureGroup.extend({ */ _nextFeature: function(e){ L.DomEvent.stop(e); - this._map.options.mapEl._currFeatureIndex = Math.min(this._map.options.mapEl._currFeatureIndex + 1, this._map.options.mapEl._featureIndexOrder.length - 1); - let nextFocus = this._map.options.mapEl._featureIndexOrder[this._map.options.mapEl._currFeatureIndex]; + this._map.featureIndex.currentIndex = Math.min(this._map.featureIndex.currentIndex + 1, this._map.featureIndex.inBoundFeatures.length - 1); + let nextFocus = this._map.featureIndex.inBoundFeatures[this._map.featureIndex.currentIndex]; nextFocus.path.focus(); this._map.closePopup(); }, diff --git a/src/mapml/layers/MapLayer.js b/src/mapml/layers/MapLayer.js index ccbd3363d..b43e3c8ff 100644 --- a/src/mapml/layers/MapLayer.js +++ b/src/mapml/layers/MapLayer.js @@ -1170,7 +1170,7 @@ export var MapMLLayer = L.Layer.extend({ mapFocusButton.innerHTML = ""; L.DomEvent.on(mapFocusButton, 'click', (e)=>{ L.DomEvent.stop(e); - map.options.mapEl._sortIndex(); + map.featureIndex._sortIndex(); map.closePopup(); map._container.focus(); }, popup); @@ -1200,10 +1200,10 @@ export var MapMLLayer = L.Layer.extend({ controlFocusButton.title = "Focus Controls"; controlFocusButton.innerHTML = ""; L.DomEvent.on(controlFocusButton, 'click', (e) => { - map.options.mapEl._sortIndex(); - map.options.mapEl._currFeatureIndex = map.options.mapEl._featureIndexOrder.length - 1; - map.options.mapEl._featureIndexOrder[0].path.setAttribute("tabindex", -1); - map.options.mapEl._featureIndexOrder[map.options.mapEl._currFeatureIndex].path.setAttribute("tabindex", 0); + map.featureIndex._sortIndex(); + map.featureIndex.currentIndex = map.featureIndex.inBoundFeatures.length - 1; + map.featureIndex.inBoundFeatures[0].path.setAttribute("tabindex", -1); + map.featureIndex.inBoundFeatures[map.featureIndex.currentIndex].path.setAttribute("tabindex", 0); L.DomEvent.stop(e); map.closePopup(); map._controlContainer.querySelector("A").focus(); From 60a6183d08e28cc82ebaba3a65a500446ee9066e Mon Sep 17 00:00:00 2001 From: Ahmad Ayubi Date: Mon, 13 Dec 2021 17:22:20 -0500 Subject: [PATCH 08/11] Fix issues templated features, add comments --- src/mapml/features/featureGroup.js | 2 +- src/mapml/handlers/FeatureIndex.js | 22 ++++++++++++++++++++++ src/mapml/layers/FeatureLayer.js | 2 ++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/mapml/features/featureGroup.js b/src/mapml/features/featureGroup.js index b40bfc2e9..90a109a62 100644 --- a/src/mapml/features/featureGroup.js +++ b/src/mapml/features/featureGroup.js @@ -37,7 +37,7 @@ export var FeatureGroup = L.FeatureGroup.extend({ }, updateInteraction: function () { - let map = this.options._leafletLayer._map || this._map; + let map = this._map || this.options._leafletLayer._map; if((this.options.onEachFeature && this.options.properties) || this.options.link) map.featureIndex.addToIndex(this, this.getPCRSCenter(), this.options.group); diff --git a/src/mapml/handlers/FeatureIndex.js b/src/mapml/handlers/FeatureIndex.js index e71d6114c..f47448f09 100644 --- a/src/mapml/handlers/FeatureIndex.js +++ b/src/mapml/handlers/FeatureIndex.js @@ -20,6 +20,12 @@ export var FeatureIndex = L.Handler.extend({ this._map.off('mapfocused', this._sortIndex); }, + /** + * Adds a svg element to the index of tabbable features, it also keeps track of the layer it's associated + center + * @param layer - the layer object the feature is associated with + * @param lc - the layer center + * @param path - the svg element that needs to be focused, can be a path or g + */ addToIndex: function (layer, lc, path) { let mc = this._mapPCRSBounds.getCenter(); let dist = Math.sqrt(Math.pow(lc.x - mc.x, 2) + Math.pow(lc.y - mc.y, 2)); @@ -29,6 +35,8 @@ export var FeatureIndex = L.Handler.extend({ path.setAttribute("tabindex", -1); index.push(elem); + + // TODO: this insertion loop has potential to be improved slightly for (let i = index.length - 1; i > 0 && index[i].dist < index[i-1].dist; i--) { let tmp = index[i]; index[i] = index[i-1]; @@ -41,6 +49,10 @@ export var FeatureIndex = L.Handler.extend({ this.outBoundFeatures = index; }, + /** + * Removes features that are no longer on the map, also moves features to the respective array depending + * on whether the feature is in the maps viewport or not + */ cleanIndex: function() { this.currentIndex = 0; this.inBoundFeatures = this.inBoundFeatures.filter((elem) => { @@ -61,6 +73,10 @@ export var FeatureIndex = L.Handler.extend({ }); }, + /** + * Sorts the index of features in the map's viewport based on distance from center + * @private + */ _sortIndex: function() { this.cleanIndex(); if(this.inBoundFeatures.length === 0) return; @@ -78,7 +94,13 @@ export var FeatureIndex = L.Handler.extend({ this.inBoundFeatures[0].path.setAttribute("tabindex", 0); }, + /** + * Event handler for 'mapfocused' event to update the map's bounds in terms of PCRS + * @param e - the event object + * @private + */ _updateMapBounds: function (e) { + // TODO: map's PCRS bounds is used in other parts of the viewer, can be moved out to the map object directly this._mapPCRSBounds = M.pixelToPCRSBounds( this._map.getPixelBounds(), this._map.getZoom(), diff --git a/src/mapml/layers/FeatureLayer.js b/src/mapml/layers/FeatureLayer.js index d61cb2d8c..35248ee7d 100644 --- a/src/mapml/layers/FeatureLayer.js +++ b/src/mapml/layers/FeatureLayer.js @@ -174,6 +174,8 @@ export var MapMLFeatures = L.FeatureGroup.extend({ _resetFeatures : function (zoom){ this.clearLayers(); + // since features are removed and re-added by zoom level, need to clean the feature index before re-adding + if(this._map) this._map.featureIndex.cleanIndex(); if(this._features && this._features[zoom]){ for(let k =0;k < this._features[zoom].length;k++){ this.addLayer(this._features[zoom][k]); From e48c52193ba135ed9883b8df580a2c9b7ed04550 Mon Sep 17 00:00:00 2001 From: Ahmad Ayubi Date: Mon, 13 Dec 2021 18:21:14 -0500 Subject: [PATCH 09/11] Merge with upstream/main --- package-lock.json | 2 +- src/mapml/handlers/FeatureIndex.js | 8 ++++---- src/mapml/layers/Crosshair.js | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6c3bbfda5..bf3c0dbaa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@maps4html/web-map-custom-element", - "version": "0.8.3", + "version": "0.9.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/mapml/handlers/FeatureIndex.js b/src/mapml/handlers/FeatureIndex.js index f47448f09..0011fd51d 100644 --- a/src/mapml/handlers/FeatureIndex.js +++ b/src/mapml/handlers/FeatureIndex.js @@ -11,13 +11,13 @@ export var FeatureIndex = L.Handler.extend({ }, addHooks: function () { - this._map.on("mapfocused", this._updateMapBounds, this); - this._map.on('mapfocused', this._sortIndex, this); + this._map.on("mapkeyboardfocused", this._updateMapBounds, this); + this._map.on('mapkeyboardfocused', this._sortIndex, this); }, removeHooks: function () { - this._map.off("mapfocused", this._updateMapBounds); - this._map.off('mapfocused', this._sortIndex); + this._map.off("mapkeyboardfocused", this._updateMapBounds); + this._map.off('mapkeyboardfocused', this._sortIndex); }, /** diff --git a/src/mapml/layers/Crosshair.js b/src/mapml/layers/Crosshair.js index 4d8902097..5793439c2 100644 --- a/src/mapml/layers/Crosshair.js +++ b/src/mapml/layers/Crosshair.js @@ -85,6 +85,7 @@ export var Crosshair = L.Layer.extend({ return false; }, + // TODO: should be merged with the 'mapfocused' event emitted by mapml-viewer and map, not trivial _isMapFocused: function (e) { //set this._map.isFocused = true if arrow buttons are used if(!this._map._container.parentNode.activeElement){ @@ -96,7 +97,7 @@ export var Crosshair = L.Layer.extend({ this._map.isFocused = false; } else this._map.isFocused = isLeafletContainer && ["keyup", "keydown"].includes(e.type); - if(this._map.isFocused) this._map.fire("mapfocused"); + if(this._map.isFocused) this._map.fire("mapkeyboardfocused"); this._addOrRemoveMapOutline(); this._addOrRemoveCrosshair(); }, From 17d28c8bcf6467f54bac376082a859a4d3dd6a17 Mon Sep 17 00:00:00 2001 From: Ahmad Ayubi Date: Thu, 16 Dec 2021 16:48:46 -0500 Subject: [PATCH 10/11] Update linkTypes, featureLinks tests --- test/e2e/core/featureLinks.test.js | 12 ++++++------ test/e2e/core/linkTypes.test.js | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/test/e2e/core/featureLinks.test.js b/test/e2e/core/featureLinks.test.js index 85e89c92e..2655851e6 100644 --- a/test/e2e/core/featureLinks.test.js +++ b/test/e2e/core/featureLinks.test.js @@ -9,11 +9,11 @@ describe("Playwright Feature Links Tests", () => { describe("Sub Part Link Tests", () => { test("Sub-point link adds new layer", async () => { - for(let i = 0; i < 4; i++) { + for(let i = 0; i < 5; i++) { await page.keyboard.press("Tab"); await page.waitForTimeout(200); } - await page.keyboard.press("Enter"); + await page.keyboard.press("Enter"); // Press enter on the point subpart of the 'Accessible Square' feature await page.waitForTimeout(1000); const layers = await page.$eval( "body > map", @@ -27,7 +27,7 @@ describe("Playwright Feature Links Tests", () => { await page.click("div > div.leaflet-control-container > div.leaflet-top.leaflet-right > div > section > div.leaflet-control-layers-overlays > fieldset:nth-child(2) > div:nth-child(1) > div > button:nth-child(1)"); await page.waitForTimeout(850); await page.click("body > map"); - for(let i = 0; i < 6; i++) { + for(let i = 0; i < 10; i++) { await page.keyboard.press("Tab"); await page.waitForTimeout(200); } @@ -35,7 +35,7 @@ describe("Playwright Feature Links Tests", () => { "body > map", (map) => map.extent ); - await page.keyboard.press("Enter"); + await page.keyboard.press("Enter"); // Press enter on the point of the 'Inplace' feature const layers = await page.$eval( "body > map", (map) => map.childElementCount @@ -62,11 +62,11 @@ describe("Playwright Feature Links Tests", () => { await page.click("div > div.leaflet-control-container > div.leaflet-top.leaflet-right > div > section > div.leaflet-control-layers-overlays > fieldset:nth-child(2) > div:nth-child(1) > div > button:nth-child(1)"); await page.waitForTimeout(850); await page.click("body > map"); - for(let i = 0; i < 5; i++) { + for(let i = 0; i < 9; i++) { await page.keyboard.press("Tab"); await page.waitForTimeout(200); } - await page.keyboard.press("Enter"); + await page.keyboard.press("Enter"); // Press enter on main part of 'Inplace' feature const layers = await page.$eval( "body > map", (map) => map.childElementCount diff --git a/test/e2e/core/linkTypes.test.js b/test/e2e/core/linkTypes.test.js index ebf105626..76751ff26 100644 --- a/test/e2e/core/linkTypes.test.js +++ b/test/e2e/core/linkTypes.test.js @@ -10,11 +10,11 @@ describe("Playwright Feature Links Tests", () => { describe("HTML Link Type Tests", () => { test("HTML _self target navigates to new page", async () => { await page.click("body > map"); - for(let i = 0; i < 7; i++) { + for(let i = 0; i < 9; i++) { await page.keyboard.press("Tab"); await page.waitForTimeout(200); } - await page.keyboard.press("Enter"); + await page.keyboard.press("Enter"); // Press enter on the feature in the top-left await page.waitForTimeout(1000); const url = await page.url(); await expect(url).toEqual("http://geogratis.gc.ca/mapml/en/cbmtile/cbmtgeom/"); @@ -23,11 +23,11 @@ describe("Playwright Feature Links Tests", () => { await page.goBack(); await page.waitForTimeout(1000); await page.click("body > map"); - for(let i = 0; i < 8; i++) { + for(let i = 0; i < 2; i++) { await page.keyboard.press("Tab"); await page.waitForTimeout(200); } - await page.keyboard.press("Enter"); + await page.keyboard.press("Enter"); // Press enter on the top point feature in the top left await page.waitForTimeout(1000); const url = await page.url(); await expect(url).toEqual("http://geogratis.gc.ca/mapml/en/cbmtile/fdi/"); @@ -40,7 +40,7 @@ describe("Playwright Feature Links Tests", () => { await page.keyboard.press("Tab"); await page.waitForTimeout(200); } - await page.keyboard.press("Enter"); + await page.keyboard.press("Enter"); // Press enter on the second feature in the top left await page.waitForTimeout(1000); const url = await page.url(); await expect(url).toEqual("http://geogratis.gc.ca/mapml/en/cbmtile/cbmtgeom/"); @@ -49,11 +49,11 @@ describe("Playwright Feature Links Tests", () => { await page.goBack(); await page.waitForTimeout(1000); await page.click("body > map"); - for(let i = 0; i < 11; i++) { + for(let i = 0; i < 1; i++) { await page.keyboard.press("Tab"); await page.waitForTimeout(200); } - await page.keyboard.press("Enter"); + await page.keyboard.press("Enter"); // Press enter on the second point in the top left await page.waitForTimeout(1000); const extent = await page.$eval( "body > map", From 50ed1e4b98e6ccfbeff71b68a003d38cf4eb2111 Mon Sep 17 00:00:00 2001 From: Ahmad Ayubi Date: Fri, 17 Dec 2021 11:35:08 -0500 Subject: [PATCH 11/11] Unit test update --- test/layers/mapMLStaticTileLayer.spec.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/layers/mapMLStaticTileLayer.spec.js b/test/layers/mapMLStaticTileLayer.spec.js index c95161617..059bf31c3 100644 --- a/test/layers/mapMLStaticTileLayer.spec.js +++ b/test/layers/mapMLStaticTileLayer.spec.js @@ -2,7 +2,8 @@ describe("MapMLStaticTileLayer Tests", function () { var map, container; beforeEach(() => { - map = L.map(document.createElement("map")); + map = L.map(document.createElement("map"), {center:[0, 0], zoom: 0}); + map.options.projection = "CBMTILE"; container = document.createElement("div"); });