PageSourceSearch

https://rokupa-map.netlify.app/resources/qgis2web.js

js rokupa-map.netlify.app collected 2026-10-03 11:21:22 UTC 38,216 bytes, 1,157 lines download raw bytes

1
2var map = new ol.Map({
3    target: 'map',
4    renderer: 'canvas',
5    layers: layersList,
6    view: new ol.View({
7         maxZoom: 28, minZoom: 1
8    })
9});
10
11//initial view - epsg:3857 coordinates if not "Match project CRS"
12map.getView().fit([-1467867.051607, 944707.532562, -1465298.767456, 946171.784070], map.getSize());
13
14//full zooms only
15map.getView().setProperties({constrainResolution: true});
16
17//change cursor
18function pointerOnFeature(evt) {
19    if (evt.dragging) {
20        return;
21    }
22    var hasFeature = map.hasFeatureAtPixel(evt.pixel, {
23        layerFilter: function(layer) {
24            return layer && (layer.get("interactive"));
25        }
26    });
27    map.getViewport().style.cursor = hasFeature ? "pointer" : "";
28}
29map.on('pointermove', pointerOnFeature);
30function styleCursorMove() {
31    map.on('pointerdrag', function() {
32        map.getViewport().style.cursor = "move";
33    });
34    map.on('pointerup', function() {
35        map.getViewport().style.cursor = "default";
36    });
37}
38styleCursorMove();
39
40////small screen definition
41    var hasTouchScreen = map.getViewport().classList.contains('ol-touch');
42    var isSmallScreen = window.innerWidth < 650;
43
44////controls container
45
46    //top left container
47    var topLeftContainer = new ol.control.Control({
48        element: (() => {
49            var topLeftContainer = document.createElement('div');
50            topLeftContainer.id = 'top-left-container';
51            return topLeftContainer;
52        })(),
53    });
54    map.addControl(topLeftContainer)
55
56    //bottom left container
57    var bottomLeftContainer = new ol.control.Control({
58        element: (() => {
59            var bottomLeftContainer = document.createElement('div');
60            bottomLeftContainer.id = 'bottom-left-container';
61            return bottomLeftContainer;
62        })(),
63    });
64    map.addControl(bottomLeftContainer)
65  
66    //top right container
67    var topRightContainer = new ol.control.Control({
68        element: (() => {
69            var topRightContainer = document.createElement('div');
70            topRightContainer.id = 'top-right-container';
71            return topRightContainer;
72        })(),
73    });
74    map.addControl(topRightContainer)
75
76    //bottom right container
77    var bottomRightContainer = new ol.control.Control({
78        element: (() => {
79            var bottomRightContainer = document.createElement('div');
80            bottomRightContainer.id = 'bottom-right-container';
81            return bottomRightContainer;
82        })(),
83    });
84    map.addControl(bottomRightContainer)
85
86//popup
87var container = document.getElementById('popup');
88var content = document.getElementById('popup-content');
89var closer = document.getElementById('popup-closer');
90var sketch;
91
92function stopMediaInPopup() {
93    var mediaElements = container.querySelectorAll('audio, video');
94    mediaElements.forEach(function(media) {
95        media.pause();
96        media.currentTime = 0;
97    });
98}
99closer.onclick = function() {
100    container.style.display = 'none';
101    closer.blur();
102    stopMediaInPopup();
103    return false;
104};
105var overlayPopup = new ol.Overlay({
106    element: container,
107	autoPan: true
108});
109map.addOverlay(overlayPopup)
110    
111    
112var NO_POPUP = 0
113var ALL_FIELDS = 1
114
115/**
116 * Returns either NO_POPUP, ALL_FIELDS or the name of a single field to use for
117 * a given layer
118 * @param layerList {Array} List of ol.Layer instances
119 * @param layer {ol.Layer} Layer to find field info about
120 */
121function getPopupFields(layerList, layer) {
122    // Determine the index that the layer will have in the popupLayers Array,
123    // if the layersList contains more items than popupLayers then we need to
124    // adjust the index to take into account the base maps group
125    var idx = layersList.indexOf(layer) - (layersList.length - popupLayers.length);
126    return popupLayers[idx];
127}
128
129//highligth collection
130var collection = new ol.Collection();
131var featureOverlay = new ol.layer.Vector({
132    map: map,
133    source: new ol.source.Vector({
134        features: collection,
135        useSpatialIndex: false // optional, might improve performance
136    }),
137    style: [new ol.style.Style({
138        stroke: new ol.style.Stroke({
139            color: '#f00',
140            width: 1
141        }),
142        fill: new ol.style.Fill({
143            color: 'rgba(255,0,0,0.1)'
144        }),
145    })],
146    updateWhileAnimating: true, // optional, for instant visual feedback
147    updateWhileInteracting: true // optional, for instant visual feedback
148});
149
150var doHighlight = true;
151var doHover = true;
152
153function createPopupField(currentFeature, currentFeatureKeys, layer) {
154    var popupText = '';
155    for (var i = 0; i < currentFeatureKeys.length; i++) {
156        if (currentFeatureKeys[i] != 'geometry' && currentFeatureKeys[i] != 'layerObject' && currentFeatureKeys[i] != 'idO') {
157            var popupField = '';
158            if (layer.get('fieldLabels')[currentFeatureKeys[i]] == "hidden field") {
159                continue;
160            } else if (layer.get('fieldLabels')[currentFeatureKeys[i]] == "inline label - visible with data") {
161                if (currentFeature.get(currentFeatureKeys[i]) == null) {
162                    continue;
163                }
164            }
165            if (layer.get('fieldLabels')[currentFeatureKeys[i]] == "inline label - always visible" ||
166                layer.get('fieldLabels')[currentFeatureKeys[i]] == "inline label - visible with data") {
167                popupField += '<th>' + layer.get('fieldAliases')[currentFeatureKeys[i]] + '</th><td>';
168            } else {
169                popupField += '<td colspan="2">';
170            }
171            if (layer.get('fieldLabels')[currentFeatureKeys[i]] == "header label - visible with data") {
172                if (currentFeature.get(currentFeatureKeys[i]) == null) {
173                    continue;
174                }
175            }
176            if (layer.get('fieldLabels')[currentFeatureKeys[i]] == "header label - always visible" ||
177                layer.get('fieldLabels')[currentFeatureKeys[i]] == "header label - visible with data") {
178                popupField += '<strong>' + layer.get('fieldAliases')[currentFeatureKeys[i]] + '</strong><br />';
179            }
180            if (layer.get('fieldImages')[currentFeatureKeys[i]] != "ExternalResource") {
181				popupField += (currentFeature.get(currentFeatureKeys[i]) != null ? autolinker.link(currentFeature.get(currentFeatureKeys[i]).toLocaleString()) + '</td>' : '');
182			} else {
183				var fieldValue = currentFeature.get(currentFeatureKeys[i]);
184				if (/\.(gif|jpg|jpeg|tif|tiff|png|avif|webp|svg)$/i.test(fieldValue)) {
185					popupField += (fieldValue != null ? '<img src="images/' + fieldValue.replace(/[\\\/:]/g, '_').trim() + '" /></td>' : '');
186				} else if (/\.(mp4|webm|ogg|avi|mov|flv)$/i.test(fieldValue)) {
187					popupField += (fieldValue != null ? '<video controls><source src="images/' + fieldValue.replace(/[\\\/:]/g, '_').trim() + '" type="video/mp4">Il tuo browser non supporta il tag video.</video></td>' : '');
188				} else if (/\.(mp3|wav|ogg|aac|flac)$/i.test(fieldValue)) {
189                    popupField += (fieldValue != null ? '<audio controls><source src="images/' + fieldValue.replace(/[\\\/:]/g, '_').trim() + '" type="audio/mpeg">Il tuo browser non supporta il tag audio.</audio></td>' : '');
190                } else {
191					popupField += (fieldValue != null ? autolinker.link(fieldValue.toLocaleString()) + '</td>' : '');
192				}
193			}
194            popupText += '<tr>' + popupField + '</tr>';
195        }
196    }
197    return popupText;
198}
199
200var highlight;
201var autolinker = new Autolinker({truncate: {length: 30, location: 'smart'}});
202
203function onPointerMove(evt) {
204    if (!doHover && !doHighlight) {
205        return;
206    }
207    var pixel = map.getEventPixel(evt.originalEvent);
208    var coord = evt.coordinate;
209    var currentFeature;
210    var currentLayer;
211    var currentFeatureKeys;
212    var clusteredFeatures;
213    var clusterLength;
214    var popupText = '<ul>';
215
216    // Collect all features and their layers at the pixel
217    var featuresAndLayers = [];
218    map.forEachFeatureAtPixel(pixel, function(feature, layer) {
219        if (layer && feature instanceof ol.Feature && (layer.get("interactive") || layer.get("interactive") === undefined)) {
220            featuresAndLayers.push({ feature, layer });
221        }
222    });
223
224    // Iterate over the features and layers in reverse order
225    for (var i = featuresAndLayers.length - 1; i >= 0; i--) {
226        var feature = featuresAndLayers[i].feature;
227        var layer = featuresAndLayers[i].layer;
228        var doPopup = false;
229        for (k in layer.get('fieldImages')) {
230            if (layer.get('fieldImages')[k] != "Hidden") {
231                doPopup = true;
232            }
233        }
234        currentFeature = feature;
235        currentLayer = layer;
236        clusteredFeatures = feature.get("features");
237        if (clusteredFeatures) {
238            clusterLength = clusteredFeatures.length;
239        }
240        if (typeof clusteredFeatures !== "undefined") {
241            if (doPopup) {
242                for(var n=0; n<clusteredFeatures.length; n++) {
243                    currentFeature = clusteredFeatures[n];
244                    currentFeatureKeys = currentFeature.getKeys();
245                    popupText += '<li><table>'
246                    popupText += '<a>' + '<b>' + layer.get('popuplayertitle') + '</b>' + '</a>';
247                    popupText += createPopupField(currentFeature, currentFeatureKeys, layer);
248                    popupText += '</table></li>';    
249                }
250            }
251        } else {
252            currentFeatureKeys = currentFeature.getKeys();
253            if (doPopup) {
254                popupText += '<li><table>';
255                popupText += '<a>' + '<b>' + layer.get('popuplayertitle') + '</b>' + '</a>';
256                popupText += createPopupField(currentFeature, currentFeatureKeys, layer);
257                popupText += '</table></li>';
258            }
259        }
260    }
261
262    if (popupText == '<ul>') {
263        popupText = '';
264    } else {
265        popupText += '</ul>';
266    }
267    
268	if (doHighlight) {
269        if (currentFeature !== highlight) {
270            if (highlight) {
271                featureOverlay.getSource().removeFeature(highlight);
272            }
273            if (currentFeature) {
274                var featureStyle
275                if (typeof clusteredFeatures == "undefined") {
276					var style = currentLayer.getStyle();
277					var styleFunction = typeof style === 'function' ? style : function() { return style; };
278					featureStyle = styleFunction(currentFeature)[0];
279				} else {
280					featureStyle = currentLayer.getStyle().toString();
281				}
282
283                if (currentFeature.getGeometry().getType() == 'Point' || currentFeature.getGeometry().getType() == 'MultiPoint') {
284                    var radius
285					if (typeof clusteredFeatures == "undefined") {
286						radius = featureStyle.getImage().getRadius();
287					} else {
288						radius = parseFloat(featureStyle.split('radius')[1].split(' ')[1]) + clusterLength;
289					}
290
291                    highlightStyle = new ol.style.Style({
292                        image: new ol.style.Circle({
293                            fill: new ol.style.Fill({
294                                color: "rgba(255, 255, 0, 1.00)"
295                            }),
296                            radius: radius
297                        })
298                    })
299                } else if (currentFeature.getGeometry().getType() == 'LineString' || currentFeature.getGeometry().getType() == 'MultiLineString') {
300
301                    var featureWidth = featureStyle.getStroke().getWidth();
302
303                    highlightStyle = new ol.style.Style({
304                        stroke: new ol.style.Stroke({
305                            color: 'rgba(255, 255, 0, 1.00)',
306                            lineDash: null,
307                            width: featureWidth
308                        })
309                    });
310
311                } else {
312                    highlightStyle = new ol.style.Style({
313                        fill: new ol.style.Fill({
314                            color: 'rgba(255, 255, 0, 1.00)'
315                        })
316                    })
317                }
318                featureOverlay.getSource().addFeature(currentFeature);
319                featureOverlay.setStyle(highlightStyle);
320            }
321            highlight = currentFeature;
322        }
323    }
324
325    if (doHover) {
326        if (popupText) {
327			content.innerHTML = popupText;
328            container.style.display = 'block';
329            overlayPopup.setPosition(coord);
330        } else {
331            container.style.display = 'none';
332            closer.blur();
333        }
334    }
335};
336
337map.on('pointermove', onPointerMove);
338
339var popupContent = '';
340var popupCoord = null;
341var featuresPopupActive = false;
342
343function updatePopup() {
344    if (popupContent) {
345        content.innerHTML = popupContent;
346        container.style.display = 'block';
347		overlayPopup.setPosition(popupCoord);
348    } else {
349        container.style.display = 'none';
350        closer.blur();
351        stopMediaInPopup();
352    }
353} 
354
355function onSingleClickFeatures(evt) {
356    if (doHover || sketch) {
357        return;
358    }
359    if (!featuresPopupActive) {
360        featuresPopupActive = true;
361    }
362    var pixel = map.getEventPixel(evt.originalEvent);
363    var coord = evt.coordinate;
364    var currentFeature;
365    var currentFeatureKeys;
366    var clusteredFeatures;
367    var popupText = '<ul>';
368    
369    map.forEachFeatureAtPixel(pixel, function(feature, layer) {
370        if (layer && feature instanceof ol.Feature && (layer.get("interactive") || layer.get("interactive") === undefined)) {
371            var doPopup = false;
372            for (var k in layer.get('fieldImages')) {
373                if (layer.get('fieldImages')[k] !== "Hidden") {
374                    doPopup = true;
375                }
376            }
377            currentFeature = feature;
378            clusteredFeatures = feature.get("features");
379            if (typeof clusteredFeatures !== "undefined") {
380                if (doPopup) {
381                    for(var n = 0; n < clusteredFeatures.length; n++) {
382                        currentFeature = clusteredFeatures[n];
383                        currentFeatureKeys = currentFeature.getKeys();
384                        popupText += '<li><table>';
385                        popupText += '<a><b>' + layer.get('popuplayertitle') + '</b></a>';
386                        popupText += createPopupField(currentFeature, currentFeatureKeys, layer);
387                        popupText += '</table></li>';    
388                    }
389                }
390            } else {
391                currentFeatureKeys = currentFeature.getKeys();
392                if (doPopup) {
393                    popupText += '<li><table>';
394                    popupText += '<a><b>' + layer.get('popuplayertitle') + '</b></a>';
395                    popupText += createPopupField(currentFeature, currentFeatureKeys, layer);
396                    popupText += '</table>';
397                }
398            }
399        }
400    });
401    if (popupText === '<ul>') {
402        popupText = '';
403    } else {
404        popupText += '</ul>';
405    }
406	
407	popupContent = popupText;
408    popupCoord = coord;
409    updatePopup();
410}
411
412function onSingleClickWMS(evt) {
413    if (doHover || sketch) {
414        return;
415    }
416    if (!featuresPopupActive) {
417        popupContent = '';
418    }
419    var coord = evt.coordinate;
420    var viewProjection = map.getView().getProjection();
421    var viewResolution = map.getView().getResolution();
422
423    for (var i = 0; i < wms_layers.length; i++) {
424        if (wms_layers[i][1] && wms_layers[i][0].getVisible()) {
425            var url = wms_layers[i][0].getSource().getFeatureInfoUrl(
426                evt.coordinate, viewResolution, viewProjection, {
427                    'INFO_FORMAT': 'text/html',
428                });
429            if (url) {
430                const wmsTitle = wms_layers[i][0].get('popuplayertitle');
431                var ldsRoller = '<div class="roller-switcher" style="height: 25px; width: 25px;"></div>';
432
433                popupCoord = coord;
434                popupContent += ldsRoller;
435                updatePopup();
436
437                var timeoutPromise = new Promise((resolve, reject) => {
438                    setTimeout(() => {
439                        reject(new Error('Timeout exceeded'));
440                    }, 5000); // (5 second)
441                });
442
443                // Function to try fetch with different option
444                function tryFetch(urls) {
445                    if (urls.length === 0) {
446                        return Promise.reject(new Error('All fetch attempts failed'));
447                    }
448                    return fetch(urls[0])
449                        .then((response) => {
450                            if (response.ok) {
451                                return response.text();
452                            } else {
453                                throw new Error('Fetch failed');
454                            }
455                        })
456                        .catch(() => tryFetch(urls.slice(1))); // Try next URL
457                }
458
459                // List of URLs to try
460                // The first URL is the original, the second is the encoded version, and the third is the proxy
461                const urlsToTry = [
462                    url,
463                    encodeURIComponent(url),
464                    'https://api.allorigins.win/raw?url=' + encodeURIComponent(url)
465                ];
466
467                Promise.race([tryFetch(urlsToTry), timeoutPromise])
468                    .then((html) => {
469                        if (html.indexOf('<table') !== -1) {
470                            popupContent += '<a><b>' + wmsTitle + '</b></a>';
471                            popupContent += html + '<p></p>';
472                            updatePopup();
473                        }
474                    })
475                    .finally(() => {
476                        setTimeout(() => {
477                            var loaderIcon = document.querySelector('.roller-switcher');
478                            if (loaderIcon) loaderIcon.remove();
479                        }, 500); // (0.5 second)
480                    });
481            }
482        }
483    }
484}
485
486map.on('singleclick', onSingleClickFeatures);
487map.on('singleclick', onSingleClickWMS);
488
489//get container
490var topLeftContainerDiv = document.getElementById('top-left-container')
491var bottomLeftContainerDiv = document.getElementById('bottom-left-container')
492var topRightContainerDiv = document.getElementById('top-right-container')
493var bottomRightContainerDiv = document.getElementById('bottom-right-container')
494
495//title
496
497//abstract
498
499
500//geolocate
501
502
503
504//measurement
505let measuring = false;
506
507	const measureButton = document.createElement('button');
508	measureButton.className = 'measure-button fas fa-ruler';
509	measureButton.title = 'Measure';
510
511	const measureControl = document.createElement('div');
512	measureControl.className = 'ol-unselectable ol-control measure-control';
513	measureControl.appendChild(measureButton);
514	map.getTargetElement().appendChild(measureControl);
515
516	// Event handler
517	function handleMeasure() {
518	  if (!measuring) {
519		selectLabel.style.display = "";
520		map.addInteraction(draw);
521		createHelpTooltip();
522		createMeasureTooltip();
523		measuring = true;
524	  } else {
525		selectLabel.style.display = "none";
526		map.removeInteraction(draw);
527		map.removeOverlay(helpTooltip);
528		map.removeOverlay(measureTooltip);
529		const staticTooltips = document.getElementsByClassName("tooltip-static");
530		while (staticTooltips.length > 0) {
531		  staticTooltips[0].parentNode.removeChild(staticTooltips[0]);
532		}
533		measureLayer.getSource().clear();
534		sketch = null;
535		measuring = false;
536	  }
537	}
538
539	measureButton.addEventListener('click', handleMeasure);
540	measureButton.addEventListener('touchstart', handleMeasure);
541
542    map.on('pointermove', function(evt) {
543        if (evt.dragging) {
544            return;
545        }
546        if (measuring) {
547            /** @type {string} */
548            var helpMsg = 'Click to start drawing';
549            if (sketch) {
550                var geom = (sketch.getGeometry());
551                if (geom instanceof ol.geom.Polygon) {
552                    helpMsg = continuePolygonMsg;
553                } else if (geom instanceof ol.geom.LineString) {
554                    helpMsg = continueLineMsg;
555                }
556            }
557            helpTooltipElement.innerHTML = helpMsg;
558            helpTooltip.setPosition(evt.coordinate);
559        }
560    });
561    
562
563    var selectLabel = document.createElement("label");
564    selectLabel.innerHTML = "&nbsp;Measure:&nbsp;";
565
566    var typeSelect = document.createElement("select");
567    typeSelect.id = "type";
568
569    var measurementOption = [
570        { value: "LineString", description: "Length" },
571        { value: "Polygon", description: "Area" }
572        ];
573    measurementOption.forEach(function (option) {
574        var optionElement = document.createElement("option");
575        optionElement.value = option.value;
576        optionElement.text = option.description;
577        typeSelect.appendChild(optionElement);
578    });
579
580    selectLabel.appendChild(typeSelect);
581    measureControl.appendChild(selectLabel);
582
583    selectLabel.style.display = "none";
584	/**
585	 * Currently drawn feature.
586	 * @type {ol.Feature}
587	 */
588
589	/**
590	 * The help tooltip element.
591	 * @type {Element}
592	 */
593	var helpTooltipElement;
594
595
596	/**
597	 * Overlay to show the help messages.
598	 * @type {ol.Overlay}
599	 */
600	var helpTooltip;
601
602
603	/**
604	 * The measure tooltip element.
605	 * @type {Element}
606	 */
607	var measureTooltipElement;
608
609
610	/**
611	 * Overlay to show the measurement.
612	 * @type {ol.Overlay}
613	 */
614	var measureTooltip;
615
616
617	/**
618	 * Message to show when the user is drawing a line.
619	 * @type {string}
620	 */
621	var continueLineMsg = 'Click to continue drawing the line';
622
623
624
625	/**
626	 * Message to show when the user is drawing a polygon.
627	 * @type {string}
628	 */
629	var continuePolygonMsg = "1click continue, 2click close";
630
631
632	var typeSelect = document.getElementById("type");
633	var typeSelectForm = document.getElementById("form_measure");
634
635	typeSelect.onchange = function (e) {		  
636	  map.removeInteraction(draw);
637	  addInteraction();
638	  map.addInteraction(draw);		  
639	};
640
641	var measureLineStyle = new ol.style.Style({
642	  stroke: new ol.style.Stroke({ 
643		color: "rgba(0, 0, 255)", //blu
644		lineDash: [10, 10],
645		width: 4
646	  }),
647	  image: new ol.style.Circle({
648		radius: 6,
649		stroke: new ol.style.Stroke({
650		  color: "rgba(255, 255, 255)", 
651		  width: 1
652		}),
653	  })
654	});
655
656	var measureLineStyle2 = new ol.style.Style({	  
657		stroke: new ol.style.Stroke({
658			color: "rgba(255, 255, 255)", 
659			lineDash: [10, 10],
660			width: 2
661		  }),
662	  image: new ol.style.Circle({
663		radius: 5,
664		stroke: new ol.style.Stroke({
665		  color: "rgba(0, 0, 255)", 
666		  width: 1
667		}),
668			  fill: new ol.style.Fill({
669		  color: "rgba(255, 204, 51, 0.4)", 
670		}),
671		  })
672	});
673
674	var labelStyle = new ol.style.Style({
675	  text: new ol.style.Text({
676		font: "14px Calibri,sans-serif",
677		fill: new ol.style.Fill({
678		  color: "rgba(0, 0, 0, 1)"
679		}),
680		stroke: new ol.style.Stroke({
681		  color: "rgba(255, 255, 255, 1)",
682		  width: 3
683		})
684	  })
685	});
686
687	var labelStyleCache = [];
688
689	var styleFunction = function (feature, type) {
690	  var styles = [measureLineStyle, measureLineStyle2];
691	  var geometry = feature.getGeometry();
692	  var type = geometry.getType();
693	  var lineString;
694	  if (!type || type === type) {
695		if (type === "Polygon") {
696		  lineString = new ol.geom.LineString(geometry.getCoordinates()[0]);
697		} else if (type === "LineString") {
698		  lineString = geometry;
699		}
700	  }
701	  if (lineString) {
702		var count = 0;
703		lineString.forEachSegment(function (a, b) {
704		  var segment = new ol.geom.LineString([a, b]);
705		  var label = formatLength(segment);
706		  if (labelStyleCache.length - 1 < count) {
707			labelStyleCache.push(labelStyle.clone());
708		  }
709		  labelStyleCache[count].setGeometry(segment);
710		  labelStyleCache[count].getText().setText(label);
711		  styles.push(labelStyleCache[count]);
712		  count++;
713		});
714	  }
715	  return styles;
716	};
717	var source = new ol.source.Vector();
718
719	var measureLayer = new ol.layer.Vector({
720	  source: source,
721	  displayInLayerSwitcher: false,
722	  style: function (feature) {
723		labelStyleCache = [];
724		return styleFunction(feature);
725	  }
726	});
727
728	map.addLayer(measureLayer);
729
730	var draw; // global so we can remove it later
731	function addInteraction() {
732	  var type = typeSelect.value;
733	  draw = new ol.interaction.Draw({
734		source: source,
735		type: /** @type {ol.geom.GeometryType} */ (type),
736		style: function (feature) {
737				  return styleFunction(feature, type);
738				}
739	  });
740
741	  var listener;
742	  draw.on('drawstart',
743		  function(evt) {
744			// set sketch
745			sketch = evt.feature;
746
747			/** @type {ol.Coordinate|undefined} */
748			var tooltipCoord = evt.coordinate;
749
750			listener = sketch.getGeometry().on('change', function(evt) {
751			  var geom = evt.target;
752			  var output;
753			  if (geom instanceof ol.geom.Polygon) {
754					  output = formatArea(/** @type {ol.geom.Polygon} */ (geom));
755					  tooltipCoord = geom.getInteriorPoint().getCoordinates();
756					} else if (geom instanceof ol.geom.LineString) {
757					  output = formatLength(/** @type {ol.geom.LineString} */ (geom));
758					  tooltipCoord = geom.getLastCoordinate();
759					}
760			  measureTooltipElement.innerHTML = output;
761			  measureTooltip.setPosition(tooltipCoord);
762			});
763		  }, this);
764
765	  draw.on('drawend',
766		  function(evt) {
767			measureTooltipElement.className = 'tooltip tooltip-static';
768			measureTooltip.setOffset([0, -7]);
769			// unset sketch
770			sketch = null;
771			// unset tooltip so that a new one can be created
772			measureTooltipElement = null;
773			createMeasureTooltip();
774			ol.Observable.unByKey(listener);
775		  }, this);
776	}
777
778
779	/**
780	 * Creates a new help tooltip
781	 */
782	function createHelpTooltip() {
783	  if (helpTooltipElement) {
784		helpTooltipElement.parentNode.removeChild(helpTooltipElement);
785	  }
786	  helpTooltipElement = document.createElement('div');
787	  helpTooltipElement.className = 'tooltip hidden';
788	  helpTooltip = new ol.Overlay({
789		element: helpTooltipElement,
790		offset: [15, 0],
791		positioning: 'center-left'
792	  });
793	  map.addOverlay(helpTooltip);
794	}
795
796
797	/**
798	 * Creates a new measure tooltip
799	 */
800	function createMeasureTooltip() {
801	  if (measureTooltipElement) {
802		measureTooltipElement.parentNode.removeChild(measureTooltipElement);
803	  }
804	  measureTooltipElement = document.createElement('div');
805	  measureTooltipElement.className = 'tooltip tooltip-measure';
806	  measureTooltip = new ol.Overlay({
807		element: measureTooltipElement,
808		offset: [0, -15],
809		positioning: 'bottom-center'
810	  });
811	  map.addOverlay(measureTooltip);
812	}
813
814
815  /**
816  * format length output
817  * @param {ol.geom.LineString} line
818  * @return {string}
819  */
820  var formatLength = function(line) {
821    var length;
822    var coordinates = line.getCoordinates();
823    length = 0;
824    var sourceProj = map.getView().getProjection();
825    for (var i = 0, ii = coordinates.length - 1; i < ii; ++i) {
826        var c1 = ol.proj.transform(coordinates[i], sourceProj, 'EPSG:4326');
827        var c2 = ol.proj.transform(coordinates[i + 1], sourceProj, 'EPSG:4326');
828        length += ol.sphere.getDistance(c1, c2);
829      }
830    var output;
831    if (length > 100) {
832      output = (Math.round(length / 1000 * 100) / 100) +
833          ' ' + 'km';
834    } else {
835      output = (Math.round(length * 100) / 100) +
836          ' ' + 'm';
837    }
838    return output;
839  };
840
841  /**
842  * Format area output.
843  * @param {ol.geom.Polygon} polygon The polygon.
844  * @return {string} Formatted area.
845  */
846	var formatArea = function (polygon) {
847		var sourceProj = map.getView().getProjection();
848		var geom = polygon.clone().transform(sourceProj, 'EPSG:3857');
849		var area = Math.abs(ol.sphere.getArea(geom));
850		var output;
851		if (area > 1000000) {
852			output = Math.round((area / 1000000) * 1000) / 1000 + ' ' + 'km<sup>2</sup>';
853		} else {
854			output = Math.round(area * 100) / 100 + ' ' + 'm<sup>2</sup>';
855		}
856		return output.replace('.', ',');
857	};
858
859  addInteraction();
860
861  var parentElement = document.querySelector(".measure-control");
862  var elementToMove = document.getElementById("form_measure");
863  if (elementToMove && parentElement) {
864    parentElement.insertBefore(elementToMove, parentElement.firstChild);
865  }
866
867
868//geocoder
869
870  //Layer to represent the point of the geocoded address
871  var geocoderLayer = new ol.layer.Vector({
872      source: new ol.source.Vector(),
873  });
874  map.addLayer(geocoderLayer);
875  var vectorSource = geocoderLayer.getSource();
876
877  //Variable used to store the coordinates of geocoded addresses
878  var obj2 = {
879  value: '',
880  letMeKnow() {
881      //console.log(`Geocoded position: ${this.gcd}`);
882  },
883  get gcd() {
884      return this.value;
885  },
886  set gcd(value) {
887      this.value = value;
888      this.letMeKnow();
889  }
890  }
891
892  var obj = {
893      value: '',
894      get label() {
895          return this.value;
896      },
897      set label(value) {
898          this.value = value;
899      }
900  }
901
902  // Function to handle the selected address
903  function onSelected(feature) {
904      obj.label = feature;
905      input.value = typeof obj.label.properties.label === "undefined"? obj.label.properties.display_name : obj.label.properties.label;
906      var coordinates = ol.proj.transform(
907      [feature.geometry.coordinates[0], feature.geometry.coordinates[1]],
908      "EPSG:4326",
909      map.getView().getProjection()
910      );
911      vectorSource.clear(true);
912      obj2.gcd = [feature.geometry.coordinates[0], feature.geometry.coordinates[1]];
913      var marker = new ol.Feature(new ol.geom.Point(coordinates));
914      var zIndex = 1;
915      marker.setStyle(new ol.style.Style({
916      image: new ol.style.Icon(({
917          anchor: [0.5, 1],
918          anchorXUnits: 'fraction',
919          anchorYUnits: 'fraction',
920          scale: 0.7,
921          opacity: 1,
922          src: "./resources/marker.png",
923          zIndex: zIndex
924      })),
925      zIndex: zIndex
926      }));
927      vectorSource.addFeature(marker);
928      map.getView().setCenter(coordinates);
929      map.getView().setZoom(18);
930  }
931
932  // Format the result in the autocomplete search bar
933  var formatResult = function (feature, el) {
934      var title = document.createElement("strong");
935      el.appendChild(title);
936      var detailsContainer = document.createElement("small");
937      el.appendChild(detailsContainer);
938      var details = [];
939      title.innerHTML = feature.properties.label || feature.properties.display_name;
940      var types = {
941      housenumber: "numéro",
942      street: "rue",
943      locality: "lieu-dit",
944      municipality: "commune",
945      };
946      if (
947      feature.properties.city &&
948      feature.properties.city !== feature.properties.name
949      ) {
950      details.push(feature.properties.city);
951      }
952      if (feature.properties.context) {
953      details.push(feature.properties.context);
954      }
955      detailsContainer.innerHTML = details.join(", ");
956  };
957
958  // Define a class to create the control button for the search bar in a div tag
959  class AddDomControl extends ol.control.Control {
960      constructor(elementToAdd, opt_options) {
961      const options = opt_options || {};
962
963      const element = document.createElement("div");
964      if (options.className) {
965          element.className = options.className;
966      }
967      element.appendChild(elementToAdd);
968
969      super({
970          element: element,
971          target: options.target,
972      });
973      }
974  }
975
976  // Function to show you can do something with the returned elements
977  function myHandler(featureCollection) {
978      //console.log(featureCollection);
979  }
980
981  // URL for API
982  const url = {"Nominatim OSM": "https://nominatim.openstreetmap.org/search?format=geojson&addressdetails=1&",
983  "France BAN": "https://api-adresse.data.gouv.fr/search/?"}
984  var API_URL = "//api-adresse.data.gouv.fr";
985
986  // Create search by adresses component
987  var containers = new Photon.Search({
988    resultsHandler: myHandler,
989    onSelected: onSelected,
990    placeholder: "Search an address",
991    formatResult: formatResult,
992    //url: API_URL + "/search/?",
993    url: url["Nominatim OSM"],
994    position: "topright",
995    // ,includePosition: function() {
996    //   return ol.proj.transform(
997    //     map.getView().getCenter(),
998    //     map.getView().getProjection(), //'EPSG:3857',
999    //     'EPSG:4326'
1000    //   );
1001    // }
1002  });
1003
1004  // Add the created DOM element within the map
1005  //var left = document.getElementById("top-left-container");
1006  var controlGeocoder = new AddDomControl(containers, {
1007    className: "photon-geocoder-autocomplete ol-unselectable ol-control",
1008  });
1009  map.addControl(controlGeocoder);
1010  var search = document.getElementsByClassName("photon-geocoder-autocomplete ol-unselectable ol-control")[0];
1011  search.style.display = "flex";
1012
1013  // Create the new button element
1014  var button = document.createElement("button");
1015  button.type = "button";
1016  button.id = "gcd-button-control";
1017  button.className = "gcd-gl-btn fa fa-search leaflet-control";
1018
1019  // Ajouter le bouton à l'élément parent
1020  search.insertBefore(button, search.firstChild);
1021  last = search.lastChild;
1022  last.style.display = "none";
1023  button.addEventListener("click", function (e) {
1024      if (last.style.display === "none") {
1025          last.style.display = "block";
1026      } else {
1027          last.style.display = "none";
1028      }
1029  });
1030  input = document.getElementsByClassName("photon-input")[0];
1031  //var searchbar = document.getElementsByClassName("photon-geocoder-autocomplete ol-unselectable ol-control")[0]
1032  //left.appendChild(searchbar);
1033        
1034
1035//layer search
1036
1037var searchLayer = new SearchLayer({
1038    layer: lyr_Rokupa_1,
1039    colName: 'PAP ID',
1040    zoom: 10,
1041    collapsed: true,
1042    map: map,
1043    maxResults: 10,
1044    showOnFocus: false
1045});
1046map.addControl(searchLayer);
1047document.getElementsByClassName('search-layer')[0].getElementsByTagName('button')[0].className += ' fa fa-binoculars';
1048document.getElementsByClassName('search-layer-input-search')[0].placeholder = 'Search feature ...';
1049    
1050
1051//scalebar
1052
1053
1054//layerswitcher
1055
1056var layerSwitcher = new ol.control.LayerSwitcher({
1057    activationMode: 'click',
1058	startActive: true,
1059	tipLabel: "Layers",
1060    target: 'top-right-container',
1061	collapseLabel: '»',
1062	collapseTipLabel: 'Close'
1063    });
1064map.addControl(layerSwitcher);
1065if (hasTouchScreen || isSmallScreen) {
1066	document.addEventListener('DOMContentLoaded', function() {
1067		setTimeout(function() {
1068			layerSwitcher.hidePanel();
1069		}, 500);
1070	});	
1071}
1072
1073
1074
1075
1076
1077
1078//attribution
1079var bottomAttribution = new ol.control.Attribution({
1080  collapsible: false,
1081  collapsed: false,
1082  className: 'bottom-attribution'
1083});
1084map.addControl(bottomAttribution);
1085
1086map.once('rendercomplete', function() {
1087  var bottomAttributionUl = bottomAttribution.element.querySelector('ul');
1088  if (bottomAttributionUl) {
1089    var layerAttrs = Array.from(bottomAttributionUl.querySelectorAll('li'))
1090      .map(function(li) { return li.innerHTML.trim(); }).filter(Boolean);
1091    var attribHtml = `
1092    <a href="https://github.com/qgis2web/qgis2web">qgis2web</a> &middot;
1093    <a href="https://openlayers.org/">OpenLayers</a> &middot;
1094    <a href="https://qgis.org/">QGIS</a>`;
1095    if (layerAttrs.length > 0) { attribHtml += ' &nbsp;|&nbsp; ' + layerAttrs.join(', '); }
1096    bottomAttributionUl.innerHTML = '<li>' + attribHtml + '</li>';
1097  }
1098});
1099
1100
1101// Disable "popup on hover" or "highlight on hover" if ol-control mouseover
1102var preDoHover = doHover;
1103var preDoHighlight = doHighlight;
1104var isPopupAllActive = false;
1105document.addEventListener('DOMContentLoaded', function() {
1106	if (doHover || doHighlight) {
1107		var controlElements = document.getElementsByClassName('ol-control');
1108		for (var i = 0; i < controlElements.length; i++) {
1109			controlElements[i].addEventListener('mouseover', function() { 
1110				doHover = false;
1111				doHighlight = false;
1112			});
1113			controlElements[i].addEventListener('mouseout', function() {
1114				doHover = preDoHover;
1115				if (isPopupAllActive) { return }
1116				doHighlight = preDoHighlight;
1117			});
1118		}
1119	}
1120});
1121
1122
1123//move controls inside containers, in order
1124    //zoom
1125    var zoomControl = document.getElementsByClassName('ol-zoom')[0];
1126    if (zoomControl) {
1127        topLeftContainerDiv.appendChild(zoomControl);
1128    }
1129    //geolocate
1130    if (typeof geolocateControl !== 'undefined') {
1131        topLeftContainerDiv.appendChild(geolocateControl);
1132    }
1133    //measure
1134    if (typeof measureControl !== 'undefined') {
1135        topLeftContainerDiv.appendChild(measureControl);
1136    }
1137    //geocoder
1138    var searchbar = document.getElementsByClassName('photon-geocoder-autocomplete ol-unselectable ol-control')[0];
1139    if (searchbar) {
1140        topLeftContainerDiv.appendChild(searchbar);
1141    }
1142    //search layer
1143    var searchLayerControl = document.getElementsByClassName('search-layer')[0];
1144    if (searchLayerControl) {
1145        topLeftContainerDiv.appendChild(searchLayerControl);
1146    }
1147    //scale line
1148    var scaleLineControl = document.getElementsByClassName('ol-scale-line')[0];
1149    if (scaleLineControl) {
1150        scaleLineControl.className += ' ol-control';
1151        bottomLeftContainerDiv.appendChild(scaleLineControl);
1152    }
1153    //attribution
1154    var attributionControl = document.getElementsByClassName('bottom-attribution')[0];
1155    if (attributionControl) {
1156        bottomRightContainerDiv.appendChild(attributionControl);
1157    }

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.