PageSourceSearch

https://www.wald-natur-erleben.de/_assets/ad1b37aebd5bc4473d558f78…/JS/q4u_gis_maps-leaflet.js?1789044290

js wald-natur-erleben.de collected 2026-10-04 19:59:15 UTC 54,541 bytes, 1,887 lines download raw bytes

1'use strict';
2
3let mapSlider;
4
5const Q4UMap = (function (document) {
6  const inDevelopment = false;
7  const centerOnRouteOnly = true;
8  const $resultContainer = $('#ajaxCallResult');
9  const link = $resultContainer.attr('data-link');
10  const routeNumber = $resultContainer.attr('data-route');
11  // const trekkingRouteNummer = $resultContainer.attr('data-trekking');
12  const specialPointsCodeNum = $resultContainer.attr('data-special-points');
13  const maptype = $resultContainer.attr('data-maptype');
14  // Number for route geoJson in controller
15  const ROUTE_CODE_NUM = 10;
16  // Number for points of interest geoJson in controller
17  const POINTS_OF_INTEREST_CODE_NUM = 0;
18  // Number for baumgiganten geoJson in controller
19  const BAUMGIGANTEN_CODE_NUM = 4;
20  const TRITTSTEINE_CODE_NUM = 6;
21  const NWF_CODE_NUM = 50;
22  const allRoutes = {};
23  const allTrekkingRoutes = {};
24  // Route style
25  const myRouteStyle = {
26    color: '#555555',
27    weight: 3
28  };
29
30  const myNwfStyle = {
31    color: '#9cb476',
32    weight: 3
33  };
34
35  const clusteringDistanceInPixels = 80;
36  const myTrekkingRouteStyle = {
37    1: {
38      color: '#27ab70',
39      weight: 4
40    },
41    2: {
42      color: '#894fc4',
43      weight: 4
44    },
45    3: {
46      color: '#345ba8',
47      weight: 4
48    },
49    4: {
50      color: '#c7329f',
51      weight: 4
52    },
53    12: {
54      color: '#3826a3',
55      weight: 4
56    },
57    13: {
58      color: '#b3ad3d',
59      weight: 4
60    },
61    14: {
62      color: '#bf3234',
63      weight: 4
64    },
65    15: {
66      color: '#8fbf2e',
67      weight: 4
68    },
69    16: {
70      color: '#ffaa00',
71      weight: 4
72    },
73    17: {
74      color: '#ff73df',
75      weight: 4
76    },
77    18: {
78      color: '#ffff00',
79      weight: 4
80    },
81    19: {
82      color: '#f57a7a',
83      weight: 4
84    },
85    20: {
86      color: '#00ffc5',
87      weight: 4
88    }
89  };
90  // Custom icon class without iconUrl
91  const CustomIcon = L.Icon.extend({
92    options: {
93      iconSize: [40, 40],
94      iconAnchor: [20, 40]
95    }
96  });
97  // let osm;
98  let map;
99  let centerCoordinates = [];
100  let paddingBottomRight;
101  let paddingTopLeft;
102  let firstPointTypeSelected = '';
103  let campingSitesLayer; // Zeltplätze
104  let campingSitesLoaded = false;
105  let centerOnPoint;
106
107  const log = function (value) {
108    if (inDevelopment) {
109      console.log(value);
110    }
111  };
112
113  /**
114   * https://github.com/domoritz/leaflet-locatecontrol
115   */
116  const locateUser = function () {
117    log('locateUser()');
118
119    const locating = L.control.locate({
120      position: 'topright',
121      drawCircle: false,
122      returnToPrevBounds: true,
123      locateOptions: {
124        watch: true,
125        enableHighAccuracy: true,
126        maximumAge: 1000
127      }
128    }).addTo(map);
129
130    map.on('locationerror', function (e) {
131      e.message = 'Geolokalisierung wird vom Benutzer blockiert';
132    });
133  };
134
135  /**
136   * Fetches data from typo3 and executes callback function if successful
137   */
138  const services = {
139    ajaxCall: function (data, callback) {
140      $.ajax(
141        {
142          dataType: 'html',
143          url: link,
144          data: data,
145          success: function (result) {
146            callback(result);
147          },
148          error: function (jqXHR, textStatus, errorThrow) {
149            log(errorThrow);
150          }
151        }
152      );
153    },
154    centerMap: function () {
155      paddingBottomRight = paddingBottomRight || [0, 100];
156      paddingTopLeft = paddingTopLeft || [0, 0];
157      map.fitBounds(centerCoordinates, {
158        paddingBottomRight: paddingBottomRight,
159        paddingTopLeft: paddingTopLeft
160      });
161    },
162    closePopup: function () {
163      const openPopup = $('.leaflet-popup-close-button');
164      if (openPopup.length > 0) {
165        openPopup[0].click();
166      }
167    },
168    capitalize: function (s) {
169      if (typeof s !== 'string') return '';
170      return s.charAt(0).toUpperCase() + s.slice(1);
171    }
172  };
173
174  /**
175   * Map control button on map to center map back on points
176   * @type {*|{}}
177   */
178  const CenterMapControl = L.Control.extend({
179
180    options: {
181      position: 'topright'
182    },
183
184    onAdd: function () {
185      const container = L.DomUtil.create('div', 'leaflet-bar leaflet-control leaflet-control-custom');
186
187      container.style.backgroundColor = 'white';
188      container.style.width = '30px';
189      container.style.height = '30px';
190
191      container.onclick = function () {
192        log('centerMapOnRoute() - control button');
193        services.centerMap();
194      };
195
196      return container;
197    }
198  });
199
200  /**
201   * 2.0 Show multiple different point types on same map, with control buttons to show/hide them
202   * multiplePointsAction in BaumgigantController
203   * @version 2.0
204   */
205  const showMultiplePointsWithSwitchMenu = function (doCenter, pointTypes) {
206    log('showMultiplePointsWithSwitchMenu...');
207    let types = [];
208    centerOnPoint = doCenter;
209    if (pointTypes !== '') {
210      types = pointTypes.split(',');
211    }
212
213    if (!centerOnPoint) {
214      if (types.includes('11')) {
215        types.push('5');
216      }
217    }
218
219    // remove empty strings from array
220    types = types.filter(function (el) {
221      return el.trim() !== '';
222    });
223
224    if (types.length > 0) {
225      if (centerOnPoint) {
226        firstPointTypeSelected = types[0];
227      }
228      $(types).each(function () {
229        switch (this) {
230          case '99':
231            showAllRoutesWithOtherPoints();
232            break;
233          case '4':
234            showBaumgigantenWithOtherPoints(this, 'all');
235            break;
236          case '44':
237            showBaumgigantenWithOtherPoints('4', 'special');
238            break;
239          case '6':
240            showTrittsteineWithOtherPoints(this, 'all');
241            break;
242          case '66':
243            showTrittsteineWithOtherPoints('6', 'special');
244            break;
245          case '50':
246            showNwfWithOtherPoints('50', 'all');
247            break;
248          case '11':
249            log('showTrekkingRoutesWithOtherPoints');
250            showTrekkingRoutesWithOtherPoints();
251            break;
252          default:
253            showPointLayerAndControlButton(this);
254        }
255      });
256    }
257  };
258
259  /**
260   * 2.0 Creates point layer, and adds control button to page
261   * @param type
262   * @version 2.0
263   */
264  const showPointLayerAndControlButton = function (type) {
265    log('showPointLayerAndControlButton... ' + type);
266    const data = {
267      pointType: type,
268      rid: 0
269    };
270    const campingMarkers = [];
271    let highlight = null;
272
273    services.ajaxCall(data, createLayerAndAddControlButton);
274
275    function createLayerAndAddControlButton(elements) {
276      const points = JSON.parse(elements);
277      let refreshmentStopsLayer; // Einkehrmöglichkeiten
278      let steppingStonesLayer; // Trittsteine
279      let rescuePointsLayer;// Rettungspunkte
280      let parkingSpotsLayer; // Parkplätze
281      let excursionDestinationsLayer; // Ausflugsziele
282      let observationsLayer; // iNaturalist
283
284      switch (type) {
285        case '1':
286          refreshmentStopsLayer = buildPointsLayer(points, type);
287          buildAndAddControlButton(refreshmentStopsLayer, 'refreshment-spots', 'Einkehrmöglichkeiten');
288          break;
289        case '2':
290          excursionDestinationsLayer = buildPointsLayer(points, type);
291          buildAndAddControlButton(excursionDestinationsLayer, 'excursion-destinations', 'Ausflugsziele');
292          break;
293        case '5':
294          campingSitesLayer = buildPointsLayer(points, type);
295          break;
296        case '6':
297          steppingStonesLayer = buildPointsLayer(points, type);
298          buildAndAddControlButton(steppingStonesLayer, 'stepping-spots', 'Trittsteine');
299          break;
300        case '8':
301          rescuePointsLayer = buildPointsLayer(points, type);
302          buildAndAddControlButton(rescuePointsLayer, 'rescue-points', 'Rettungspunkte');
303          break;
304        case '9':
305          parkingSpotsLayer = buildPointsLayer(points, type);
306          buildAndAddControlButton(parkingSpotsLayer, 'parking-spots', 'Parkplätze');
307          break;
308        case '80':
309          observationsLayer = buildPointsLayer(points, type);
310          buildAndAddControlButton(observationsLayer, 'observation-points');
311      }
312    }
313
314    function buildPointsLayer(points, type) {
315      log('buildPointsLayer(' + type + ')');
316      let tempMarker;
317
318      return L.geoJSON(
319        points,
320        {
321          pointToLayer: function (feature, latlng) {
322            if (type === '80') {
323              tempMarker = L.marker(latlng, {
324                icon: getINaturalistIcon(feature),
325                iconAnchor: [-200, 0],
326                riseOnHover: true
327              });
328            } else {
329              tempMarker = L.marker(latlng, {
330                icon: getMarkerIcon(type),
331                riseOnHover: true
332              });
333            }
334
335            tempMarker.on('click', function (e) {
336              if (type === '5') {
337                changeIcon(feature);
338              }
339              selectSlideOrShowPopup(feature);
340            })
341              .on('mouseover', function (e) {
342                if (type === '5') {
343                  log(this);
344                  log(feature);
345                  L.popup().setLatLng(e.latlng).setContent(feature.properties.name).openOn(map);
346                }
347              });
348            if (type === '5') {
349              campingMarkers.push(tempMarker);
350              campingSitesLoaded = true;
351              map.on('click', removeHighlight);
352            }
353            return tempMarker;
354          }
355        }
356      );
357    }
358
359    function buildAndAddControlButton(specificSpotsLayer, className) {
360      let arePointshownOnMap = false;
361      let tempCluster;
362      if (className === 'observation-points') {
363        tempCluster = L.markerClusterGroup({
364          disableClusteringAtZoom: 20,
365          maxClusterRadius: clusteringDistanceInPixels
366        });
367      } else {
368        tempCluster = L.markerClusterGroup({
369          disableClusteringAtZoom: 14,
370          maxClusterRadius: clusteringDistanceInPixels
371        });
372      }
373
374      $('div#map-controls').on('click', 'button.' + className, function () {
375        services.closePopup();
376        if (arePointshownOnMap) {
377          map.removeLayer(tempCluster);
378          tempCluster.removeLayer(specificSpotsLayer);
379          map.addLayer(tempCluster);
380          arePointshownOnMap = false;
381        } else {
382          map.removeLayer(tempCluster);
383          tempCluster.addLayer(specificSpotsLayer);
384          map.addLayer(tempCluster);
385          arePointshownOnMap = true;
386        }
387      });
388
389      tempCluster.addLayer(specificSpotsLayer);
390
391      // show this cluster if this type is first in the list
392
393      if (centerOnPoint) {
394        if (type === firstPointTypeSelected) {
395          map.addLayer(tempCluster);
396          arePointshownOnMap = true;
397
398          // set centering points and options
399          centerCoordinates = tempCluster.getBounds();
400          paddingBottomRight = [0, 40];
401          services.centerMap();
402        }
403      } else {
404        tempCluster.addLayer(specificSpotsLayer);
405        map.addLayer(tempCluster);
406      }
407    }
408
409    function selectSlideOrShowPopup(feature) {
410      log('selectSlideOrShowPopup()');
411      if (type === '2' || type === '1' || type === '80') {
412        showPopup(feature);
413      } else {
414        if (feature.properties.url !== '' && feature.properties.url !== undefined) {
415          openSlideOrGoToPage(feature);
416        } else {
417          showPopup(feature);
418        }
419      }
420    }
421
422    function showPopup(feature) {
423      log('Show popup');
424
425      const popup = L.popup({
426        offset: [0, -30]
427      });
428
429      popup.setLatLng([feature.geometry.coordinates[1], feature.geometry.coordinates[0]])
430        .setContent(popupTemplate(type, feature.properties))
431        .openOn(map);
432    }
433
434    function changeIcon(feature) {
435      log('change icon for camping site');
436
437      removeHighlight();
438
439      for (let y = 0; y < campingMarkers.length; y++) {
440        if (campingMarkers[y].feature.properties.objectid === feature.properties.objectid) {
441          campingMarkers[y].setIcon(getHighlightIcon(feature));
442          highlight = campingMarkers[y];
443          break;
444        }
445      }
446    }
447
448    // Function for removing highlight
449    function removeHighlight() {
450      // Check for highlight
451      if (highlight !== null) {
452        // Set default icon
453        highlight.setIcon(getMarkerIcon('5'));
454        // Unset highlight
455        highlight = null;
456      }
457    }
458
459    // Function for getting new highlight icon
460    function getHighlightIcon() {
461      return getMarkerIcon('zeltplatz_orange');
462    }
463  };
464
465  /**
466   * Shows routes, used only when show with other point types on same map
467   * @version 2.0
468   */
469  const showAllRoutesWithOtherPoints = function () {
470    log('showAllRoutesWithOtherPoints...');
471
472    let centerCoordinatesForCentering = [];
473    let allRoutesArray = [];
474    let data;
475    const geoJsonsArray = [];
476    let iteration = 0;
477
478    if (routeNumber !== '') {
479      allRoutesArray = routeNumber.split(',');
480    } else {
481      return;
482    }
483
484    // set all routes as not ready to show on map
485    for (const a of allRoutesArray) {
486      allRoutes[a] = false;
487    }
488
489    // check if all routes are ready to be show
490    (function showRoutesWhenReady() {
491      setTimeout(function () {
492        if (iteration++ < 100) {
493          if (!areRoutesReady()) {
494            showRoutesWhenReady();
495          } else {
496            addRoutesToMap();
497          }
498        }
499      }, 200);
500    })();
501
502    // get data for each route
503    for (const i in allRoutesArray) {
504      data = {
505        pointType: ROUTE_CODE_NUM,
506        rid: allRoutesArray[i]
507      };
508      services.ajaxCall(data, getGeoJson);
509    }
510
511    // prepare route data as geoJson and add to geoJsonsArray
512    function getGeoJson(elements) {
513      const routes = JSON.parse(elements);
514
515      for (const routeNum in routes.features) {
516        if (routes.features.hasOwnProperty(routeNum)) {
517          const route = routes.features[routeNum];
518          centerCoordinatesForCentering = centerCoordinatesForCentering.concat(route.geometry.coordinates);
519          geoJsonsArray.push(L.geoJSON(
520            route,
521            {
522              style: myRouteStyle
523            }
524          ).on('click', function (event) {
525            window.location = event.layer.feature.properties.contentpage;
526          }));
527          allRoutes[route.properties.rid] = true;
528        }
529      }
530    }
531
532    // show route data stored in geoJsonsArray on map
533    function addRoutesToMap() {
534      let arePointshownOnMap = false;
535      const tempRouteClickCluster = L.markerClusterGroup({
536        disableClusteringAtZoom: 14,
537        maxClusterRadius: clusteringDistanceInPixels
538      });
539      const tempRouteCluster = L.markerClusterGroup({
540        disableClusteringAtZoom: 14,
541        maxClusterRadius: clusteringDistanceInPixels
542      });
543      const className = 'routes-areas';
544      for (const l in geoJsonsArray) {
545        const layers = geoJsonsArray[l].getLayers();
546        for (const y in layers) {
547          const polygon = L.polygon(L.GeoJSON.coordsToLatLngs(layers[y].feature.geometry.coordinates), { color: 'red' });
548          const clickArea = L.geoJSON(polygon.toGeoJSON(), {
549            color: 'green',
550            opacity: 0.1,
551            title: layers[y].feature.properties.beschriftung,
552            url: layers[y].feature.properties.contentpage
553          }).on('click', function () {
554            log(this.options.url);
555            window.location = this.options.url;
556          }).on('mouseover', function (e) {
557            L.popup().setLatLng(e.latlng).setContent(this.options.title).openOn(map);
558          }).on('mouseout', function () {
559            map.closePopup();
560          });
561          tempRouteClickCluster.addLayer(clickArea);
562        }
563        tempRouteCluster.addLayer(geoJsonsArray[l]);
564      }
565
566      $('div#map-controls').on('click', 'button.' + className, function () {
567        const openPopup = $('.leaflet-popup-close-button');
568        if (arePointshownOnMap) {
569          map.removeLayer(tempRouteClickCluster);
570          map.removeLayer(tempRouteCluster);
571          arePointshownOnMap = false;
572        } else {
573          map.addLayer(tempRouteClickCluster);
574          map.addLayer(tempRouteCluster);
575          arePointshownOnMap = true;
576        }
577        if (openPopup.length > 0) {
578          openPopup[0].click();
579        }
580      });
581
582      // show this cluster if this type is first in the list
583      if (firstPointTypeSelected === '99') {
584        map.addLayer(tempRouteClickCluster);
585        map.addLayer(tempRouteCluster);
586        arePointshownOnMap = true;
587
588        if (centerOnPoint) {
589          // set centering points and options
590          centerCoordinates = L.GeoJSON.coordsToLatLngs(centerCoordinatesForCentering);
591          paddingBottomRight = [0, 0];
592          services.centerMap();
593        }
594      }
595    }
596
597    function areRoutesReady() {
598      for (const r in allRoutes) {
599        if (!allRoutes[r]) {
600          return allRoutes[r];
601        }
602      }
603      return true;
604    }
605  };
606
607  /**
608   * 2.0 Shows trekking routes, used only when show with other point types on same map
609   * @version 2.0
610   */
611  const showTrekkingRoutesWithOtherPoints = function () {
612    log('showTrekkingRoutesWithOtherPoints...');
613
614    let centerCoordinatesForCentering = [];
615    let trekkingRoutesArray = [];
616    let data;
617    const geoJsonsArray = [];
618    let iteration = 0;
619
620    let trekkingRouteNummer = '';
621    trekkingRouteNummer += '1,2,3,4,12,13,14,15';
622    trekkingRouteNummer += ',16,17,18,19,20';
623
624    if (trekkingRouteNummer !== '') {
625      trekkingRoutesArray = trekkingRouteNummer.split(',');
626    } else {
627      return;
628    }
629
630    // set all routes as not ready to show on map
631    for (const a of trekkingRoutesArray) {
632      allTrekkingRoutes[a] = false;
633    }
634
635    // check if all routes are ready to be show
636    (function showTrekkingRoutesWhenReady() {
637      setTimeout(function () {
638        if (iteration++ < 100) {
639          if (!areTrekkingRoutesReady() || !campingSitesLoaded) {
640            log('not ready');
641            log(campingSitesLoaded);
642            showTrekkingRoutesWhenReady();
643          } else {
644            addTrekkingRoutesToMap();
645          }
646        }
647      }, 800);
648    })();
649
650    // get data for each route
651    for (const i in trekkingRoutesArray) {
652      data = {
653        pointType: 11,
654        rid: trekkingRoutesArray[i]
655      };
656      services.ajaxCall(data, getGeoJson);
657    }
658
659    // prepare route data as geoJson and add to geoJsonsArray
660    function getGeoJson(elements) {
661      const trekkingRoutes = JSON.parse(elements);
662      for (const trekkingRouteNum in trekkingRoutes.features) {
663        if (trekkingRoutes.features.hasOwnProperty(trekkingRouteNum)) {
664          const trekkingRoute = trekkingRoutes.features[trekkingRouteNum];
665          centerCoordinatesForCentering = centerCoordinatesForCentering.concat(trekkingRoute.geometry.coordinates);
666          geoJsonsArray.push(L.geoJSON(
667            trekkingRoute,
668            {
669              style: myTrekkingRouteStyle[trekkingRoute.properties.nummer]
670            }
671          ).on('click', function (event) {
672            openSlideOrGoToPage(event.layer.feature);
673          }).on('mouseover', function (event) {
674            L.popup().setLatLng(event.latlng).setContent(event.layer.feature.properties.name).openOn(map);
675            this.bringToFront();
676            this.setStyle({
677              weight: 5
678            });
679          }).on('mouseout', function () {
680            map.closePopup();
681            this.setStyle({
682              weight: 4
683            });
684          }));
685          allTrekkingRoutes[trekkingRoute.properties.nummer] = true;
686        }
687      }
688    }
689
690    // show trekking route data stored in geoJsonsArray on map
691    function addTrekkingRoutesToMap() {
692      log('addRoutesToMap');
693
694      const tempRouteCluster = L.markerClusterGroup({
695        disableClusteringAtZoom: 14,
696        maxClusterRadius: clusteringDistanceInPixels
697      });
698      const className = 'trekking-routes';
699      let arePointshownOnMap = false;
700
701      for (const l in geoJsonsArray) {
702        tempRouteCluster.addLayer(geoJsonsArray[l]);
703      }
704
705      $('div#map-controls').on('click', 'button.' + className, function () {
706        services.closePopup();
707        if (arePointshownOnMap) {
708          map.removeLayer(tempRouteCluster);
709          map.removeLayer(campingSitesLayer);
710          arePointshownOnMap = false;
711        } else {
712          map.addLayer(tempRouteCluster);
713          map.addLayer(campingSitesLayer);
714          arePointshownOnMap = true;
715        }
716      });
717
718      if (centerOnPoint) {
719        // show this cluster if this type is first in the list
720        if (firstPointTypeSelected === '11') {
721          map.addLayer(tempRouteCluster);
722          map.addLayer(campingSitesLayer);
723          arePointshownOnMap = true;
724
725          // set centering points and options
726          centerCoordinates = L.GeoJSON.coordsToLatLngs(centerCoordinatesForCentering);
727          paddingBottomRight = [0, 0];
728          paddingTopLeft = [88, 0];
729          services.centerMap();
730        }
731      } else {
732        map.addLayer(tempRouteCluster);
733        map.addLayer(campingSitesLayer);
734      }
735    }
736
737    function areTrekkingRoutesReady() {
738      for (const r in allTrekkingRoutes) {
739        if (!allTrekkingRoutes[r]) {
740          return allTrekkingRoutes[r];
741        }
742      }
743      return true;
744    }
745  };
746
747  /**
748   * 2.0 Shows baumgiganten in combination with other point types and/or routes
749   *
750   * @version 2.0
751   */
752  const showBaumgigantenWithOtherPoints = function (type, focusOn) {
753    log('showBaumgigantenWithOtherPoints...');
754
755    const markersAll = [];
756    const markers = [];
757    const baumgigantenCluster = L.markerClusterGroup({
758      disableClusteringAtZoom: 14,
759      maxClusterRadius: clusteringDistanceInPixels
760    });
761    const data = {
762      pointType: BAUMGIGANTEN_CODE_NUM,
763      rid: 0
764    };
765    let highlight = null;
766    let pointMarker;
767    let pointsForCentering = [];
768
769    services.ajaxCall(data, addBaumgigantenToMap);
770
771    function addBaumgigantenToMap(elements) {
772      log('addBaumgigantenToMap()');
773
774      const baumgiganten = JSON.parse(elements);
775      const classNameAll = 'baumgiganten-all';
776      const classNameSpecial = 'baumgiganten-special';
777      const $mapControls = $('div#map-controls');
778      let areAllShownOnMap = false;
779      let areSpecialShowOnMap = false;
780
781      for (const baumgigant in baumgiganten.features) {
782        pointsForCentering = pointsForCentering.concat([baumgiganten.features[baumgigant].geometry.coordinates]);
783      }
784
785      const baumgigantenAllMarkers = L.geoJSON(
786        baumgiganten,
787        {
788          pointToLayer: function (feature, latlng) {
789            pointMarker = L.marker(latlng, {
790              // Set default icon
791              icon: getDefaultIcon(feature),
792              riseOnHover: true
793            });
794            pointMarker.on('click', function () {
795              changeIcon(feature, 'all');
796              selectSlideOrShowPopup(feature);
797            });
798            markersAll.push(pointMarker);
799            return pointMarker;
800          }
801        }
802      );
803
804      const baumgigantenWithTextMarkers = L.geoJSON(
805        baumgiganten,
806        {
807          filter: function (feature) {
808            return feature.properties.info === 'yes';
809          },
810          pointToLayer: function (feature, latlng) {
811            pointMarker = L.marker(latlng, {
812              // Set default icon
813              icon: getDefaultIcon(feature),
814              riseOnHover: true
815            });
816            pointMarker.on('click', function () {
817              changeIcon(feature, 'special');
818              selectSlideOrShowPopup(feature);
819            });
820            markers.push(pointMarker);
821            return pointMarker;
822          }
823        }
824      );
825
826      // ALL baumgiganten control button
827      $mapControls.on('click', 'button.' + classNameAll, function () {
828        const openPopup = $('.leaflet-popup-close-button');
829
830        if (areAllShownOnMap) {
831          // remove all from map
832
833          map.removeLayer(baumgigantenCluster);
834
835          baumgigantenCluster.removeLayer(baumgigantenAllMarkers);
836
837          map.addLayer(baumgigantenCluster);
838
839          areAllShownOnMap = false;
840        } else {
841          // add all on map
842          $('button.ctrl.baumgiganten-special').removeClass('active');
843
844          map.removeLayer(baumgigantenCluster);
845
846          baumgigantenCluster.removeLayer(baumgigantenWithTextMarkers);
847          baumgigantenCluster.addLayer(baumgigantenAllMarkers);
848
849          map.addLayer(baumgigantenCluster);
850
851          areAllShownOnMap = true;
852          areSpecialShowOnMap = false;
853        }
854        if (openPopup.length > 0) {
855          openPopup[0].click();
856        }
857      });
858
859      // Special Baumgiganten control button
860      $mapControls.on('click', 'button.' + classNameSpecial, function () {
861        const openPopup = $('.leaflet-popup-close-button');
862
863        if (areSpecialShowOnMap) {
864          // remove specials from map
865
866          map.removeLayer(baumgigantenCluster);
867
868          baumgigantenCluster.removeLayer(baumgigantenWithTextMarkers);
869
870          map.addLayer(baumgigantenCluster);
871
872          areSpecialShowOnMap = false;
873        } else {
874          // add specials to map
875
876          $('button.ctrl.baumgiganten-all').removeClass('active');
877
878          map.removeLayer(baumgigantenCluster);
879
880          baumgigantenCluster.removeLayer(baumgigantenAllMarkers);
881          baumgigantenCluster.addLayer(baumgigantenWithTextMarkers);
882
883          map.addLayer(baumgigantenCluster);
884
885          areSpecialShowOnMap = true;
886          areAllShownOnMap = false;
887        }
888        if (openPopup.length > 0) {
889          openPopup[0].click();
890        }
891      });
892
893      if (centerOnPoint) {
894        if (firstPointTypeSelected === '4') {
895          baumgigantenCluster.addLayer(baumgigantenAllMarkers);
896          map.addLayer(baumgigantenCluster);
897          areAllShownOnMap = true;
898
899          // set centering points and options
900          centerCoordinates = L.GeoJSON.coordsToLatLngs(pointsForCentering);
901          paddingBottomRight = [0, 40];
902          services.centerMap();
903        }
904      } else {
905        switch (focusOn) {
906          case 'all':
907            log('all');
908            baumgigantenCluster.addLayer(baumgigantenAllMarkers);
909            map.addLayer(baumgigantenCluster);
910            break;
911          case 'special':
912            log('special');
913            baumgigantenCluster.addLayer(baumgigantenWithTextMarkers);
914            map.addLayer(baumgigantenCluster);
915            break;
916        }
917      }
918
919      // Add map click handler, remove highlight
920      map.on('click', removeHighlight);
921    }
922
923    function selectSlideOrShowPopup(feature) {
924      log('selectSlideOrShowPopup');
925
926      if (feature.properties.contentpage === '') {
927        showPopup(feature);
928      } else {
929        log('Select Slider');
930        openOverlay(feature.properties.url);
931      }
932    }
933
934    function showPopup(feature) {
935      log('showPopup()');
936
937      const popup = L.popup({
938        offset: [0, -30]
939      });
940
941      popup.setLatLng([feature.geometry.coordinates[1], feature.geometry.coordinates[0]])
942        .setContent(popupTemplate(type, feature.properties))
943        .openOn(map);
944      popup.on('remove', function () {
945        removeHighlight();
946      });
947    }
948
949    // Changes marker icon when marker is clicked
950    function changeIcon(feature, arraySelection) {
951      log('changeIcon for tree: ' + feature.properties.baumnummer);
952
953      // Remove highlight
954      removeHighlight();
955
956      // Set highlight icon
957      switch (arraySelection) {
958        case 'all':
959          for (let i = 0; i < markersAll.length; i++) {
960            if (markersAll[i].feature.properties.baumnummer === feature.properties.baumnummer) {
961              markersAll[i].setIcon(getHighlightIcon(feature));
962              highlight = markersAll[i];
963              break;
964            }
965          }
966          break;
967        case 'special':
968          for (let y = 0; y < markers.length; y++) {
969            if (markers[y].feature.properties.baumnummer === feature.properties.baumnummer) {
970              markers[y].setIcon(getHighlightIcon(feature));
971              highlight = markers[y];
972              break;
973            }
974          }
975          break;
976      }
977    }
978
979    // Function for getting new default icon
980    function getDefaultIcon(feature) {
981      if (feature.properties.contentpage === '') {
982        return getMarkerIcon('baumgigant_dark');
983      } else {
984        return getMarkerIcon('baumgigant_light');
985      }
986    }
987
988    // Function for getting new highlight icon
989    function getHighlightIcon(feature) {
990      if (feature.properties.contentpage === '') {
991        return getMarkerIcon('baumgigant_orange');
992      } else {
993        return getMarkerIcon('baumgigant_orange_overlay');
994      }
995    }
996
997    // Function for removing highlight
998    function removeHighlight() {
999      // Check for highlight
1000      if (highlight !== null) {
1001        // Set default icon
1002        highlight.setIcon(getDefaultIcon(highlight.feature));
1003        // Unset highlight
1004        highlight = null;
1005      }
1006    }
1007  };
1008
1009  /**
1010   * 2.0 Shows Naturwaldfläche in combination with other point types and/or routes
1011   *
1012   * @version 2.0
1013   */
1014  const showNwfWithOtherPoints = function (type, focusOn) {
1015    log('showNwfWithOtherPoints()');
1016
1017    const data = {
1018      pointType: NWF_CODE_NUM,
1019      rid: 0
1020    };
1021
1022    let centerCoordinatesForCentering = [];
1023
1024    services.ajaxCall(data, addNwfToMap);
1025
1026    function addNwfToMap(elements) {
1027      log('addNwfToMap()');
1028
1029      const naturWaldFlaechen = JSON.parse(elements);
1030      const className = 'nwf-areas';
1031      let naturWaldFlaechenPoly;
1032
1033      const nwfLayers = [];
1034      for (const nwfNum in naturWaldFlaechen.features) {
1035        const nwf = naturWaldFlaechen.features[nwfNum];
1036        naturWaldFlaechenPoly = L.geoJSON(
1037          nwf,
1038          {
1039            style: myNwfStyle
1040          }
1041        ).on('click', function (event) {
1042          showPopup(nwf, event);
1043        });
1044
1045        nwfLayers.push(naturWaldFlaechenPoly);
1046
1047        if (firstPointTypeSelected === '50') {
1048          const tempArray = getAllCoordinatesForNwf(nwf.geometry.coordinates);
1049          centerCoordinatesForCentering.push(...tempArray);
1050        } else if (nwf.properties.objectId === '4255') {
1051          centerCoordinatesForCentering = getAllCoordinatesForNwf(nwf.geometry.coordinates);
1052        }
1053      }
1054
1055      const nwfLayerGroup = L.layerGroup(nwfLayers);
1056
1057      $('div#map-controls').on('click', 'button.' + className, function () {
1058        services.closePopup();
1059        const state = $('div#map-controls button.nwf-areas').hasClass('active');
1060        if (state) {
1061          map.addLayer(nwfLayerGroup);
1062        } else {
1063          map.removeLayer(nwfLayerGroup);
1064        }
1065      });
1066
1067      if (centerOnPoint) {
1068        map.addLayer(nwfLayerGroup);
1069        centerCoordinates = L.GeoJSON.coordsToLatLngs(centerCoordinatesForCentering);
1070        paddingBottomRight = [0, 0];
1071        paddingTopLeft = [88, 0];
1072        services.centerMap();
1073      } else {
1074        map.addLayer(nwfLayerGroup);
1075      }
1076
1077      const state = $('div#map-controls button.nwf-areas').hasClass('active');
1078      if (state) {
1079        map.addLayer(nwfLayerGroup);
1080      } else {
1081        map.removeLayer(nwfLayerGroup);
1082      }
1083    }
1084
1085    function getAllCoordinatesForNwf(arr) {
1086      const allCoordinates = [];
1087      for (let i = 0; i < arr.length; i++) {
1088        for (let j = 0; j < arr[i].length; j++) {
1089          for (let k = 0; k < arr[i][j].length; k++) {
1090            allCoordinates.push(arr[i][j][k]);
1091          }
1092        }
1093      }
1094      return allCoordinates;
1095    }
1096
1097    function showPopup(feature, event) {
1098      log('showPopup()');
1099
1100      const popup = L.popup({
1101        offset: [0, -30]
1102      });
1103      log(feature.properties);
1104      popup.setLatLng(event.latlng)
1105        .setContent(popupTemplate('50', feature.properties))
1106        .openOn(map);
1107    }
1108  };
1109
1110  /**
1111   * 2.0 Shows Trittsteine in combination with other point types and/or routes
1112   *
1113   * @version 2.0
1114   */
1115  const showTrittsteineWithOtherPoints = function (type, focusOn) {
1116    log('showTrittsteineWithOtherPoints...');
1117
1118    const markersAll = [];
1119    const markers = [];
1120    const trittsteineCluster = L.markerClusterGroup({
1121      disableClusteringAtZoom: 14,
1122      maxClusterRadius: clusteringDistanceInPixels
1123    });
1124    const data = {
1125      pointType: TRITTSTEINE_CODE_NUM,
1126      rid: 0
1127    };
1128    let highlight = null;
1129    let pointMarker;
1130    let pointsForCentering = [];
1131
1132    services.ajaxCall(data, addTrittsteineToMap);
1133
1134    function addTrittsteineToMap(elements) {
1135      log('addTrittsteineToMap()');
1136
1137      const trittsteine = JSON.parse(elements);
1138      const classNameAll = 'trittsteine-all';
1139      const classNameSpecial = 'trittsteine-special';
1140      const $mapControls = $('div#map-controls');
1141      let areAllShownOnMap = false;
1142      let areSpecialShowOnMap = false;
1143
1144      for (const trittstein in trittsteine.features) {
1145        pointsForCentering = pointsForCentering.concat([trittsteine.features[trittstein].geometry.coordinates]);
1146      }
1147
1148      const trittsteineAllMarkers = L.geoJSON(
1149        trittsteine,
1150        {
1151          pointToLayer: function (feature, latlng) {
1152            pointMarker = L.marker(latlng, {
1153              // Set default icon
1154              icon: getDefaultIcon(feature),
1155              riseOnHover: true
1156            });
1157            pointMarker.on('click', function () {
1158              changeIcon(feature, 'all');
1159              selectSlideOrShowPopup(feature);
1160            });
1161            markersAll.push(pointMarker);
1162            return pointMarker;
1163          }
1164        }
1165      );
1166
1167      const trittsteineWithTextMarkers = L.geoJSON(
1168        trittsteine,
1169        {
1170          filter: function (feature) {
1171            return feature.properties.info === 'yes';
1172          },
1173          pointToLayer: function (feature, latlng) {
1174            pointMarker = L.marker(latlng, {
1175              // Set default icon
1176              icon: getDefaultIcon(feature),
1177              riseOnHover: true
1178            });
1179            pointMarker.on('click', function () {
1180              changeIcon(feature, 'special');
1181              selectSlideOrShowPopup(feature);
1182            });
1183            markers.push(pointMarker);
1184            return pointMarker;
1185          }
1186        }
1187      );
1188
1189      // ALL trittsteine control button
1190      $mapControls.on('click', 'button.' + classNameAll, function () {
1191        const openPopup = $('.leaflet-popup-close-button');
1192
1193        if (areAllShownOnMap) {
1194          // remove all from map
1195
1196          map.removeLayer(trittsteineCluster);
1197
1198          trittsteineCluster.removeLayer(trittsteineAllMarkers);
1199
1200          map.addLayer(trittsteineCluster);
1201
1202          areAllShownOnMap = false;
1203        } else {
1204          // add all on map
1205          $('button.ctrl.trittsteine-special').removeClass('active');
1206
1207          map.removeLayer(trittsteineCluster);
1208
1209          trittsteineCluster.removeLayer(trittsteineWithTextMarkers);
1210          trittsteineCluster.addLayer(trittsteineAllMarkers);
1211
1212          map.addLayer(trittsteineCluster);
1213
1214          areAllShownOnMap = true;
1215          areSpecialShowOnMap = false;
1216        }
1217        if (openPopup.length > 0) {
1218          openPopup[0].click();
1219        }
1220      });
1221
1222      // Special Trittsteine control button
1223      $mapControls.on('click', 'button.' + classNameSpecial, function () {
1224        const openPopup = $('.leaflet-popup-close-button');
1225
1226        if (areSpecialShowOnMap) {
1227          // remove specials from map
1228
1229          map.removeLayer(trittsteineCluster);
1230
1231          trittsteineCluster.removeLayer(trittsteineWithTextMarkers);
1232
1233          map.addLayer(trittsteineCluster);
1234
1235          areSpecialShowOnMap = false;
1236        } else {
1237          // add specials to map
1238
1239          $('button.ctrl.trittsteine-all').removeClass('active');
1240
1241          map.removeLayer(trittsteineCluster);
1242
1243          trittsteineCluster.removeLayer(trittsteineAllMarkers);
1244          trittsteineCluster.addLayer(trittsteineWithTextMarkers);
1245
1246          map.addLayer(trittsteineCluster);
1247
1248          areSpecialShowOnMap = true;
1249          areAllShownOnMap = false;
1250        }
1251        if (openPopup.length > 0) {
1252          openPopup[0].click();
1253        }
1254      });
1255
1256      if (centerOnPoint) {
1257        if (firstPointTypeSelected === '6') {
1258          trittsteineCluster.addLayer(trittsteineAllMarkers);
1259          map.addLayer(trittsteineCluster);
1260          areAllShownOnMap = true;
1261
1262          // set centering points and options
1263          centerCoordinates = L.GeoJSON.coordsToLatLngs(pointsForCentering);
1264          paddingBottomRight = [0, 40];
1265          services.centerMap();
1266        }
1267      } else {
1268        switch (focusOn) {
1269          case 'all':
1270            log('all');
1271            trittsteineCluster.addLayer(trittsteineAllMarkers);
1272            map.addLayer(trittsteineCluster);
1273            break;
1274          case 'special':
1275            log('special');
1276            trittsteineCluster.addLayer(trittsteineWithTextMarkers);
1277            map.addLayer(trittsteineCluster);
1278            break;
1279        }
1280      }
1281
1282      // Add map click handler, remove highlight
1283      map.on('click', removeHighlight);
1284    }
1285
1286    function selectSlideOrShowPopup(feature) {
1287      log('selectSlideOrShowPopup');
1288
1289      if (feature.properties.contentpage === '') {
1290        showPopup(feature);
1291      } else {
1292        log('Select Slider');
1293        openOverlay(feature.properties.url);
1294      }
1295    }
1296
1297    function showPopup(feature) {
1298      log('showPopup()');
1299
1300      const popup = L.popup({
1301        offset: [0, -30]
1302      });
1303
1304      popup.setLatLng([feature.geometry.coordinates[1], feature.geometry.coordinates[0]])
1305        .setContent(popupTemplate(type, feature.properties))
1306        .openOn(map);
1307      popup.on('remove', function () {
1308        removeHighlight();
1309      });
1310    }
1311
1312    // Changes marker icon when marker is clicked
1313    function changeIcon(feature, arraySelection) {
1314      log('changeIcon for tree: ' + feature.properties.id);
1315
1316      // Remove highlight
1317      removeHighlight();
1318
1319      // Set highlight icon
1320      switch (arraySelection) {
1321        case 'all':
1322          for (let i = 0; i < markersAll.length; i++) {
1323            if (markersAll[i].feature.properties.id === feature.properties.id) {
1324              markersAll[i].setIcon(getHighlightIcon(feature));
1325              highlight = markersAll[i];
1326              break;
1327            }
1328          }
1329          break;
1330        case 'special':
1331          for (let y = 0; y < markers.length; y++) {
1332            if (markers[y].feature.properties.id === feature.properties.id) {
1333              markers[y].setIcon(getHighlightIcon(feature));
1334              highlight = markers[y];
1335              break;
1336            }
1337          }
1338          break;
1339      }
1340    }
1341
1342    // Function for getting new default icon
1343    function getDefaultIcon(feature) {
1344      if (feature.properties.contentpage === '') {
1345        return getMarkerIcon('trittstein');
1346      } else {
1347        return getMarkerIcon('trittstein_description');
1348      }
1349    }
1350
1351    // Function for getting new highlight icon
1352    function getHighlightIcon(feature) {
1353      if (feature.properties.contentpage === '') {
1354        return getMarkerIcon('trittstein_active');
1355      } else {
1356        return getMarkerIcon('trittstein_description_active');
1357      }
1358    }
1359
1360    // Function for removing highlight
1361    function removeHighlight() {
1362      // Check for highlight
1363      if (highlight !== null) {
1364        // Set default icon
1365        highlight.setIcon(getDefaultIcon(highlight.feature));
1366        // Unset highlight
1367        highlight = null;
1368      }
1369    }
1370  };
1371
1372  /**
1373   * Show one route on single page route view
1374   * singlePageRouteViewAction in BaumgigantController
1375   * @version 2.0
1376   */
1377  const showRouteSinglePageView = function () {
1378    log('showRoute()');
1379
1380    // Number 10 for route
1381    const data = {
1382      pointType: ROUTE_CODE_NUM,
1383      rid: routeNumber
1384    };
1385
1386    services.ajaxCall(data, addRoutesToMap);
1387
1388    function addRoutesToMap(elements) {
1389      const routes = JSON.parse(elements);
1390
1391      for (const route in routes.features) {
1392        if (routes.features.hasOwnProperty(route)) {
1393          const r = routes.features[route];
1394          centerCoordinates = centerCoordinates.concat(r.geometry.coordinates);
1395          L.geoJSON(
1396            r,
1397            {
1398              style: myRouteStyle
1399            }
1400          ).addTo(map);
1401        }
1402      }
1403      if (centerOnRouteOnly) {
1404        log('centerMapOnRoute() - route');
1405
1406        // set centering points and options
1407        centerCoordinates = L.GeoJSON.coordsToLatLngs(centerCoordinates);
1408        paddingBottomRight = [0, 100];
1409        services.centerMap();
1410      }
1411      showPointsOfInterestOnRouteSinglePageView();
1412    }
1413  };
1414
1415  /**
1416   * Shows point of interest belonging to one route
1417   * @version 2.0
1418   */
1419  const showPointsOfInterestOnRouteSinglePageView = function () {
1420    const markers = [];
1421    const data = {
1422      pointType: POINTS_OF_INTEREST_CODE_NUM,
1423      rid: routeNumber
1424    }; // use this as parameter for switch function in backend Action to fetch correct JSON data
1425    const cluster = L.markerClusterGroup({
1426      disableClusteringAtZoom: 14
1427    });
1428    let pointMarker;
1429    let highlight = null;
1430
1431    services.ajaxCall(data, addPointOfInterestToMap);
1432
1433    function addPointOfInterestToMap(elements) {
1434      const pois = JSON.parse(elements);
1435      for (const poi in pois.features) {
1436        if (!centerOnRouteOnly) {
1437          centerCoordinates = centerCoordinates.concat([pois.features[poi].geometry.coordinates]);
1438        }
1439      }
1440
1441      const poisMarkers = L.geoJSON(
1442        pois,
1443        {
1444          pointToLayer: function (feature, latlng) {
1445            pointMarker = L.marker(latlng, {
1446              // Set default icon
1447              icon: getDefaultIcon(feature),
1448              riseOnHover: true
1449            });
1450            pointMarker.on('click', function () {
1451              log(feature.properties);
1452              changeIcon(feature);
1453              scrollToContent(feature);
1454            });
1455            markers.push(pointMarker);
1456            return pointMarker;
1457          }
1458        }
1459      );
1460
1461      cluster.addLayer(poisMarkers);
1462      map.addLayer(cluster);
1463
1464      // Add map click handler, remove highlight
1465      map.on('click', function () {
1466        removeHighlight();
1467        // $('button.overlay__close').click();
1468      });
1469    }
1470
1471    function scrollToContent(feature) {
1472      log('scroll to content');
1473      const $contentDiv = $('[data-poi="' + feature.properties.pUid + '"]');
1474      log(feature.properties.pUid);
1475      log($contentDiv);
1476      $('html, body').animate({
1477        scrollTop: $($contentDiv).offset().top - $('.header').height()
1478      }, 1000);
1479    }
1480
1481    // Changes marker icon when marker is clicked
1482    function changeIcon(feature) {
1483      // Remove highlight
1484      removeHighlight();
1485
1486      // Set highlight icon
1487      for (let i = 0; i < markers.length; i++) {
1488        if (markers[i].feature.properties.pointid === feature.properties.pointid) {
1489          markers[i].options.zIndexOffset = 10000;
1490          markers[i].setIcon(getHighlightIcon(feature.properties.positionOnRoute));
1491          highlight = markers[i];
1492          break;
1493        } else {
1494          markers[i].options.zIndexOffset = 0;
1495        }
1496      }
1497    }
1498
1499    // Function for getting new default icon
1500    function getDefaultIcon(feature) {
1501      return L.divIcon({
1502        className: 'route-marker',
1503        html: feature.properties.positionOnRoute,
1504        iconSize: [15, 15]
1505      });
1506    }
1507
1508    // Function for getting new highlight icon
1509    function getHighlightIcon(position) {
1510      return L.divIcon({
1511        className: 'route-marker route-marker--highlighted',
1512        html: position,
1513        iconSize: [15, 15]
1514      });
1515    }
1516
1517    // Function for removing highlight
1518    function removeHighlight() {
1519      log('removeHighlight()');
1520      // Check for highlight
1521      if (highlight !== null) {
1522        log('removing highlighting');
1523        // Set default icon
1524        highlight.setIcon(getDefaultIcon(highlight.feature));
1525        // Unset highlight
1526        highlight = null;
1527      }
1528    }
1529  };
1530
1531  /**
1532   * returns correct marker for given type of point
1533   * @param type
1534   * @returns {*}
1535   */
1536  const getMarkerIcon = function (type) {
1537    let iconUrl;
1538
1539    switch (type) {
1540      case 'baumgigant_light':
1541        iconUrl = '/fileadmin/Icons/Baumgigant_with_overlay_lightgreen.png';
1542        break;
1543      case 'baumgigant_dark':
1544        iconUrl = '/fileadmin/Icons/Baumgigant_darkgreen.png';
1545        break;
1546      case 'baumgigant_orange':
1547        iconUrl = '/fileadmin/Icons/Baumgigant_orange.png';
1548        break;
1549      case 'baumgigant_orange_overlay':
1550        iconUrl = '/fileadmin/Icons/Baumgigant_with_overlay_orange.png';
1551        break;
1552      case 'trittstein':
1553        iconUrl = '/fileadmin/Icons/trittstein.png';
1554        break;
1555      case 'trittstein_description':
1556        iconUrl = '/fileadmin/Icons/trittstein_description.png';
1557        break;
1558      case 'trittstein_active':
1559        iconUrl = '/fileadmin/Icons/trittstein_active.png';
1560        break;
1561      case 'trittstein_description_active':
1562        iconUrl = '/fileadmin/Icons/trittstein_description_active.png';
1563        break;
1564      case 'zeltplatz_orange':
1565        iconUrl = '/fileadmin/Icons/Zeltplatz_orange.png';
1566        break;
1567      case '1':
1568        iconUrl = '/fileadmin/Icons/Einkehrmoeglichkeiten_darkgreen.png';
1569        break;
1570      case '2':
1571        iconUrl = '/fileadmin/Icons/Ausflugsziel.png';
1572        break;
1573      case '5':
1574        iconUrl = '/fileadmin/Icons/Zeltplatz.png';
1575        break;
1576      case '6':
1577        iconUrl = '/fileadmin/Icons/Trittstein_darkgreen.png';
1578        break;
1579      case '8':
1580        iconUrl = '/fileadmin/Icons/Rettungspunkt.png';
1581        break;
1582      case '9':
1583        iconUrl = '/fileadmin/Icons/Parkplatz.png';
1584        break;
1585      case '80':
1586        iconUrl = '/fileadmin/Icons/iNaturalist.png';
1587        break;
1588    }
1589    return new CustomIcon({
1590      iconUrl: iconUrl
1591    });
1592  };
1593
1594  const getINaturalistIcon = function (feature) {
1595    let iconUrl;
1596
1597    switch (feature.properties.type) {
1598      case 'Actinopterygii':
1599        iconUrl = '/fileadmin/Icons/iNaturalist_Blue.png';
1600        break;
1601      case 'Amphibia':
1602        iconUrl = '/fileadmin/Icons/iNaturalist_Blue.png';
1603        break;
1604      case 'Arachnida':
1605        iconUrl = '/fileadmin/Icons/iNaturalist_Blue.png';
1606        break;
1607      case 'Aves':
1608        iconUrl = '/fileadmin/Icons/iNaturalist_Blue.png';
1609        break;
1610      case 'Fungi':
1611        iconUrl = '/fileadmin/Icons/iNaturalist_Magenta.png';
1612        break;
1613      case 'Insecta':
1614        iconUrl = '/fileadmin/Icons/iNaturalist_Orange.png';
1615        break;
1616      case 'Mammalia':
1617        iconUrl = '/fileadmin/Icons/iNaturalist_Blue.png';
1618        break;
1619      case 'Mollusca':
1620        iconUrl = '/fileadmin/Icons/iNaturalist_Orange.png';
1621        break;
1622      case 'Plantae':
1623        iconUrl = '/fileadmin/Icons/iNaturalist_Green.png';
1624        break;
1625      default:
1626        iconUrl = '/fileadmin/Icons/iNaturalist_Grey.png';
1627        break;
1628    }
1629
1630    return new CustomIcon({
1631      iconUrl: iconUrl
1632    });
1633  };
1634
1635  // START Popup templates
1636  const popupTemplate = function (type, properties) {
1637    let template;
1638
1639    switch (type) {
1640      case '1':
1641        template = popupEinkehrTemplate(properties);
1642        break;
1643      case '2':
1644        template = popupAusflugzielTemplate(properties);
1645        break;
1646      case '4':
1647        template = popupBaumgigantTemplate(properties);
1648        break;
1649      case '5':
1650        template = popupZeltplatzTemplate(properties);
1651        break;
1652      case '6':
1653        template = popupTrittsteinTemplate(properties);
1654        break;
1655      case '8':
1656        template = popupRettungspunkteTemplate(properties);
1657        break;
1658      case '9':
1659        template = popupParkplatzTemplate(properties);
1660        break;
1661      case '50':
1662        template = popupNwfTemplate(properties);
1663        break;
1664      case '80':
1665        template = popupObservationTemplate(properties);
1666        break;
1667    }
1668    return template;
1669  };
1670
1671  const popupObservationTemplate = function (properties) {
1672    const name = services.capitalize(properties.name);
1673    const taxonCommonName = services.capitalize(properties.taxonCommonName);
1674    const place = services.capitalize(properties.place);
1675    let title = '';
1676    let content = '';
1677
1678    if (name !== '') {
1679      title += name + ' / ' + taxonCommonName;
1680    } else {
1681      title = taxonCommonName;
1682    }
1683    const taxonName = services.capitalize(properties.taxonName);
1684    const url = properties.url;
1685    const photo = properties.photo;
1686    const date = properties.date;
1687    content += `
1688<div class="inaturalist-popup">
1689  <a class="inaturalist-popup__image" href="${url}" target="_blank">
1690    <img src="${photo}" alt="">
1691  </a>
1692
1693  <h2>
1694    <a href="${url}" target="_blank">
1695      ${title}
1696    </a>
1697    <p>
1698      (${taxonName})
1699    </p>
1700  </h2>
1701
1702  <div class="inaturalist-popup__place">${place}</div>
1703
1704  <div class="inaturalist-popup__date">${date}</div>
1705</div>
1706    `;
1707
1708    return content;
1709  };
1710
1711  const popupParkplatzTemplate = function (properties) {
1712    let content = '<strong>Parkplatz</strong><br>';
1713    log(properties);
1714    if (properties.typ !== '') {
1715      content += properties.typ + '<br>';
1716    }
1717
1718    if (properties.beschreibung !== '') {
1719      content += properties.beschreibung + '<br>';
1720    }
1721
1722    if (properties.link !== '') {
1723      content += properties.link + '<br>';
1724    }
1725    return content;
1726  };
1727
1728  const popupRettungspunkteTemplate = function (properties) {
1729    let content = '<strong>Rettungspunkt</strong><br>';
1730
1731    content += 'Rettungspunktnummer: ' + properties.retpktnr;
1732    return content;
1733  };
1734
1735  const popupEinkehrTemplate = function (properties) {
1736    let content = '<strong>Einkehrmöglichkeit</strong><br>';
1737    const name = properties.name;
1738    let description = properties.url;
1739
1740    log(name);
1741    log(description);
1742    if (description.indexOf('http') > -1) {
1743      let title;
1744      if (description.indexOf('https') > -1) {
1745        log('s');
1746        title = description.substr(8, description.length - 1);
1747        log(title);
1748      } else {
1749        log('not s');
1750        title = description.substr(7, description.length - 1);
1751      }
1752      if (title.length > 0) {
1753        if (title.charAt(title.length - 1) === '/') {
1754          title = title.slice(0, -1);
1755        }
1756      }
1757      description = '<a href="' + description + '" target="_blank">' + title + '</a>';
1758      log(description);
1759    }
1760
1761    if (name !== '') {
1762      content += '<br>' + name + '<br>';
1763    }
1764
1765    if (description !== '') {
1766      content += description + '<br>';
1767    }
1768    return content;
1769  };
1770
1771  const popupAusflugzielTemplate = function (properties) {
1772    let content = '<h4><strong>Ausflugziel</strong></h4>';
1773
1774    content += `<div>Typ: ${properties.typ} </div>`;
1775    content += `<div>Beschreibung: ${properties.beschreibung}</div>`;
1776    content += (properties.url !== '') ? `<a href="${properties.url}" target="_blank">Website</a>` : '';
1777    return content;
1778  };
1779
1780  const popupZeltplatzTemplate = function (properties) {
1781    let content = '<strong>Zeltplatz</strong><br>';
1782
1783    content += 'Name: ' + properties.name + '<br>';
1784    content += 'Beschreibung: ' + properties.beschreibung + '<br>';
1785    return content;
1786  };
1787
1788  const popupTrittsteinTemplate = function (properties) {
1789    let content = '<strong>Trittstein</strong><br>';
1790
1791    content += 'Trittsteintyp: ' + properties.trittsteintyp + '<br>';
1792    content += 'Name: ' + properties.name + '<br>';
1793    content += 'Beschreibung: ' + properties.beschreibung + '<br>';
1794    content += 'Fläche (ha): ' + properties.flaeche + '<br>';
1795    return content;
1796  };
1797
1798  const popupBaumgigantTemplate = function (properties) {
1799    let content = '<strong>Baumgigant</strong><br>';
1800
1801    // content += 'Baumnummer: ' + properties.baumnummer + '<br>';
1802    // content += 'Name: ' + properties.name + '<br>';
1803    // content += 'Besonderheit: ' + properties.besonderheit + '<br>';
1804    content += 'Baumart: ' + properties.baumart + '<br>';
1805    // content += 'Revier: ' + properties.rev + '<br>';
1806    return content;
1807  };
1808
1809  const popupNwfTemplate = function (properties) {
1810    let content = '<strong>' + properties.nwfName + '</strong><br>';
1811
1812    if (properties.link) {
1813      content += '<a href="' + properties.link + '">Mehr</a><br>';
1814    }
1815    return content;
1816  };
1817  // END Popup templates
1818
1819  const openSlideOrGoToPage = function (feature) {
1820    log('openSlideOrGoToPage()');
1821    if (feature.properties.internal === 1) {
1822      openOverlay(feature.properties.url);
1823    } else {
1824      log('Open external url');
1825      if (feature.properties.url !== '') {
1826        Object.assign(document.createElement('a'), {
1827          target: '_blank',
1828          href: feature.properties.url
1829        }).click();
1830      }
1831    }
1832  };
1833
1834  const openOverlay = function (url) {
1835    log('openOverlay() - ' + url);
1836
1837    Slider.removeDeepLink();
1838    Overlay.showOverlay(url, 1, false);
1839  };
1840
1841  const initializeMap = function () {
1842    map = L.map(
1843      'mapid',
1844      {
1845        maxBoundsViscosity: 0.9
1846      }
1847    );
1848
1849    // For changing to openstreetmaps
1850    // const osmUrl = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
1851    // const osmAttrib = '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors';
1852    // osm = new L.TileLayer(osmUrl, { minZoom: 10, maxZoom: 18, attribution: osmAttrib });
1853    // map.addLayer(osm);
1854    L.esri.basemapLayer('Topographic').addTo(map);
1855    map.zoomControl.remove();
1856
1857    map.addControl(new CenterMapControl());
1858
1859    switch (maptype) {
1860      case 'singlePageRouteView':
1861        showRouteSinglePageView();
1862        // eslint-disable-next-line no-undef
1863        SinglePageRouteView.init();
1864        break;
1865      case 'multiplePoints':
1866        // point types are selected in typo3 backend
1867        showMultiplePointsWithSwitchMenu(true, specialPointsCodeNum);
1868        // eslint-disable-next-line no-undef
1869        ControlOverlay.init();
1870        break;
1871    }
1872    locateUser();
1873  };
1874
1875  return {
1876    initializeMap,
1877    showMultiplePointsWithSwitchMenu
1878  };
1879})(window.document);
1880
1881document.addEventListener(
1882  'DOMContentLoaded', function () {
1883    if (document.querySelector('.tx-q4u-gis-maps') != null) {
1884      Q4UMap.initializeMap();
1885    }
1886  }
1887);

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.