xref: /webtrees/resources/views/modules/place-hierarchy/map.phtml (revision 75f2a4831adecfe14c5b50312beb437d05654f96)
1a634ddebSGreg Roach<?php
2a634ddebSGreg Roach
310e06497SGreg Roachdeclare(strict_types=1);
410e06497SGreg Roach
5a634ddebSGreg Roachuse Fisharebest\Webtrees\View;
6a634ddebSGreg Roach
77c2c99faSGreg Roach/**
87c2c99faSGreg Roach * @var array<mixed> $data
9c9c6f2ecSGreg Roach * @var object       $leaflet_config
107c2c99faSGreg Roach */
117c2c99faSGreg Roach
12a634ddebSGreg Roach?>
13a634ddebSGreg Roach
1455ea0389SGreg Roach<div class="row gchart wt-place-hierarchy-wrapper wt-fullscreen-container">
15*75f2a483SDavid Drury    <div id="wt-map" class="col-sm-9 wt-ajax-load wt-map" dir="ltr"></div>
16*75f2a483SDavid Drury    <ul class="col-sm-3 wt-map-sidebar wt-page-options-value list-unstyled px-md-1 mb-0"></ul>
17a634ddebSGreg Roach</div>
18a634ddebSGreg Roach
19a634ddebSGreg Roach<?php View::push('javascript') ?>
2074b9ba3fSGreg Roach<script>
21c68bbde3SGreg Roach  'use strict';
22a634ddebSGreg Roach
23bd6ca2dbSDavid Drury  (function () {
24728c8c27SGreg Roach    const config = <?= json_encode($leaflet_config, JSON_THROW_ON_ERROR) ?>;
25a634ddebSGreg Roach
26a634ddebSGreg Roach    let map = null;
27*75f2a483SDavid Drury    const sidebar = document.querySelector('.wt-map-sidebar');
28bd6ca2dbSDavid Drury
29bd6ca2dbSDavid Drury    const scrollOptions = {
30bd6ca2dbSDavid Drury      behavior: "smooth",
31aeea31bdSGreg Roach      block: "nearest",
32bd6ca2dbSDavid Drury      inline: "start"
33bd6ca2dbSDavid Drury    };
34ab039d30SDavid Drury
35ab039d30SDavid Drury    // Map components
36a634ddebSGreg Roach    let markers = L.markerClusterGroup({
37a634ddebSGreg Roach      showCoverageOnHover: false,
38a634ddebSGreg Roach    });
39a634ddebSGreg Roach
40f352d954SDavid Drury    /**
41f352d954SDavid Drury     * Passed to resetControl to
42f352d954SDavid Drury     * perform necessary reset actions on map
43b2e5f20eSGreg Roach     *
44b2e5f20eSGreg Roach     * @param {Event} event
45f352d954SDavid Drury     */
46b2e5f20eSGreg Roach    let resetCallback = function (event) {
47b2e5f20eSGreg Roach      event.preventDefault();
48c68bbde3SGreg Roach      map.flyToBounds(markers.getBounds(), { padding: [50, 30], maxZoom: 15 });
49b2e5f20eSGreg Roach    };
50a634ddebSGreg Roach
51ab039d30SDavid Drury    /**
52ab039d30SDavid Drury     * @private
53ab039d30SDavid Drury     */
54ab039d30SDavid Drury    let _drawMap = function () {
55b7b71725SGreg Roach      map = webtrees.buildLeafletJsMap('wt-map', config, resetCallback);
56a634ddebSGreg Roach    };
57a634ddebSGreg Roach
58ab039d30SDavid Drury    /**
59ab039d30SDavid Drury     * @private
60ab039d30SDavid Drury     */
61ab039d30SDavid Drury    let _buildMapData = function () {
62728c8c27SGreg Roach      let data = <?= json_encode($data['markers'], JSON_THROW_ON_ERROR) ?>;
63a634ddebSGreg Roach
64ab039d30SDavid Drury      let geoJsonLayer = L.geoJson(data, {
65a634ddebSGreg Roach        pointToLayer: function (feature, latlng) {
66a634ddebSGreg Roach          return new L.Marker(latlng, {
67a634ddebSGreg Roach            icon: L.BeautifyIcon.icon({
68a634ddebSGreg Roach              icon: 'bullseye fas',
69c68bbde3SGreg Roach              borderColor: 'transparent',
70a634ddebSGreg Roach              backgroundColor: '#1e90ff',
71c68bbde3SGreg Roach              iconShape: 'marker',
72c68bbde3SGreg Roach              textColor: 'white',
73a634ddebSGreg Roach            }),
74a634ddebSGreg Roach            title: feature.properties.tooltip,
75a634ddebSGreg Roach            id: feature.id,
76a634ddebSGreg Roach          })
77c68bbde3SGreg Roach            .on('popupopen', function (e) {
78bd6ca2dbSDavid Drury              let item = document.querySelector('.mapped[data-wt-feature-id="' + e.target.feature.id + '"]');
79bd6ca2dbSDavid Drury              item.classList.add('messagebox');
80bd6ca2dbSDavid Drury              item.scrollIntoView(scrollOptions);
81a634ddebSGreg Roach            })
82c68bbde3SGreg Roach            .on('popupclose', function () {
83bd6ca2dbSDavid Drury              sidebar.querySelectorAll('.mapped').forEach(e => e.classList.remove('messagebox'));
84a634ddebSGreg Roach            });
85a634ddebSGreg Roach        },
86a634ddebSGreg Roach        onEachFeature: function (feature, layer) {
87a634ddebSGreg Roach          layer.bindPopup(feature.properties.popup);
88a634ddebSGreg Roach        },
89a634ddebSGreg Roach      });
90a634ddebSGreg Roach
91a634ddebSGreg Roach      if (data.features.length > 0) {
92a634ddebSGreg Roach        markers.addLayer(geoJsonLayer);
93c68bbde3SGreg Roach        map.addLayer(markers);
9479de923dSGreg Roach      }
95ab039d30SDavid Drury
96728c8c27SGreg Roach      map.fitBounds(<?= json_encode($data['bounds'], JSON_THROW_ON_ERROR) ?>, { padding: [50, 30] });
97bd6ca2dbSDavid Drury      sidebar.innerHTML = <?= json_encode($data['sidebar'], JSON_THROW_ON_ERROR) ?>;
98a634ddebSGreg Roach   };
99a634ddebSGreg Roach
100bd6ca2dbSDavid Drury    window.onload = function() {
101a634ddebSGreg Roach      // Activate marker popup when sidebar entry clicked
102bd6ca2dbSDavid Drury      sidebar.querySelectorAll('.mapped').forEach((element) => {
103bd6ca2dbSDavid Drury        var eventId = parseInt(element.dataset.wtFeatureId);
104bd6ca2dbSDavid Drury
105bd6ca2dbSDavid Drury        element.addEventListener('click', () => {
106a634ddebSGreg Roach          // first close any existing
107a634ddebSGreg Roach          map.closePopup();
108a634ddebSGreg Roach          //find the marker corresponding to the clicked event
109a634ddebSGreg Roach          let mkrLayer = markers.getLayers().filter(function (v) {
110bd6ca2dbSDavid Drury            return v.feature !== undefined && v.feature.id === eventId;
111a634ddebSGreg Roach          });
112bd6ca2dbSDavid Drury
113a634ddebSGreg Roach          let mkr = mkrLayer.pop();
114bd6ca2dbSDavid Drury
115a634ddebSGreg Roach          markers.zoomToShowLayer(mkr, function (e) {
116a634ddebSGreg Roach            mkr.openPopup();
117a634ddebSGreg Roach          });
118bd6ca2dbSDavid Drury
119a634ddebSGreg Roach          return false;
120bd6ca2dbSDavid Drury        });
121bd6ca2dbSDavid Drury
122bd6ca2dbSDavid Drury        // stop clicking on a person also opening the popup
123bd6ca2dbSDavid Drury        element.querySelectorAll('a').forEach((el) => {
124bd6ca2dbSDavid Drury          el.addEventListener('click', (e) => {
125a634ddebSGreg Roach            e.stopPropagation();
126a634ddebSGreg Roach          });
127a634ddebSGreg Roach        });
128bd6ca2dbSDavid Drury      });
129bd6ca2dbSDavid Drury    }
130a634ddebSGreg Roach
131a634ddebSGreg Roach    _drawMap();
132ab039d30SDavid Drury    _buildMapData();
133a634ddebSGreg Roach  })();
134a634ddebSGreg Roach</script>
135a634ddebSGreg Roach<?php View::endpush() ?>
136