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