xref: /webtrees/resources/views/modules/places/tab.phtml (revision c9c6f2ec6e88594e58f14a6418e0de5aaa1484bd)
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