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