xref: /webtrees/resources/views/modules/places/tab.phtml (revision 4e54fb47ea2fc584c07c0c135853d49a85735c1a)
1<?php
2
3declare(strict_types=1);
4
5use Fisharebest\Webtrees\I18N;
6
7/**
8 * @var array<mixed> $data
9 * @var object       $leaflet_config
10 */
11
12?>
13
14<div class="row gchart wt-places-tab-wrapper wt-fullscreen-container">
15    <div id="wt-map" class="col-sm-9 wt-ajax-load wt-map" dir="ltr"></div>
16    <ul class="col-sm-3 wt-map-sidebar wt-page-options-value list-unstyled px-md-1"></ul>
17</div>
18
19<script>
20  'use strict';
21
22  (function () {
23    const config = <?= json_encode($leaflet_config, JSON_THROW_ON_ERROR) ?>;
24
25    let map = null;
26    const sidebar = document.querySelector('.wt-map-sidebar');
27
28    const scrollOptions = {
29      behavior: "smooth",
30      block: "nearest",
31      inline: "start"
32    };
33
34    // Map components
35    let markers = L.markerClusterGroup({
36        showCoverageOnHover: false,
37    });
38
39    /**
40     * Passed to resetControl to
41     * perform necessary reset actions on map
42     *
43     * @param {Event} event
44     */
45    let resetCallback = function (event) {
46      event.preventDefault();
47      map.flyToBounds(markers.getBounds(), {padding: [50, 30], maxZoom: 15 });
48    }
49
50    /**
51     *
52     * @private
53     */
54    let _drawMap = function() {
55      map = webtrees.buildLeafletJsMap('wt-map', config, resetCallback);
56    };
57
58    /**
59     *
60     * @private
61     */
62    let _buildMapData = function() {
63      let data = <?= json_encode($data, JSON_THROW_ON_ERROR) ?>;
64
65      if (data.features.length === 0) {
66        map.fitWorld();
67        sidebar.innerHTML = '<div class="bg-info text-white text-center">' + <?= json_encode(I18N::translate('Nothing to show'), JSON_THROW_ON_ERROR) ?> + '</div>';
68      } else {
69        sidebar.innerHTML = '';
70        let geoJsonLayer = L.geoJson(data, {
71          pointToLayer: function(feature, latlng) {
72            return new L.Marker(latlng, {
73              icon: L.BeautifyIcon.icon({
74                icon           : feature.properties.icon["name"],
75                borderColor    : "transparent",
76                backgroundColor: feature.properties.icon["color"],
77                iconShape      : "marker",
78                textColor      : "white",
79              }),
80              title: feature.properties.tooltip,
81              id   : feature.id,
82            })
83            .on("popupopen", function(e) {
84              let item = document.querySelector('.gchart[data-wt-feature-id="' + e.target.feature.id + '"]');
85              item.classList.add('messagebox');
86              item.scrollIntoView(scrollOptions);
87            })
88            .on("popupclose", function() {
89              sidebar.childNodes.forEach(e => e.classList.remove('messagebox'));
90            });
91          },
92          onEachFeature: function(feature, layer) {
93              layer.bindPopup(feature.properties.summary);
94              sidebar.innerHTML += `<li class="gchart px-md-2" data-wt-feature-id=${feature.id}>${feature.properties.summary}</li>`;
95          },
96        });
97        markers.addLayer(geoJsonLayer);
98        map.addLayer(markers);
99        map.fitBounds(markers.getBounds(), {padding: [50, 30], maxZoom: 15});
100      }
101    };
102
103    // Can't use window.onload here. seems to be because of AJAX loading
104    const _loadListeners = function() {
105      // Activate marker popup when sidebar entry clicked
106      sidebar.querySelectorAll('.gchart').forEach((element) => {
107        const eventId = parseInt(element.dataset.wtFeatureId);
108
109        element.addEventListener('click', () => {
110          // first close any existing
111          map.closePopup();
112          //find the marker corresponding to the clicked event
113          const mkrLayer = markers.getLayers().filter(function (v) {
114            return v.feature !== undefined && v.feature.id === eventId;
115          });
116
117          let mkr = mkrLayer.pop();
118
119          markers.zoomToShowLayer(mkr, function (e) {
120            mkr.openPopup();
121          });
122        });
123
124        // stop click on a person also opening the popup
125        element.querySelectorAll('a').forEach((el) => {
126          el.addEventListener('click', (e) => {
127            e.stopPropagation();
128          });
129        });
130      });
131    };
132
133    _drawMap();
134    _buildMapData();
135    _loadListeners();
136  })();
137</script>
138