diff options
-rw-r--r-- | index.html | 73 | ||||
-rw-r--r-- | main.js | 229 | ||||
-rw-r--r-- | style.css | 61 |
3 files changed, 310 insertions, 53 deletions
@@ -21,58 +21,31 @@ <h5 class="my-0">Källor och licensinformation</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" title="Stäng" aria-label="Stäng"></button> </div> - <div class="modal-body pt-2"> - <ul class="mb-2"> - <li><i>Transmissionsnät för el</i> från - <a href="https://svk.se" target="_blank">Svenska Kraftnät (SvK)</a>. - </li> - <li><i>Dammregistret</i> från - <a href="https://smhi.se" target="_blank">Sveriges meteorologiska och hydrologiska institut (SMHI)</a>, - CC-BY-4.0 (<a href="https://www.smhi.se/data/oppna-data/villkor-for-anvandning-1.30622" target="_blank">öppna data</a>). - </li> - <li><i>Mineralrättsregistret</i> från - <a href="https://www.sgu.se/bergsstaten/" target="_blank">Bergsstaten</a>, - CC0 (<a href="https://creativecommons.org/publicdomain/zero/1.0/deed.sv" target="_blank">öppna data</a>). - </li> - <li><i>Vindbruk</i> från - <a href="https://www.energimyndigheten.se/energisystem-och-analys/elproduktion/vindkraft/vindbrukskollen/" target="_blank">Länsstyrelserna och Energimyndigheten</a>, - CC0 (<a href="https://ext-geodatakatalog-forv.lansstyrelsen.se/GeodataKatalogen/codelist/metadata/anvandningsrestriktioner.xml#CC01.0" target="_blank">öppna data</a>). - </li> - <li><i>Skogsbruk</i>, <i>Skogliga biotopskyddsområden</i> och <i>Naturvårdsavtal</i> från - <a href="https://skogsstyrelsen.se" target="_blank">Skogsstyrelsen</a>, - CC0 (<a href="https://www.skogsstyrelsen.se/sjalvservice/karttjanster/geodatatjanster/villkor-for-nyttjande-av-skogsstyrelsens-kartdatabaser/" target="_blank">öppna data</a>). - </li> - <li><i>Naturvårdsregistret</i> och <i>Naturvårdsavtal</i> från - <a href="https://www.naturvardsverket.se/" target="_blank">Naturvårdsverket</a>, - CC0 (<a href="https://geodata.naturvardsverket.se/nedladdning/naturvardsregistret/Naturvardsregistret_beskrivning_av_oppna_data.pdf" target="_blank">öppna data</a>). - </li> - <li><i>Riksintresse naturvård</i> och <i>frilufsliv</i> från - <a href="https://www.naturvardsverket.se/" target="_blank">Naturvårdsverket</a> - och - <a href="https://www.lansstyrelsen.se/" target="_blank">Länsstyrelsen</a>, - CC-BY-4.0 (<a href="https://ext-geodatakatalog-forv.lansstyrelsen.se/GeodataKatalogen/codelist/metadata/anvandningsrestriktioner.xml#CCby4.0" target="_blank">öppna data</a>). - </li> - <li><i>Riksintresse Rennäringen</i> skikt från - <a href="https://sametinget.se" target="_blank">Sametinget</a>, - CC-BY-4.0 (<a href="https://ext-geodatakatalog-forv.lansstyrelsen.se/GeodataKatalogen/codelist/metadata/anvandningsrestriktioner.xml#CCby4.0" target="_blank">öppna data</a>). - <i>Samebyarnas betesområden</i> och <i>flyttled</i> från - © <a href="https://sametinget.se" target="_blank">Sametingets</a> - Rennäringens markanvändningsdatabas (IRENMARK). - </li> - <li>Bakgrund kartor från - © <a href="https://lantmateriet.se" target="_blank">Lantmäteriet</a>, CC0 - (<a href="https://www.lantmateriet.se/sv/geodata/vara-produkter/oppna-data/#anchor-1" target="_blank">öppna data</a>). - </li> - <li>Webbkartan: - © <a href="https://guilhem.se" target="_blank">Guilhem Moulin</a>, AGPLv3+. - <a href="https://git.guilhem.org/KlimatanalysNorr/webmap" target="_blank">Källkod</a>. - </li> - <li>Backend-verktyg: - © <a href="https://guilhem.se" target="_blank">Guilhem Moulin</a>, GPLv3+. - <a href="https://git.guilhem.org/KlimatanalysNorr/tools" target="_blank">Källkod</a>. + <div id="info-body" class="modal-body"> + <ul class="list-group list-group-flush mb-2"> + <li class="list-group-item"> + <h6>Bakgrund kartor</h6> + <p>© <a href="https://lantmateriet.se" target="_blank">Lantmäteriet</a></p> + <p>Licensvillkor: <a href="https://www.lantmateriet.se/sv/geodata/vara-produkter/oppna-data/#anchor-1" target="_blank">CC0 1.0 Universiell</a></p> + </li> + <li class="list-group-item"> + <h6>Webbkartan</h6> + <p>© Guilhem Moulin</p> + <p>Licensvillkor: <a href="https://www.gnu.org/licenses/agpl-3.0.en.html" target="_blank">AGPLv3+</a></p> + <p class="small text-muted"><i class="bi bi-file-earmark-code"></i> + <a href="https://git.guilhem.org/KlimatanalysNorr/webmap" target="_blank">Källkod <i class="bi bi-box-arrow-up-right"></i></a></p> + </li> + <li class="list-group-item"> + <h6>Backend verktyg</h6> + <p>© Guilhem Moulin</p> + <p>Licensvillkor: <a href="https://www.gnu.org/licenses/gpl-3.0.en.html" target="_blank">GPLv3+</a> och + (endast CGI) <a href="https://www.gnu.org/licenses/agpl-3.0.en.html" target="_blank">AGPLv3+</a></p> + <p class="small text-muted"><i class="bi bi-file-earmark-code"></i> + <a href="https://git.guilhem.org/KlimatanalysNorr/tools" target="_blank">Källkod <i class="bi bi-box-arrow-up-right"></i></a></p> </li> </ul> - <p class="small mb-0">Webbkartan är utvecklad av + <div id="info-accordion" class="accordion accordion-flush"></div> + <p class="small text-muted info-credits">Webbkartan är utvecklad av <a href="https://guilhem.se" target="_blank">Guilhem Datakonsult</a> på uppdrag av <a href="https://www.klimatanalysnorr.se" target="_blank">Klimatanalys Norr projektet</a>.</p> </div> @@ -483,10 +483,189 @@ if (window.location === window.parent.location) { btn.classList.replace('btn-dark', 'btn-light'); btn.setAttribute('aria-expanded', 'false'); backdrop.classList.remove('modal-backdrop', 'show'); + infoMetadataAccordions.forEach(function(x, idx) { + /* collapse all accordions */ + const body = x.element.parentNode.parentNode; + const name = 'info-accordion-collapse-' + idx; + if (body.id === name) { + body.classList.remove('show'); + } + if (body.parentNode !== null) { + const headers = body.parentNode.getElementsByClassName('accordion-header'); + for (let i = 0; i < headers.length; i++) { + const buttons = headers[i].getElementsByClassName('accordion-button'); + for (let j = 0; j < buttons.length; j++) { + const btn = buttons[j]; + if (btn.getAttribute('data-bs-target') === '#' + name) { + btn.setAttribute('aria-expanded', 'false'); + btn.classList.add('collapsed'); + } + } + } + } + }); }); btn.onclick = function(event) { - modal.toggle(); + infoMetadataAccordions.forEach((x) => x.element.replaceChildren()); + modal.show(); + Promise.allSettled(Object.entries(vectorLayers).map(function([grp,lyr]) { + const url = lyr.getSource().getUrls()[0]; + if (url === undefined || url.length <= 16 || url.substr(url.length - 16) !== '/{z}/{x}/{y}.pbf') { + throw new Error(`Invalid URL ${url}`); + } + return fetch(url.substr(0, url.length - 16) + '/metadata.json') + .then(function(resp0) { + if (resp0.status === 200) { + return resp0.json().then((x) => [grp,x]); + } else { + throw new Error(`${resp0.url} [${resp0.status}]`); + } + }); + })) + .then(function(rs) { + const metadata = Object.fromEntries(rs.filter(function(r) { + if (r.status === 'fulfilled') { + return true; + } else if (r.status === 'rejected') { + console.log(r.reason); + } + return false; + }).map((r) => r.value)); + + infoMetadataAccordions.forEach(function(x) { + const ul = x.element; + const groupnames = new Set(); + const last_updated = []; + x.items.forEach(function([groupname, _]) { + const layer_group = metadata[groupname]; + if (layer_group === undefined) { + return; + } + if (!groupnames.has(groupname)) { + groupnames.add(groupname); + if (layer_group.last_updated !== undefined) { + last_updated.push(layer_group.last_updated); + } + } + }); + if (last_updated.length > 0) { + /* show creation time of the MVT layers */ + const li = document.createElement('li'); + li.classList.add('list-group-item', 'text-muted'); + ul.appendChild(li) + const i = document.createElement('i'); + i.classList.add('bi', 'bi-clock'); + li.appendChild(i); + const t = document.createTextNode( + ' Lokalt skikt (vectiler) genererades ' + + last_updated + .sort() + .map((ts) => new Date(ts).toLocaleDateString('sv-SE')) + .join('; ') + '.' + ); + li.appendChild(t); + } + + const source_files = new Set(); + x.items.forEach(function([groupname, layername]) { + /* for each source file associated with the accordion header, show copyright, license and timing information */ + const layer_group = metadata[groupname]; + if (layer_group === undefined || layer_group.layers === undefined || layer_group.source_files === undefined) { + return; + } + const def = layer_group.layers[layername]; + if (def === undefined || def.source_files === undefined) { + return; + } + def.source_files.forEach(function(source_file) { + if (source_files.has(source_file)) { + return; + } + const x = layer_group.source_files[source_file]; + source_files.add(source_file); + + const li = document.createElement('li'); + li.classList.add('list-group-item'); + ul.appendChild(li) + const h = document.createElement('h6'); + li.appendChild(h) + if (x.description !== undefined && x.description !== null) { + const t = document.createTextNode(x.description); + h.appendChild(t); + } + + if (x.copyright !== undefined && x.copyright !== null) { + let p = document.createElement('p'); + li.appendChild(p) + const t = document.createTextNode(x.copyright); + p.appendChild(t); + } + + if (x.license !== undefined && x.license !== null) { + let p = document.createElement('p'); + li.appendChild(p) + p.appendChild(document.createTextNode('Licensvillkor: ')); + const t = document.createTextNode(x.license.name); + if (x.license.url === undefined || x.license.url === null) { + p.appendChild(t); + } else { + const a = document.createElement('a'); + a.href = x.license.url; + a.target = '_blank'; + a.appendChild(t); + p.appendChild(a); + } + } + + if (x.product_url !== undefined && x.product_url !== null) { + let p = document.createElement('p'); + li.appendChild(p) + const t = document.createTextNode('Produktlänk '); + const i = document.createElement('i'); + i.classList.add('bi', 'bi-box-arrow-up-right'); + const a = document.createElement('a'); + a.href = x.product_url; + a.target = '_blank'; + a.appendChild(t); + a.appendChild(i); + p.appendChild(a); + } + + if (x.last_modified !== undefined && x.last_modified !== null) { + const p = document.createElement('p'); + p.classList.add('small', 'text-muted'); + li.appendChild(p); + const i = document.createElement('i'); + i.classList.add('bi', 'bi-file-earmark-code'); + p.appendChild(i); + p.appendChild(document.createTextNode(' ')); + const t0 = document.createTextNode('Källfil'); + if (x.url === undefined || x.url === null) { + p.appendChild(t0); + } else { + const a = document.createElement('a'); + p.appendChild(a); + const i = document.createElement('i'); + i.classList.add('bi', 'bi-box-arrow-up-right'); + a.appendChild(t0); + a.appendChild(document.createTextNode(' ')); + a.appendChild(i); + a.href = x.url; + a.target = '_blank'; + } + const t1 = document.createTextNode(' ändrades senast '); + p.appendChild(t1); + const d = new Date(x.last_modified); + const td = document.createTextNode(d.toLocaleDateString('sv-SE')); + p.appendChild(td); + const t2 = document.createTextNode('.') + p.appendChild(t2); + } + }); + }); + }); + }); }; })(); @@ -3270,6 +3449,7 @@ const [vectorLayers, featureOverlayLayer] = (function() { /* layer selection panel */ +const infoMetadataAccordions = []; (function() { const modal = document.getElementById('layer-selection-panel'); modal.classList.add('modal'); @@ -3502,6 +3682,53 @@ const [vectorLayers, featureOverlayLayer] = (function() { location.hash = '#' + searchParams.toString(); }; })(); + + (function() { + const accordion = document.getElementById('info-accordion'); + layerHierarchy.forEach(function(x, idx) { + const item = document.createElement('div'); + accordion.appendChild(item); + item.classList.add('accordion-item'); + + const header = document.createElement('div'); + item.appendChild(header); + header.classList.add('accordion-header'); + + const btn = document.createElement('button'); + header.appendChild(btn); + + const collapse = document.createElement('div'); + item.appendChild(collapse); + collapse.id = 'info-accordion-collapse-' + idx; + collapse.classList.add('accordion-collapse', 'collapse'); + + btn.type = 'button'; + btn.setAttribute('data-bs-toggle', 'collapse'); + btn.setAttribute('data-bs-target', '#' + collapse.id); + btn.setAttribute('aria-expanded', 'false'); + btn.setAttribute('aria-controls', collapse.id); + btn.classList.add('accordion-button', 'collapsed'); + + const t = document.createTextNode(x.text); + btn.appendChild(t); + + const body = document.createElement('div'); + body.classList.add('accordion-body'); + collapse.appendChild(body); + + const ul = document.createElement('ul'); + ul.classList.add('list-group', 'list-group-flush'); + body.appendChild(ul); + + infoMetadataAccordions.push({ + element: ul, + items: x._layers.map(function(k) { + const groupname = k.split('_', 1)[0]; + return [ groupname, k.slice(groupname.length + 1) ]; + }), + }); + }); + })(); })(); /* legend panel */ @@ -278,9 +278,60 @@ body.inprogress { -webkit-user-select: text; -moz-user-select: text; user-select: text; + --modal-info-padding-x: .5rem; + --modal-info-bg-light: rgba(0, 0, 0, .08); } -#modal-info .modal-body ul > li { - padding: 0.05rem 0; +#modal-info .list-group-item, +#modal-info { + --bs-list-group-border-width: 1px; +} +#modal-info .accordion { + --bs-accordion-active-bg: var(--bs-accordion-bg); + --bs-accordion-active-color: var(--bs-body-color); + --bs-accordion-btn-padding-x: .5rem; + --bs-accordion-btn-padding-y: .025rem; + --bs-accordion-btn-focus-box-shadow: none; + --bs-accordion-body-padding-x: var(--modal-info-padding-x); + --bs-accordion-body-padding-y: 0; + --bs-accordion-btn-active-bg: var(--modal-info-bg-light); + margin: 0 calc(var(--bs-accordion-btn-padding-x)*-1); +} +#modal-info .accordion-item { + border: none; +} +#modal-info .accordion-header > .accordion-button[aria-expanded="false"]:hover { + background-color: rgb(from var(--modal-info-bg-light) r g b / calc(alpha*.4)); +} +#modal-info .accordion-header > .accordion-button[aria-expanded="true"] { + background-color: var(--bs-accordion-btn-active-bg); +} +#modal-info ul.list-group > li.list-group-item { + padding: .3rem var(--modal-info-padding-x); + margin: 0 calc(var(--modal-info-padding-x)*-1); + border: none; +} +#modal-info ul.list-group > li.list-group-item:not(:first-child) { + border-top: var(--bs-list-group-border-width) solid var(--modal-info-bg-light); +} +#info-body > ul.list-group > li.list-group-item:last-child, +#info-accordion > .accordion-item:not(:last-child) ul.list-group > li.list-group-item:last-child { + border-bottom: var(--bs-list-group-border-width) solid var(--modal-info-bg-light); +} +#modal-info .modal-body ul.list-group > li.list-group-item:not(.text-muted):hover { + background-color: rgb(from var(--modal-info-bg-light) r g b / calc(alpha*.4)); +} +#info-body { + padding-top: 0; + padding-bottom: 0; +} +#info-body > ul.list-group > li.list-group-item p, +#modal-info .accordion-body ul.list-group > li.list-group-item p { + margin: .05rem 0 0 0; +} +#info-body > ul.list-group > li.list-group-item h6, +#modal-info .accordion-body ul.list-group > li.list-group-item h6 { + margin: .05rem 0 0 0; + font-size: 1.15rem } #modal-info .modal-body a { color: inherit; @@ -290,6 +341,12 @@ body.inprogress { opacity: .8; text-decoration: underline; } +#modal-info .modal-body .info-credits { + margin: 0 calc(var(--modal-info-padding-x)*-1); + padding: .3rem var(--modal-info-padding-x); + margin-top: .3rem; + border-top: var(--bs-list-group-border-width) solid var(--modal-info-bg-light); +} .ol-overlaycontainer-stopevent .modal-backdrop.show { pointer-events: auto; |