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