diff options
author | Guilhem Moulin <guilhem@fripost.org> | 2025-06-14 22:12:57 +0200 |
---|---|---|
committer | Guilhem Moulin <guilhem@fripost.org> | 2025-06-15 18:34:05 +0200 |
commit | fd662f3d3fac0f8b11e8e883409b1828cbfca3bd (patch) | |
tree | 3f5b8b1760f8483f5ba1e4714debeee79e52d09b /src | |
parent | 0fc7bdd8bf374c36fa0ba27702d1fafed09277ac (diff) |
Undo splitting out to multiple files.
The reason is that we want the different modules to produce side-effects
(to avoid creating functions and keeping references to it) and we
therefore need to control the order in which they are inlined during
`vite build`. Unfortunately this doesn't seem to be possible right now,
cf. https://github.com/storybookjs/storybook/issues/30768 .
This reverts commits 670bba058d83620abdb3e8db5fd4ea89dba08142,
05a018f27aba3a20fd581cb88daa8afbbd3407de and
0fc7bdd8bf374c36fa0ba27702d1fafed09277ac.
Diffstat (limited to 'src')
-rw-r--r-- | src/layers.js | 1908 | ||||
-rw-r--r-- | src/map.js | 103 | ||||
-rw-r--r-- | src/popover.js | 1348 | ||||
-rw-r--r-- | src/style.css | 650 |
4 files changed, 0 insertions, 4009 deletions
diff --git a/src/layers.js b/src/layers.js deleted file mode 100644 index 688bb44..0000000 --- a/src/layers.js +++ /dev/null @@ -1,1908 +0,0 @@ -/*********************************************************************** - * Copyright © 2024-2025 Guilhem Moulin <info@guilhem.se> - * Vector and raster layer definitions - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - **********************************************************************/ - -import CircleStyle from 'ol/style/Circle.js'; -import Fill from 'ol/style/Fill.js'; -import Icon from 'ol/style/Icon.js'; -import RegularShape from 'ol/style/RegularShape.js'; -import Stroke from 'ol/style/Stroke.js'; -import Style from 'ol/style/Style.js'; - -/* TODO: this should really be refactored… */ -export const layers = { - 'mrr.appr_ec': { - legend: { zoomLevel: 4 }, - style: [0, .1, .5, .5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 5].map(function(width, z) { - return new Style({ - zIndex: 22, - fill: new Fill({ - color: [247, 170, 67, Math.max((.2-1)/8 * z + 1, 0)], - }), - stroke: width === 0 ? undefined : new Stroke({ - width: width, - color: [151, 173, 23, 1], - }), - }); - }), - }, - 'mrr.appl_ec': { - legend: { zoomLevel: 4 }, - style: [0, .1, .5, .5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 5].map(function(width, z) { - return new Style({ - zIndex: 25, - fill: new Fill({ - color: [247, 170, 67, Math.max((.2-1)/8 * z + 1, 0)], - }), - stroke: width === 0 ? undefined : new Stroke({ - width: width, - color: [197, 14, 31, 1], - lineDash: width >= 1.5 ? [2 * width] : undefined, - }), - }); - }), - }, - 'mrr.appr_met': { - legend: { zoomLevel: 4 }, - style: [0, .1, .5, .5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 5].map(function(width, z) { - return new Style({ - zIndex: 24, - fill: new Fill({ - color: [0, 0, 0, Math.max((.2-.4)/4 * z + .4, 0)], - }), - stroke: width === 0 ? undefined : new Stroke({ - width: width, - color: [151, 173, 23, 1], - }), - }); - }), - }, - 'mrr.appl_met': { - legend: { zoomLevel: 4 }, - style: [0, .1, .5, .5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 5].map(function(width, z) { - return new Style({ - zIndex: 26, - fill: new Fill({ - color: [0, 0, 0, Math.max((.2-.4)/4 * z + .4, 0)], - }), - stroke: width === 0 ? undefined : new Stroke({ - width: width, - color: [197, 14, 31, 1], - lineDash: width >= 1.5 ? [2 * width] : undefined, - }), - }); - }), - }, - 'mrr.appr_ogd': { - legend: { zoomLevel: 4 }, - style: [0, .1, .5, .5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 5].map(function(width, z) { - return new Style({ - zIndex: 24, - fill: new Fill({ - color: [30, 55, 87, Math.max((.2-.4)/4 * z + .4, 0)], - }), - stroke: width === 0 ? undefined : new Stroke({ - width: width, - color: [151, 173, 23, 1], - }), - }); - }), - }, - 'mrr.appl_ogd': { - legend: { zoomLevel: 4 }, - style: [0, .1, .5, .5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 5].map(function(width, z) { - return new Style({ - zIndex: 26, - fill: new Fill({ - color: [30, 55, 87, Math.max((.2-.4)/4 * z + .4, 0)], - }), - stroke: width === 0 ? undefined : new Stroke({ - width: width, - color: [197, 14, 31, 1], - lineDash: width >= 1.5 ? [2 * width] : undefined, - }), - }); - }), - }, - 'mrr.appr_dl': { - legend: { zoomLevel: 4 }, - style: [0, .1, .5, .5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 5].map(function(width, z) { - return new Style({ - zIndex: 20, - fill: new Fill({ - color: [228, 53, 45, Math.max((.2-1)/6 * z + 1, 0)], - }), - stroke: width === 0 ? undefined : new Stroke({ - width: width, - color: [151, 173, 23, 1], - }), - }); - }), - }, - - 'svk.ledningar': { - legend: { zoomLevel: 5, type: 'linestring', reuse_canvas: true }, - style: [1, 1.5, 2, 2, 2, 2, 3, 4, 5, 6, 8, 10].map(function(width) { - return new Style({ - zIndex: 52, - stroke: new Stroke({ - color: 'black', - width: width, - }), - }); - }), - }, - 'svk.stolpar': { - legend: { zoomLevel: 5, type: 'point' }, - style: [undefined, undefined, undefined, undefined, undefined] - .concat([3, 4, 5, 6, 8, 10, 15].map(function(radius) { - return new Style({ - zIndex: 51, - image: new CircleStyle({ - radius: radius, - fill: new Fill({ - color: 'black', - }), - }), - }); - })), - }, - 'svk.transmissionsnatsprojekt': { - legend: { zoomLevel: 5, type: 'linestring' }, - style: [1, 1.5, 2, 2, 2, 2, 3, 4, 5, 6, 8, 10].map(function(width) { - return new Style({ - zIndex: 53, - stroke: new Stroke({ - color: 'black', - width: width, - lineDash: [4 * width], - }), - }); - }), - }, - 'svk.stationer': { - legend: { zoomLevel: 3, type: 'point' }, - style: [3, 4, 5, 6, 7, 8.5, 10].map(function(radius) { - return new Style({ - zIndex: 50, - image: new RegularShape({ - radius: radius, - points: 4, - angle: Math.PI/4, - fill: new Fill({ - color: 'black', - }), - }), - }); - }) - .concat([.5, 1, 1.5, 2, 2].map(function(width) { - return new Style({ - zIndex: 50, - fill: new Fill({ - color: 'rgba(128, 128, 128, .7)', - }), - stroke: new Stroke({ - width: width, - color: 'rgb(0, 0, 0)', - }), - }); - })), - }, - - 'vbk.area_current': { - legend: { zoomLevel: 1 }, - style: [.5, 1, 1.5, 1.5, 2, 2, 2.5, 2.5, 3, 3.5, 4, 5].map(function(width, z) { - return new Style({ - zIndex: 10, - fill: new Fill({ - color: [168, 198, 223, Math.max((.2-1)/8 * z + 1, 0)], - }), - stroke: width === 0 ? undefined : new Stroke({ - width: width, - color: [56, 96, 130, 1], - }), - }); - }), - }, - 'vbk.area_notcurrent': { - legend: { zoomLevel: 1 }, - style: [.5, 1, 1.5, 1.5, 2, 2, 2.5, 2.5, 3, 3.5, 4, 5].map(function(width, z) { - return new Style({ - zIndex: 10, - fill: new Fill({ - color: [222, 163, 199, Math.max((.2-1)/8 * z + 1, 0)], - }), - stroke: width === 0 ? undefined : new Stroke({ - width: width, - color: [148, 55, 112, 1], - lineDash: width >= 1.5 ? [2 * width] : undefined, - }), - }); - }), - }, - 'vbk.offshore_completed': { - legend: { zoomLevel: 1 }, - style: [.5, 1, 1.5, 1.5, 2, 2, 2.5, 2.5, 3, 3.5, 4, 5].map(function(width) { - return new Style({ - zIndex: 17, - fill: new Fill({ - color: [38, 107, 29, .5], - }), - stroke: width === 0 ? undefined : new Stroke({ - width: width, - color: [38, 107, 29, 1], - }), - }); - }), - }, - 'vbk.offshore_approved': { - legend: { zoomLevel: 1 }, - style: [.5, 1, 1.5, 1.5, 2, 2, 2.5, 2.5, 3, 3.5, 4, 5].map(function(width) { - return new Style({ - zIndex: 16, - fill: new Fill({ - color: [56, 160, 44, .5], - }), - stroke: width === 0 ? undefined : new Stroke({ - width: width, - color: [56, 160, 44, 1], - }), - }); - }), - }, - 'vbk.offshore_amended': { - legend: { zoomLevel: 2 }, - style: [4, 8, 16, 16, 32, 32, 64, 64, 64, 128, 128, 128].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - const w = z < 4 ? .5 : z <= 5 ? 1.5 : 4; - patternCanvas.width = width/2; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'rgba(247, 105, 162, 1)'; - patternContext.beginPath(); - patternContext.arc(.75*patternCanvas.width, .75*patternCanvas.height, 1.5*w, 0, 2*Math.PI, true) - patternContext.fill(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 17, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: 2*w, - color: [247, 105, 162, 1], - lineDash: [8 * w], - }), - }); - }), - }, - 'vbk.offshore_rejected': { - legend: { zoomLevel: 1 }, - style: [.5, 1, 1.5, 1.5, 2, 2, 2.5, 2.5, 3, 3.5, 4, 5].map(function(width) { - return new Style({ - zIndex: 11, - fill: new Fill({ - color: [227, 26, 28, .5], - }), - stroke: width === 0 ? undefined : new Stroke({ - width: width, - color: [227, 26, 28, 1], - }), - }); - }), - }, - 'vbk.offshore_appealed': { - legend: { zoomLevel: 1 }, - style: [.5, 1, 1.5, 1.5, 2, 2, 2.5, 2.5, 3, 3.5, 4, 5].map(function(width) { - return new Style({ - zIndex: 15, - fill: new Fill({ - color: [177, 88, 40, .5], - }), - stroke: width === 0 ? undefined : new Stroke({ - width: width, - color: [177, 88, 40, 1], - }), - }); - }), - }, - 'vbk.offshore_applied': { - legend: { zoomLevel: 1 }, - style: [.5, 1, 1.5, 1.5, 2, 2, 2.5, 2.5, 3, 3.5, 4, 5].map(function(width) { - return new Style({ - zIndex: 14, - fill: new Fill({ - color: [255, 127, 0, .5], - }), - stroke: width === 0 ? undefined : new Stroke({ - width: width, - color: [255, 128, 0, 1], - }), - }); - }), - }, - 'vbk.offshore_consultation': { - legend: { zoomLevel: 1 }, - style: [.5, 1, 1.5, 1.5, 2, 2, 2.5, 2.5, 3, 3.5, 4, 5].map(function(width) { - return new Style({ - zIndex: 13, - fill: new Fill({ - color: [254, 217, 118, .65], - }), - stroke: width === 0 ? undefined : new Stroke({ - width: width, - color: [254, 183, 82, 1], - }), - }); - }), - }, - 'vbk.offshore_investigation': { - legend: { zoomLevel: 1 }, - style: [4, 8, 16, 16, 32, 32, 64, 64, 64, 128, 128, 128].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - const w = z < 4 ? .5 : z <= 5 ? 1.5 : 4; - patternCanvas.width = width*2; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'transparent'; - patternContext.strokeStyle = 'rgba(68, 90, 166, 1)'; - patternContext.lineWidth = w; - patternContext.beginPath(); - patternContext.moveTo(0, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, 0); - patternContext.stroke(); - patternContext.moveTo(-patternCanvas.width, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, -patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, 2*patternCanvas.height); - patternContext.lineTo(2*patternCanvas.width, 0); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 12, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: 2*w, - color: [68, 90, 166, 1], - lineDash: [8 * w], - }), - }); - }), - }, - 'vbk.offshore_revoked': { - legend: { zoomLevel: 1 }, - style: [.5, 1, 1.5, 1.5, 2, 2, 2.5, 2.5, 3, 3.5, 4, 5].map(function(width) { - return new Style({ - zIndex: 10, - fill: new Fill({ - color: [105, 61, 154, .5], - }), - stroke: width === 0 ? undefined : new Stroke({ - width: width, - color: [105, 62, 153, 1], - }), - }); - }), - }, - 'vbk.station_completed': { - legend: { zoomLevel: 7, type: 'point' }, - style: [undefined, undefined, undefined, undefined, .125, .125, .25, .5, 1, 2, 4, 8].map(function(scale) { - return scale === undefined ? undefined : new Style({ - zIndex: 99, - image: new Icon({ - src: '/assets/icons/wind-turbine-completed.svg', - declutter: 'none', - scale: scale, - }), - }); - }), - }, - 'vbk.station_processed': { - legend: { zoomLevel: 7, type: 'point' }, - style: [undefined, undefined, undefined, undefined, .125, .125, .25, .5, 1, 2, 4, 8].map(function(scale) { - return scale === undefined ? undefined : new Style({ - zIndex: 99, - image: new Icon({ - src: '/assets/icons/wind-turbine-processed.svg', - declutter: 'none', - scale: scale, - }), - }); - }), - }, - 'vbk.station_approved': { - legend: { zoomLevel: 7, type: 'point' }, - style: [undefined, undefined, undefined, undefined, .125, .125, .25, .5, 1, 2, 4, 8].map(function(scale) { - return scale === undefined ? undefined : new Style({ - zIndex: 99, - image: new Icon({ - src: '/assets/icons/wind-turbine-approved.svg', - declutter: 'none', - scale: scale, - }), - }); - }), - }, - 'vbk.station_revoked': { - legend: { zoomLevel: 7, type: 'point' }, - style: [undefined, undefined, undefined, undefined, .125, .125, .25, .5, 1, 2, 4, 8].map(function(scale) { - return scale === undefined ? undefined : new Style({ - zIndex: 99, - image: new Icon({ - src: '/assets/icons/wind-turbine-revoked.svg', - declutter: 'none', - scale: scale, - }), - }); - }), - }, - 'vbk.station_rejected': { - legend: { zoomLevel: 7, type: 'point' }, - style: [undefined, undefined, undefined, undefined, .125, .125, .25, .5, 1, 2, 4, 8].map(function(scale) { - return scale === undefined ? undefined : new Style({ - zIndex: 99, - image: new Icon({ - src: '/assets/icons/wind-turbine-rejected.svg', - declutter: 'none', - scale: scale, - }), - }); - }), - }, - 'vbk.station_dismounted': { - legend: { zoomLevel: 7, type: 'point' }, - style: [undefined, undefined, undefined, undefined, .125, .125, .25, .5, 1, 2, 4, 8].map(function(scale) { - return scale === undefined ? undefined : new Style({ - zIndex: 99, - image: new Icon({ - src: '/assets/icons/wind-turbine-dismounted.svg', - declutter: 'none', - scale: scale, - }), - }); - }), - }, - 'vbk.station_appealed': { - legend: { zoomLevel: 7, type: 'point' }, - style: [undefined, undefined, undefined, undefined, .125, .125, .25, .5, 1, 2, 4, 8].map(function(scale) { - return scale === undefined ? undefined : new Style({ - zIndex: 99, - image: new Icon({ - src: '/assets/icons/wind-turbine-appealed.svg', - declutter: 'none', - scale: scale, - }), - }); - }), - }, - - /* Documentation at - * https://www.skogsstyrelsen.se/globalassets/sjalvservice/karttjanster/geodatatjanster/produktbeskrivningar/utforda-avverkningar---produktbeskrivning.pdf - * */ - 'avverk.utford': { - legend: { zoomLevel: 7 }, - style: [0, 0, 0, 0, 0, .5, .75, 1, 1, 1, 1, 1].map(function(width, z) { - return new Style({ - zIndex: 10, - fill: new Fill({ - color: [255, 102, 102, Math.max((.2-1)/8 * z + 1, 0)], - }), - stroke: width === 0 ? undefined : new Stroke({ - width: width, - color: [204, 0, 0, 1], - }), - }); - }), - }, - /* Documentation at - * https://www.skogsstyrelsen.se/globalassets/sjalvservice/karttjanster/geodatatjanster/produktbeskrivningar/yttre-granser-for-avverkningsanmalda-omraden---produktbeskrivning.pdf - * */ - 'avverk.anmald': { - legend: { zoomLevel: 7 }, - style: [0, 0, 0, 0, 0, .5, .75, 1, 1, 1, 1, 1].map(function(width, z) { - return new Style({ - zIndex: 10, - fill: (width === undefined || width === 0) ? - new Fill({ color: [255, 102, 102, Math.max((.2-1)/8 * z + 1, 0)*.75] }) : - (function() { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - const slope = 45 * Math.PI/180; - const spacing = z < 10 ? z*2 : 40; - const len = Math.hypot(1, slope); - const w = patternCanvas.width = Math.round(1/len + spacing) - const h = patternCanvas.height = Math.round(slope/len + spacing * slope); - - patternContext.fillStyle = 'rgba(255, 102, 102, .1)'; - patternContext.fillRect(0, 0, patternCanvas.width, patternCanvas.height); - patternContext.strokeStyle = 'rgba(204, 0, 0, 1)'; - patternContext.lineWidth = Math.max(1, width/2); - patternContext.beginPath(); - patternContext.moveTo(0, h); - patternContext.lineTo(w, 0); - patternContext.moveTo(-w, h); - patternContext.lineTo(w, -h); - patternContext.moveTo(0, 2*h); - patternContext.lineTo(2*w, 0); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Fill({ color: context.createPattern(patternCanvas, 'repeat') }); - })(), - stroke: width === 0 ? undefined : new Stroke({ - width: width, - color: [204, 0, 0, 1], - lineDash: width >= 1.5 ? [2 * width] : undefined, - }), - }); - }), - }, - - 'skydd.tilltradesforbud': { - legend: { zoomLevel: 2 }, - style: [1, 1.5, 2, 3, 3.5, 4, 5, 5, 6, 7, 8, 10].map(function(width) { - return new Style({ - zIndex: 23, - fill: new Fill({ - /* transparent fill so clicking the inside of the polygon triggers a popover */ - /* XXX could also use a custom renderer but that doesn't seem to work */ - color: [0, 0, 0, 0], - }), - stroke: width === 0 ? undefined : new Stroke({ - width: width, - color: [255, 0, 0, 1], - }), - }); - }), - }, - 'skydd.nationalpark': { - legend: { zoomLevel: 1 }, - style: [8, 16, 32, 32, 64, 64, 128, 128, 128, 256, 256, 256].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'transparent'; - patternContext.strokeStyle = 'rgba(0, 55, 0, 1)'; - patternContext.lineWidth = z < 4 ? .5 : z <= 5 ? 1 : 2; - patternContext.beginPath(); - patternContext.moveTo(0, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, 0); - patternContext.stroke(); - patternContext.moveTo(-patternCanvas.width, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, -patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, 2*patternCanvas.height); - patternContext.lineTo(2*patternCanvas.width, 0); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 22, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 2 ? 1 : z < 4 ? 2 : z <= 5 ? 4 : 8, - color: [0, 55, 0, 1], - }), - }); - }), - }, - 'skydd.naturreservat': { - legend: { zoomLevel: 1 }, - style: [8, 16, 32, 32, 64, 64, 128, 128, 128, 256, 256, 256].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'transparent'; - patternContext.strokeStyle = 'rgba(7, 181, 7, 1)'; - patternContext.lineWidth = z < 4 ? .5 : z <= 5 ? 1 : 2; - patternContext.beginPath(); - patternContext.moveTo(0, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, 0); - patternContext.stroke(); - patternContext.moveTo(-patternCanvas.width, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, -patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, 2*patternCanvas.height); - patternContext.lineTo(2*patternCanvas.width, 0); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 21, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 2 ? 1 : z < 4 ? 2 : z <= 5 ? 4 : 8, - color: [7, 181, 7, 1], - }), - }); - }), - }, - 'skydd.naturreservat_kommunalt': { - legend: { zoomLevel: 2 }, - style: [4, 8, 16, 16, 32, 32, 64, 64, 64, 128, 128, 128].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'transparent'; - patternContext.strokeStyle = 'rgba(7, 181, 7, 1)'; - patternContext.lineWidth = z < 4 ? .5 : z <= 5 ? 1 : 2; - patternContext.beginPath(); - patternContext.moveTo(0, 0); - patternContext.lineTo(patternCanvas.width, patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, -patternCanvas.height); - patternContext.lineTo(2*patternCanvas.width, patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(-patternCanvas.width, 0); - patternContext.lineTo(patternCanvas.width, 2*patternCanvas.height); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 20, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 2 ? 1 : z < 4 ? 2 : z <= 5 ? 4 : 8, - color: [7, 181, 7, 1], - }), - }); - }), - }, - 'skydd.naturvardsomrade': { - legend: { zoomLevel: 2 }, - style: [4, 8, 16, 16, 32, 32, 64, 64, 64, 128, 128, 128].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'transparent'; - patternContext.strokeStyle = 'rgba(176, 255, 176, 1)'; - patternContext.lineWidth = z < 4 ? .5 : z <= 5 ? 1 : 2; - patternContext.beginPath(); - patternContext.moveTo(0, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, 0); - patternContext.stroke(); - patternContext.moveTo(-patternCanvas.width, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, -patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, 2*patternCanvas.height); - patternContext.lineTo(2*patternCanvas.width, 0); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 19, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 2 ? 1 : z < 4 ? 2 : z <= 5 ? 4 : 8, - color: [176, 255, 176, 1], - }), - }); - }), - }, - 'skydd.djur_och_vaxtskyddsomrade': { - legend: { zoomLevel: 2 }, - style: [4, 8, 16, 16, 32, 32, 64, 64, 64, 128, 128, 128].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'transparent'; - patternContext.strokeStyle = 'rgba(255, 255, 0, 1)'; - patternContext.lineWidth = z < 4 ? .5 : z <= 5 ? 1 : 2; - patternContext.beginPath(); - patternContext.moveTo(0, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, 0); - patternContext.stroke(); - patternContext.moveTo(-patternCanvas.width, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, -patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, 2*patternCanvas.height); - patternContext.lineTo(2*patternCanvas.width, 0); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 18, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 2 ? 1 : z < 4 ? 2 : z <= 5 ? 4 : 8, - color: [255, 255, 0, 1], - }), - }); - }), - }, - 'skydd.kulturreservat': { - legend: { zoomLevel: 2 }, - style: [4, 8, 16, 16, 32, 32, 64, 64, 64, 128, 128, 128].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'transparent'; - patternContext.strokeStyle = 'rgba(154, 102, 255, 1)'; - patternContext.lineWidth = z < 4 ? .5 : z <= 5 ? 1 : 2; - patternContext.beginPath(); - patternContext.moveTo(0, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, 0); - patternContext.stroke(); - patternContext.moveTo(-patternCanvas.width, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, -patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, 2*patternCanvas.height); - patternContext.lineTo(2*patternCanvas.width, 0); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 17, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 2 ? 1 : z < 4 ? 2 : z <= 5 ? 4 : 8, - color: [154, 102, 255, 1], - }), - }); - }), - }, - 'skydd.vattenskyddsomrade': { - legend: { zoomLevel: 2 }, - style: [4, 8, 16, 16, 32, 32, 64, 64, 64, 128, 128, 128].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'transparent'; - patternContext.strokeStyle = 'rgba(0, 105, 212, 1)'; - patternContext.lineWidth = z < 4 ? .5 : z <= 5 ? 1 : 2; - patternContext.beginPath(); - patternContext.moveTo(0, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, 0); - patternContext.stroke(); - patternContext.moveTo(-patternCanvas.width, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, -patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, 2*patternCanvas.height); - patternContext.lineTo(2*patternCanvas.width, 0); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 16, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 2 ? 1 : z < 4 ? 2 : z <= 5 ? 4 : 8, - color: [0, 105, 212, 1], - }), - }); - }), - }, - 'skydd.landskapsbildsskyddsomrade': { - legend: { zoomLevel: 2 }, - style: [4, 8, 16, 16, 32, 32, 64, 64, 64, 128, 128, 128].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'transparent'; - patternContext.strokeStyle = 'rgba(135, 110, 71, 1)'; - patternContext.lineWidth = z < 4 ? .5 : z <= 5 ? 1 : 2; - patternContext.beginPath(); - patternContext.moveTo(0, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, 0); - patternContext.stroke(); - patternContext.moveTo(-patternCanvas.width, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, -patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, 2*patternCanvas.height); - patternContext.lineTo(2*patternCanvas.width, 0); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 15, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 2 ? 1 : z < 4 ? 2 : z <= 5 ? 4 : 8, - color: [134, 110, 71, 1], - }), - }); - }), - }, - 'skydd.skogligt_biotopskyddsomrade': { - legend: { zoomLevel: 2 }, - style: [4, 8, 16, 16, 32, 32, 64, 64, 64, 128, 128, 128].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'transparent'; - patternContext.strokeStyle = 'rgba(135, 90, 71, 1)'; - patternContext.lineWidth = z < 4 ? .5 : z <= 5 ? 1 : 2; - patternContext.beginPath(); - patternContext.moveTo(0, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, 0); - patternContext.stroke(); - patternContext.moveTo(-patternCanvas.width, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, -patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, 2*patternCanvas.height); - patternContext.lineTo(2*patternCanvas.width, 0); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 14, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 4 ? .5 : z <= 5 ? 1 : 2, - color: [134, 90, 71, 1], - }), - }); - }), - }, - 'skydd.ovrigt_biotopskyddsomrade': { - legend: { zoomLevel: 2 }, - style: [4, 8, 16, 16, 32, 32, 64, 64, 64, 128, 128, 128].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'transparent'; - patternContext.strokeStyle = 'rgba(255, 95, 0, 1)'; - patternContext.lineWidth = z < 4 ? .5 : z <= 5 ? 1 : 2; - patternContext.beginPath(); - patternContext.moveTo(0, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, 0); - patternContext.stroke(); - patternContext.moveTo(-patternCanvas.width, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, -patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, 2*patternCanvas.height); - patternContext.lineTo(2*patternCanvas.width, 0); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 13, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 4 ? .5 : z <= 5 ? 1 : 2, - color: [255, 95, 0, 1], - }), - }); - }), - }, - 'skydd.naturminne_yta': { - legend: { zoomLevel: 2 }, - style: [4, 8, 16, 16, 32, 32, 64, 64, 64, 128, 128, 128].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'transparent'; - patternContext.strokeStyle = 'rgba(113, 0, 116, 1)'; - patternContext.lineWidth = z < 4 ? .5 : z <= 5 ? 1 : 2; - patternContext.beginPath(); - patternContext.moveTo(0, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, 0); - patternContext.stroke(); - patternContext.moveTo(-patternCanvas.width, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, -patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, 2*patternCanvas.height); - patternContext.lineTo(2*patternCanvas.width, 0); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 12, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 2 ? 1 : z < 4 ? 2 : z <= 5 ? 4 : 8, - color: [134, 0, 116, 1], - }), - }); - }), - }, - 'skydd.naturminne_punkt': { - legend: { zoomLevel: 6, type: 'point' }, - style: [undefined, undefined, undefined, undefined].concat([3, 4, 6, 8, 12, 16, 20, 24].map(function(width) { - return new Style({ - zIndex: 12, - image: new CircleStyle({ - radius: width, - fill: new Fill({ - color: 'rgba(113, 0, 116, .5)', - }), - stroke: new Stroke({ - width: Math.log2(width)/2, - color: 'rgba(113, 0, 116, 1)', - }), - }), - }); - })) - }, - 'skydd.interimistiskt_forbud': { - legend: { zoomLevel: 2 }, - style: [4, 8, 16, 16, 32, 32, 64, 64, 64, 128, 128, 128].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'transparent'; - patternContext.strokeStyle = 'rgba(168, 0, 0, 1)'; - patternContext.lineWidth = z < 4 ? .5 : z <= 5 ? 1 : 2; - patternContext.beginPath(); - patternContext.moveTo(0, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, 0); - patternContext.stroke(); - patternContext.moveTo(-patternCanvas.width, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, -patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, 2*patternCanvas.height); - patternContext.lineTo(2*patternCanvas.width, 0); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 11, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 2 ? 1 : z < 4 ? 2 : z <= 5 ? 4 : 8, - color: [168, 0, 0, 1], - }), - }); - }), - }, - 'skydd.fageldirektivet': { - legend: { zoomLevel: 1 }, - style: [8, 16, 32, 32, 64, 64, 128, 128, 128, 256, 256, 256].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width*2; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'transparent'; - patternContext.strokeStyle = 'rgba(230, 0, 0, 1)'; - patternContext.lineWidth = z < 4 ? .5 : z <= 5 ? 1 : 2; - patternContext.beginPath(); - patternContext.moveTo(0, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, 0); - patternContext.stroke(); - patternContext.moveTo(-patternCanvas.width, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, -patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, 2*patternCanvas.height); - patternContext.lineTo(2*patternCanvas.width, 0); - patternContext.stroke(); - patternContext.beginPath(); - patternContext.lineWidth *= 6; - patternContext.moveTo(-.5*patternCanvas.width, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, -.5*patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, 1.5*patternCanvas.height); - patternContext.lineTo(1.5*patternCanvas.width, 0); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 10, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 4 ? .5 : z <= 5 ? 1 : 2, - color: [230, 0, 0, 1], - }), - }); - }), - }, - 'skydd.habitatdirektivet': { - legend: { zoomLevel: 1 }, - style: [8, 16, 32, 32, 64, 64, 128, 128, 128, 256, 256, 256].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width*2; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'transparent'; - patternContext.strokeStyle = 'rgba(0, 77, 168, 1)'; - patternContext.lineWidth = z < 4 ? .5 : z <= 5 ? 1 : 2; - patternContext.beginPath(); - patternContext.moveTo(0, 0); - patternContext.lineTo(patternCanvas.width, patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, -patternCanvas.height); - patternContext.lineTo(2*patternCanvas.width, patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(-patternCanvas.width, 0); - patternContext.lineTo(patternCanvas.width, 2*patternCanvas.height); - patternContext.stroke(); - patternContext.beginPath(); - patternContext.lineWidth *= 6; - patternContext.moveTo(0, -.5*patternCanvas.height); - patternContext.lineTo(1.5*patternCanvas.width, patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(-.5*patternCanvas.width, 0); - patternContext.lineTo(patternCanvas.width, 1.5*patternCanvas.height); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 10, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 4 ? .5 : z <= 5 ? 1 : 2, - color: [0, 77, 168, 1], - }), - }); - }), - }, - 'skydd.helcom': { - legend: { zoomLevel: 1 }, - style: [4, 8, 16, 16, 32, 32, 64, 64, 64, 128, 128, 128].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'rgba(130, 130, 130, 1)'; - const r = z < 5 ? (z+1)*.75 : z*.5; - patternContext.beginPath(); - patternContext.arc(.5*patternCanvas.width, .5*patternCanvas.height, r, 0, 2*Math.PI, true) - patternContext.fill(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 9, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 2 ? 1 : z < 4 ? 2 : z <= 5 ? 4 : 8, - color: [130, 130, 130, 1], - }), - }); - }), - }, - 'skydd.ramsar': { - legend: { zoomLevel: 1 }, - style: [4, 8, 16, 16, 32, 32, 64, 64, 64, 128, 128, 128].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'rgba(195, 0, 255, 1)'; - const r = z < 5 ? (z+1)*.75 : z*.5; - patternContext.beginPath(); - patternContext.arc(.25*patternCanvas.width, .25*patternCanvas.height, r, 0, 2*Math.PI, true) - patternContext.fill(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 9, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 2 ? 1 : z < 4 ? 2 : z <= 5 ? 4 : 8, - color: [195, 0, 255, 1], - }), - }); - }), - }, - 'skydd.ospar': { - legend: { zoomLevel: 1 }, - style: [4, 8, 16, 16, 32, 32, 64, 64, 64, 128, 128, 128].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'rgba(168, 0, 0, 1)'; - const r = z < 5 ? (z+1)*.75 : z*.5; - patternContext.beginPath(); - patternContext.arc(.25*patternCanvas.width, .75*patternCanvas.height, r, 0, 2*Math.PI, true) - patternContext.fill(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 9, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 2 ? 1 : z < 4 ? 2 : z <= 5 ? 4 : 8, - color: [168, 0, 0, 1], - }), - }); - }), - }, - 'skydd.varldsarv': { - legend: { zoomLevel: 1 }, - style: [4, 8, 16, 16, 32, 32, 64, 64, 64, 128, 128, 128].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'rgba(168, 0, 0, 1)'; - const r = z < 5 ? (z+1)*.75 : z*.5; - patternContext.beginPath(); - patternContext.arc(.75*patternCanvas.width, .25*patternCanvas.height, r, 0, 2*Math.PI, true) - patternContext.fill(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 9, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 2 ? 1 : z < 4 ? 2 : z <= 5 ? 4 : 8, - color: [168, 0, 0, 1], - }), - }); - }), - }, - 'skydd.biosfarsomraden': { - legend: { zoomLevel: 1 }, - style: [4, 8, 16, 16, 32, 32, 64, 64, 64, 128, 128, 128].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'rgba(131, 0, 219, 1)'; - const r = z < 5 ? (z+1)*.75 : z*.5; - patternContext.beginPath(); - patternContext.arc(.75*patternCanvas.width, .75*patternCanvas.height, r, 0, 2*Math.PI, true) - patternContext.fill(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 9, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 2 ? 1 : z < 4 ? 2 : z <= 5 ? 4 : 8, - color: [131, 0, 219, 1], - }), - }); - }), - }, - 'skydd.naturvardsavtal': { - legend: { zoomLevel: 1 }, - style: [8, 16, 32, 32, 64, 64, 128, 128, 128, 256, 256, 256].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'transparent'; - patternContext.strokeStyle = 'rgba(255, 0, 197, 1)'; - patternContext.lineWidth = z < 4 ? .5 : z <= 5 ? 1 : 2; - patternContext.beginPath(); - patternContext.moveTo(0, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, 0); - patternContext.stroke(); - patternContext.moveTo(-patternCanvas.width, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, -patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, 2*patternCanvas.height); - patternContext.lineTo(2*patternCanvas.width, 0); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 21, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 4 ? .5 : z <= 5 ? 1 : 2, - color: [255, 0, 197, 1], - }), - }); - }), - }, - 'skydd.naturvardsavtal_skogsstyrelsen': { - legend: { zoomLevel: 2 }, - style: [4, 8, 16, 16, 32, 32, 64, 64, 64, 128, 128, 128].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'transparent'; - patternContext.strokeStyle = 'rgba(255, 0, 197, 1)'; - patternContext.lineWidth = z < 4 ? .5 : z <= 5 ? 1 : 2; - patternContext.beginPath(); - patternContext.moveTo(0, 0); - patternContext.lineTo(patternCanvas.width, patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, -patternCanvas.height); - patternContext.lineTo(2*patternCanvas.width, patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(-patternCanvas.width, 0); - patternContext.lineTo(patternCanvas.width, 2*patternCanvas.height); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 20, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 4 ? .5 : z <= 5 ? 1 : 2, - color: [255, 0, 197, 1], - }), - }); - }), - }, - 'skydd.atervatningsavtal': { - legend: { zoomLevel: 0 }, - style: [0, 1, 2, 3, 4, 5, 6].map(function(width) { - return new Style({ - zIndex: 5, - fill: new Fill({ - color: [255, 115, 0, .4], - }), - stroke: width === 0 ? undefined : new Stroke({ - width: .5, - color: [255, 115, 0, 1], - }), - }); - }) - .concat([7, 8, 9, 10, 11].map(function() { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = 16; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'transparent'; - patternContext.strokeStyle = 'rgba(255, 115, 0, 1)'; - patternContext.lineWidth = 1; - patternContext.beginPath(); - patternContext.moveTo(0, 0); - patternContext.lineTo(patternCanvas.width, patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, -patternCanvas.height); - patternContext.lineTo(2*patternCanvas.width, patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(-patternCanvas.width, 0); - patternContext.lineTo(patternCanvas.width, 2*patternCanvas.height); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 5, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: new Stroke({ - width: 1.5, - color: [255, 115, 0, 1], - }), - }); - })), - }, - 'nv.naturvarde_sks': { - legend: { zoomLevel: 0 }, - style: [0, 1, 2, 3, 4, 5].map(function(width) { - return new Style({ - zIndex: 6, - fill: new Fill({ - color: [255, 170, 0, .2], - }), - stroke: width === 0 ? undefined : new Stroke({ - width: .5, - color: [255, 170, 0, .8], - }), - }); - }) - .concat([6, 7, 8, 9, 10, 11].map(function() { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = 16; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'transparent'; - patternContext.strokeStyle = 'rgba(255, 170, 0, 1)'; - patternContext.lineWidth = 1; - patternContext.beginPath(); - patternContext.moveTo(0, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, 0); - patternContext.stroke(); - patternContext.moveTo(-patternCanvas.width, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, -patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, 2*patternCanvas.height); - patternContext.lineTo(2*patternCanvas.width, 0); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 6, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: new Stroke({ - width: 1.5, - color: [255, 170, 0, 1], - }), - }); - })), - }, - 'nv.nyckelbiotop': { - legend: { zoomLevel: 0 }, - style: [0, 1, 2, 3, 4, 5].map(function(width) { - return new Style({ - zIndex: 6, - fill: new Fill({ - color: [217, 148, 9, .2], - }), - stroke: width === 0 ? undefined : new Stroke({ - width: .5, - color: [217, 148, 9, .8], - }), - }); - }) - .concat([6, 7, 8, 9, 10, 11].map(function() { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = 16; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'transparent'; - patternContext.strokeStyle = 'rgba(217, 148, 9, 1)'; - patternContext.lineWidth = 1; - patternContext.beginPath(); - patternContext.moveTo(0, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, 0); - patternContext.stroke(); - patternContext.moveTo(-patternCanvas.width, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, -patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, 2*patternCanvas.height); - patternContext.lineTo(2*patternCanvas.width, 0); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 6, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: new Stroke({ - width: 1.5, - color: [217, 148, 9, 1], - }), - }); - })), - }, - 'nv.nyckelbiotop_storskogsbruk': { - legend: { zoomLevel: 0 }, - style: [0, 1, 2, 3, 4, 5].map(function(width) { - return new Style({ - zIndex: 6, - fill: new Fill({ - color: [217, 148, 9, .2], - }), - stroke: width === 0 ? undefined : new Stroke({ - width: .5, - color: [217, 148, 9, .8], - }), - }); - }) - .concat([6, 7, 8, 9, 10, 11].map(function() { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = 16; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'transparent'; - patternContext.strokeStyle = 'rgba(217, 148, 9, 1)'; - patternContext.lineWidth = 1; - patternContext.beginPath(); - patternContext.moveTo(0, 0); - patternContext.lineTo(patternCanvas.width, patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, -patternCanvas.height); - patternContext.lineTo(2*patternCanvas.width, patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(-patternCanvas.width, 0); - patternContext.lineTo(patternCanvas.width, 2*patternCanvas.height); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 6, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: new Stroke({ - width: 1.5, - color: [217, 148, 9, 1], - }), - }); - })), - }, - 'nv.sumpskog': { - legend: { zoomLevel: 5 }, - style: [.5, 1, 1.5, 1.5, 2, 2, 2.5, 2.5, 3, 3.5, 4, 5].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - const w = Math.max(1, width); - patternCanvas.width = z < 2 ? 2 : z < 4 ? 4 : z <= 5 ? 6 : 8; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'transparent'; - patternContext.strokeStyle = 'rgba(158, 200, 215, 1)'; - patternContext.lineWidth = w; - patternContext.beginPath(); - patternContext.moveTo(0, 0); - patternContext.lineTo(patternCanvas.width, 0); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 5, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: w/2, - color: [158, 200, 215, 1], - }), - }); - }), - }, - 'nv.pagaende_naturreservatsbildning': { - legend: { zoomLevel: 1 }, - style: [8, 16, 32, 32, 64, 64, 128, 128, 128, 256, 256, 256].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'transparent'; - patternContext.setLineDash([width/4, width/4]); - patternContext.strokeStyle = 'rgba(7, 181, 7, 1)'; - patternContext.lineWidth = z < 4 ? .5 : z <= 5 ? 1 : 2; - patternContext.beginPath(); - patternContext.moveTo(width/4, 0); - patternContext.lineTo(width/4, patternCanvas.height); - patternContext.stroke(); - patternContext.beginPath(); - patternContext.lineDashOffset = width/4; - patternContext.moveTo(3*width/4, 0); - patternContext.lineTo(3*width/4, patternCanvas.height); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 10, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 2 ? 1 : z < 4 ? 2 : z <= 5 ? 3 : 4, - color: [7, 181, 7, 1], - lineDash: [width/8, width/4], - }), - }); - }), - }, - 'nv.snus': { - legend: { zoomLevel: 1 }, - style: [.5, 1, 1.5, 1.5, 2, 2, 2.5, 2.5, 3, 3.5, 4, 5].map(function(width) { - return new Style({ - zIndex: 4, - fill: new Fill({ - color: [168,168,0,.2], - }), - stroke: width === 0 ? undefined : new Stroke({ - width: width, - color: [168,77,0,.75], - }), - }); - }), - }, - - 'ri.naturvard': { - legend: { zoomLevel: 0 }, - style: [8, 16, 32, 32, 64, 64, 128, 128, 128, 256, 256, 256].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'transparent'; - patternContext.strokeStyle = 'rgba(154, 230, 0, 1)'; - patternContext.lineWidth = z < 4 ? .5 : z <= 5 ? 1 : 2; - patternContext.beginPath(); - patternContext.moveTo(0, 0); - patternContext.lineTo(patternCanvas.width, patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, -patternCanvas.height); - patternContext.lineTo(2*patternCanvas.width, patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(-patternCanvas.width, 0); - patternContext.lineTo(patternCanvas.width, 2*patternCanvas.height); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 8, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 2 ? 1 : z < 4 ? 2 : z <= 5 ? 4 : 8, - color: [154, 230, 0, 1], - }), - }); - }), - }, - 'ri.friluftsliv': { - legend: { zoomLevel: 0 }, - style: [8, 16, 32, 32, 64, 64, 128, 128, 128, 256, 256, 256].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'transparent'; - patternContext.strokeStyle = 'rgba(0, 127, 232, 1)'; - patternContext.lineWidth = z < 4 ? .5 : z <= 5 ? 1 : 2; - patternContext.beginPath(); - patternContext.moveTo(0, 0); - patternContext.lineTo(patternCanvas.width, patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, -patternCanvas.height); - patternContext.lineTo(2*patternCanvas.width, patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(-patternCanvas.width, 0); - patternContext.lineTo(patternCanvas.width, 2*patternCanvas.height); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 8, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 2 ? 1 : z < 4 ? 2 : z <= 5 ? 4 : 8, - color: [0, 127, 232, 1], - }), - }); - }), - }, - 'ri.rorligt_friluftsliv': { - legend: { zoomLevel: 0 }, - style: [8, 16, 32, 32, 64, 64, 128, 128, 128, 256, 256, 256].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'rgba(187, 227, 212, .25)'; - patternContext.fillRect(0, 0, patternCanvas.width, patternCanvas.height); - patternContext.strokeStyle = 'rgba(56, 151, 117, 1)'; - patternContext.lineWidth = z < 4 ? .5 : z <= 5 ? 1 : 2; - patternContext.beginPath(); - patternContext.moveTo(0, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, 0); - patternContext.stroke(); - patternContext.moveTo(-patternCanvas.width, patternCanvas.height); - patternContext.lineTo(patternCanvas.width, -patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, 2*patternCanvas.height); - patternContext.lineTo(2*patternCanvas.width, 0); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 8, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 2 ? 2 : z < 4 ? 4 : z <= 5 ? 8 : 16, - color: [56, 151, 117, 1], - lineDash: [width/4, width/3], - }), - }); - }), - }, - 'ri.obruten_kust': { - legend: { zoomLevel: 0 }, - style: [8, 16, 32, 32, 64, 64, 128, 128, 128, 256, 256, 256].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'rgba(227, 227, 187, .25)'; - patternContext.fillRect(0, 0, patternCanvas.width, patternCanvas.height); - patternContext.strokeStyle = 'rgba(156, 158, 56, 1)'; - patternContext.lineWidth = z < 4 ? .5 : z <= 5 ? 1 : 2; - patternContext.beginPath(); - patternContext.moveTo(0, 0); - patternContext.lineTo(patternCanvas.width, patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, -patternCanvas.height); - patternContext.lineTo(2*patternCanvas.width, patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(-patternCanvas.width, 0); - patternContext.lineTo(patternCanvas.width, 2*patternCanvas.height); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 8, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 2 ? 2 : z < 4 ? 4 : z <= 5 ? 8 : 16, - color: [156, 158, 56, 1], - lineDash: [width/4, width/3], - }), - }); - }), - }, - 'ri.obrutet_fjall': { - legend: { zoomLevel: 0 }, - style: [8, 16, 32, 32, 64, 64, 128, 128, 128, 256, 256, 256].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = width; - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'rgba(255, 255, 209, .25)'; - patternContext.fillRect(0, 0, patternCanvas.width, patternCanvas.height); - patternContext.strokeStyle = 'rgba(219, 183, 60, 1)'; - patternContext.lineWidth = z < 4 ? .5 : z <= 5 ? 1 : 2; - patternContext.beginPath(); - patternContext.moveTo(0, 0); - patternContext.lineTo(patternCanvas.width, patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(0, -patternCanvas.height); - patternContext.lineTo(2*patternCanvas.width, patternCanvas.height); - patternContext.stroke(); - patternContext.moveTo(-patternCanvas.width, 0); - patternContext.lineTo(patternCanvas.width, 2*patternCanvas.height); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 8, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 2 ? 2 : z < 4 ? 4 : z <= 5 ? 8 : 16, - color: [219, 183, 60, 1], - lineDash: [width/4, width/3], - }), - }); - }), - }, - 'ri.skyddade_vattendrag': { - legend: { zoomLevel: 0 }, - style: [8, 16, 32, 32, 64, 64, 128, 128, 128, 256, 256, 256].map(function(width, z) { - return new Style({ - zIndex: 8, - fill: new Fill({ - color: [102, 157, 240, .25], - }), - stroke: width === 0 ? undefined : new Stroke({ - width: z < 2 ? 2 : z < 4 ? 4 : z <= 5 ? 8 : 16, - color: [41, 109, 197, 1], - lineDash: [width/4, width/3], - }), - }); - }), - }, - - 'ren.betesomrade': { - legend: { zoomLevel: 0 }, - style: [1, 1.5, 2, 3, 3.5, 4, 5, 5, 6, 7, 8, 10].map(function(width) { - return new Style({ - zIndex: 4, - fill: new Fill({ - /* transparent fill so clicking the inside of the polygon triggers a popover */ - /* XXX could also use a custom renderer but that doesn't seem to work */ - color: [0, 0, 0, 0], - }), - stroke: width === 0 ? undefined : new Stroke({ - width: width, - color: [179, 153, 102, 1], - }), - }); - }), - }, - 'ren.flyttled': { - legend: { zoomLevel: 2, type: 'linestring' }, - style: [.75, 1, 1.5, 2, 3, 4, 5, 5, 6, 7, 8, 10].map(function(width) { - return new Style({ - zIndex: 7, - stroke: new Stroke({ - width: 2*width, - color: [119, 99, 59, 1], - lineDash: [4 * width], - }), - }); - }), - }, - 'ren.riks_ren': { - legend: { zoomLevel: 1 }, - style: [.5, 1, 1.5, 1.5, 2, 2, 2.5, 2.5, 3, 3.5, 4, 5].map(function(width, z) { - const patternCanvas = document.createElement('canvas'); - const patternContext = patternCanvas.getContext('2d'); - patternCanvas.width = z < 4 ? 4 : z <= 5 ? 8 : Math.pow(2, Math.round(Math.log2(width) + 3)); - patternCanvas.height = patternCanvas.width; - patternContext.fillStyle = 'transparent'; - patternContext.strokeStyle = 'rgba(179, 153, 102, 1)'; - patternContext.lineWidth = Math.max(1, width/2); - patternContext.beginPath(); - patternContext.moveTo(0, 0); - patternContext.lineTo(patternCanvas.width, 0); - patternContext.stroke(); - - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return new Style({ - zIndex: 6, - fill: new Fill({ - color: context.createPattern(patternCanvas, 'repeat'), - }), - stroke: width === 0 ? undefined : new Stroke({ - width: width, - color: [179, 153, 102, 1], - }), - }); - }), - }, - 'ren.omr_riks': { - legend: { zoomLevel: 2 }, - style: [.5, .5, 1, 1, 1, 1.5, 1.5, 1.5, 2, 2, 2, 2].map(function(width, z) { - return new Style({ - zIndex: 5, - fill: new Fill({ - color: [203, 190, 163, Math.max((.3-.5)/8 * z + .5, 0)], - }), - stroke: width === 0 ? undefined : new Stroke({ - width: width, - color: [179, 153, 102, 1], - }), - }); - }), - }, - - /* Documentation at - * https://www.smhi.se/polopoly_fs/1.34541!/dammprod%202013_3%2C%20beskrivning%2C%20SVAR2012_2.pdf - * */ - 'misc.dammar': { - legend: { zoomLevel: 5, type: 'point' }, - style: [2, 3, 4, 4, 4, 6, 8, 8, 8, 10, 16, 32].map(function(width) { - return new Style({ - zIndex: 59, - image: new CircleStyle({ - radius: width, - fill: new Fill({ - color: 'rgb(219, 30, 42)', - }), - stroke: new Stroke({ - width: Math.log2(width) * 2/5, - color: 'rgb(128, 17, 25)', - }), - }), - }); - }), - }, - - 'misc.gigafactories': { - legend: { zoomLevel: 1, type: 'point' }, - style: [4, 6, 7, 8, 10, 12].map(function(width) { - return new Style({ - zIndex: 60, - image: new CircleStyle({ - radius: width, - fill: new Fill({ - color: 'rgb(152, 78, 163)', - }), - stroke: new Stroke({ - width: Math.log2(width) * 2/5, - color: 'rgb(119, 61, 128)', - }), - }), - }); - }) - .concat([1.5, 2, 2, 2, 2, 2].map(function(width) { - return new Style({ - zIndex: 58, - fill: new Fill({ - color: 'rgba(152, 78, 163, .4)', - }), - stroke: new Stroke({ - width: width, - color: 'rgb(119, 61, 128)', - }), - }); - })), - }, - - 'kskog.1' : { style: [ 56, 168, 0, .2] }, /* #1 Sannolikt kontinuitetsskog (preciserad) */ - 'kskog.2' : { style: [169, 0, 230, .2] }, /* #2 Sannolikt påverkad kontinuitetsskog (preciserad) */ - 'kskog.3' : { style: [152, 230, 0, .2] }, /* #3 Sannolikt kontinuitetsskog i fjällen (grövre precisering) */ - 'kskog.4' : { style: [ 76, 115, 0, .2] }, /* #4 Potentiell kontinuitetsskog (2015) */ -}; diff --git a/src/map.js b/src/map.js deleted file mode 100644 index 5a751e6..0000000 --- a/src/map.js +++ /dev/null @@ -1,103 +0,0 @@ -/*********************************************************************** - * Copyright © 2024-2025 Guilhem Moulin <info@guilhem.se> - * Map base setup - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - **********************************************************************/ - -import Map from 'ol/Map.js'; -import View from 'ol/View.js'; -import TileLayer from 'ol/layer/Tile.js'; - -import WMTS from 'ol/source/WMTS.js'; -import WMTSTileGrid from 'ol/tilegrid/WMTS.js'; - -import proj4 from 'proj4'; -import { get as getProjection } from 'ol/proj.js'; -import { register as registerProjection } from 'ol/proj/proj4.js'; - -proj4.defs('EPSG:3006', '+proj=utm +zone=33 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs'); -registerProjection(proj4); - -export const projection = getProjection('EPSG:3006'); - -/* Lantmäteriet uses a tile-scheme where the origin (upper-left corner) is at - * N8500000 E-1200000 (SWEREF99 TM), where each tile is 256×256 pixels, and where - * the resolution at level 0 is 4096m per pixel (each side is 1048.576km long). - * - * https://www.lantmateriet.se/globalassets/geodata/geodatatjanster/tb_twk_visning_cache_v1.1.0.pdf - * https://www.lantmateriet.se/globalassets/geodata/geodatatjanster/tb_twk_visning-oversiktlig_v1.0.3.pdf - * - * We set the extent to a 4×4 tiles square at level 2 (1024px = 1048.576km per - * side) somehow centered on Norrbotten and Västerbotten, and zoom in from there. - * This represent a TILEROW (x) offset of 5, and a TILECOL (y) offset of 2. - */ -export const extent = [110720, 6927136, 1159296, 7975712]; - -/* XXX using the topowebbcache WMTS is fine for testing (as it doesn't require - * authentication) but not in production in a public instance as doing so would - * violate its current terms of use (as of January 2024 it's not CC0 open data). - * See - * - * https://www.lantmateriet.se/sv/om-lantmateriet/Rattsinformation/upphovsratt-och-publicering-av-lantmateriets-geografiska-information/ - * https://www.lantmateriet.se/sv/kartor/vara-karttjanster/min-karta/#anchor-2 - * https://help.locusmap.eu/topic/support-for-swedish-lantmateriets-min-karta-wms - * - * More precise background maps might be available in the future as open data, - * though: - * - * https://www.lantmateriet.se/sv/om-lantmateriet/press/nyheter/lantmateriets-arbete-mot-oppna-data-i-full-gang/ - * https://ext-geodatakatalog.lansstyrelsen.se/GeodataKatalogen/srv/swe/catalog.search#/map uses - * https://api.lantmateriet.se/open/topowebb-ccby/v1/wmts/token/3c3a9cf47e7cb5ea24542d40d19698/?layer=topowebb&style=default&tilematrixset=3006&Service=WMTS&Request=GetTile&Version=1.0.0&Format=image/png&TileMatrix=7&TileCol=237&TileRow=155 - */ -export const baseMapSource = new WMTS({ - url: undefined, - version: '1.0.0', - style: 'default', - matrixSet: '3006', - format: 'image/png', - tileGrid: new WMTSTileGrid({ - extent: extent, - // https://www.lantmateriet.se/globalassets/geodata/geodatatjanster/tb_twk_visning-oversiktlig_v1.0.3.pdf - tileSize: 256, - origin: [-1200000, 8500000], - resolutions: [4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8], - matrixIds: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - }), - projection: projection, - wrapX: false, - crossOrigin: 'anonymous', -}); - -const view = new View({ - projection: projection, - extent: extent, - showFullExtent: true, - /* center of the bbox of the Norrbotten and Västerbotten geometries */ - center: [694767.48, 7338176.57], - zoom: 1, - enableRotation: false, - resolutions: [1024, 512, 256, 128, 64, 32, 16, 8], - constrainResolution: false, -}); - -export const map = new Map({ - controls: [], - view: view, - layers: [ - new TileLayer({ - source: baseMapSource - }), - ], -}); diff --git a/src/popover.js b/src/popover.js deleted file mode 100644 index 7080711..0000000 --- a/src/popover.js +++ /dev/null @@ -1,1348 +0,0 @@ -/*********************************************************************** - * Copyright © 2024-2025 Guilhem Moulin <info@guilhem.se> - * Popup and feature overlays - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - **********************************************************************/ - -import Overlay from 'ol/Overlay.js'; -import Stroke from 'ol/style/Stroke.js'; -import Style from 'ol/style/Style.js'; -import VectorTileLayer from 'ol/layer/VectorTile.js'; - -import { Popover } from 'bootstrap'; - -import { map } from './map.js'; - -/* return an <a> tag with the given URL and optional text */ -const reURL = new RegExp('^https?://', 'i'); -const formatLink = function(url, text) { - if (url == null || typeof url !== 'string' || !reURL.test(url)) { - return url; - } - const a = document.createElement('a'); - a.href = url; - a.target = '_blank'; - if (text != null && text !== '') { - const t = document.createTextNode(text + ' '); - a.appendChild(t); - } - const i = document.createElement('i'); - i.classList.add('bi', 'bi-box-arrow-up-right'); - a.appendChild(i); - return a; -}; - -/* test a condition on the field maps */ -const condField = function(cond, k) { - if (Array.isArray(cond)) { - return cond.includes(k); - } - if (cond instanceof RegExp) { - return cond.test(k); - } - return cond(k); -}; -/* filter fields by condition */ -const filterFields = function(k, fields) { - return fields.map(function(v) { - if (v.cond == null || condField(v.cond, k)) { - return v; - } - }).filter((f) => f != null); -}; -/* filter fields using a pre-built map */ -const mapFields = function(k, fieldMap, fields) { - if (fields === undefined) { - return fieldMap.map((v) => k[v]); - } - return fields.map(function(v) { - if (!Array.isArray(v)) { - return fieldMap[v]; - } else if (condField(v[1], k)) { - return fieldMap[v[0]]; - } - }).filter((f) => f !== undefined); -}; -/* pre-build the field map so we don't need to duplicate objects accross layers */ -const mkFieldMap = function(fieldMap) { - return Object.fromEntries(Object.entries(fieldMap).map(function([k, o]) { - if (typeof o === 'string') { - return [k, {key: k, desc: o}]; - } else { - return [k, Object.assign(o, {key: k})]; - } - })); -}; - -const LAYERS = { - svk: { - ledningar: { - title: 'Kraftledning (befintlig)', - fields: [ - { key: 'Placement', desc: 'Förläggning' }, - { key: 'Voltage', desc: 'Spänning', unit: 'kV' }, - { key: 'geom_length', desc: 'Ledlängd', fn: 'length' }, - ], - }, - transmissionsnatsprojekt: { - title: 'Transmissionsnätsprojekt', - fields: [ - { key: 'Name', desc: 'Projektnamn' }, - { key: 'Voltage', desc: 'Spänning', unit: 'kV' }, - { key: 'Url', desc: 'Länk', fn: formatLink }, - ], - }, - }, - - misc: { - gigafactories: { - title: 'Stor industrisatsning', - fields: [ - { key: 'Name', desc: 'Namn' }, - { key: 'Url', desc: 'Länk', fn: formatLink }, - ], - }, - dammar: { - /* Documentation at - * https://www.smhi.se/polopoly_fs/1.34541!/dammprod%202013_3%2C%20beskrivning%2C%20SVAR2012_2.pdf */ - title: 'Damm', - fields: [ - { key: 'DNamn', desc: 'Dammenhetens namn' }, - { key: 'Namn', desc: 'Dammanläggningens namn' }, - { key: 'LST_OBJID', desc: 'Länsnr', classes: ['feature-objid'] }, - { key: 'Status', desc: 'Status', fn: (v) => v === 1 ? 'Befintlig damm' : v === 2 ? 'Fd. damm' : '' }, - //{ key: 'Regleringstyp', desc: 'Regleringstyp' }, - { key: 'ByggAr', desc: 'Byggår' }, - { key: 'DammHojd', desc: 'Dammhöjd', unit: 'm' }, - { key: 'KronLangd', desc: 'Krönlängd', unit: 'm' }, - { key: 'Fiskvag', desc: 'Fiskväg', fn: (v) => - v === 1 ? 'Bassängtrappa' : - v === 2 ? 'Denilränna' : - v === 3 ? 'Slitsränna' : - v === 4 ? 'Omlöp' : - v === 5 ? 'Inlöp' : - v === 6 ? 'Ålledare' : - v === 7 ? 'Smoltränna' : - v === 8 ? 'Okänd typ' : - v === 9 ? 'Ingen' : - v === 10 ? 'Annan' : - null }, - { key: 'HARO', desc: 'Huvudavrinningsområdesnummer', classes: ['feature-objid'] }, - { key: 'Vattendistrikt', desc: 'Vattendistrikt', classes: ['feature-objid'] }, - { key: 'Verksamhet', desc: 'Verksamhet', fn: (v) => - v === 1 ? 'Kraftproduktion' : - v === 2 ? 'Industri' : - v === 3 ? 'Sjöfart' : - v === 4 ? 'Invallning' : - v === 5 ? 'Vattenförsörjning' : - v === 6 ? 'Spegeldamm' : - v === 7 ? 'Historisk' : - v === 8 ? 'Övrigt' : - null }, - { key: 'DG', desc: 'Högsta dämningsgräns', unit: 'm' }, - { key: 'SG', desc: 'Lägsta sänkningsgräns', unit: 'm' }, - { key: 'MY', desc: 'Magasinsyta', unit: 'km²' }, - { key: 'RV', desc: 'Reglerbar volym', unit: 'Mm³' }, - { key: 'Kommentar', desc: 'Kommentar' }, - ], - }, - }, -}; - - -LAYERS.mrr = {}; -(function() { - const fields = [ - { key: 'name', desc: 'Namn' }, - { key: 'mineral', desc: 'Koncessionsmineral', cond: (i) => i < 6 }, - { key: 'owners', desc: 'Ägare', cond: [0,2,4] }, - { key: 'owners', desc: 'Sökande', cond: [1,3,5] }, - { key: 'conc_name', desc: 'Tillhörande bearbetnings\u00ADkoncession(er)', cond: [6] }, - { key: 'licenceid', desc: 'Tillståndsid', classes: ['feature-attr-mrr-license-id'], cond: [0,2,4,6] }, - { key: 'geom_area', desc: 'Areal', fn: 'area' }, - { key: 'validfrom', desc: 'Giltig från', cond: [0,2,4] }, - { key: 'validto', desc: 'Giltig till', cond: [0,2,4] }, - { key: 'diarynr', desc: 'Diarienummer', classes: ['feature-attr-dnr'] }, - { key: 'appl_date', desc: 'Ansökningsdatum' }, - { key: 'dec_date', desc: 'Beslutsdatum', cond: [0,2,4,6] }, - ]; - Object.entries({ - ec: 'Bearbetningskoncession', - met: 'Undersökningstillstånd, metaller och industrimineral', - ogd: 'Undersökningstillstånd, olja, gas och diamant', - }) - .flatMap(([k, title]) => [ - /* don't use Object.entries() to guaranty ordering */ - ['appr', 'beviljad'], /* even index */ - ['appl', 'ansökt'], /* odd index */ - ].map(([a,b]) => [a + '_' + k, title + ' \u2013 ' + b])) - .concat([['appr_dl', 'Markanvisning till koncession']]) /* index #6 */ - .forEach(([k, title], idx) => LAYERS.mrr[k] = { title, fields: filterFields(idx, fields) }); -})(); - - -LAYERS.vbk = {}; -(function() { - const fieldMap = mkFieldMap({ - Projektnamn: 'Projektnamn', - OmrID: { desc: 'Områdes-ID', classes: ['feature-objid'] }, - AntalVerk: 'Aktuella verk', - AntalEjXY: 'Antal ej koordinatsatta verk', - Projektstatus: 'Projektstatus', - Diarienummer: 'Diarienummer', - geom_area: { desc: 'Areal', fn: 'area' }, - Calprod: { desc: 'Beräknad årsproduktion', unit: 'GWh' }, - PlaneradByggstart: 'Planerad byggstart', - PlaneratDrift: 'Planerat drifttagande', - AndringsansokanPagar: 'Ändringsansökan pågår', - UnderByggnation: 'Under byggnation', - Organisationsnamn: 'Verksamhetsutövare', - Organisationsnummer: { desc: 'Organisationsnummer', classes: ['feature-orgnr'] }, - SamradsunderlagInlamnat: 'Samrådsunderlag inlämnat', - AnsokanInlamnat: 'Tillståndsansökan inlämnad', - AnsokanAterkallad: 'Tillståndsansökan återkallad', - AnsokanBeviljad: 'Tillståndsansökan beviljad', - AnsokanAvslagen: 'Tillståndsansökan avslagen', - AnsokanOverklagad: 'Överklagad', - Natura2000_Ansokan: 'Natura2000 ansökan', - Natura2000_Beslutdatum: 'Natura2000 beslutsdatum', - Uppfort: 'Parken uppförd', - PlaneratAntalVerkMin: 'Planerat antal verk (min)', - PlaneratAntalVerkMax: 'Planerat antal verk (max)', - PlaneradHojdMin: { desc: 'Panerad totalhöjd (min)', unit: 'm' }, - PlaneradHojdMax: { desc: 'Panerad totalhöjd (max)', unit: 'm' }, - PlaneradProduktionMin: { desc: 'Planerad årsproduktion (min)', unit: 'GWh' }, - PlaneradProduktionMax: { desc: 'Planerad årsproduktion (max)', unit: 'GWh' }, - BeviljatAntalVerk: 'Beviljat antal verk', - UppfortAntalVerk: 'Uppfört antal verk', - BeviljadMaxhojd: { desc: 'Beviljad maxhöjd', unit: 'm' }, - InstalleradEffekt: { desc: 'Installerad effekt', unit: 'MW' }, - ElNamn: 'Elområde', - SenasteUppdaterat: 'Senast uppdaterat', - }); - - Object.entries({ - current: null, - notcurrent: ' \u2013 ej aktuell', - }) - .forEach(([k, title]) => LAYERS.vbk['area_' + k] = { - title: 'Landbaserad projekteringsområde för vindkraft' + (title ?? ''), - fields: mapFields(k, fieldMap, [ - 'Projektnamn', - 'OmrID', - 'AntalVerk', - 'AntalEjXY', - 'geom_area', - 'Calprod', - 'PlaneradByggstart', - 'PlaneratDrift', - 'AndringsansokanPagar', - ['UnderByggnation', ['current']], - 'Organisationsnamn', - 'Organisationsnummer', - 'ElNamn', - 'SenasteUppdaterat', - ]), - }); - - [ - ['completed', /* 0 */ 'uppförd'], - ['approved', /* 1 */ 'tillståndsansökan beviljad'], - ['amended', /* 2 */ 'ändringsansökan'], - ['rejected', /* 3 */ 'tillståndsansökan avslagen'], - ['appealed', /* 4 */ 'överklagad'], - ['applied', /* 5 */ 'tillståndsansökan inlämnad'], - ['consultation', /* 6 */ 'samråd inför tillståndsansökan'], - ['investigation', /* 7 */ 'inledande undersökningar'], - ['revoked', /* 8 */ 'inte aktuell eller återkallad'], - ] - .forEach(([k, title], idx) => LAYERS.vbk['offshore_' + k] = { - title: 'Havsbaserad vindkraft \u2013 ' + title, - fields: mapFields(idx, fieldMap, [ - 'Projektnamn', - 'OmrID', - 'Organisationsnamn', - 'Organisationsnummer', - 'Projektstatus', - 'Diarienummer', - ['AndringsansokanPagar', [1,2,4]], - 'geom_area', - ['SamradsunderlagInlamnat', (i) => i <= 6 || i === 8], - ['AnsokanInlamnat', (i) => i <= 5 || i === 8], - ['AnsokanAterkallad', [8]], - ['AnsokanBeviljad', [0,1,4,8]], - ['AnsokanAvslagen', [3,8]], - ['AnsokanOverklagad', [0,1,3,4,8]], - ['Natura2000_Ansokan', (i) => i !== 2], - ['Natura2000_Beslutdatum', (i) => i !== 2], - ['UnderByggnation', [1]], - ['PlaneratAntalVerkMin', (i) => i > 0], - ['PlaneratAntalVerkMax', (i) => i > 0], - ['PlaneradHojdMin', (i) => i > 0], - ['PlaneradHojdMax', (i) => i > 0], - ['PlaneradProduktionMin', (i) => i > 0], - ['PlaneradProduktionMax', (i) => i > 0], - ['PlaneradByggstart', (i) => i > 0], - ['Uppfort', [0,8]], - ['PlaneratDrift', (i) => i > 0], - ['BeviljatAntalVerk', [0,1,4,8]], - ['UppfortAntalVerk', [0,8]], - ['BeviljadMaxhojd', [0,1,4,8]], - ['InstalleradEffekt', [0]], - ['Calprod', [0]], - 'ElNamn', - 'SenasteUppdaterat', - ]), - }); - - Object.assign(fieldMap, mkFieldMap({ - VerkID: { desc: 'Verk-ID', classes: ['feature-objid'] }, - Status: 'Status', - Handlingstyp: 'Handlingstyp', - MB_Tillstand: 'Miljöbalken tillstånd tidsbegränsning', - Uppfort: 'Uppförandedatum',/* override previous def */ - Totalhojd: { desc: 'Totalhöjd', unit: 'm' }, - Navhojd: { desc: 'Navhöjd', unit: 'm' }, - Rotordiameter: { desc: 'Rotordiameter', unit: 'm' }, - Maxeffekt: { desc: 'Maxeffekt', unit: 'MW' }, - Fabrikat: 'Fabrikat', - Modell: 'Modell', - Placering: 'Placering', - })); - - [ - ['completed', /* 0 */ 'uppfört'], - ['approved', /* 1 */ 'beviljat'], - ['rejected', /* 2 */ 'avslagit/nekat'], - ['processed', /* 3 */ 'handlagt'], - ['dismounted', /* 4 */ 'nedmonterat'], - ['appealed', /* 5 */ 'överklagat'], - ['revoked', /* 6 */ 'inte aktuell eller återkallad'], - ] - .forEach(([k, title], idx) => LAYERS.vbk['station_' + k] = { - title: 'Landbaserad vindkraftverk \u2013 ' + title, - fields: mapFields(idx, fieldMap, [ - 'VerkID', - 'OmrID', - 'Projektnamn', - 'Status', - 'Handlingstyp', - ['Uppfort', [0,4,6]], - 'MB_Tillstand', - 'Totalhojd', - 'Navhojd', - 'Rotordiameter', - 'Maxeffekt', - 'Calprod', - 'Fabrikat', - 'Modell', - 'Organisationsnamn', - 'Organisationsnummer', - 'Placering', - 'ElNamn', - 'SenasteUppdaterat', - ]), - }); -})(); - - -LAYERS.avverk = {}; -(function() { - const zeroIsNull = (v) => v > 0 ? v : null; - const fieldMap = mkFieldMap({ - /* Documentation at - * https://www.skogsstyrelsen.se/globalassets/sjalvservice/karttjanster/geodatatjanster/produktbeskrivningar/utforda-avverkningar---produktbeskrivning.pdf - * and - * https://www.skogsstyrelsen.se/globalassets/sjalvservice/karttjanster/geodatatjanster/produktbeskrivningar/yttre-granser-for-avverkningsanmalda-omraden---produktbeskrivning.pdf - */ - Beteckn: { desc: 'Ärendebeteckning', classes: ['feature-objid'] }, - ArendeAr: 'Registeringsår', - Inkomdatum: 'Inkom datum', - Skogstyp: 'Skogstyp', - Avvdatum: 'Datum för avverkning', - KallaDatum: 'Ursprung för datum för avverkning', - AnmaldHa: { desc: 'Areal anmält', unit: 'ha' }, - NatforHa: { desc: 'Areal naturlig föryngring', unit: 'ha', fn: zeroIsNull }, - SkogsodlHa: { desc: 'Areal plantering', unit: 'ha', fn: zeroIsNull }, - AvvSasong: 'Avverkningssäsong', - Avverktyp: 'Avverkningstyp', - ArendeStatus: 'Ärendestatus', - AvvHa: { desc: 'Avverkad areal', unit: 'ha' }, - geom_area: { desc: 'Areal för ytan', fn: 'area' }, - }); - - LAYERS.avverk.utford = { - title: 'Utförd avverkning', - fields: mapFields(fieldMap, [ - 'Beteckn', - 'ArendeAr', - 'Skogstyp', - 'AnmaldHa', - 'NatforHa', - 'Avverktyp', - 'Avvdatum', - 'KallaDatum', - 'geom_area', - ]), - }; - - LAYERS.avverk.anmald = { - title: 'Avverkningsanmälansområde', - fields: mapFields(fieldMap, [ - 'Beteckn', - 'Inkomdatum', - 'ArendeAr', - 'AnmaldHa', - 'NatforHa', - 'SkogsodlHa', - 'AvvSasong', - 'ArendeStatus', - 'AvvHa', - ]), - }; -})(); - - -LAYERS.skydd = {}; -(function() { - const fieldMap = mkFieldMap({ - NVRID: { desc: 'NVR-ID', classes: ['feature-objid'] }, - FORSKRNAMN: 'Föreskriftsområde', - OBJEKTNAMN: 'Namn', - NAMN: 'Namn', - BESLSTAT: 'Beslutsstatus', - FORESKRTYP: 'Föreskriftstyp', - FORESKRIFT: 'Föreskriftssubtyp', - FRANDATUM: 'Från datum', - TILLDATUM: 'Till datum', - BESKRIVN: 'Beskrivning', - geom_area: { desc: 'Areal', fn: 'area' }, - - SKYDDSTYP: 'Skyddstyp', - BESLSTATUS: 'Beslutsstatus', - URSBESLDAT: 'Beslutsdatum (bildande)', - URSGALLDAT: 'Ursprungligt gällandedatum', - SENGALLDAT: 'Senaste gällandedatum', - FORVALTARE: 'Förvaltare', - IUCNKAT: 'IUCN-kategori', - DIARIENR: { desc: 'Diarienummer', classes: ['feature-attr-dnr'] }, - LAGRUM: 'Lagrum', - BESLMYND: 'Beslutsmyndighet', - LAND_HA: { desc: 'Areal land', unit: 'ha' }, - VATTEN_HA: { desc: 'Areal vatten', unit: 'ha' }, - SKOG_HA: { desc: 'Skogsmarksareal', unit: 'ha' }, - - IKRAFTDATF: 'Ikraftträdandedatum föreskrifter', - TILLSYNSMH: 'Tillsynsmyndighet', - PROVNMHTIL: 'Prövningsmyndighet tillstånd', - PROVNMHDIS: 'Prövningsmyndighet dispens', - - NAME: 'Namn', - RAMSAR_ID: { desc: 'Ramsar-ID', classes: ['feature-objid'] }, - LEGAL_ACT: 'Rättsakt', - URSPR_BESL: 'Ursprungligt beslutsdatum', - SEN_BESLUT: 'Senaste beslutsdatum', - LINK: { desc: 'Länk', fn: formatLink }, - }); - - LAYERS.skydd.tilltradesforbud = { - title: 'Tillträdesförbud', - fields: mapFields(fieldMap, [ - 'NVRID', - 'FORSKRNAMN', - 'OBJEKTNAMN', - 'BESLSTAT', - 'FORESKRTYP', - 'FORESKRIFT', - 'FRANDATUM', - 'TILLDATUM', - 'BESKRIVN', - 'geom_area', - ]), - }; - - /* Nationella skyddsformer från Naturvårdsregistret */ - const isSurface = (k) => !/_punkt$/.test(k); - Object.entries({ - nationalpark: 'Nationalpark', - naturreservat: 'Naturreservat', - naturreservat_kommunalt: 'Kommunalt naturreservat', - naturvardsomrade: 'Naturvårdsområde', - djur_och_vaxtskyddsomrade: 'Djur- och växtskyddsområde', - kulturreservat: 'Kulturreservat', - vattenskyddsomrade: 'Vattenskyddsområden', - landskapsbildsskyddsomrade: 'Landskapsbildsskyddsområde', - ovrigt_biotopskyddsomrade: 'Biotopskydd utanför skogsmark', - naturminne_yta: 'Naturminne (yta)', - naturminne_punkt: 'Naturminne (punkt)', - interimistiskt_forbud: 'Interimistiskt förbud', - }) - .forEach(([k, title]) => LAYERS.skydd[k] = { - title: title, - fields: mapFields(k, fieldMap, [ - 'NVRID', - 'NAMN', - 'SKYDDSTYP', - 'BESLSTATUS', - 'URSBESLDAT', - ['URSGALLDAT', (k) => k !== 'vattenskyddsomrade'], - ['SENGALLDAT', (k) => k !== 'vattenskyddsomrade'], - ['FORVALTARE', (k) => k !== 'vattenskyddsomrade'], - ['IKRAFTDATF', (k) => k === 'vattenskyddsomrade'], - 'IUCNKAT', - 'DIARIENR', - 'LAGRUM', - 'BESLMYND', - ['TILLSYNSMH', (k) => k === 'vattenskyddsomrade'], - ['PROVNMHTIL', (k) => k === 'vattenskyddsomrade'], - ['PROVNMHDIS', (k) => k === 'vattenskyddsomrade'], - ['geom_area', isSurface], - ['LAND_HA', isSurface], - ['VATTEN_HA', isSurface], - ['SKOG_HA', isSurface], - ]), - }); - - /* Natura 2000-områden */ - (function() { - const fields = [ - { key: 'SITE_CODE', desc: 'Områdeskod', classes: ['feature-objid'] }, - { key: 'NAMN', desc: 'Namn' }, - { key: 'OMRADESTYP', desc: 'Områdestyp' }, - { key: 'UPPLAMNARE', desc: 'Uppgiftslämnare' }, - { key: 'SPA_DATUM', desc: 'SPA-datum' }, - { key: 'SCI_FORSL', desc: 'SCI-förslagsdatum' }, - { key: 'SCI_DATUM', desc: 'SCI-datum' }, - { key: 'SAC_DATUM', desc: 'SAC-datum' }, - fieldMap.geom_area, - { key: 'KVALITET', desc: 'Kvalitet' }, - { key: 'KARAKTAR', desc: 'Kännetecken för området' }, - { key: 'ARTER', desc: 'Arter' }, - { key: 'NATURTYPER', desc: 'Naturtyper' }, - { key: 'BEVPLAN', desc: 'Bevarandeplan', fn: formatLink }, - ]; - Object.entries({ - fageldirektivet: 'Fågeldirektivet (SPA)', - habitatdirektivet: 'Art- och habitatdirektivet (SCI)', - }) - .forEach(([k, title]) => LAYERS.skydd[k] = { title, fields }); - })(); - - /* Områden med internationell status */ - LAYERS.skydd.helcom = { - title: 'Marina skyddade områden (Helcom MPA)', - fields: mapFields(fieldMap, [ 'NAME', 'geom_area' ]), - }; - - LAYERS.skydd.ramsar = { - title: 'Ramsar-områden (Våtmarkskonventionen)', - fields: mapFields(fieldMap, [ - 'RAMSAR_ID', - 'SKYDDSTYP', - 'NAMN', - 'geom_area', - 'LAND_HA', - 'VATTEN_HA', - 'SKOG_HA', - 'URSPR_BESL', - 'SEN_BESLUT', - 'LEGAL_ACT', - 'LINK', - ]), - }; - - LAYERS.skydd.ospar = { - title: 'Marina skyddade områden (Ospar MPA)', - fields: [ - { key: 'ORIGIN', desc: 'Ursprung' }, - { key: 'NAMN_N2000', desc: 'N2000-namn' }, - { key: 'MPA_ID', desc: 'MPA-ID', classes: ['feature-objid'] }, - { key: 'MPA_NAMN', desc: 'MPA-namn' }, - { key: 'N2000_SITE', desc: 'N2000-ID', classes: ['feature-objid'] }, - fieldMap.geom_area, - ], - }; - - LAYERS.skydd.varldsarv = { - title: 'Världsarv med mycket höga naturvärden (Unesco)', - fields: mapFields(fieldMap, [ 'NAMN', 'geom_area' ]), - }; - - LAYERS.skydd.naturvardsavtal = { - title: 'Naturvårdsavtal (Naturvårdsverket, Länsstyrelsen)', - fields: [ - { key: 'ID', desc: 'ID', classes: ['feature-objid'] }, - { key: 'OBJNAMN', desc: 'Namn' }, - { key: 'FASTBET', desc: 'Fastighet', classes: ['feature-objid'] }, - { key: 'DATSTART', desc: 'Giltig från' }, - { key: 'DATSLUT', desc: 'Giltig till' }, - { key: 'DIARIENRNV', desc: 'Diarienummer', classes: ['feature-attr-dnr'] }, - { key: 'STATUS', desc: 'Satus' }, - fieldMap.geom_area, - ], - }; -})(); - -(function() { - const fieldMap = mkFieldMap({ - Beteckn: { desc: 'Ärendebeteckning', classes: ['feature-objid'] }, - Biotyp: { desc: 'Biotopkategori' }, - Naturtyp: { desc: 'Skogstyp' }, - ArendeAr: { desc: 'Registeringsår' }, - geom_area: { desc: 'Areal', fn: 'area' }, - AreaProd: { desc: 'Skogsmarksareal', unit: 'ha' }, - Datbeslut: { desc: 'Beslutsdatum' }, - Url: { desc: 'Länk', fn: (v) => formatLink(v, 'Skogens Pärlor') }, - NvaTyp: 'Biotopkategori', - DatAvtal: 'Avtalsdatum', - Undertyp: 'Undertyp', - AvtalatDatum: 'Avtalat datum', - Objnamn: 'Objektnamn', - Datinv: 'Datum för fältinventering', - }); - - LAYERS.skydd.skogligt_biotopskyddsomrade = { - title: 'Biotopskydd i skogsmark', - fields: mapFields(fieldMap, [ - 'Beteckn', - 'Biotyp', - 'Naturtyp', - 'ArendeAr', - 'geom_area', - 'AreaProd', - 'Datbeslut', - 'Url', - ]), - }; - LAYERS.skydd.naturvardsavtal_skogsstyrelsen = { - title: 'Naturvårdsavtal (Skogsstyrelsen)', - fields: mapFields(fieldMap, [ - 'Beteckn', - 'ArendeAr', - 'NvaTyp', - 'Naturtyp', - 'DatAvtal', - 'geom_area', - 'AreaProd', - 'Url', - 'Undertyp', - ]), - }; - - LAYERS.skydd.atervatningsavtal = { - title: 'Återvätningsavtal', - fields: mapFields(fieldMap, [ - 'Beteckn', - 'ArendeAr', - 'AvtalatDatum', - 'geom_area', - 'Url', - ]), - }; - - LAYERS.nv = {}; - Object.assign(fieldMap, mkFieldMap(Object.fromEntries( - [1,2,3].map((i) => [`Biotop${i}`, `Biotoptyp #${i}`]).concat( - [1,2,3,4,5,6,7,8].map((i) => [`Beskrivn${i}`, `Nyckelord #${i} som beskriver objektet`]) - )))); - LAYERS.nv.naturvarde_sks = { - title: 'Objekt med naturvärden (Skogsstyrelsen)', - fields: mapFields(fieldMap, [ - 'Beteckn', - 'Objnamn', - 'Datinv', - 'Biotop1', 'Biotop2', 'Biotop3', - 'Beskrivn1', 'Beskrivn2', 'Beskrivn3', - 'geom_area', - 'Url', - ]), - }; - LAYERS.nv.nyckelbiotop = { - title: 'Nyckelbiotop (Skogsstyrelsen)', - fields: mapFields(fieldMap, [ - 'Beteckn', - 'Objnamn', - 'Datinv', - 'Biotop1', 'Biotop2', 'Biotop3', - 'Beskrivn1', 'Beskrivn2', 'Beskrivn3', 'Beskrivn4', 'Beskrivn5', 'Beskrivn6', 'Beskrivn7', 'Beskrivn8', - 'geom_area', - 'Url', - ]), - }; - LAYERS.nv.nyckelbiotop_storskogsbruk = { - title: 'Nyckelbiotop (storskogsbruket)', - fields: [ - { key: 'Org', desc: 'Uppgifter lämnade av' }, - { key: 'InkomDatum', desc: 'Inkom datum' }, - fieldMap.geom_area, - fieldMap.Url, - ], - }; - - LAYERS.nv.sumpskog = { - title: 'Sumpskog', - fields: [ - { key: 'Namn', desc: 'Objektnamn' }, - { key: 'Tradtext', desc: 'Skogstyp' }, - { key: 'Hydrtext', desc: 'Hydrologisk typ' }, - { key: 'Delklass', desc: 'Klass på delobjektet' }, - { key: 'Klassu', desc: 'Klass på objektet' }, - { key: 'Lovandel', desc: 'Andel löv' }, - { key: 'Andelva', desc: 'Andel öppet vatten' }, - { key: 'Krontakn', desc: 'Krontäckning' }, - { key: 'Huggklas', desc: 'Huggningsklass' }, - { key: 'Ingrepp', desc: 'Ingrepp på delobjekt (max 4)' }, - { key: 'Ingrpavv', desc: 'Grad av påverkan på delobjekt (max 4)' }, - { key: 'Objnyck', desc: 'Nyckelord på objektnivå' }, - { key: 'Delnyck', desc: 'Nyckelord på delobjektsnivå' }, - { key: 'Flygar', desc: 'Flygbildsår' }, - { key: 'Faltdat', desc: 'Datum för fältbesök' }, - { key: 'Invtekn', desc: 'Inventeringsteknik' }, - { key: 'Invdat', desc: 'Inventeringdatum' }, - { key: 'Ansvmynd', desc: 'Ansvarig myndighet' }, - fieldMap.geom_area, - fieldMap.Url, - ], - }; -})(); - -LAYERS.nv.pagaende_naturreservatsbildning = { - title: 'Pågående naturreservatsbildning', - fields: [ - { key: 'NAMN', desc: 'Objektnamn' }, - /* XXX unclear what "GRANSJUST" means, just a guess */ - { key: 'GRANSJUST', desc: 'Senast justerat' }, - { key: 'geom_area', desc: 'Areal', fn: 'area' }, - ], -}; - -LAYERS.nv.snus = { - title: 'Skyddsvärd statlig skog', - fields: [ - { key: 'NAMN', desc: 'Objektnamn' }, - { key: 'AR', desc: 'År' }, - { key: 'NATURGEOGR', desc: 'Naturgeografisk region', classes: ['feature-objid'] }, - { key: 'OBJEKTKATE', desc: 'Objektskategori', classes: ['feature-objid'] }, - { key: 'MARKAGARE', desc: 'Markägare' }, - { key: 'VARDEKARNA', desc: 'Areal värdekärna', unit: 'ha' }, - { key: 'UTV_MARK', desc: 'Areal utvecklingsmark', unit: 'ha' }, - { key: 'TOTAL_AREA', desc: 'Totalareal', unit: 'ha' }, - { key: 'LAND', desc: 'Areal land', unit: 'ha' }, - { key: 'VATTEN', desc: 'Areal vatten', unit: 'ha' }, - { key: 'PROD_SKOG', desc: 'Areal produktiv skogsmark', unit: 'ha' }, - { key: 'SKOG_O_FJG', desc: 'Areal produktiv skogsmark ovanför fjällnära gräns', unit: 'ha' }, - { key: 'SKOG_N_FJG', desc: 'Areal produktiv skogsmark nedanför fjällnära gräns', unit: 'ha' }, - { key: 'SKYDDSZON', desc: 'Areal skyddszon', unit: 'ha' }, - { key: 'ARRO_MARK', desc: 'Areal arronderingsmark', unit: 'ha' }, - { key: 'KRITERIER', desc: 'Kriterier för urval' }, - { key: 'BESKRIVN', desc: 'Beskrivning av området' }, - { key: 'LST_BEDOMN', desc: 'Länsstyrelsens bedömning' }, - { key: 'KALLOR', desc: 'Källor' }, - ], -}; - -LAYERS.ri = {}; -(function() { - const fieldMap = mkFieldMap({ - NAMN: 'Namn', - SKYDD: 'Skydd', - AMNESOMRAD: 'Ämnesområde', - AMNESOMR: 'Ämnesområde', - OMRADESNR: { desc: 'Områdesnummer', classes: ['feature-objid'] }, - BESKRIVNIN: { desc: 'Beskrivning', fn: formatLink }, - LANK_VARDE: { desc: 'Länk värdebeskrivning', fn: formatLink }, - LAGRUM: 'Lagrum', - BESLUTSDAT: 'Beslutsdatum', - BESLDATUM: 'Beslutsdatum', - ARENDENR: { desc: 'Ärendenummer', classes: ['feature-attr-dnr'] }, - LANK_BESLU: { desc: 'Länk beslut', fn: formatLink }, - AKTIVITET: 'Aktivitet', - NATURTYP: 'Naturtyp', - ORGINALID: { desc: 'Original-ID', classes: ['feature-objid'] }, - RIKSID: { desc: 'Riks-ID', classes: ['feature-objid'] }, - geom_area: { desc: 'Areal', fn: 'area' }, - AREA_LAND_: { desc: 'Areal land', unit: 'ha' }, - AREA_VATTE: { desc: 'Areal vatten', unit: 'ha' }, - }); - LAYERS.ri.naturvard = { - title: 'Riksintresse naturvård', - fields: mapFields(fieldMap, [ - 'NAMN', - 'SKYDD', - 'AMNESOMRAD', - 'BESKRIVNIN', - 'LAGRUM', - 'BESLUTSDAT', - 'ORGINALID', - 'RIKSID', - 'geom_area', - ]), - }; - LAYERS.ri.friluftsliv = { - title: 'Riksintresse friluftsliv', - fields: mapFields(fieldMap, [ - 'NAMN', - 'SKYDD', - 'AMNESOMR', - 'OMRADESNR', - 'LANK_VARDE', - 'LAGRUM', - 'BESLDATUM', - 'ARENDENR', - 'LANK_BESLU', - 'AKTIVITET', - 'NATURTYP', - 'geom_area', - 'AREA_LAND_', - 'AREA_VATTE', - ]), - }; - - Object.assign(fieldMap, mkFieldMap({ - METODBESKR: 'Metodbeskrivning', - TILLKDATUM: 'Tillkomstdatum', - REVDATUM: 'Revisionsdatum', - ANM: 'Anmärkning', - OBJEKTLANK: { desc: 'Objektlänk', fn: formatLink }, - REFERENS: 'Referens', - OBJTYP: 'Objekttyp', - ORIGINALID: fieldMap.ORGINALID, - DIG_SKALA: { desc: 'Digitaliseringsskala', fn: (v) => v > 0 ? v : null }, - })); - [ - ['rorligt_friluftsliv', /* 0 */ 'rörligt friluftsliv (MB 4 kap 1§ och 2§)'], - ['obruten_kust', /* 1 */ 'obruten kust (MB 4 kap 3§)'], - ['obrutet_fjall', /* 2 */ 'obrutet fjäll (MB 4 kap 5§)'], - ['skyddade_vattendrag', /* 3 */ 'skyddade vattendrag (MB 4 kap 6§)'], - ] - .forEach(([k, title], idx) => LAYERS.ri[k] = { - title: 'Riksintresse ' + title, - fields: mapFields(idx, fieldMap, [ - 'NAMN', - 'BESKRIVNIN', - 'METODBESKR', - 'TILLKDATUM', - 'REVDATUM', - ['OBJTYP', [1]], - ['ANM', [0,1,3]], - ['DIG_SKALA', [3]], - 'OBJEKTLANK', - 'geom_area', - 'ORIGINALID', - 'REFERENS', - ]), - }); -})(); - - -LAYERS.ren = { - betesomrade: { - title: 'Samebyarnas betesområde', - fields: [ - { key: 'NAMN', desc: 'Sameby' }, - { key: 'SAMEBY_TYP', desc: 'Samebys typ' }, - { key: 'SIGNATUR', desc: 'Signatur' }, - { key: 'AKTUALITET', desc: 'Aktualitet' }, - { key: 'geom_area', desc: 'Areal', fn: 'area' }, - ], - }, - flyttled: { - title: 'Samebyarnas markanvändningsredovisning \u2013 flyttled', - fields: [ - { key: 'LED_ID', desc: 'Led-ID', classes: ['feature-objid'], fn: (v) => v > 0 ? v : null }, - { key: 'SAMEBY1', desc: 'Sameby #1' }, - { key: 'SAMEBY2', desc: 'Sameby #2' }, - { key: 'SAMEBY3', desc: 'Sameby #3' }, - { key: 'BESKRIVNIN', desc: 'Beskrivning' }, - { key: 'ARSTID', desc: 'Årstid' }, - { key: 'RIKSINTR', desc: 'Riksintresse' }, - { key: 'FAST_LED', desc: 'Fast led' }, - { key: 'AKTUALITET', desc: 'Aktualitet' }, - { key: 'SIGNATUR', desc: 'Signatur' }, - { key: 'geom_length', desc: 'Ledlängd', fn: 'length' }, - ], - }, - riks_ren: { - title: 'Riksintresse rennäring', - fields: [ - { key: 'LAGRUM', desc: 'Lagrum' }, - { key: 'AKTUALITET', desc: 'Aktualitet' }, - { key: 'SIGNATUR', desc: 'Signatur' }, - { key: 'geom_area', desc: 'Areal', fn: 'area' }, - ], - }, - omr_riks: { - title: '(Kärn)områden av riksintresse rennäring', - fields: [ - { key: 'OMR_NR', desc: 'Områdes-ID', classes: ['feature-objid'] }, - { key: 'LANK', desc: 'Länk' }, - { key: 'ARET_RUNT', desc: 'Årets runt' }, - { key: 'SAMEBY', desc: 'Sameby' }, - { key: 'ANSVARIG', desc: 'Ansvarig' }, - { key: 'AKTUALITET', desc: 'Aktualitet' }, - { key: 'SIGNATUR', desc: 'Signatur' }, - { key: 'geom_area', desc: 'Areal', fn: 'area' }, - ], - }, -}; - - - -/* format value to HTML */ -const formatValue = function(value, options) { - let unit = options?.unit; - if (options?.fn == null) { - /* no-op */ - } else if (typeof options.fn === 'function') { - value = options.fn(value); - } else if (options.fn === 'length' && typeof value === 'number' && unit == null) { - if (value < 1000) { - unit = 'm'; - } else { - value /= 1000; - value = Math.round(value*100) / 100; - unit = 'km'; - } - } else if (options.fn === 'area' && typeof value === 'number' && unit == null) { - if (value < 10000) { - unit = 'm²'; - } else if (value < 10000 * 10000) { - value /= 10000; - unit = 'ha'; - } else { - value /= 1000000; - unit = 'km²'; - } - value = Math.round(value*100) / 100; - } - if (value == null) { - return null; - } - if (value instanceof HTMLElement) { - return value; - } - switch (typeof value) { - case 'boolean': - return document.createTextNode(value ? 'Ja' : 'Nej'); - case 'string': - return document.createTextNode(value); - case 'number': - if (unit != null) { - return document.createTextNode(value.toLocaleString('sv-SE') + '\u202F' + unit); - } - return document.createTextNode(value.toString()); - default: - return null; - } -}; - -/* turn the properties into a fine <table> */ -const formatFeaturePropertiesToHTML = function(properties) { - 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.fields.forEach(function(field) { - const tr = document.createElement('tr'); - tbody.appendChild(tr); - - const th = document.createElement('th'); - th.setAttribute('scope', 'row'); - tr.appendChild(th); - const textDesc = document.createTextNode(field.desc); - th.appendChild(textDesc); - - const td = document.createElement('td'); - tr.appendChild(td); - const v = formatValue(properties[field.key], field); - if (v != null) { - td.appendChild(v); - } - field.classes?.forEach?.((c) => td.classList.add(c)); - }); - - const content = document.createElement('div'); - if (def.title != null) { - const h = document.createElement('h6'); - content.appendChild(h); - const textNode = document.createTextNode(def.title); - h.appendChild(textNode); - } - - content.appendChild(table); - return content; -}; - -/* Initialize popup overlay with the give map and HTML element */ -let popupOverlay = null; -(function() { - popupOverlay = new Overlay({ - stopEvent: true, - element: document.getElementById('popup'), - }); - map.addOverlay(popupOverlay); -})(); - -let featureOverlayLayer = null; -let overlayAttributes = [], - overlayAttrIdx = 0, - mapSources = {}; -/* Clear the highlighted feature list and make the overlay layer invisible */ -const disposeFeatureOverlay = function() { - if (featureOverlayLayer?.getVisible?.()) { - featureOverlayLayer.setVisible(false); - featureOverlayLayer.changed(); - } - /* clear the overlay list */ - overlayAttributes = []; - overlayAttrIdx = 0; - mapSources = {}; -} - -let popover = null; -/* Clear overlay layer and dispose popover */ -export const disposePopover = function() { - disposeFeatureOverlay(); - if (popover?.tip != null) { - popover.dispose(); - } -}; - -/* Initialize popover on the given map */ -(function() { - featureOverlayLayer = new VectorTileLayer({ - zIndex: 65535, - declutter: false, - visible: false, - renderMode: 'vector', - style: null, - map: map, - }); - - const header = document.createElement('div'); - header.classList.add('d-flex'); - - const headerGrabbingArea = document.createElement('div'); - headerGrabbingArea.classList.add('flex-grow-1', 'grabbing-area', 'pe-2', 'me-2'); - header.appendChild(headerGrabbingArea); - - const pageNode = document.createElement('h6'); - headerGrabbingArea.appendChild(pageNode); - - headerGrabbingArea.onmousedown = function(event) { - /* move the popover around */ - if (event.button != 0) { - return; - } - const popoverTip = popover.tip; - if (popoverTip.classList.contains('popover-maximized')) { - return; - } - headerGrabbingArea.classList.add('grabbing-area-grabbed'); - - if (!popoverTip.classList.contains('popover-detached')) { - /* detach popover tip */ - popoverTip.classList.add('popover-detached'); - const rect = popoverTip.getBoundingClientRect(); - const style = popoverTip.style; - style.display = 'none'; /* avoid reflows between the following assignments */ - style.position = 'absolute'; - style.transform = ''; - style.inset = `${rect.top}px auto auto ${rect.left}px`; - style.display = ''; - } - - let clientX = event.clientX, clientY = event.clientY; - document.onmousemove = function(event) { - const offsetX = clientX - event.clientX; - const offsetY = clientY - event.clientY; - clientX = event.clientX; - clientY = event.clientY; - popoverTip.style.top = (popoverTip.offsetTop - offsetY).toString() + 'px'; - popoverTip.style.left = (popoverTip.offsetLeft - offsetX).toString() + 'px'; - }; - - document.onmouseup = function(event) { - /* done moving around */ - if (event.button != 0) { - return; - } - headerGrabbingArea.classList.remove('grabbing-area-grabbed'); - document.onmousemove = null; - document.onmouseup = null; - }; - }; - - /* current number page and total page count */ - const pageNum = document.createElement('span'); - const pageCount = document.createElement('span'); - pageNode.appendChild(document.createTextNode('Träff ')); - pageNode.appendChild(pageNum); - pageNode.appendChild(document.createTextNode(' av ')); - pageNode.appendChild(pageCount); - - /* highlight a feature */ - const featureOverlayStyle = new Style({ - stroke: new Stroke({ - color: 'rgba(0, 255, 255, .8)', - width: 3, - }), - }); - const highlightFeature = function(layer_group, layer, id) { - const source = mapSources[layer_group]; - if (source == null) { - return; - } - if (featureOverlayLayer.getSource() !== source) { - /* console.log('Updating source for feature overlay layer'); */ - featureOverlayLayer.setVisible(false); - featureOverlayLayer.setSource(source); - } - featureOverlayLayer.setStyle(function(feature) { - if (feature.getId() === id && feature.getProperties().layer === layer) { - return featureOverlayStyle; - } - }); - featureOverlayLayer.setVisible(true); - featureOverlayLayer.changed(); - }; - /* highlight the feature at index overlayAttrIdx within the CGI reply list */ - const refreshPopover = function() { - const attr = overlayAttributes[overlayAttrIdx]; - highlightFeature(attr.layer_group, attr.layer, attr.ogc_fid); - - pageNum.innerHTML = (overlayAttrIdx + 1).toString(); - const content = formatFeaturePropertiesToHTML(attr); - popover.tip.getElementsByClassName('popover-body')[0].replaceChildren(content); - }; - /* go back/forward in the overlayAttributes list */ - const onClickPageChange = function(event, offset) { - const btn = event.target; - if (btn.classList.contains('disabled') || popover?.tip == null) { - return; - } - if (overlayAttrIdx + offset < 0 || overlayAttrIdx + offset > overlayAttributes.length - 1) { - return; /* out of range */ - } - - overlayAttrIdx += offset; - if (overlayAttrIdx < 1) { - btnPrev.classList.add('disabled'); - } else { - btnPrev.classList.remove('disabled'); - } - if (overlayAttrIdx < overlayAttributes.length - 1) { - btnNext.classList.remove('disabled'); - } else { - btnNext.classList.add('disabled'); - } - - refreshPopover(); - setTimeout(function() { btn.blur() }, 100); - }; - - /* control buttons */ - const btnPrev = document.createElement('button'); - btnPrev.classList.add('popover-button', 'popover-button-prev'); - btnPrev.setAttribute('type', 'button'); - btnPrev.title = 'Föregående träff'; - btnPrev.setAttribute('aria-label', btnPrev.title); - btnPrev.onclick = function(event) { - return onClickPageChange(event, -1); - }; - - const btnNext = document.createElement('button'); - btnNext.classList.add('popover-button', 'popover-button-next'); - btnNext.setAttribute('type', 'button'); - btnNext.title = 'Nästa träff'; - btnNext.setAttribute('aria-label', btnNext.title); - btnNext.onclick = function(event) { - return onClickPageChange(event, +1); - }; - - const btnExpand = document.createElement('button'); - btnExpand.classList.add('popover-button', 'popover-button-expand'); - btnExpand.setAttribute('type', 'button'); - const btnExpandTitle = 'Förstora'; - const btnExpandTitle2 = 'Förminska'; - btnExpand.setAttribute('aria-label', btnExpand.title); - btnExpand.onclick = function() { /* maximize or reduce the popover */ - if (popover?.tip == null) { - return; - } - if (!popover.tip.classList.contains('popover-maximized')) { - popover.tip.classList.add('popover-maximized'); - btnExpand.classList.replace('popover-button-expand', 'popover-button-reduce'); - btnExpand.title = btnExpandTitle2; - btnExpand.setAttribute('aria-label', btnExpand.title); - } else { - popover.tip.classList.remove('popover-maximized'); - btnExpand.classList.replace('popover-button-reduce', 'popover-button-expand'); - btnExpand.title = btnExpandTitle; - btnExpand.setAttribute('aria-label', btnExpand.title); - } - setTimeout(function() { btnExpand.blur() }, 100); - }; - - const btnClose = document.createElement('button'); - btnClose.classList.add('popover-button', 'popover-button-close'); - btnClose.setAttribute('type', 'button'); - btnClose.title = 'Stäng'; - btnClose.setAttribute('aria-label', btnClose.title); - btnClose.onclick = disposePopover; - - header.appendChild(btnPrev); - header.appendChild(btnNext); - header.appendChild(btnExpand); - header.appendChild(btnClose); - - const container0 = map.getViewport().getElementsByClassName('ol-overlaycontainer-stopevent')[0]; - map.on('singleclick', function(event) { - disposeFeatureOverlay(); - - /* dispose any pre-existing popover if not in detached mode */ - popover = Popover.getInstance(popupOverlay.element); - if (popover?.tip != null && !popover.tip.classList.contains('popover-detached')) { - popover.dispose(); - } - - const size = event.map.getSize(); - if (size[0] < 576 || size[1] < 576) { - return; /* skip popover if the map is too small */ - } - - /* unclear how many feature we'll find, don't render prev/next buttons for now */ - pageNode.classList.add('d-none'); - btnPrev.classList.add('d-none', 'disabled'); - btnNext.classList.add('d-none', 'disabled'); - - /* never start in maximized mode */ - if (popover?.tip != null) { - popover.tip.classList.remove('popover-maximized'); - } - btnExpand.classList.replace('popover-button-reduce', 'popover-button-expand'); - btnExpand.title = btnExpandTitle; - btnExpand.setAttribute('aria-label', btnExpand.title); - - const fetch_body = []; - event.map.forEachFeatureAtPixel(event.pixel, function(feature, layer) { - const layerGroup = layer.get('layerGroup'); - const layerName = feature.getProperties().layer; - mapSources[layerGroup] ??= layer.getSource(); - const def = layerName != null ? LAYERS[layerGroup][layerName] : null; - if (def?.fields == null) { - /* skip layers which didn't opt-in for popover */ - return false; - } - if (fetch_body.length === 0) { - /* first feature in the list, mark cursor and detached popover as in-progress */ - document.body.classList.add('inprogress'); - popover?.tip?.classList?.add?.('inprogress'); - } - fetch_body.push({ - layer_group: layerGroup, - layer: layerName, - fid: feature.getId() ?? -1, - }); - if (fetch_body.length >= 100) { - return true; /* enough matches already, stop detection here */ - } - }, { - hitTolerance: 5, - checkWrapped: false, - layerFilter: (lyr) => lyr.get('layerGroup') != null, - }); - - if (fetch_body.length === 0) { - /* no feature at pixel (or only within layers which didn't opt-in for popover) */ - if (popover?.tip != null) { - /* dispose pre-detached popover */ - popover.dispose(); - } - return; - } - - fetch('/q', { - method: 'POST', - body: JSON.stringify(fetch_body), - headers: { - 'Content-Type': 'application/json; charset=UTF-8', - }, - }) - .then(function(resp) { - if (resp.status === 200) { - return resp.json(); - } else { - throw new Error(`${resp.url} [${resp.status}]`); - } - }) - .then(function(data) { - /* 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; - if (overlayAttributes.length === 0) { - /* couldn't fetch any attribute for feature(s) at pixel */ - if (popover?.tip != null) { - /* dispose pre-detached popover */ - popover.dispose(); - } - return; - } - - pageCount.innerHTML = overlayAttributes.length.toString(); - if (overlayAttributes.length >= 2) { - /* render prev/pre buttons */ - btnNext.classList.remove('d-none', 'disabled'); - btnPrev.classList.remove('d-none'); - pageNode.classList.remove('d-none'); - } - if (popover?.tip == null) { - /* create a new popover (we're not already showing one in detached mode) */ - pageNum.innerHTML = (overlayAttrIdx + 1).toString(); - popupOverlay.setPosition(event.coordinate); - - const attr = overlayAttributes[0]; - highlightFeature(attr.layer_group, attr.layer, attr.ogc_fid); - popover = new Popover(popupOverlay.element, { - 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: formatFeaturePropertiesToHTML(attr), - html: true, - placement: 'right', - fallbackPlacements: ['right', 'left', 'bottom', 'top'], - container: container0, - }); - popover.show(); - } - else if (popover.tip.classList.contains('popover-detached')) { - /* update existing detached mode popover */ - refreshPopover(); - popover.tip.classList.remove('inprogress'); - } - }) - .catch(function(e) { - console.log(e); - }) - .finally(function() { - /* remove in-progress marking on the cursor */ - document.body.classList.remove('inprogress'); - }); - }); -})(); diff --git a/src/style.css b/src/style.css deleted file mode 100644 index cf7fc86..0000000 --- a/src/style.css +++ /dev/null @@ -1,650 +0,0 @@ -@import "~bootstrap/dist/css/bootstrap.css"; -@import "~bootstrap-icons/font/bootstrap-icons.css"; -@import "~ol/ol.css"; - -html, body { - margin: 0; - height: 100%; - --ol-foreground-color: var(--bs-body-color); - --ol-background-color: var(--bs-body-bg); - - /* highlight non-bootstrapy style */ - --ol-accent-background-color: red; - --ol-subtle-background-color: red; - --ol-partial-background-color: red; - --ol-subtle-foreground-color: red; - --ol-brand-color: red; -} - -#map { - position: absolute; - top: 0; - bottom: 0; - width: 100%; - --map-container-padding: 1rem; -} - -body.inprogress { - cursor: wait; -} - -#map-control-container { - --map-menu-spacing: .5em; - position: absolute; - padding: var(--map-container-padding); - display: flex; - justify-content: flex-end; - width: 100%; - height: 100%; -} -@media screen and (max-width: 767px), screen and (max-height: 767px) { - #map { - --map-container-padding: .5rem; - } -} - -#zoom-control { - position: absolute; - margin-left: var(--map-container-padding); - margin-top: var(--map-container-padding); -} -#zoom-control .ol-zoom { - position: relative; - display: block; - width: revert; - top: auto; - left: auto; - pointer-events: auto; -} -#zoom-control .ol-zoomslider { - margin-top: .5rem; - position: relative; - display: block; - width: revert; - top: auto; - left: auto; - padding: 10px 0; - - background-color: RGBA(var(--bs-body-bg-rgb), .95); - border-radius: var(--bs-modal-border-radius); - border: var(--bs-modal-border-width) solid var(--bs-modal-border-color); - overflow-y: hidden; - z-index: 0; -} -#zoom-control .ol-zoomslider::after { - content: ""; - position: absolute; - top: 3%; - left: calc(50% - 3px); - width: 6px; - height: 94%; - background-color: RGBA(211, 212, 213, .4); - border-radius: 5px; - border: var(--bs-modal-border-width) solid var(--bs-modal-border-color); - cursor: pointer; - pointer-events: auto; -} -#zoom-control button.ol-zoomslider-thumb { - z-index: 10; - height: 10px; - width: 80%; - margin: 0 auto; - padding: 0; - pointer-events: auto; -} - -.ol-scale-line { - display: block; - width: revert; - height: revert; - top: auto; - bottom: var(--map-container-padding); - left: var(--map-container-padding); - z-index: 0; - - padding: .5rem; - background-color: RGBA(var(--bs-body-bg-rgb), .95); - background-clip: padding-box; - border: var(--bs-modal-border-width) solid var(--bs-modal-border-color); - border-radius: var(--bs-modal-border-radius); - pointer-events: auto; -} -.ol-scale-line-inner { - border: 1px solid var(--bs-body-color); - border-top: none; - color: var(--bs-body-color); - font-size: 80%; - margin: 0; -} - -#map-menu { - position: relative; -} -@media screen and (min-width: 576px) { - #map-menu > .ol-control > button { - font-size: 150%; - } -} -@media screen and (min-width: 768px) { - #map-menu > .ol-control > button { - font-size: 200%; - } - #zoom-control > .ol-zoom > button { - font-size: 120%; - } -} -#map-menu > * { - margin-bottom: var(--map-menu-spacing); - pointer-events: auto; -} -@media screen and (max-width: 767px) { - #map-control-container { - --map-menu-spacing: .25rem; - } - .ol-scale-line-inner { - font-size: 70%; - } -} - -#map-menu > .ol-control { - position: relative; - inset: initial; -} - -.ol-control { - background: none; - border: none; - outline: none; /* eslint-disable-line css/use-baseline */ -} -.ol-control button.btn { - --bs-btn-padding-x: 0.5rem; - --bs-btn-padding-y: 0.5rem; - display: block; - margin: 0; - padding: var(--bs-btn-padding-y) var(--bs-btn-padding-x); - width: auto; - height: auto; - font-weight: bold; - text-decoration: none; - font-size: inherit; - text-align: center; - color: var(--bs-btn-color); - background-color: var(--bs-btn-bg); - border-radius: var(--bs-btn-border-radius); - border: var(--bs-btn-border-width) solid var(--bs-btn-border-color); -} -.ol-control button.btn:focus:not(:focus-visible, :hover) { - text-decoration: none; - color: var(--bs-btn-color); - background-color: var(--bs-btn-bg); - border-color: var(--bs-btn-border-color); - outline: none; /* eslint-disable-line css/use-baseline */ -} -.ol-control button.btn:hover, -.ol-control button.btn:focus-visible { - text-decoration: none; - color: var(--bs-btn-hover-color); - background-color: var(--bs-btn-hover-bg); - border-color: var(--bs-btn-hover-border-color); - outline: none; /* eslint-disable-line css/use-baseline */ -} -.btn-light, .btn-dark { - --bs-btn-border-color: var(--bs-btn-hover-border-color); -} - -#map-control-container[aria-hidden="true"], -#layer-selection-panel[aria-hidden="true"], -#map-legend-panel[aria-hidden="true"] { - display: none; -} -#layer-selection-panel, -#map-legend-panel { - position: relative; - margin-left: 0; - margin-right: var(--map-menu-spacing); - font-size: medium; - z-index: 11; - height: max-content; - max-height: 100%; - pointer-events: auto; - --bs-modal-color: var(--bs-body-color); - --bs-modal-padding: .75rem; -} -#layer-selection-panel { - /*min-width: min-content;*/ - /*max-width: 35%;*/ - /*width: revert;*/ - max-width: 360px; -} -#map-legend-panel { - max-width: 410px; -} -@keyframes fade-in { - from { - opacity: 0; - } - to { - opacity: 1; - } -} -#map-legend-panel .modal-body { - -webkit-user-select: text; - -moz-user-select: text; - user-select: text; /* eslint-disable-line css/use-baseline */ -} -#layer-selection-panel[aria-hidden="false"], -#map-legend-panel[aria-hidden="false"] { - animation: fade-in .25s ease-in-out both; - display: block; -} - -@media screen and (max-aspect-ratio: .75), screen and (max-width: 460px) { - /* 4/3 in portrait mode, likely mobile in portrait mode */ - #map-control-container { - flex-direction: column-reverse; - } - #map-menu { - display: flex; - justify-content: flex-end; - } - #map-menu > * { - margin-bottom: 0; - margin-left: var(--map-menu-spacing); - } - #map-menu .ol-full-screen { - display: none; - } - #layer-selection-panel, - #map-legend-panel { - margin: var(--map-menu-spacing) 0 0 auto; - } -} - -#map-legend-button.disabled button { - color: rgb(from var(--bs-btn-color) r g b / calc(alpha*.25)); - pointer-events: none; -} -@media screen and (max-width: 200px) { - #layer-selection-button, - #map-legend-button, - #age-filter-button, - #export-to-image, - #layer-selection-panel, - #map-legend-panel, - #map-menu .ol-full-screen { - display: none; - } -} -@media screen and (max-height: 576px), screen and (max-width: 500px) { - #zoom-control .ol-zoomslider { - display: none; - } -} -@media screen and (max-width: 300px), screen and (max-height: 300px) { - body { - --bs-body-font-size: .8rem; - } - .ol-control button.btn { - --bs-btn-padding-x: 0.4rem; - --bs-btn-padding-y: 0.4rem; - } -} -#info-modal { - /* close the modal when clicking the backdrop */ - pointer-events: none; - -webkit-user-select: text; - -moz-user-select: text; - user-select: text; /* eslint-disable-line css/use-baseline */ - --bs-modal-header-padding: 1rem; - --modal-info-padding-x: var(--bs-modal-header-padding); - --modal-info-padding-y: .5rem; - --modal-info-bg-light: rgba(0, 0, 0, .08); -} -#info-modal .modal-header { - padding: var(--modal-info-padding-y) var(--modal-info-padding-x); -} -#info-modal .list-group-item, -#info-modal { - --bs-list-group-border-width: 1px; -} -#info-accordion { - --bs-accordion-active-bg: var(--bs-accordion-bg); - --bs-accordion-active-color: var(--bs-body-color); - --bs-accordion-btn-padding-x: 0; - --bs-accordion-btn-padding-y: .025rem; - --bs-accordion-btn-focus-box-shadow: none; - --bs-accordion-body-padding-x: 0; - --bs-accordion-body-padding-y: 0; - --bs-accordion-btn-active-bg: var(--modal-info-bg-light); - padding: 0 var(--modal-info-padding-x); -} -#info-modal .accordion-item { - border: none; -} -#info-modal .accordion-header > .accordion-button[aria-expanded="false"]:hover { - background-color: rgb(from var(--modal-info-bg-light) r g b / calc(alpha*.4)); -} -#info-modal .accordion-header > .accordion-button[aria-expanded="true"] { - background-color: var(--bs-accordion-btn-active-bg); -} -#info-modal ul.list-group > li.list-group-item { - padding: .3rem 0; - border: none; -} -#info-modal ul.list-group > li.list-group-item:last-child { - padding-bottom: var(--modal-info-padding-y); -} -#info-body > ul.list-group { - margin-top: var(--modal-info-padding-y); - border-top: var(--bs-list-group-border-width) solid var(--modal-info-bg-light); - padding: 0 var(--modal-info-padding-x); -} -#info-modal 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-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); -} -#info-modal .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: var(--modal-info-padding-y) 0; -} -#info-body > ul.list-group > li.list-group-item p, -#info-modal .accordion-body ul.list-group > li.list-group-item p { - margin: 0; -} -#info-body > ul.list-group > li.list-group-item h6, -#info-modal .accordion-body ul.list-group > li.list-group-item h6 { - margin: .05rem 0 .15rem 0; - font-size: 1.15rem; -} -#info-modal .modal-body a { - color: inherit; - text-decoration: none; -} -#info-modal .modal-body a:hover { - opacity: .8; - text-decoration: underline; -} -#info-modal .modal-body .info-credits { - border-top: var(--bs-list-group-border-width) solid var(--modal-info-bg-light); - padding: var(--modal-info-padding-y) var(--modal-info-padding-x) 0 var(--modal-info-padding-x); - margin: 0; -} - -.ol-overlaycontainer-stopevent .modal-backdrop.show { - pointer-events: auto; -} - -#layer-selection-panel .accordion { - --bs-accordion-active-bg: var(--bs-accordion-bg); - --bs-accordion-active-color: var(--bs-body-color); - --bs-accordion-btn-padding-x: 0; - --bs-accordion-btn-padding-y: 0; - --bs-accordion-btn-focus-box-shadow: none; - --bs-accordion-body-padding-x: 0; - --bs-accordion-body-padding-y: 0; -} -#layer-selection-panel .accordion-item { - border: none; -} -#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; - border: none; -} -#layer-selection-panel .accordion-item .form-check { - padding-left: 0; - margin: 0.125rem 0 0 0; -} -#layer-selection-panel .accordion-item:first-child .form-check { - margin-top: 0; -} -#layer-selection-panel .accordion-header > .accordion-button[aria-expanded="true"] { - padding-bottom: 0.125rem; - margin-bottom: 0.125rem; -} -#layer-selection-panel .accordion-header > .accordion-button > .form-check > .form-check-input, -#layer-selection-panel .accordion > .accordion-item > .form-check > .form-check-input { - margin-left: 0; - float: none; -} -#layer-selection-panel .accordion-item .form-check > .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; -} -#map-legend-panel .list-group-flush > .list-group-item { - border: none; - padding: 0; -} -#map-legend-panel .modal-body > ul.list-group > li.list-group-item:not(.d-none) ~ li.list-group-item:not(.d-none) { - border-top: var(--bs-list-group-border-width) solid var(--bs-list-group-border-color); - margin-top: .5rem; - padding-top: .5rem; -} -#map-legend-panel .list-group .list-group-item.h4, -#map-legend-panel .list-group .list-group-item.h5, -#map-legend-panel .list-group .list-group-item.h6 { - margin: 0 0 .25rem 0; -} -#map-legend-panel .list-group .list-group-item:not(.d-none) ~ .list-group-item.h5:not(.d-none) { - margin-top: .125rem; -} -#map-legend-panel .list-group .list-group-item.h4 { - font-size: 1.3rem; -} -#map-legend-panel .list-group .list-group-item.h5 { - font-size: 1.05rem; -} -#map-legend-panel .list-group .list-group-item.h6 { - font-size: 1rem; -} -#map-legend-panel .list-group .list-group-item .map-legend-symbol { - /* 24px */ - height: calc(var(--bs-body-line-height) * var(--bs-body-font-size)) !important; -} -#map-legend-panel .list-group .list-group-item .map-legend-symbol > * { - width: 32px; - margin-right: .5rem; -} -#map-legend-panel .list-group .list-group-item .map-legend-symbol img { - margin-left: auto; - margin-right: auto; - display: block; -} -#map-legend-panel .list-group .list-group-item:not(.h4,.h5,.h6):hover { - background-color: var(--bs-list-group-action-hover-bg); -} - -#age-filter-modal .modal-body .btn-group { - width: 100%; -} -#age-filter-modal .age-filter-infotext { - margin: 0 0 var(--bs-modal-padding) 0; -} -#age-filter-form .age-filter-settings .age-filter-settings-desc { - margin: var(--bs-modal-padding) 0; -} -#age-filter-form .age-filter-settings { - margin: 0 0 var(--bs-modal-padding) 0; -} -#age-filter-form .age-filter-settings p.text-muted { - margin: 0; -} -#age-filter-modal p { - -webkit-user-select: text; - -moz-user-select: text; - user-select: text; /* eslint-disable-line css/use-baseline */ -} - -.popover { - --bs-popover-header-padding-x: .75rem; - --bs-popover-header-padding-y: .5rem; - --bs-popover-body-offset-x: .3rem; - --bs-popover-body-padding-x: calc(var(--bs-popover-header-padding-x) - var(--bs-popover-body-offset-x)); - --bs-popover-body-padding-y: .5rem; - --bs-popover-header-bg: var(--bs-popover-bg); - --bs-popover-zindex: 1000; - --bs-popover-max-width: 450px; - width: var(--bs-popover-max-width); - pointer-events: auto; -} -.popover.popover-maximized { - --bs-popover-header-padding-x: 1rem; - --bs-popover-header-padding-y: 1rem; - --bs-popover-body-padding-y: 1rem; - --bs-popover-body-offset-x: .5rem; - --bs-popover-font-size: 1rem; -} -.popover.inprogress > .popover-header, -.popover.inprogress > .popover-body { - filter: opacity(70%); - pointer-events: none; -} -.popover-header { - -webkit-user-select: none; - -moz-user-select: none; - user-select: none; /* eslint-disable-line css/use-baseline */ - --bs-heading-color: var(--bs-popover-header-color); -} -.popover-header h5, .popover-header h6 { - line-height: var(--bs-body-line-height); - vertical-align: middle; - margin: 0; -} -.popover-body { - -webkit-user-select: text; - -moz-user-select: text; - user-select: text; /* eslint-disable-line css/use-baseline */ - max-height: 40vh; - overflow: auto auto; -} -.popover.popover-maximized .popover-body { - max-height: calc(100% - 2*var(--bs-popover-header-padding-y) - var(--bs-body-line-height)*var(--bs-popover-font-size) - var(--bs-popover-border-width)); -} -.popover-body h6, .popover-body h5 { - margin-bottom: var(--bs-popover-body-padding-y); - margin-left: calc(var(--bs-popover-header-padding-x) - var(--bs-popover-body-padding-x)); - margin-right: calc(var(--bs-popover-header-padding-x) - var(--bs-popover-body-padding-x)); -} -.popover.popover-maximized .popover-body h5, -.popover.popover-maximized .popover-body h6 { - font-size: calc(1.2 * var(--bs-popover-font-size)); -} -.popover-body .table { - --bs-table-bg: none; - --bs-table-hover-bg: rgba(0, 0, 0, .04); - --bs-table-bg-padding-y: .1rem; - margin: 0; -} -.popover.popover-maximized .popover-body .table { - --bs-table-hover-bg: none; - --bs-table-bg-padding-y: .5rem; -} -.popover.popover-maximized .popover-body .table tr:nth-of-type(2n+1) { - background: rgba(0, 0, 0, .05); -} -.popover-body table > tbody > tr > th[scope="row"] { - font-style: italic; - padding-right: .75em; - font-weight: normal; -} -.popover .popover-body table > tbody > tr > th[scope="row"] { - width: 35%; -} -.popover-body table > tbody > tr > th[scope="row"], -.popover-body table > tbody > tr > td { - padding: var(--bs-table-bg-padding-y) var(--bs-popover-body-offset-x); -} -.feature-attr-mrr-license-id, .feature-attr-dnr, .feature-objid, .feature-orgnr { - font-family: var(--bs-font-monospace); - word-wrap: break-word; -} - -/* inspired from bootstrap's .btn-close */ -.popover-header .popover-button { - box-sizing: content-box; - width: 1em; - height: 1em; - padding: 0.25em 0.25em; - color: #000; - background: transparent var(--popover-button-icon) center/1em auto no-repeat; - border: 0; - border-radius: 0.375rem; - opacity: .5; -} -.popover-header .popover-button:hover { - text-decoration: none; - opacity: .75; -} -.popover-header .popover-button:focus { - outline: 0; /* eslint-disable-line css/use-baseline */ - box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); - opacity: 1; -} -.popover-header .popover-button:disabled, .popover-header .popover-button.disabled { - pointer-events: none; - opacity: .25; -} - -/* SVG from bootstrap icons v1.11.0 (released under MIT License) */ -.popover-header .popover-button-prev { - --popover-button-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath transform='scale(1.3799) translate(-2.2025 -2.2025)' d='M10 12.796V3.204L4.519 8zm-.659.753-5.48-4.796a1 1 0 0 1 0-1.506l5.48-4.796A1 1 0 0 1 11 3.204v9.592a1 1 0 0 1-1.659.753'/%3e%3c/svg%3e"); -} -.popover-header .popover-button-next { - --popover-button-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath transform='scale(1.3799) translate(-2.2025 -2.2025)' d='M6 12.796V3.204L11.481 8zm.659.753 5.48-4.796a1 1 0 0 0 0-1.506L6.66 2.451C6.011 1.885 5 2.345 5 3.204v9.592a1 1 0 0 0 1.659.753'/%3e%3c/svg%3e"); -} -.popover-header .popover-button-expand { - --popover-button-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M5.828 10.172a.5.5 0 0 0-.707 0l-4.096 4.096V11.5a.5.5 0 0 0-1 0v3.975a.5.5 0 0 0 .5.5H4.5a.5.5 0 0 0 0-1H1.732l4.096-4.096a.5.5 0 0 0 0-.707m4.344-4.344a.5.5 0 0 0 .707 0l4.096-4.096V4.5a.5.5 0 1 0 1 0V.525a.5.5 0 0 0-.5-.5H11.5a.5.5 0 0 0 0 1h2.768l-4.096 4.096a.5.5 0 0 0 0 .707'/%3e%3c/svg%3e"); -} -.popover-header .popover-button-reduce { - --popover-button-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.172 15.828a.5.5 0 0 0 .707 0l4.096-4.096V14.5a.5.5 0 1 0 1 0v-3.975a.5.5 0 0 0-.5-.5H1.5a.5.5 0 0 0 0 1h2.768L.172 15.121a.5.5 0 0 0 0 .707M15.828.172a.5.5 0 0 0-.707 0l-4.096 4.096V1.5a.5.5 0 1 0-1 0v3.975a.5.5 0 0 0 .5.5H14.5a.5.5 0 0 0 0-1h-2.768L15.828.879a.5.5 0 0 0 0-.707'/%3e%3c/svg%3e"); -} -.popover-header .popover-button-close { - --popover-button-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath transform='scale(1.3332) translate(-2 -2)' d='M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8z'/%3e%3c/svg%3e"); -} - -.popover:not(.popover-maximized) .grabbing-area { - cursor: move; /* fallback if grab cursor is unsupported */ - cursor: grab; - cursor: -moz-grab; - cursor: -webkit-grab; -} -.popover:not(.popover-maximized) .grabbing-area.grabbing-area-grabbed { - cursor: grabbing; - cursor: -moz-grabbing; - cursor: -webkit-grabbing; -} -.popover.popover-detached > .popover-arrow, -.popover.popover-maximized > .popover-arrow { - display: none; -} -.popover.popover-maximized { - position: relative !important; - inset: 0 !important; - transform: none !important; - margin: calc(.75*var(--map-container-padding)) auto !important; - --bs-popover-max-width: calc(100vw - 1.5*var(--map-container-padding)); - height: calc(100vh - 1.5*var(--map-container-padding)); - animation: fade-in .25s ease-in-out both; -} -@media screen and (min-width: 1280px) { - .popover.popover-maximized { - --bs-popover-max-width: 1280px; - } -} -@media screen and (min-height: 1920px) { - .popover.popover-maximized { - height: 1920px; - margin-top: calc(50vh - 960px) !important; - margin-bottom: calc(50vh - 960px) !important; - } -} |