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