xref: /webtrees/resources/views/modules/places/tab.phtml (revision 57ef7ac6db560b286523c95faa3ff1c86603f361)
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>
32dd6b2bfcSGreg Roach    "use strict";
33dd6b2bfcSGreg Roach
34dd6b2bfcSGreg Roach    window.WT_OSM = (function() {
35c9c6f2ecSGreg Roach        const config = <?= json_encode($leaflet_config) ?>;
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() {
52*57ef7ac6Smiqrogroove                    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 = "";
85dd6b2bfcSGreg Roach            let data            = <?= json_encode($data) ?>;
86dd6b2bfcSGreg Roach
87597fb44bSDavid Drury            if (data.features.length === 0) {
88597fb44bSDavid Drury                map.fitWorld();
89597fb44bSDavid Drury                sidebar_content += '<div class="bg-info text-white text-center">' + <?= json_encode(I18N::translate('Nothing to show')) ?> + '</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) {
106dd6b2bfcSGreg Roach                            let item = sidebar.children(".gchart[data-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);
1170d123f04SDavid Drury                        sidebar_content += `<li class="gchart px-md-2" data-id=${feature.id}>${feature.properties.summary}</li>`;
118dd6b2bfcSGreg Roach                    },
119dd6b2bfcSGreg Roach                });
120dd6b2bfcSGreg Roach                markers.addLayer(geoJsonLayer);
121597fb44bSDavid Drury                map.addLayer(markers);
122*57ef7ac6Smiqrogroove                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