diff options
author | Guilhem Moulin <guilhem@fripost.org> | 2025-05-27 00:59:37 +0200 |
---|---|---|
committer | Guilhem Moulin <guilhem@fripost.org> | 2025-05-27 01:05:17 +0200 |
commit | 6c388d0b828e62562e43cecb801bb8979b593c1d (patch) | |
tree | 0ec76e8a95deeb5f336ac2a4b270460f44ce46aa | |
parent | 736bc1ff68a0e0110c36f457a97ff6976048cb3e (diff) |
Popover: Dynamically generate HTML from properties.
There is no need to pre-generate and cache the HTML for all features.
-rw-r--r-- | main.js | 182 |
1 files changed, 93 insertions, 89 deletions
@@ -3621,12 +3621,12 @@ const [vectorLayers, featureOverlayLayer] = (function() { featureOverlayLayer.changed(); }; const refreshPopover = function() { - const x = overlayAttributes[overlayAttrIdx]; - updateFeatureOverlayLayer(x.layer_group, x.layer, x.id); + const attr = overlayAttributes[overlayAttrIdx]; + updateFeatureOverlayLayer(attr.layer_group, attr.layer, attr.ogc_fid); pageNum.innerHTML = (overlayAttrIdx + 1).toString(); - popover.tip.getElementsByClassName('popover-body')[0]. - replaceChildren(x.formattedContent); + const content = formatFeaturePropertiesToHTML(attr); + popover.tip.getElementsByClassName('popover-body')[0].replaceChildren(content); }; const onClickPageChange = function(event, offset) { const btn = event.target; @@ -3713,6 +3713,86 @@ const [vectorLayers, featureOverlayLayer] = (function() { header.appendChild(btnExpand); header.appendChild(btnClose); + const formatFeaturePropertiesToHTML = function(properties) { + /* turn the properties into a fine table */ + const table = document.createElement('table'); + table.classList.add('table', 'table-sm', 'table-borderless', 'table-hover'); + + const tbody = document.createElement('tbody'); + table.appendChild(tbody); + + const def = layers[properties.layer_group + '_' + properties.layer]; + def.popover.forEach(function([desc, key, opts]) { + let v = properties[key]; + if (opts === undefined) { + opts = {}; + } + if (opts.fn !== undefined) { + if (opts.fn === 'length') { + if (v < 1000) { + opts.unit = 'm'; + } else { + v /= 1000.; + v = Math.round(v*100) / 100.; + opts.unit = 'km'; + } + } else if (opts.fn === 'area') { + if (v < 10000) { + opts.unit = 'm²'; + } else if (v < 10000 * 10000) { + v /= 10000.; + opts.unit = 'ha'; + } else { + v /= 1000000.; + opts.unit = 'km²'; + } + v = Math.round(v*100) / 100.; + } else { + v = opts.fn(v); + } + } + if (v === undefined || v === null) { + v = document.createTextNode(''); + } else if (!(v instanceof HTMLElement)) { + if (typeof(v) === 'number' && opts.unit !== undefined) { + v = v.toLocaleString('sv-SE'); + } else if (typeof(v) === 'boolean') { + v = v ? 'Ja' : 'Nej'; + } + if (opts.unit !== undefined && v !== '') { + v += '\u202F' + opts.unit; + } + v = document.createTextNode(v); + } + + const tr = document.createElement('tr'); + tbody.appendChild(tr); + + const td1 = document.createElement('td'); + tr.appendChild(td1); + const textDesc = document.createTextNode(desc); + td1.appendChild(textDesc); + + const td2 = document.createElement('td'); + tr.appendChild(td2); + td2.appendChild(v); + if (opts.classes !== undefined) { + opts.classes.forEach((c) => td2.classList.add(c)); + } + }); + + const content = document.createElement('div'); + if (def.popoverTitle !== undefined) { + const h = document.createElement('h6'); + content.appendChild(h); + const textNode = document.createTextNode(def.popoverTitle); + h.appendChild(textNode); + } + + content.appendChild(table); + return content; + }; + const container0 = map.getViewport().getElementsByClassName('ol-overlaycontainer-stopevent')[0]; map.on('singleclick', function(event) { /* clear the overlay list */ @@ -3795,90 +3875,14 @@ const [vectorLayers, featureOverlayLayer] = (function() { /* the data is received from the CGI in the order it was sent */ /* TODO optimizations on the CGI would break the above assumption, so the * decoded JSON response would need to be reordered to match fetch_body */ - overlayAttributes = data.map(function(properties) { - /* turn the properties into a fine table */ - const table = document.createElement('table'); - table.classList.add('table', 'table-sm', 'table-borderless', 'table-hover'); - - const tbody = document.createElement('tbody'); - table.appendChild(tbody); - - const def = layers[properties.layer_group + '_' + properties.layer]; - def.popover.forEach(function([desc, key, opts]) { - let v = properties[key]; - if (opts === undefined) { - opts = {}; - } - if (opts.fn !== undefined) { - if (opts.fn === 'length') { - if (v < 1000) { - opts.unit = 'm'; - } else { - v /= 1000.; - v = Math.round(v*100) / 100.; - opts.unit = 'km'; - } - } else if (opts.fn === 'area') { - if (v < 10000) { - opts.unit = 'm²'; - } else if (v < 10000 * 10000) { - v /= 10000.; - opts.unit = 'ha'; - } else { - v /= 1000000.; - opts.unit = 'km²'; - } - v = Math.round(v*100) / 100.; - } else { - v = opts.fn(v); - } - } - if (v === undefined || v === null) { - v = document.createTextNode(''); - } else if (!(v instanceof HTMLElement)) { - if (typeof(v) === 'number' && opts.unit !== undefined) { - v = v.toLocaleString('sv-SE'); - } else if (typeof(v) === 'boolean') { - v = v ? 'Ja' : 'Nej'; - } - if (opts.unit !== undefined && v !== '') { - v += '\u202F' + opts.unit; - } - v = document.createTextNode(v); - } - - const tr = document.createElement('tr'); - tbody.appendChild(tr); - - const td1 = document.createElement('td'); - tr.appendChild(td1); - const textDesc = document.createTextNode(desc); - td1.appendChild(textDesc); - - const td2 = document.createElement('td'); - tr.appendChild(td2); - td2.appendChild(v); - if (opts.classes !== undefined) { - opts.classes.forEach((c) => td2.classList.add(c)); - } - }); - - const content = document.createElement('div'); - if (def.popoverTitle !== undefined) { - const h = document.createElement('h6'); - content.appendChild(h); - const textNode = document.createTextNode(def.popoverTitle); - h.appendChild(textNode); + overlayAttributes = data + if (overlayAttributes.length === 0) { + if (popover !== null) { + /* dispose pre-detached popover */ + popover.dispose(); } - - content.appendChild(table); - return { - layer_group: properties.layer_group, - layer: properties.layer, - id: properties.ogc_fid, - formattedContent: content - }; - }); + return; + } pageCount.innerHTML = overlayAttributes.length.toString(); if (overlayAttributes.length >= 2) { @@ -3893,18 +3897,18 @@ const [vectorLayers, featureOverlayLayer] = (function() { popupOverlay.setPosition(event.coordinate); const attr = overlayAttributes[0]; + updateFeatureOverlayLayer(attr.layer_group, attr.layer, attr.ogc_fid); popover = new Popover(popup, { template: '<div class="popover" role="tooltip"><div class="popover-arrow"></div>' + '<div class="popover-header"></div><div class="popover-body"></div></div>', title: header, - content: attr.formattedContent, + content: formatFeaturePropertiesToHTML(attr), html: true, placement: 'right', fallbackPlacements: ['right', 'left', 'bottom', 'top'], container: container0, }); popover.show(); - updateFeatureOverlayLayer(attr.layer_group, attr.layer, attr.id); } else if (popover.tip.classList.contains('popover-detached')) { /* update existing detached mode popover */ |