xref: /webtrees/resources/views/modules/places/tab.phtml (revision 681f977f4f3f9d177de72b508564d08c53d10eaf)
1d70512abSGreg Roach<?php
2d70512abSGreg Roach
310e06497SGreg Roachdeclare(strict_types=1);
410e06497SGreg Roach
5d70512abSGreg Roachuse Fisharebest\Webtrees\I18N;
6d70512abSGreg Roach
77c2c99faSGreg Roach/**
87c2c99faSGreg Roach * @var array<mixed> $data
9c9c6f2ecSGreg Roach * @var object       $leaflet_config
107c2c99faSGreg Roach */
117c2c99faSGreg Roach
12d70512abSGreg Roach?>
13dd6b2bfcSGreg Roach
14*681f977fSGreg Roach<div class="row gx-1 wt-places-tab-wrapper wt-fullscreen-container">
15*681f977fSGreg Roach    <div class="col-sm-9">
16*681f977fSGreg Roach        <div id="wt-map" class="wt-ajax-load wt-map" dir="ltr"></div>
17*681f977fSGreg Roach    </div>
18*681f977fSGreg Roach    <div class="col-sm-3">
19*681f977fSGreg Roach        <ul class="wt-map-sidebar list-unstyled mb-0"></ul>
20*681f977fSGreg Roach    </div>
21dd6b2bfcSGreg Roach</div>
22dd6b2bfcSGreg Roach
2374b9ba3fSGreg Roach<script>
24ffb44950SGreg Roach  'use strict';
25dd6b2bfcSGreg Roach
2689b00848SDavid Drury  (function () {
27728c8c27SGreg Roach    const config = <?= json_encode($leaflet_config, JSON_THROW_ON_ERROR) ?>;
28dd6b2bfcSGreg Roach
29dd6b2bfcSGreg Roach    let map = null;
3075f2a483SDavid Drury    const sidebar = document.querySelector('.wt-map-sidebar');
3189b00848SDavid Drury
3289b00848SDavid Drury    const scrollOptions = {
3389b00848SDavid Drury      behavior: "smooth",
34aeea31bdSGreg Roach      block: "nearest",
3589b00848SDavid Drury      inline: "start"
3689b00848SDavid Drury    };
37597fb44bSDavid Drury
38597fb44bSDavid Drury    // Map components
39dd6b2bfcSGreg Roach    let markers = L.markerClusterGroup({
40dd6b2bfcSGreg Roach        showCoverageOnHover: false,
41dd6b2bfcSGreg Roach    });
42dd6b2bfcSGreg Roach
43f352d954SDavid Drury    /**
44f352d954SDavid Drury     * Passed to resetControl to
45f352d954SDavid Drury     * perform necessary reset actions on map
46b2e5f20eSGreg Roach     *
47b2e5f20eSGreg Roach     * @param {Event} event
48f352d954SDavid Drury     */
49b2e5f20eSGreg Roach    let resetCallback = function (event) {
50b2e5f20eSGreg Roach      event.preventDefault();
5157ef7ac6Smiqrogroove      map.flyToBounds(markers.getBounds(), {padding: [50, 30], maxZoom: 15 });
52f352d954SDavid Drury    }
53dd6b2bfcSGreg Roach
54dd6b2bfcSGreg Roach    /**
55dd6b2bfcSGreg Roach     *
56dd6b2bfcSGreg Roach     * @private
57dd6b2bfcSGreg Roach     */
58dd6b2bfcSGreg Roach    let _drawMap = function() {
59b7b71725SGreg Roach      map = webtrees.buildLeafletJsMap('wt-map', config, resetCallback);
60dd6b2bfcSGreg Roach    };
61dd6b2bfcSGreg Roach
62597fb44bSDavid Drury    /**
63597fb44bSDavid Drury     *
64597fb44bSDavid Drury     * @private
65597fb44bSDavid Drury     */
66597fb44bSDavid Drury    let _buildMapData = function() {
67728c8c27SGreg Roach      let data = <?= json_encode($data, JSON_THROW_ON_ERROR) ?>;
68dd6b2bfcSGreg Roach
69597fb44bSDavid Drury      if (data.features.length === 0) {
70597fb44bSDavid Drury        map.fitWorld();
7189b00848SDavid Drury        sidebar.innerHTML = '<div class="bg-info text-white text-center">' + <?= json_encode(I18N::translate('Nothing to show'), JSON_THROW_ON_ERROR) ?> + '</div>';
72597fb44bSDavid Drury      } else {
7389b00848SDavid Drury        sidebar.innerHTML = '';
74597fb44bSDavid Drury        let geoJsonLayer = L.geoJson(data, {
75dd6b2bfcSGreg Roach          pointToLayer: function(feature, latlng) {
76dd6b2bfcSGreg Roach            return new L.Marker(latlng, {
77dd6b2bfcSGreg Roach              icon: L.BeautifyIcon.icon({
78dd6b2bfcSGreg Roach                icon           : feature.properties.icon["name"],
79dd6b2bfcSGreg Roach                borderColor    : "transparent",
8080993423SGreg Roach                backgroundColor: feature.properties.icon["color"],
81dd6b2bfcSGreg Roach                iconShape      : "marker",
8280993423SGreg Roach                textColor      : "white",
83dd6b2bfcSGreg Roach              }),
84dd6b2bfcSGreg Roach              title: feature.properties.tooltip,
85dd6b2bfcSGreg Roach              id   : feature.id,
86dd6b2bfcSGreg Roach            })
87dd6b2bfcSGreg Roach            .on("popupopen", function(e) {
88*681f977fSGreg Roach              let item = document.querySelector('.wt-places-tab-wrapper [data-wt-feature-id="' + e.target.feature.id + '"]');
8989b00848SDavid Drury              item.classList.add('messagebox');
9089b00848SDavid Drury              item.scrollIntoView(scrollOptions);
91dd6b2bfcSGreg Roach            })
92dd6b2bfcSGreg Roach            .on("popupclose", function() {
9389b00848SDavid Drury              sidebar.childNodes.forEach(e => e.classList.remove('messagebox'));
94dd6b2bfcSGreg Roach            });
95dd6b2bfcSGreg Roach          },
96dd6b2bfcSGreg Roach          onEachFeature: function(feature, layer) {
97dd6b2bfcSGreg Roach              layer.bindPopup(feature.properties.summary);
98*681f977fSGreg Roach              sidebar.innerHTML += `<li class="mb-1 wt-page-options-value" data-wt-feature-id=${feature.id}>${feature.properties.summary}</li>`;
99dd6b2bfcSGreg Roach          },
100dd6b2bfcSGreg Roach        });
101dd6b2bfcSGreg Roach        markers.addLayer(geoJsonLayer);
102597fb44bSDavid Drury        map.addLayer(markers);
10357ef7ac6Smiqrogroove        map.fitBounds(markers.getBounds(), {padding: [50, 30], maxZoom: 15});
104dd6b2bfcSGreg Roach      }
105dd6b2bfcSGreg Roach    };
106dd6b2bfcSGreg Roach
10789b00848SDavid Drury    // Can't use window.onload here. seems to be because of AJAX loading
10889b00848SDavid Drury    const _loadListeners = function() {
109dd6b2bfcSGreg Roach      // Activate marker popup when sidebar entry clicked
110*681f977fSGreg Roach      sidebar.querySelectorAll('.wt-places-tab-wrapper [data-wt-feature-id]').forEach((element) => {
111815856a7SGreg Roach        const eventId = parseInt(element.dataset.wtFeatureId);
11289b00848SDavid Drury
11389b00848SDavid Drury        element.addEventListener('click', () => {
114dd6b2bfcSGreg Roach          // first close any existing
115dd6b2bfcSGreg Roach          map.closePopup();
116dd6b2bfcSGreg Roach          //find the marker corresponding to the clicked event
117815856a7SGreg Roach          const mkrLayer = markers.getLayers().filter(function (v) {
11889b00848SDavid Drury            return v.feature !== undefined && v.feature.id === eventId;
119dd6b2bfcSGreg Roach          });
12089b00848SDavid Drury
121dd6b2bfcSGreg Roach          let mkr = mkrLayer.pop();
12289b00848SDavid Drury
123dd6b2bfcSGreg Roach          markers.zoomToShowLayer(mkr, function (e) {
124dd6b2bfcSGreg Roach            mkr.openPopup();
125dd6b2bfcSGreg Roach          });
12689b00848SDavid Drury        });
12789b00848SDavid Drury
12889b00848SDavid Drury        // stop click on a person also opening the popup
12989b00848SDavid Drury        element.querySelectorAll('a').forEach((el) => {
13089b00848SDavid Drury          el.addEventListener('click', (e) => {
131dd6b2bfcSGreg Roach            e.stopPropagation();
132dd6b2bfcSGreg Roach          });
133597fb44bSDavid Drury        });
13489b00848SDavid Drury      });
135815856a7SGreg Roach    };
136dd6b2bfcSGreg Roach
137597fb44bSDavid Drury    _drawMap();
138597fb44bSDavid Drury    _buildMapData();
13989b00848SDavid Drury    _loadListeners();
140597fb44bSDavid Drury  })();
141dd6b2bfcSGreg Roach</script>
142