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