1d70512abSGreg Roach<?php 2d70512abSGreg Roach 3d70512abSGreg Roachuse Fisharebest\Webtrees\I18N; 4d70512abSGreg Roach 5d70512abSGreg Roach?> 6dd6b2bfcSGreg Roach 7dd6b2bfcSGreg Roach<div class="py-4"> 8dd6b2bfcSGreg Roach <div class="row gchart osm-wrapper"> 9d21f0b10SGreg Roach <div id="osm-map" class="col-sm-9 wt-ajax-load osm-user-map" dir="ltr"></div> 10*0d123f04SDavid Drury <ul class="col-sm-3 osm-sidebar wt-page-options-value list-unstyled px-md-1"></ul> 11dd6b2bfcSGreg Roach </div> 12dd6b2bfcSGreg Roach</div> 13dd6b2bfcSGreg Roach 14dd6b2bfcSGreg Roach<style> 15dd6b2bfcSGreg Roach .osm-wrapper, .osm-user-map { 16*0d123f04SDavid Drury height: 70vh 17dd6b2bfcSGreg Roach } 18dd6b2bfcSGreg Roach 19dd6b2bfcSGreg Roach .osm-sidebar { 20dd6b2bfcSGreg Roach height: 100%; 21dd6b2bfcSGreg Roach overflow-y: auto; 22dd6b2bfcSGreg Roach font-size: small; 23dd6b2bfcSGreg Roach } 24dd6b2bfcSGreg Roach</style> 25dd6b2bfcSGreg Roach 26dd6b2bfcSGreg Roach<script type="application/javascript"> 27dd6b2bfcSGreg Roach "use strict"; 28dd6b2bfcSGreg Roach 29dd6b2bfcSGreg Roach window.WT_OSM = (function () { 30dd6b2bfcSGreg Roach let baseData = { 31dd6b2bfcSGreg Roach minZoom: 2, 32dd6b2bfcSGreg Roach providerName: "OpenStreetMap.Mapnik", 33dd6b2bfcSGreg Roach providerOptions: [], 34dd6b2bfcSGreg Roach }; 35dd6b2bfcSGreg Roach 36dd6b2bfcSGreg Roach let map = null; 37dd6b2bfcSGreg Roach let zoom = null; 38*0d123f04SDavid Drury let sidebar = $(".osm-sidebar"); 39dd6b2bfcSGreg Roach let markers = L.markerClusterGroup({ 40dd6b2bfcSGreg Roach showCoverageOnHover: false, 41dd6b2bfcSGreg Roach }); 42dd6b2bfcSGreg Roach 43dd6b2bfcSGreg Roach let resetControl = L.Control.extend({ 44dd6b2bfcSGreg Roach options: { 45dd6b2bfcSGreg Roach position: "topleft", 46dd6b2bfcSGreg Roach }, 47dd6b2bfcSGreg Roach 48dd6b2bfcSGreg Roach onAdd: function (map) { 49dd6b2bfcSGreg Roach let container = L.DomUtil.create("div", "leaflet-bar leaflet-control leaflet-control-custom"); 50dd6b2bfcSGreg Roach container.onclick = function () { 51dd6b2bfcSGreg Roach if (zoom) { 52dd6b2bfcSGreg Roach map.flyTo(markers.getBounds().getCenter(), zoom); 53dd6b2bfcSGreg Roach } else { 54dd6b2bfcSGreg Roach map.flyToBounds(markers.getBounds().pad(0.2)); 55dd6b2bfcSGreg Roach } 564125a3e1SGreg Roach sidebar.scrollTo(sidebar.children(":first")); 574125a3e1SGreg Roach 58dd6b2bfcSGreg Roach return false; 59dd6b2bfcSGreg Roach }; 60dd6b2bfcSGreg Roach let anchor = L.DomUtil.create("a", "leaflet-control-reset", container); 6157862dd5SDavid Drury let reset = <?= json_encode(I18N::translate('Reset to initial map state')) ?>; 62dd6b2bfcSGreg Roach anchor.href = "#"; 6357862dd5SDavid Drury anchor.title = reset; 64dd6b2bfcSGreg Roach anchor.role = "button"; 65dd6b2bfcSGreg Roach $(anchor).attr("aria-label", "reset"); 66dd6b2bfcSGreg Roach let image = L.DomUtil.create("i", "fas fa-redo", anchor); 6757862dd5SDavid Drury image.alt = reset; 68dd6b2bfcSGreg Roach 69dd6b2bfcSGreg Roach return container; 70dd6b2bfcSGreg Roach }, 71dd6b2bfcSGreg Roach }); 72dd6b2bfcSGreg Roach 73dd6b2bfcSGreg Roach /** 74dd6b2bfcSGreg Roach * 75dd6b2bfcSGreg Roach * @private 76dd6b2bfcSGreg Roach */ 77dd6b2bfcSGreg Roach let _drawMap = function () { 78dd6b2bfcSGreg Roach map = L.map("osm-map", { 79dd6b2bfcSGreg Roach center: [0, 0], 80dd6b2bfcSGreg Roach minZoom: baseData.minZoom, // maxZoom set by leaflet-providers.js 81dd6b2bfcSGreg Roach zoomControl: false, // remove default 82dd6b2bfcSGreg Roach }); 83dd6b2bfcSGreg Roach L.tileLayer.provider(baseData.providerName, baseData.providerOptions).addTo(map); 84dd6b2bfcSGreg Roach L.control.zoom({ // Add zoom with localised text 8557862dd5SDavid Drury zoomInTitle: <?= json_encode(I18N::translate('Zoom in')) ?>, 8657862dd5SDavid Drury zoomOutTitle: <?= json_encode(I18N::translate('Zoom out')) ?>, 87dd6b2bfcSGreg Roach }).addTo(map); 88dd6b2bfcSGreg Roach }; 89dd6b2bfcSGreg Roach 90dd6b2bfcSGreg Roach let _addLayer = function () { 91dd6b2bfcSGreg Roach let geoJsonLayer; 92*0d123f04SDavid Drury let sidebar_content = ""; 93dd6b2bfcSGreg Roach 94dd6b2bfcSGreg Roach let data = <?= json_encode($data) ?>; 95dd6b2bfcSGreg Roach 96dd6b2bfcSGreg Roach geoJsonLayer = L.geoJson(data, { 97dd6b2bfcSGreg Roach pointToLayer: function (feature, latlng) { 98dd6b2bfcSGreg Roach return new L.Marker(latlng, { 99dd6b2bfcSGreg Roach icon: L.BeautifyIcon.icon({ 100dd6b2bfcSGreg Roach icon: feature.properties.icon["name"], 101dd6b2bfcSGreg Roach borderColor: "transparent", 10280993423SGreg Roach backgroundColor: feature.properties.icon["color"], 103dd6b2bfcSGreg Roach iconShape: "marker", 10480993423SGreg Roach textColor: "white", 105dd6b2bfcSGreg Roach }), 106dd6b2bfcSGreg Roach title: feature.properties.tooltip, 107dd6b2bfcSGreg Roach alt: feature.properties.tooltip, 108dd6b2bfcSGreg Roach id: feature.id, 109dd6b2bfcSGreg Roach }) 110dd6b2bfcSGreg Roach .on("popupopen", function (e) { 111dd6b2bfcSGreg Roach let item = sidebar.children(".gchart[data-id=" + e.target.feature.id + "]"); 112dd6b2bfcSGreg Roach item.addClass("messagebox"); 113dd6b2bfcSGreg Roach sidebar.scrollTo(item); 114dd6b2bfcSGreg Roach }) 115dd6b2bfcSGreg Roach .on("popupclose", function () { 116*0d123f04SDavid Drury sidebar.children(".gchart") 117dd6b2bfcSGreg Roach .removeClass("messagebox"); 118dd6b2bfcSGreg Roach }); 119dd6b2bfcSGreg Roach }, 120dd6b2bfcSGreg Roach onEachFeature: function (feature, layer) { 121dd6b2bfcSGreg Roach layer.bindPopup(feature.properties.summary); 122*0d123f04SDavid Drury sidebar_content += `<li class="gchart px-md-2" data-id=${feature.id}>${feature.properties.summary}</li>`; 123dd6b2bfcSGreg Roach }, 124dd6b2bfcSGreg Roach }); 125dd6b2bfcSGreg Roach 126dd6b2bfcSGreg Roach if (data.features.length > 0) { 127*0d123f04SDavid Drury sidebar.append(sidebar_content); 128dd6b2bfcSGreg Roach markers.addLayer(geoJsonLayer); 129dd6b2bfcSGreg Roach map 130dd6b2bfcSGreg Roach .addControl(new resetControl()) 131dd6b2bfcSGreg Roach .addLayer(markers); 132dd6b2bfcSGreg Roach 133dd6b2bfcSGreg Roach if (data.features.length === 1) { 134dd6b2bfcSGreg Roach map.setView(markers.getBounds().getCenter(), data.features[0].properties.zoom); 135dd6b2bfcSGreg Roach } else { 136dd6b2bfcSGreg Roach map.fitBounds(markers.getBounds().pad(0.2)) 137dd6b2bfcSGreg Roach } 138dd6b2bfcSGreg Roach } else { 139dd6b2bfcSGreg Roach map.fitWorld(); 140*0d123f04SDavid Drury sidebar.append('<div class="bg-info text-white">' + <?= json_encode(I18N::translate('No mappable items')) ?> + "</div>"); 141dd6b2bfcSGreg Roach } 142dd6b2bfcSGreg Roach }; 143dd6b2bfcSGreg Roach 144dd6b2bfcSGreg Roach /** 145dd6b2bfcSGreg Roach * 146dd6b2bfcSGreg Roach * @param elem 147dd6b2bfcSGreg Roach * @returns {$} 148dd6b2bfcSGreg Roach */ 149dd6b2bfcSGreg Roach 150dd6b2bfcSGreg Roach $.fn.scrollTo = function (elem) { 151dd6b2bfcSGreg Roach let _this = $(this); 152dd6b2bfcSGreg Roach _this.animate({ 153dd6b2bfcSGreg Roach scrollTop: elem.offset().top - _this.offset().top + _this.scrollTop(), 154dd6b2bfcSGreg Roach }); 155dd6b2bfcSGreg Roach return this; 156dd6b2bfcSGreg Roach }; 157dd6b2bfcSGreg Roach 158dd6b2bfcSGreg Roach return { 159dd6b2bfcSGreg Roach drawMap: function () { 160dd6b2bfcSGreg Roach _drawMap(); 161dd6b2bfcSGreg Roach _addLayer(); 162dd6b2bfcSGreg Roach 163dd6b2bfcSGreg Roach // Activate marker popup when sidebar entry clicked 164*0d123f04SDavid Drury sidebar 165dd6b2bfcSGreg Roach .on("click", ".gchart", function (e) { 166dd6b2bfcSGreg Roach // first close any existing 167dd6b2bfcSGreg Roach map.closePopup(); 168dd6b2bfcSGreg Roach let eventId = $(this).data("id"); 169dd6b2bfcSGreg Roach //find the marker corresponding to the clicked event 170dd6b2bfcSGreg Roach let mkrLayer = markers.getLayers().filter(function (v) { 171dd6b2bfcSGreg Roach return typeof(v.feature) !== "undefined" && v.feature.id === eventId; 172dd6b2bfcSGreg Roach }); 173dd6b2bfcSGreg Roach let mkr = mkrLayer.pop(); 174dd6b2bfcSGreg Roach // Unfortunately zoomToShowLayer zooms to maxZoom 175dd6b2bfcSGreg Roach // when all marker in a cluster have exactly the 176dd6b2bfcSGreg Roach // same co-ordinates 177dd6b2bfcSGreg Roach markers.zoomToShowLayer(mkr, function (e) { 178dd6b2bfcSGreg Roach mkr.openPopup(); 179dd6b2bfcSGreg Roach }); 180dd6b2bfcSGreg Roach return false; 181dd6b2bfcSGreg Roach }) 182dd6b2bfcSGreg Roach .on("click", "a", function (e) { // stop click on a person also opening the popup 183dd6b2bfcSGreg Roach e.stopPropagation(); 184dd6b2bfcSGreg Roach }); 185dd6b2bfcSGreg Roach }, 186dd6b2bfcSGreg Roach }; 187dd6b2bfcSGreg Roach })(); 188dd6b2bfcSGreg Roach 189dd6b2bfcSGreg Roach WT_OSM.drawMap(); 190dd6b2bfcSGreg Roach</script> 191