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