1d70512abSGreg Roach<?php 2d70512abSGreg Roach 3d70512abSGreg Roachuse Fisharebest\Webtrees\I18N; 4d70512abSGreg Roach 57c2c99faSGreg Roach/** 67c2c99faSGreg Roach * @var array<mixed> $data 7*c9c6f2ecSGreg Roach * @var object $leaflet_config 87c2c99faSGreg Roach */ 97c2c99faSGreg Roach 10d70512abSGreg Roach?> 11dd6b2bfcSGreg Roach 12dd6b2bfcSGreg Roach<div class="py-4"> 13dd6b2bfcSGreg Roach <div class="row gchart osm-wrapper"> 14d21f0b10SGreg Roach <div id="osm-map" class="col-sm-9 wt-ajax-load osm-user-map" dir="ltr"></div> 150d123f04SDavid Drury <ul class="col-sm-3 osm-sidebar wt-page-options-value list-unstyled px-md-1"></ul> 16dd6b2bfcSGreg Roach </div> 17dd6b2bfcSGreg Roach</div> 18dd6b2bfcSGreg Roach 19dd6b2bfcSGreg Roach<style> 20dd6b2bfcSGreg Roach .osm-wrapper, .osm-user-map { 210d123f04SDavid Drury height: 70vh 22dd6b2bfcSGreg Roach } 23dd6b2bfcSGreg Roach 24dd6b2bfcSGreg Roach .osm-sidebar { 25dd6b2bfcSGreg Roach height: 100%; 26dd6b2bfcSGreg Roach overflow-y: auto; 27dd6b2bfcSGreg Roach font-size: small; 28dd6b2bfcSGreg Roach } 29dd6b2bfcSGreg Roach</style> 30dd6b2bfcSGreg Roach 3174b9ba3fSGreg Roach<script> 32dd6b2bfcSGreg Roach "use strict"; 33dd6b2bfcSGreg Roach 34dd6b2bfcSGreg Roach window.WT_OSM = (function() { 35*c9c6f2ecSGreg Roach const config = <?= json_encode($leaflet_config) ?>; 36dd6b2bfcSGreg Roach 37dd6b2bfcSGreg Roach let map = null; 38dd6b2bfcSGreg Roach let zoom = null; 39597fb44bSDavid Drury let sidebar = $('.osm-sidebar'); 40597fb44bSDavid Drury 41597fb44bSDavid Drury // Map components 42dd6b2bfcSGreg Roach let markers = L.markerClusterGroup({ 43dd6b2bfcSGreg Roach showCoverageOnHover: false, 44dd6b2bfcSGreg Roach }); 45dd6b2bfcSGreg Roach 46dd6b2bfcSGreg Roach let resetControl = L.Control.extend({ 47dd6b2bfcSGreg Roach options: { 48dd6b2bfcSGreg Roach position: "topleft", 49dd6b2bfcSGreg Roach }, 50dd6b2bfcSGreg Roach onAdd: function(map) { 51dd6b2bfcSGreg Roach let container = L.DomUtil.create("div", "leaflet-bar leaflet-control leaflet-control-custom"); 52dd6b2bfcSGreg Roach container.onclick = function() { 53dd6b2bfcSGreg Roach if (zoom) { 54dd6b2bfcSGreg Roach map.flyTo(markers.getBounds().getCenter(), zoom); 55dd6b2bfcSGreg Roach } else { 56dd6b2bfcSGreg Roach map.flyToBounds(markers.getBounds().pad(0.2)); 57dd6b2bfcSGreg Roach } 584125a3e1SGreg Roach sidebar.scrollTo(sidebar.children(":first")); 594125a3e1SGreg Roach 60dd6b2bfcSGreg Roach return false; 61dd6b2bfcSGreg Roach }; 62*c9c6f2ecSGreg Roach let reset = config.i18n.reset; 63597fb44bSDavid Drury let anchor = L.DomUtil.create('a', 'leaflet-control-reset', container); 64597fb44bSDavid Drury anchor.setAttribute('aria-label', reset); 65597fb44bSDavid Drury anchor.href = '#'; 6657862dd5SDavid Drury anchor.title = reset; 67597fb44bSDavid Drury anchor.role = 'button'; 68597fb44bSDavid Drury let image = L.DomUtil.create('i', 'fas fa-redo', anchor); 6957862dd5SDavid Drury image.alt = reset; 70dd6b2bfcSGreg Roach 71dd6b2bfcSGreg Roach return container; 72dd6b2bfcSGreg Roach }, 73dd6b2bfcSGreg Roach }); 74dd6b2bfcSGreg Roach 75dd6b2bfcSGreg Roach /** 76dd6b2bfcSGreg Roach * 77dd6b2bfcSGreg Roach * @private 78dd6b2bfcSGreg Roach */ 79dd6b2bfcSGreg Roach let _drawMap = function() { 80*c9c6f2ecSGreg Roach map = webtrees.buildLeafletJsMap('osm-map', config) 81*c9c6f2ecSGreg Roach .addControl(new resetControl()); 82dd6b2bfcSGreg Roach }; 83dd6b2bfcSGreg Roach 84597fb44bSDavid Drury /** 85597fb44bSDavid Drury * 86597fb44bSDavid Drury * @private 87597fb44bSDavid Drury */ 88597fb44bSDavid Drury let _buildMapData = function() { 890d123f04SDavid Drury let sidebar_content = ""; 90dd6b2bfcSGreg Roach let data = <?= json_encode($data) ?>; 91dd6b2bfcSGreg Roach 92597fb44bSDavid Drury if (data.features.length === 0) { 93597fb44bSDavid Drury map.fitWorld(); 94597fb44bSDavid Drury sidebar_content += '<div class="bg-info text-white text-center">' + <?= json_encode(I18N::translate('Nothing to show')) ?> + '</div>'; 95597fb44bSDavid Drury } else { 96597fb44bSDavid Drury if (data.features.length === 1) { 97597fb44bSDavid Drury //fudge factor - maps zooms to maximum permitted otherwise 98ef9d8accSGreg Roach zoom = data.features[0].properties.zoom; 99597fb44bSDavid Drury } 100597fb44bSDavid Drury let geoJsonLayer = L.geoJson(data, { 101dd6b2bfcSGreg Roach pointToLayer: function(feature, latlng) { 102dd6b2bfcSGreg Roach return new L.Marker(latlng, { 103dd6b2bfcSGreg Roach icon: L.BeautifyIcon.icon({ 104dd6b2bfcSGreg Roach icon : feature.properties.icon["name"], 105dd6b2bfcSGreg Roach borderColor : "transparent", 10680993423SGreg Roach backgroundColor: feature.properties.icon["color"], 107dd6b2bfcSGreg Roach iconShape : "marker", 10880993423SGreg Roach textColor : "white", 109dd6b2bfcSGreg Roach }), 110dd6b2bfcSGreg Roach title: feature.properties.tooltip, 111dd6b2bfcSGreg Roach alt : feature.properties.tooltip, 112dd6b2bfcSGreg Roach id : feature.id, 113dd6b2bfcSGreg Roach }) 114dd6b2bfcSGreg Roach .on("popupopen", function(e) { 115dd6b2bfcSGreg Roach let item = sidebar.children(".gchart[data-id=" + e.target.feature.id + "]"); 116dd6b2bfcSGreg Roach item.addClass("messagebox"); 117dd6b2bfcSGreg Roach sidebar.scrollTo(item); 118dd6b2bfcSGreg Roach }) 119dd6b2bfcSGreg Roach .on("popupclose", function() { 1200d123f04SDavid Drury sidebar.children(".gchart") 121dd6b2bfcSGreg Roach .removeClass("messagebox"); 122dd6b2bfcSGreg Roach }); 123dd6b2bfcSGreg Roach }, 124dd6b2bfcSGreg Roach onEachFeature: function(feature, layer) { 125dd6b2bfcSGreg Roach layer.bindPopup(feature.properties.summary); 1260d123f04SDavid Drury sidebar_content += `<li class="gchart px-md-2" data-id=${feature.id}>${feature.properties.summary}</li>`; 127dd6b2bfcSGreg Roach }, 128dd6b2bfcSGreg Roach }); 129dd6b2bfcSGreg Roach markers.addLayer(geoJsonLayer); 130597fb44bSDavid Drury map.addLayer(markers); 131597fb44bSDavid Drury if (zoom) { 132597fb44bSDavid Drury map.setView(markers.getBounds().getCenter(), zoom); 133dd6b2bfcSGreg Roach } else { 13445e60b72SGreg Roach map.fitBounds(markers.getBounds(), {padding: [50, 30]}); 135dd6b2bfcSGreg Roach } 136dd6b2bfcSGreg Roach } 137597fb44bSDavid Drury sidebar.append(sidebar_content); 138dd6b2bfcSGreg Roach }; 139dd6b2bfcSGreg Roach 140dd6b2bfcSGreg Roach /** 141dd6b2bfcSGreg Roach * @param elem 142dd6b2bfcSGreg Roach * @returns {$} 143dd6b2bfcSGreg Roach */ 144dd6b2bfcSGreg Roach $.fn.scrollTo = function(elem) { 145dd6b2bfcSGreg Roach let _this = $(this); 146dd6b2bfcSGreg Roach _this.animate({ 147dd6b2bfcSGreg Roach scrollTop: elem.offset().top - _this.offset().top + _this.scrollTop(), 148dd6b2bfcSGreg Roach }); 149dd6b2bfcSGreg Roach return this; 150dd6b2bfcSGreg Roach }; 151dd6b2bfcSGreg Roach 152dd6b2bfcSGreg Roach // Activate marker popup when sidebar entry clicked 153597fb44bSDavid Drury $(function() { 1540d123f04SDavid Drury sidebar 155597fb44bSDavid Drury // open marker popup if sidebar event is clicked 156597fb44bSDavid Drury .on('click', '.gchart', function(e) { 157dd6b2bfcSGreg Roach // first close any existing 158dd6b2bfcSGreg Roach map.closePopup(); 159597fb44bSDavid Drury let eventId = $(this).data('id'); 160dd6b2bfcSGreg Roach //find the marker corresponding to the clicked event 161dd6b2bfcSGreg Roach let mkrLayer = markers.getLayers().filter(function(v) { 162597fb44bSDavid Drury return typeof(v.feature) !== 'undefined' && v.feature.id === eventId; 163dd6b2bfcSGreg Roach }); 164dd6b2bfcSGreg Roach let mkr = mkrLayer.pop(); 165dd6b2bfcSGreg Roach // Unfortunately zoomToShowLayer zooms to maxZoom 166dd6b2bfcSGreg Roach // when all marker in a cluster have exactly the 167dd6b2bfcSGreg Roach // same co-ordinates 168dd6b2bfcSGreg Roach markers.zoomToShowLayer(mkr, function(e) { 169dd6b2bfcSGreg Roach mkr.openPopup(); 170dd6b2bfcSGreg Roach }); 171597fb44bSDavid Drury 172dd6b2bfcSGreg Roach return false; 173dd6b2bfcSGreg Roach }) 174597fb44bSDavid Drury .on('click', 'a', function(e) { // stop click on a person also opening the popup 175dd6b2bfcSGreg Roach e.stopPropagation(); 176dd6b2bfcSGreg Roach }); 177597fb44bSDavid Drury }); 178dd6b2bfcSGreg Roach 179597fb44bSDavid Drury _drawMap(); 180597fb44bSDavid Drury _buildMapData(); 181597fb44bSDavid Drury 182597fb44bSDavid Drury return "Leaflet map interface for webtrees-2"; 183597fb44bSDavid Drury })(); 184dd6b2bfcSGreg Roach</script> 185