1d70512abSGreg Roach<?php 2d70512abSGreg Roach 3d70512abSGreg Roachuse Fisharebest\Webtrees\I18N; 4d70512abSGreg Roach 57c2c99faSGreg Roach/** 67c2c99faSGreg Roach * @var array<mixed> $data 7c9c6f2ecSGreg 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> 32*ffb44950SGreg Roach 'use strict'; 33dd6b2bfcSGreg Roach 34dd6b2bfcSGreg Roach window.WT_OSM = (function() { 35728c8c27SGreg Roach const config = <?= json_encode($leaflet_config, JSON_THROW_ON_ERROR) ?>; 36dd6b2bfcSGreg Roach 37dd6b2bfcSGreg Roach let map = null; 38597fb44bSDavid Drury let sidebar = $('.osm-sidebar'); 39597fb44bSDavid Drury 40597fb44bSDavid Drury // Map components 41dd6b2bfcSGreg Roach let markers = L.markerClusterGroup({ 42dd6b2bfcSGreg Roach showCoverageOnHover: false, 43dd6b2bfcSGreg Roach }); 44dd6b2bfcSGreg Roach 45dd6b2bfcSGreg Roach let resetControl = L.Control.extend({ 46dd6b2bfcSGreg Roach options: { 47dd6b2bfcSGreg Roach position: "topleft", 48dd6b2bfcSGreg Roach }, 49dd6b2bfcSGreg Roach onAdd: function(map) { 50dd6b2bfcSGreg Roach let container = L.DomUtil.create("div", "leaflet-bar leaflet-control leaflet-control-custom"); 51dd6b2bfcSGreg Roach container.onclick = function() { 5257ef7ac6Smiqrogroove map.flyToBounds(markers.getBounds(), {padding: [50, 30], maxZoom: 15}); 534125a3e1SGreg Roach sidebar.scrollTo(sidebar.children(":first")); 544125a3e1SGreg Roach 55dd6b2bfcSGreg Roach return false; 56dd6b2bfcSGreg Roach }; 57c9c6f2ecSGreg Roach let reset = config.i18n.reset; 58597fb44bSDavid Drury let anchor = L.DomUtil.create('a', 'leaflet-control-reset', container); 59597fb44bSDavid Drury anchor.setAttribute('aria-label', reset); 60597fb44bSDavid Drury anchor.href = '#'; 6157862dd5SDavid Drury anchor.title = reset; 62597fb44bSDavid Drury anchor.role = 'button'; 63597fb44bSDavid Drury let image = L.DomUtil.create('i', 'fas fa-redo', anchor); 6457862dd5SDavid Drury image.alt = reset; 65dd6b2bfcSGreg Roach 66dd6b2bfcSGreg Roach return container; 67dd6b2bfcSGreg Roach }, 68dd6b2bfcSGreg Roach }); 69dd6b2bfcSGreg Roach 70dd6b2bfcSGreg Roach /** 71dd6b2bfcSGreg Roach * 72dd6b2bfcSGreg Roach * @private 73dd6b2bfcSGreg Roach */ 74dd6b2bfcSGreg Roach let _drawMap = function() { 75c9c6f2ecSGreg Roach map = webtrees.buildLeafletJsMap('osm-map', config) 76c9c6f2ecSGreg Roach .addControl(new resetControl()); 77dd6b2bfcSGreg Roach }; 78dd6b2bfcSGreg Roach 79597fb44bSDavid Drury /** 80597fb44bSDavid Drury * 81597fb44bSDavid Drury * @private 82597fb44bSDavid Drury */ 83597fb44bSDavid Drury let _buildMapData = function() { 840d123f04SDavid Drury let sidebar_content = ""; 85728c8c27SGreg Roach let data = <?= json_encode($data, JSON_THROW_ON_ERROR) ?>; 86dd6b2bfcSGreg Roach 87597fb44bSDavid Drury if (data.features.length === 0) { 88597fb44bSDavid Drury map.fitWorld(); 89728c8c27SGreg Roach sidebar_content += '<div class="bg-info text-white text-center">' + <?= json_encode(I18N::translate('Nothing to show'), JSON_THROW_ON_ERROR) ?> + '</div>'; 90597fb44bSDavid Drury } else { 91597fb44bSDavid Drury let geoJsonLayer = L.geoJson(data, { 92dd6b2bfcSGreg Roach pointToLayer: function(feature, latlng) { 93dd6b2bfcSGreg Roach return new L.Marker(latlng, { 94dd6b2bfcSGreg Roach icon: L.BeautifyIcon.icon({ 95dd6b2bfcSGreg Roach icon : feature.properties.icon["name"], 96dd6b2bfcSGreg Roach borderColor : "transparent", 9780993423SGreg Roach backgroundColor: feature.properties.icon["color"], 98dd6b2bfcSGreg Roach iconShape : "marker", 9980993423SGreg Roach textColor : "white", 100dd6b2bfcSGreg Roach }), 101dd6b2bfcSGreg Roach title: feature.properties.tooltip, 102dd6b2bfcSGreg Roach alt : feature.properties.tooltip, 103dd6b2bfcSGreg Roach id : feature.id, 104dd6b2bfcSGreg Roach }) 105dd6b2bfcSGreg Roach .on("popupopen", function(e) { 106d4786c66SGreg Roach let item = sidebar.children(".gchart[data-wt-feature-id=" + e.target.feature.id + "]"); 107dd6b2bfcSGreg Roach item.addClass("messagebox"); 108dd6b2bfcSGreg Roach sidebar.scrollTo(item); 109dd6b2bfcSGreg Roach }) 110dd6b2bfcSGreg Roach .on("popupclose", function() { 1110d123f04SDavid Drury sidebar.children(".gchart") 112dd6b2bfcSGreg Roach .removeClass("messagebox"); 113dd6b2bfcSGreg Roach }); 114dd6b2bfcSGreg Roach }, 115dd6b2bfcSGreg Roach onEachFeature: function(feature, layer) { 116dd6b2bfcSGreg Roach layer.bindPopup(feature.properties.summary); 117d4786c66SGreg Roach sidebar_content += `<li class="gchart px-md-2" data-wt-feature-id=${feature.id}>${feature.properties.summary}</li>`; 118dd6b2bfcSGreg Roach }, 119dd6b2bfcSGreg Roach }); 120dd6b2bfcSGreg Roach markers.addLayer(geoJsonLayer); 121597fb44bSDavid Drury map.addLayer(markers); 12257ef7ac6Smiqrogroove map.fitBounds(markers.getBounds(), {padding: [50, 30], maxZoom: 15}); 123dd6b2bfcSGreg Roach } 124597fb44bSDavid Drury sidebar.append(sidebar_content); 125dd6b2bfcSGreg Roach }; 126dd6b2bfcSGreg Roach 127dd6b2bfcSGreg Roach /** 128dd6b2bfcSGreg Roach * @param elem 129dd6b2bfcSGreg Roach * @returns {$} 130dd6b2bfcSGreg Roach */ 131dd6b2bfcSGreg Roach $.fn.scrollTo = function(elem) { 132dd6b2bfcSGreg Roach let _this = $(this); 133dd6b2bfcSGreg Roach _this.animate({ 134dd6b2bfcSGreg Roach scrollTop: elem.offset().top - _this.offset().top + _this.scrollTop(), 135dd6b2bfcSGreg Roach }); 136dd6b2bfcSGreg Roach return this; 137dd6b2bfcSGreg Roach }; 138dd6b2bfcSGreg Roach 139dd6b2bfcSGreg Roach // Activate marker popup when sidebar entry clicked 140597fb44bSDavid Drury $(function() { 1410d123f04SDavid Drury sidebar 142597fb44bSDavid Drury // open marker popup if sidebar event is clicked 143597fb44bSDavid Drury .on('click', '.gchart', function(e) { 144dd6b2bfcSGreg Roach // first close any existing 145dd6b2bfcSGreg Roach map.closePopup(); 146597fb44bSDavid Drury let eventId = $(this).data('id'); 147dd6b2bfcSGreg Roach //find the marker corresponding to the clicked event 148dd6b2bfcSGreg Roach let mkrLayer = markers.getLayers().filter(function(v) { 149597fb44bSDavid Drury return typeof(v.feature) !== 'undefined' && v.feature.id === eventId; 150dd6b2bfcSGreg Roach }); 151dd6b2bfcSGreg Roach let mkr = mkrLayer.pop(); 152dd6b2bfcSGreg Roach // Unfortunately zoomToShowLayer zooms to maxZoom 153dd6b2bfcSGreg Roach // when all marker in a cluster have exactly the 154dd6b2bfcSGreg Roach // same co-ordinates 155dd6b2bfcSGreg Roach markers.zoomToShowLayer(mkr, function(e) { 156dd6b2bfcSGreg Roach mkr.openPopup(); 157dd6b2bfcSGreg Roach }); 158597fb44bSDavid Drury 159dd6b2bfcSGreg Roach return false; 160dd6b2bfcSGreg Roach }) 161597fb44bSDavid Drury .on('click', 'a', function(e) { // stop click on a person also opening the popup 162dd6b2bfcSGreg Roach e.stopPropagation(); 163dd6b2bfcSGreg Roach }); 164597fb44bSDavid Drury }); 165dd6b2bfcSGreg Roach 166597fb44bSDavid Drury _drawMap(); 167597fb44bSDavid Drury _buildMapData(); 168597fb44bSDavid Drury 169597fb44bSDavid Drury return "Leaflet map interface for webtrees-2"; 170597fb44bSDavid Drury })(); 171dd6b2bfcSGreg Roach</script> 172