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 13<div class="py-4"> 14 <div class="row gchart osm-wrapper"> 15 <div id="osm-map" class="col-sm-9 wt-ajax-load osm-user-map" dir="ltr"></div> 16 <ul class="col-sm-3 osm-sidebar wt-page-options-value list-unstyled px-md-1"></ul> 17 </div> 18</div> 19 20<?php View::push('styles') ?> 21<style> 22 .osm-wrapper, .osm-user-map { 23 height: 70vh 24 } 25 26 .osm-sidebar { 27 height: 100%; 28 overflow-x: hidden; 29 overflow-y: auto; 30 font-size: small; 31 } 32 33 .flag { 34 border: 1px solid grey !important; 35 height: 15px; 36 width: 25px; 37 } 38</style> 39<?php View::endpush() ?> 40 41<?php View::push('javascript') ?> 42<script> 43 "use strict"; 44 45 window.WT_OSM = (function () { 46 const config = <?= json_encode($leaflet_config) ?>; 47 48 let map = null; 49 let zoom = null; 50 let sidebar = $('.osm-sidebar'); 51 52 // Map components 53 let markers = L.markerClusterGroup({ 54 showCoverageOnHover: false, 55 }); 56 57 let resetControl = L.Control.extend({ 58 options: { 59 position: "topleft", 60 }, 61 62 onAdd: function (map) { 63 let container = L.DomUtil.create("div", "leaflet-bar leaflet-control leaflet-control-custom"); 64 container.onclick = function () { 65 if (zoom) { 66 map.flyTo(markers.getBounds().getCenter(), zoom); 67 } else { 68 map.flyToBounds(markers.getBounds().pad(0.2)); 69 } 70 sidebar.scrollTo(sidebar.children(":first")); 71 72 return false; 73 }; 74 let anchor = L.DomUtil.create("a", "leaflet-control-reset", container); 75 let reset = config.i18n.reset; 76 anchor.setAttribute('aria-label', reset); 77 anchor.href = "#"; 78 anchor.title = reset; 79 anchor.role = "button"; 80 let image = L.DomUtil.create("i", "fas fa-redo", anchor); 81 image.alt = reset; 82 83 return container; 84 }, 85 }); 86 87 /** 88 * @private 89 */ 90 let _drawMap = function() { 91 map = webtrees.buildLeafletJsMap('osm-map', config) 92 .addControl(new resetControl()); 93 }; 94 95 /** 96 * @private 97 */ 98 let _buildMapData = function () { 99 let data = <?= json_encode($data['markers']) ?>; 100 101 let geoJsonLayer = L.geoJson(data, { 102 pointToLayer: function (feature, latlng) { 103 return new L.Marker(latlng, { 104 icon: L.BeautifyIcon.icon({ 105 icon : 'bullseye fas', 106 borderColor : "transparent", 107 backgroundColor: '#1e90ff', 108 iconShape : "marker", 109 textColor : "white", 110 }), 111 title: feature.properties.tooltip, 112 alt : feature.properties.tooltip, 113 id : feature.id, 114 }) 115 .on("popupopen", function (e) { 116 let item = sidebar.children(".mapped[data-id=" + e.target.feature.id + "]"); 117 item.addClass("messagebox"); 118 sidebar.scrollTo(item); 119 }) 120 .on("popupclose", function () { 121 sidebar.children(".mapped") 122 .removeClass("messagebox"); 123 }); 124 }, 125 onEachFeature: function (feature, layer) { 126 layer.bindPopup(feature.properties.popup); 127 }, 128 }); 129 130 if (data.features.length > 0) { 131 markers.addLayer(geoJsonLayer); 132 map.addLayer(markers) 133 } 134 135 map.fitBounds(<?= json_encode($data['bounds']) ?>, {padding: [50, 30]}); 136 sidebar.append(<?= json_encode($data['sidebar']) ?>); 137 }; 138 139 /** 140 * @param elem 141 * @returns {$} 142 */ 143 $.fn.scrollTo = function (elem) { 144 let _this = $(this); 145 _this.animate({ 146 scrollTop: elem.offset().top - _this.offset().top + _this.scrollTop(), 147 }); 148 return this; 149 }; 150 151 // Activate marker popup when sidebar entry clicked 152 $(function () { 153 sidebar 154 // open marker popup if sidebar event is clicked 155 .on("click", ".mapped", function (e) { 156 // first close any existing 157 map.closePopup(); 158 let eventId = $(this).data("id"); 159 //find the marker corresponding to the clicked event 160 let mkrLayer = markers.getLayers().filter(function (v) { 161 return typeof (v.feature) !== "undefined" && v.feature.id === eventId; 162 }); 163 let mkr = mkrLayer.pop(); 164 // Unfortunately zoomToShowLayer zooms to maxZoom 165 // when all marker in a cluster have exactly the 166 // same co-ordinates 167 markers.zoomToShowLayer(mkr, function (e) { 168 mkr.openPopup(); 169 }); 170 return false; 171 }) 172 .on("click", "a", function (e) { // stop click on a person also opening the popup 173 e.stopPropagation(); 174 }); 175 }); 176 177 _drawMap(); 178 _buildMapData(); 179 180 return "Leaflet map interface for webtrees-2"; 181 })(); 182</script> 183<?php View::endpush() ?> 184