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