xref: /webtrees/resources/views/modules/places/tab.phtml (revision 2b817d024385cac90d58e3d310c606510a7302ad)
1d70512abSGreg Roach<?php
2d70512abSGreg Roach
3d70512abSGreg Roachuse Fisharebest\Webtrees\I18N;
4d70512abSGreg Roach
57c2c99faSGreg Roach/**
67c2c99faSGreg Roach * @var array<mixed> $data
7c9c6f2ecSGreg Roach * @var object       $leaflet_config
87c2c99faSGreg Roach */
97c2c99faSGreg Roach
10d70512abSGreg Roach?>
11dd6b2bfcSGreg Roach
12dd6b2bfcSGreg Roach<div class="py-4">
1384df6051SGreg Roach    <div class="row gchart wt-places-tab-wrapper">
1484df6051SGreg Roach        <div id="wt-map" class="col-sm-9 wt-ajax-load wt-map wt-places-tab-map" dir="ltr"></div>
1584df6051SGreg Roach        <ul class="col-sm-3 wt-places-tab-sidebar wt-page-options-value list-unstyled px-md-1"></ul>
16dd6b2bfcSGreg Roach    </div>
17dd6b2bfcSGreg Roach</div>
18dd6b2bfcSGreg Roach
1974b9ba3fSGreg Roach<script>
20ffb44950SGreg Roach  'use strict';
21dd6b2bfcSGreg Roach
2289b00848SDavid Drury  (function () {
23728c8c27SGreg Roach    const config = <?= json_encode($leaflet_config, JSON_THROW_ON_ERROR) ?>;
24dd6b2bfcSGreg Roach
25dd6b2bfcSGreg Roach    let map       = null;
2684df6051SGreg Roach    const sidebar = document.querySelector('.wt-places-tab-sidebar');
2789b00848SDavid Drury
2889b00848SDavid Drury    const scrollOptions = {
2989b00848SDavid Drury      behavior: "smooth",
3089b00848SDavid Drury      block: "start",
3189b00848SDavid Drury      inline: "start"
3289b00848SDavid Drury    };
33597fb44bSDavid Drury
34597fb44bSDavid Drury    // Map components
35dd6b2bfcSGreg Roach    let markers = L.markerClusterGroup({
36dd6b2bfcSGreg Roach        showCoverageOnHover: false,
37dd6b2bfcSGreg Roach    });
38dd6b2bfcSGreg Roach
39dd6b2bfcSGreg Roach    let resetControl = L.Control.extend({
40dd6b2bfcSGreg Roach      options: {
41dd6b2bfcSGreg Roach          position: "topleft",
42dd6b2bfcSGreg Roach      },
43dd6b2bfcSGreg Roach      onAdd: function(map) {
44dd6b2bfcSGreg Roach        let container = L.DomUtil.create("div", "leaflet-bar leaflet-control leaflet-control-custom");
45dd6b2bfcSGreg Roach        container.onclick = function() {
4657ef7ac6Smiqrogroove            map.flyToBounds(markers.getBounds(), {padding: [50, 30], maxZoom: 15});
47*2b817d02SDavid Drury            sidebar.firstElementChild.scrollIntoView(scrollOptions);
484125a3e1SGreg Roach
49dd6b2bfcSGreg Roach            return false;
50dd6b2bfcSGreg Roach        };
51c9c6f2ecSGreg Roach        let reset    = config.i18n.reset;
52597fb44bSDavid Drury        let anchor   = L.DomUtil.create('a', 'leaflet-control-reset', container);
53597fb44bSDavid Drury        anchor.setAttribute('aria-label', reset);
54597fb44bSDavid Drury        anchor.href  = '#';
5557862dd5SDavid Drury        anchor.title = reset;
56597fb44bSDavid Drury        anchor.role  = 'button';
57597fb44bSDavid Drury        let image    = L.DomUtil.create('i', 'fas fa-redo', anchor);
5857862dd5SDavid Drury        image.alt    = reset;
59dd6b2bfcSGreg Roach
60dd6b2bfcSGreg Roach        return container;
61dd6b2bfcSGreg Roach      },
62dd6b2bfcSGreg Roach  });
63dd6b2bfcSGreg Roach
64dd6b2bfcSGreg Roach    /**
65dd6b2bfcSGreg Roach     *
66dd6b2bfcSGreg Roach     * @private
67dd6b2bfcSGreg Roach     */
68dd6b2bfcSGreg Roach    let _drawMap = function() {
6989b00848SDavid Drury      map = webtrees.buildLeafletJsMap('wt-map', config)
70c9c6f2ecSGreg Roach      .addControl(new resetControl());
71dd6b2bfcSGreg Roach    };
72dd6b2bfcSGreg Roach
73597fb44bSDavid Drury    /**
74597fb44bSDavid Drury     *
75597fb44bSDavid Drury     * @private
76597fb44bSDavid Drury     */
77597fb44bSDavid Drury    let _buildMapData = function() {
78728c8c27SGreg Roach      let data = <?= json_encode($data, JSON_THROW_ON_ERROR) ?>;
79dd6b2bfcSGreg Roach
80597fb44bSDavid Drury      if (data.features.length === 0) {
81597fb44bSDavid Drury        map.fitWorld();
8289b00848SDavid Drury        sidebar.innerHTML = '<div class="bg-info text-white text-center">' + <?= json_encode(I18N::translate('Nothing to show'), JSON_THROW_ON_ERROR) ?> + '</div>';
83597fb44bSDavid Drury      } else {
8489b00848SDavid Drury        sidebar.innerHTML = '';
85597fb44bSDavid Drury        let geoJsonLayer = L.geoJson(data, {
86dd6b2bfcSGreg Roach          pointToLayer: function(feature, latlng) {
87dd6b2bfcSGreg Roach            return new L.Marker(latlng, {
88dd6b2bfcSGreg Roach              icon: L.BeautifyIcon.icon({
89dd6b2bfcSGreg Roach                icon           : feature.properties.icon["name"],
90dd6b2bfcSGreg Roach                borderColor    : "transparent",
9180993423SGreg Roach                backgroundColor: feature.properties.icon["color"],
92dd6b2bfcSGreg Roach                iconShape      : "marker",
9380993423SGreg Roach                textColor      : "white",
94dd6b2bfcSGreg Roach              }),
95dd6b2bfcSGreg Roach              title: feature.properties.tooltip,
96dd6b2bfcSGreg Roach              alt  : feature.properties.tooltip,
97dd6b2bfcSGreg Roach              id   : feature.id,
98dd6b2bfcSGreg Roach            })
99dd6b2bfcSGreg Roach            .on("popupopen", function(e) {
10089b00848SDavid Drury              let item = document.querySelector('.gchart[data-wt-feature-id="' + e.target.feature.id + '"]');
10189b00848SDavid Drury              item.classList.add('messagebox');
10289b00848SDavid Drury              item.scrollIntoView(scrollOptions);
103dd6b2bfcSGreg Roach            })
104dd6b2bfcSGreg Roach            .on("popupclose", function() {
10589b00848SDavid Drury              sidebar.childNodes.forEach(e => e.classList.remove('messagebox'));
10689b00848SDavid Drury              sidebar.firstElementChild.scrollIntoView(scrollOptions);
107dd6b2bfcSGreg Roach            });
108dd6b2bfcSGreg Roach          },
109dd6b2bfcSGreg Roach          onEachFeature: function(feature, layer) {
110dd6b2bfcSGreg Roach              layer.bindPopup(feature.properties.summary);
11189b00848SDavid Drury              sidebar.innerHTML += `<li class="gchart px-md-2" data-wt-feature-id=${feature.id}>${feature.properties.summary}</li>`;
112dd6b2bfcSGreg Roach          },
113dd6b2bfcSGreg Roach        });
114dd6b2bfcSGreg Roach        markers.addLayer(geoJsonLayer);
115597fb44bSDavid Drury        map.addLayer(markers);
11657ef7ac6Smiqrogroove        map.fitBounds(markers.getBounds(), {padding: [50, 30], maxZoom: 15});
117dd6b2bfcSGreg Roach      }
118dd6b2bfcSGreg Roach    };
119dd6b2bfcSGreg Roach
12089b00848SDavid Drury    // Can't use window.onload here. seems to be because of AJAX loading
12189b00848SDavid Drury    const _loadListeners = function() {
122dd6b2bfcSGreg Roach      // Activate marker popup when sidebar entry clicked
12389b00848SDavid Drury      sidebar.querySelectorAll('.gchart').forEach((element) => {
12489b00848SDavid Drury        var eventId = parseInt(element.dataset.wtFeatureId);
12589b00848SDavid Drury
12689b00848SDavid Drury        element.addEventListener('click', () => {
127dd6b2bfcSGreg Roach          // first close any existing
128dd6b2bfcSGreg Roach          map.closePopup();
129dd6b2bfcSGreg Roach          //find the marker corresponding to the clicked event
130dd6b2bfcSGreg Roach          let mkrLayer = markers.getLayers().filter(function (v) {
13189b00848SDavid Drury            return v.feature !== undefined && v.feature.id === eventId;
132dd6b2bfcSGreg Roach          });
13389b00848SDavid Drury
134dd6b2bfcSGreg Roach          let mkr = mkrLayer.pop();
13589b00848SDavid Drury
136dd6b2bfcSGreg Roach          markers.zoomToShowLayer(mkr, function (e) {
137dd6b2bfcSGreg Roach            mkr.openPopup();
138dd6b2bfcSGreg Roach          });
139597fb44bSDavid Drury
140dd6b2bfcSGreg Roach          return false;
14189b00848SDavid Drury        });
14289b00848SDavid Drury
14389b00848SDavid Drury        // stop click on a person also opening the popup
14489b00848SDavid Drury        element.querySelectorAll('a').forEach((el) => {
14589b00848SDavid Drury          el.addEventListener('click', (e) => {
146dd6b2bfcSGreg Roach            e.stopPropagation();
147dd6b2bfcSGreg Roach          });
148597fb44bSDavid Drury        });
14989b00848SDavid Drury      });
15089b00848SDavid Drury    }
151dd6b2bfcSGreg Roach
152597fb44bSDavid Drury    _drawMap();
153597fb44bSDavid Drury    _buildMapData();
15489b00848SDavid Drury    _loadListeners();
155597fb44bSDavid Drury  })();
156dd6b2bfcSGreg Roach</script>
157