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