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