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