aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuilhem Moulin <guilhem@fripost.org>2024-01-20 15:53:52 +0100
committerGuilhem Moulin <guilhem@fripost.org>2024-01-20 15:55:50 +0100
commitb6924ae728eafdba7436e1da776467cf6edd8c7c (patch)
tree8ce429a62402b92574fcdc1e31b519b7a64759f3
parentfd88c1d218347602b00398b1e5d326c8078992e7 (diff)
Support layer hierarchy with arbitary depth.
-rw-r--r--main.js188
-rw-r--r--style.css10
2 files changed, 109 insertions, 89 deletions
diff --git a/main.js b/main.js
index ce7c5cc..947d201 100644
--- a/main.js
+++ b/main.js
@@ -521,6 +521,22 @@ const layers = {
},
};
+const layerHierarchy = [
+ {
+ text: 'Transmissionsnät för el',
+ children: [
+ {
+ text: 'Kraftledningar',
+ layer: ['svk_lines', 'svk_pylons'],
+ },
+ {
+ text: 'Stationer',
+ layer: 'svk_stations',
+ },
+ ],
+ },
+];
+
const vectorSource = new VectorTile({
url: '/public/xyztiles/{z}/{x}/{y}.pbf',
format: new MVT({
@@ -583,23 +599,85 @@ map.addLayer(new VectorTileLayer({
accordion.id = 'layer-selection-accordion';
accordion.classList.add('accordion', 'accordion-flush');
- const setIndeterminateAndChecked = function(input, children) {
- const childrenStyles = Object.values(children.reduce(function(result, child) {
- if (Array.isArray(child.layerName)) {
- child.layerName.forEach(function(layerName) {
- result[layerName] = (styles[layerName] !== undefined);
- });
- } else {
- result[child.layerName] = (styles[child.layerName] !== undefined);
- }
- return result;
- }, {}));
- input.indeterminate = children.length <= 1 ? false : childrenStyles.slice(1).some((v) => v !== childrenStyles[0]);
- input.checked = childrenStyles.every((v) => v);
+ (function collectLayers(list) {
+ list.forEach(function(elem) {
+ elem._layers = elem.layer === undefined ? []
+ : Array.isArray(elem.layer) ? elem.layer
+ : [elem.layer];
+ if (elem.children !== undefined && elem.children.length > 0) {
+ collectLayers(elem.children);
+ elem.children.forEach(function(child) {
+ child._layers.forEach((l) => elem._layers.push(l));
+ });
+ };
+ });
+ })(layerHierarchy);
+
+ const setIndeterminateAndChecked = function(list) {
+ return list.forEach(function(elem) {
+ const layerStyles = elem._layers.map((lyr) => styles[lyr] !== undefined);
+ elem._input.indeterminate = elem._layers.length <= 1 ? false
+ : layerStyles.slice(1).some((v) => v !== layerStyles[0]);
+ if (!elem._input.indeterminate) {
+ /* keep checked value if indeterminate */
+ elem._input.checked = layerStyles.every((v) => v);
+ }
+ if (elem.children !== undefined && elem.children.length > 0) {
+ setIndeterminateAndChecked(elem.children);
+ }
+ });
};
+ const onClickFunction = function(layerList, event) {
+ layerList.forEach(function(lyr) {
+ if (event.target.checked) {
+ styles[lyr] = layers[lyr].style;
+ } else {
+ delete styles[lyr];
+ }
+ });
+ setIndeterminateAndChecked(layerHierarchy);
+ vectorSource.changed();
+ };
+
+ let layerId = 0;
+ const addAccordionGroup = function(parentNode, children) {
+ const ul = document.createElement('ul');
+ parentNode.appendChild(ul);
+ ul.classList.add('list-group', 'list-group-flush');
- let accordionCollapseId = 0, inputId = 0;
- const addAccordionItem = function(headerText, children) {
+ children.forEach(function(child) {
+ const li = document.createElement('li');
+ ul.appendChild(li);
+ li.classList.add('list-group-item');
+
+ const div = document.createElement('div');
+ li.appendChild(div);
+ div.classList.add('d-inline-flex');
+
+ const input = child._input = document.createElement('input');
+ div.appendChild(input);
+ input.classList.add('form-check-input');
+ input.type = 'checkbox';
+ input.id = 'layer' + layerId++;
+
+ const label = document.createElement('label');
+ div.appendChild(label);
+ label.classList.add('form-check-label');
+ label.setAttribute('for', input.id);
+
+ const textNode = document.createTextNode(child.text);
+ label.appendChild(textNode);
+
+ if (child.children !== undefined && child.children.length > 0) {
+ addAccordionGroup(li, child.children);
+ };
+
+ input.onclick = function(event) {
+ return onClickFunction(child._layers, event);
+ };
+ });
+ };
+ layerHierarchy.forEach(function(x, idx) {
const item = document.createElement('div');
accordion.appendChild(item);
item.classList.add('accordion-item');
@@ -613,7 +691,7 @@ map.addLayer(new VectorTileLayer({
const collapse = document.createElement('div');
item.appendChild(collapse);
- collapse.id = 'accordion-collapse-' + accordionCollapseId++;
+ collapse.id = 'accordion-collapse-' + idx;
collapse.classList.add('accordion-collapse', 'collapse');
// collapse.setAttribute('data-bs-parent', '#' + accordion.id);
@@ -630,93 +708,31 @@ map.addLayer(new VectorTileLayer({
span0.setAttribute('data-bs-toggle', 'collapse');
span0.setAttribute('data-bs-target', '');
- const input0 = document.createElement('input');
+ const input0 = x._input = document.createElement('input');
span0.appendChild(input0);
input0.classList.add('form-check-input');
input0.type = 'checkbox';
- input0.id = 'layer' + inputId++;
+ input0.id = 'layer' + layerId++;
const label0 = document.createElement('label');
span0.appendChild(label0);
label0.classList.add('form-check-label');
label0.setAttribute('for', input0.id);
- const text0 = document.createTextNode(headerText);
+ const text0 = document.createTextNode(x.text);
label0.appendChild(text0);
- setIndeterminateAndChecked(input0, children);
-
- const inputs = Object.values(children).map(function(child) {
- const input = document.createElement('input');
- setIndeterminateAndChecked(input, [child]);
- return input;
- });
-
const body = document.createElement('div');
collapse.appendChild(body);
body.classList.add('accordion-body');
- const group = document.createElement('ul');
- body.appendChild(group);
- group.classList.add('list-group', 'list-group-flush');
-
- children.forEach(function(child, i) {
- const li = document.createElement('li');
- group.appendChild(li);
- li.classList.add('list-group-item');
-
- const input = inputs[i];
- li.appendChild(input);
- input.classList.add('form-check-input');
- input.type = 'checkbox';
- input.id = 'layer' + inputId++;
-
- const label = document.createElement('label');
- li.appendChild(label);
- label.classList.add('form-check-label');
- label.setAttribute('for', input.id);
-
- const text = document.createTextNode(child.text);
- label.appendChild(text);
- });
+ addAccordionGroup(body, x.children);
input0.onclick = function(event) {
- children.forEach(function(child, i) {
- const layerNames = Array.isArray(child.layerName) ? child.layerName : [child.layerName];
- layerNames.forEach(function(layerName) {
- if (input0.checked) {
- styles[layerName] = layers[layerName].style;
- inputs[i].checked = true;
- } else {
- delete styles[layerName];
- inputs[i].checked = false;
- }
- });
- });
- vectorSource.changed();
+ return onClickFunction(x._layers, event);
};
-
- inputs.forEach(function(input, i) {
- input.onclick = function(event) {
- const layerNames = Array.isArray(children[i].layerName) ? children[i].layerName : [children[i].layerName];
- layerNames.forEach(function(layerName) {
- if (input.checked) {
- styles[layerName] = layers[layerName].style;
- } else {
- delete styles[layerName];
- }
- });
-
- setIndeterminateAndChecked(input0, children);
- vectorSource.changed();
- };
- });
- };
-
- addAccordionItem('Transmissionsnät för el', [
- {layerName: ['svk_lines', 'svk_pylons'], text: 'Kraftledningar'},
- {layerName: 'svk_stations', text: 'Stationer'},
- ]);
+ });
+ setIndeterminateAndChecked(layerHierarchy);
(function() {
const item = document.createElement('div');
@@ -732,7 +748,7 @@ map.addLayer(new VectorTileLayer({
input.classList.add('form-check-input');
input.type = 'checkbox';
input.setAttribute('role', 'switch');
- input.id = 'layer' + inputId++;
+ input.id = 'layer' + layerId++;
const label = document.createElement('label');
div.appendChild(label);
diff --git a/style.css b/style.css
index 5838586..af20935 100644
--- a/style.css
+++ b/style.css
@@ -268,8 +268,8 @@ html, body {
#layer-selection-panel .accordion-item {
border: none;
}
-#layer-selection-panel .accordion-body {
- padding-left: 1em;
+#layer-selection-panel .accordion-body .list-group {
+ padding-left: 1.5em;
}
#layer-selection-panel .accordion .list-group.list-group-flush > .list-group-item {
padding: 0;
@@ -292,6 +292,10 @@ html, body {
float: none;
}
#layer-selection-panel .accordion-item .form-check > .form-check-input,
-#layer-selection-panel .accordion-item .list-group-item > .form-check-input {
+#layer-selection-panel .accordion-item .list-group-item > .d-inline-flex > .form-check-input {
margin-right: .5em !important;
}
+#layer-selection-panel .accordion-header > .accordion-button > .form-check > .form-check-label,
+#layer-selection-panel .accordion-item .form-check > .form-check-label {
+ display: inline;
+}