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