Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature index #636

Merged
merged 31 commits into from
May 27, 2022
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
7503bb9
Add feature indexing
ben-lu-uw Dec 13, 2021
28b3a33
Toggle feature index on or off
ben-lu-uw Dec 14, 2021
428c22e
Toggle feature index on or off
ben-lu-uw Dec 14, 2021
364442c
Check overlap on focus
ben-lu-uw Dec 15, 2021
7b73f0b
Fix function name
ben-lu-uw Dec 15, 2021
2772b20
Replace table with output element
ben-lu-uw Dec 15, 2021
54c9e6a
Add CSS for 'more results'
ben-lu-uw Dec 16, 2021
6e44a18
Limit output to having 9 items at a time
ben-lu-uw Dec 17, 2021
b080af2
Optimize the SVG using SVGOMG
ben-lu-uw Dec 17, 2021
a7f1af0
Optimize the SVG using SVGOMG
ben-lu-uw Dec 17, 2021
7e361ef
Hide output when empty
ben-lu-uw Dec 17, 2021
64fb95f
Adding thin outline to reticle
ben-lu-uw Dec 17, 2021
ef177f9
Focus on feature when number key is pressed
ben-lu-uw Dec 20, 2021
6d02a1a
Refactor code
ben-lu-uw Dec 20, 2021
bd9ac2a
Fix focusing on feature when number key is pressed
ben-lu-uw Dec 20, 2021
ef0d304
Fix failing tests
ben-lu-uw Dec 21, 2021
b6ec7ce
Add feature index overlay tests
ben-lu-uw Dec 21, 2021
ecd0a5b
Make esc key return focus to leaflet container
ben-lu-uw Dec 21, 2021
464969e
Increase reticle size, update tests
ben-lu-uw Dec 22, 2021
04db697
Update feature index overlay output
ben-lu-uw Dec 23, 2021
4445e69
change feature index font
ben-lu-uw May 2, 2022
a795264
Update span attribute
ben-lu-uw May 2, 2022
e6bec6a
Add feature index overlay option
ben-lu-uw May 3, 2022
c2c88e8
Fix cs of us_pop_density.mapml
ben-lu-uw May 3, 2022
2e43c86
Improve feature index styling for visual users (#1)
ben-lu-uw May 9, 2022
bedc2ae
Fix index popup issue + make sure index keys are valid onKeyDown
ben-lu-uw May 19, 2022
621f15f
Fix tabbing issue + add popup test
ben-lu-uw May 19, 2022
36ba188
Change popup behaviour
ben-lu-uw May 19, 2022
215b4c0
Remove features from tabindex when FeatureIndexOverlay is enabled
ben-lu-uw May 20, 2022
12a6616
Update feature index screen reading behavior (#2)
ben-lu-uw May 26, 2022
b0e233f
Hide reticle when popup is open
ben-lu-uw May 27, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/mapml-viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ export class MapViewer extends HTMLElement {

this.setControls(false,false,true);
this._crosshair = M.crosshair().addTo(this._map);

if(M.options.featureIndexOverlayOption) this._featureIndexOverlay = M.featureIndexOverlay().addTo(this._map);
// https://github.com/Maps4HTML/Web-Map-Custom-Element/issues/274
this.setAttribute('role', 'application');
// Make the Leaflet container element programmatically identifiable
Expand Down
68 changes: 66 additions & 2 deletions src/mapml.css
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@
}

/* Disable pointer events where they'd interfere with the intended action. */
.mapml-feature-index-box,
.leaflet-tooltip,
.leaflet-crosshair *,
.mapml-layer-item-settings .mapml-control-layers summary label,
Expand Down Expand Up @@ -649,7 +650,7 @@ button.mapml-button:disabled,
box-sizing: border-box;
}

.mapml-layer-item,
.mapml-layer-item,
.mapml-layer-grouped-extents,
.mapml-layer-extent {
background-color: #fff;
Expand Down Expand Up @@ -751,7 +752,7 @@ label.mapml-layer-item-toggle {
/*
* Feature styles.
*/

.mapml-vector-container svg :is(
[role="link"]:focus,
[role="link"]:hover,
Expand Down Expand Up @@ -803,3 +804,66 @@ label.mapml-layer-item-toggle {
right: 0;
}



/**
* Feature Index
*/
.mapml-feature-index-box {
ben-lu-uw marked this conversation as resolved.
Show resolved Hide resolved
margin: -8% 0 0 -8%;
width: 16%;
left: 50%;
top: 50%;
position: absolute;
z-index: 10000;
outline: 2px solid #fff;
}

.mapml-feature-index-box:after{
display: block;
content: '';
padding-top: 100%;
}

.mapml-feature-index-box > svg {
position: absolute;
width: 100%;
height: 100%;
}

.mapml-feature-index {
ben-lu-uw marked this conversation as resolved.
Show resolved Hide resolved
outline: 1px solid #000000;
contain: content;
border-radius: 4px;
background-color: #fff;
cursor: default;
z-index: 1000;
position: absolute;
top: auto;
left: 50%;
-ms-transform: translateX(-50%);
transform: translateX(-50%);
bottom: 30px;
padding-top: 5px;
height: 92px;
width: 450px;
font-size: 16px;
}

.mapml-feature-index-content > span{
width: 140px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: inline-block;
padding-left: 5px;
padding-right: 5px;
}

.mapml-feature-index-content > span > kbd{
background-color: lightgrey;
padding-right: 4px;
padding-left: 4px;
border-radius: 4px;
}

7 changes: 5 additions & 2 deletions src/mapml/features/featureGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,16 @@ export var FeatureGroup = L.FeatureGroup.extend({
this._map.featureIndex.inBoundFeatures[index].path.setAttribute("tabindex", 0);
}
}
} else if (!([9, 16, 13, 27].includes(e.keyCode))){
} else if (!([9, 16, 13, 27, 49, 50, 51, 52, 53, 54, 55].includes(e.keyCode))){
this._map.featureIndex.currentIndex = 0;
this._map.featureIndex.inBoundFeatures[0].path.focus();
} else if(e.keyCode === 27){
this._map.featureIndex.currentIndex = 0;
this._map._container.focus();
}

if(e.target.tagName.toUpperCase() !== "G") return;
if((e.keyCode === 9 || e.keyCode === 16 || e.keyCode === 13) && e.type === "keyup") {
if((e.keyCode === 9 || e.keyCode === 16 || e.keyCode === 13 || (e.keyCode >= 49 && e.keyCode <= 55)) && e.type === "keyup") {
this.openTooltip();
} else if (e.keyCode === 13 || e.keyCode === 32){
this.closeTooltip();
Expand Down
3 changes: 1 addition & 2 deletions src/mapml/handlers/FeatureIndex.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,7 @@ export var FeatureIndex = L.Handler.extend({
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);
if(!M.options.featureIndexOverlayOption) this.inBoundFeatures[0].path.setAttribute("tabindex", 0);
},

/**
Expand Down
4 changes: 4 additions & 0 deletions src/mapml/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ import {AnnounceMovement} from "./handlers/AnnounceMovement";
import { FeatureIndex } from "./handlers/FeatureIndex";
import { Options } from "./options";
import "./keyboard";
import {featureIndexOverlay, FeatureIndexOverlay} from "./layers/FeatureIndexOverlay";

/* global L, Node */
(function (window, document, undefined) {
Expand Down Expand Up @@ -655,6 +656,9 @@ M.debugOverlay = debugOverlay;
M.Crosshair = Crosshair;
M.crosshair = crosshair;

M.FeatureIndexOverlay = FeatureIndexOverlay;
M.featureIndexOverlay = featureIndexOverlay;

M.Feature = Feature;
M.feature = feature;

Expand Down
185 changes: 185 additions & 0 deletions src/mapml/layers/FeatureIndexOverlay.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
export var FeatureIndexOverlay = L.Layer.extend({
onAdd: function (map) {
let svgInnerHTML = `<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 100 100"><path fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M0 0h100v100H0z" color="#000" overflow="visible"/></svg>`;

this._container = L.DomUtil.create("div", "mapml-feature-index-box", map._container);
this._container.innerHTML = svgInnerHTML;

this._output = L.DomUtil.create("output", "mapml-feature-index", map._container);
Malvoz marked this conversation as resolved.
Show resolved Hide resolved
this._output.setAttribute("role", "status");
this._output.setAttribute("aria-live", "polite");
this._output.setAttribute("aria-atomic", "true");
this._body = L.DomUtil.create("span", "mapml-feature-index-content", this._output);
this._body.index = 0;

map.on("layerchange layeradd layerremove overlayremove", this._toggleEvents, this);
map.on('moveend focus templatedfeatureslayeradd', this._checkOverlap, this);
map.on("keydown", this._onKeyDown, this);
this._addOrRemoveFeatureIndex();
},

_checkOverlap: function () {
this._map.fire("mapkeyboardfocused");
let bounds = this._map.getPixelBounds();
let center = bounds.getCenter();
let wRatio = Math.abs(bounds.min.x - bounds.max.x) / (this._map.options.mapEl.width);
let hRatio = Math.abs(bounds.min.y - bounds.max.y) / (this._map.options.mapEl.height);

let reticleDimension = (getComputedStyle(this._container).width).replace(/[^\d.]/g,'');
if((getComputedStyle(this._container).width).slice(-1) === "%") {
reticleDimension = reticleDimension * this._map.options.mapEl.width / 100;
}
let w = wRatio * reticleDimension / 2;
let h = hRatio * reticleDimension / 2;
let minPoint = L.point(center.x - w, center.y + h);
let maxPoint = L.point(center.x + w, center.y - h);
let b = L.bounds(minPoint, maxPoint);
let featureIndexBounds = M.pixelToPCRSBounds(b,this._map.getZoom(),this._map.options.projection);

let features = this._map.featureIndex.inBoundFeatures;
let index = 1;
let keys = Object.keys(features);
let body = this._body;

body.innerHTML = "";
body.index = 0;

body.allFeatures = [];
keys.forEach(i => {
let layer = features[i].layer;
let layers = features[i].layer._layers;
let bounds = L.bounds();

if(layers) {
let keys = Object.keys(layers);
keys.forEach(j => {
if(!bounds) bounds = L.bounds(layer._layers[j]._bounds.min, layer._layers[j]._bounds.max);
bounds.extend(layer._layers[j]._bounds.min);
bounds.extend(layer._layers[j]._bounds.max);
});
} else if(layer._bounds){
bounds = L.bounds(layer._bounds.min, layer._bounds.max);
}

if(featureIndexBounds.overlaps(bounds)){
let label = features[i].path.getAttribute("aria-label");

if (index < 8){
body.appendChild(this._updateOutput(label, index, index));
}
if (index % 7 === 0 || index === 1) {
body.allFeatures.push([]);
}
body.allFeatures[Math.floor((index - 1) / 7)].push({label, index, layer});
if (body.allFeatures[1] && body.allFeatures[1].length === 1){
body.appendChild(this._updateOutput("More results", 0, 9));
}
index += 1;
}
});
this._addToggleKeys();
},

_updateOutput: function (label, index, key) {
let span = document.createElement("span");
span.setAttribute("data-index", index);
span.innerHTML = `<kbd>${key}</kbd>` + " " + label;
return span;
},

_addToggleKeys: function () {
let allFeatures = this._body.allFeatures;
for(let i = 0; i < allFeatures.length; i++){
if(allFeatures[i].length === 0) return;
if(allFeatures[i - 1]){
let label = "Previous results";
allFeatures[i].push({label});
}

if(allFeatures[i + 1] && allFeatures[i + 1].length > 0){
let label = "More results";
allFeatures[i].push({label});
}
}
},

_onKeyDown: function (e){
let body = this._body;
let key = e.originalEvent.keyCode;
if (key >= 49 && key <= 55){
if(!body.allFeatures[body.index]) return;
let feature = body.allFeatures[body.index][key - 49];
if (!feature) return;
let layer = feature.layer;
if (layer) {
this._map.featureIndex.currentIndex = feature.index - 1;
if (layer._popup){
this._map.closePopup();
layer.openPopup();
}
else layer.options.group.focus();
}
} else if(key === 56){
this._newContent(body, -1);
} else if(key === 57){
this._newContent(body, 1);
}
},

_newContent: function (body, direction) {
let index = body.firstChild.getAttribute("data-index");
let newContent = body.allFeatures[Math.floor(((index - 1) / 7) + direction)];
if(newContent && newContent.length > 0){
body.innerHTML = "";
body.index += direction;
for(let i = 0; i < newContent.length; i++){
let feature = newContent[i];
let index = feature.index ? feature.index : 0;
let key = i + 1;
if (feature.label === "More results") key = 9;
if (feature.label === "Previous results") key = 8;
body.appendChild(this._updateOutput(feature.label, index, key));
}
}
},

_toggleEvents: function (){
this._map.on("viewreset move moveend focus blur", this._addOrRemoveFeatureIndex, this);

},

_addOrRemoveFeatureIndex: function (e) {
let obj = this;
let features = this._body.allFeatures ? this._body.allFeatures.length : 0;
setTimeout(function() {
if (e && e.type === "focus") {
obj._container.removeAttribute("hidden");
if (features !== 0) obj._output.classList.remove("mapml-screen-reader-output");
} else if (e && e.originalEvent && e.originalEvent.type === 'pointermove') {
obj._container.setAttribute("hidden", "");
obj._output.classList.add("mapml-screen-reader-output");
} else if (e && e.target._popup) {

} else if (e && e.type === "blur") {
obj._container.setAttribute("hidden", "");
obj._output.classList.add("mapml-screen-reader-output");
} else if (obj._map.isFocused) {
obj._container.removeAttribute("hidden");
if (features !== 0) {
obj._output.classList.remove("mapml-screen-reader-output");
} else {
obj._output.classList.add("mapml-screen-reader-output");
}
} else {
obj._container.setAttribute("hidden", "");
obj._output.classList.add("mapml-screen-reader-output");
}
}, 0);

},

});

export var featureIndexOverlay = function (options) {
return new FeatureIndexOverlay(options);
};
1 change: 1 addition & 0 deletions src/mapml/layers/TemplatedFeaturesLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ export var TemplatedFeaturesLayer = L.Layer.extend({
_pullFeatureFeed(this._getfeaturesUrl(), MAX_PAGES)
.then(function() {
map.addLayer(features);
map.fire("templatedfeatureslayeradd");
M.TemplatedFeaturesLayer.prototype._updateTabIndex(context);
})
.catch(function (error) { console.log(error);});
Expand Down
1 change: 1 addition & 0 deletions src/mapml/options.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export var Options = {
featureIndexOverlayOption: false,
announceMovement: false,
locale: {
cmBack: "Back",
Expand Down
2 changes: 2 additions & 0 deletions src/web-map.js
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,8 @@ export class WebMap extends HTMLMapElement {

this.setControls(false,false,true);
this._crosshair = M.crosshair().addTo(this._map);
if(M.options.featureIndexOverlayOption) this._featureIndexOverlay = M.featureIndexOverlay().addTo(this._map);

if (this.hasAttribute('name')) {
var name = this.getAttribute('name');
if (name) {
Expand Down
Loading