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