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