xref: /webtrees/resources/views/modules/pedigree-map/chart.phtml (revision c68bbde3fd3a1107017d0bcdef7ad21101600e21)
19ec21bfdSGreg Roach<?php
2d70512abSGreg Roach
39ec21bfdSGreg Roachuse Fisharebest\Webtrees\I18N;
49ec21bfdSGreg Roachuse Fisharebest\Webtrees\View;
59ec21bfdSGreg Roach
69ec21bfdSGreg Roach/**
7dc270d8cSGreg Roach * @var array<mixed> $data
8c9c6f2ecSGreg Roach * @var object       $leaflet_config
99ec21bfdSGreg Roach */
109ec21bfdSGreg Roach?>
119ec21bfdSGreg Roach
123dcc812bSGreg Roach<div class="py-4">
133dcc812bSGreg Roach    <div class="row gchart osm-wrapper">
14a2e602dbSGreg 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>
163dcc812bSGreg Roach    </div>
173dcc812bSGreg Roach</div>
183dcc812bSGreg Roach
193dcc812bSGreg Roach<?php View::push('styles') ?>
203dcc812bSGreg Roach<style>
213dcc812bSGreg Roach    .osm-wrapper, .osm-user-map {
220d123f04SDavid Drury        height: 70vh
233dcc812bSGreg Roach    }
243dcc812bSGreg Roach
253dcc812bSGreg Roach    .osm-sidebar {
263dcc812bSGreg Roach        height: 100%;
273dcc812bSGreg Roach        overflow-y: auto;
283dcc812bSGreg Roach        font-size: small;
293dcc812bSGreg Roach    }
303dcc812bSGreg Roach
313dcc812bSGreg Roach</style>
323dcc812bSGreg Roach<?php View::endpush() ?>
333dcc812bSGreg Roach
343dcc812bSGreg Roach<?php View::push('javascript') ?>
3529eb5762SGreg Roach<script>
3629eb5762SGreg Roach  'use strict';
373dcc812bSGreg Roach
383dcc812bSGreg Roach  window.WT_OSM = (function () {
39c9c6f2ecSGreg Roach    const config = <?= json_encode($leaflet_config) ?>;
4098579324SDavid Drury    const minZoom = 2;
413dcc812bSGreg Roach
423dcc812bSGreg Roach    let map = null;
430d123f04SDavid Drury    let sidebar = $('.osm-sidebar');
4498579324SDavid Drury
4598579324SDavid Drury// Map components
463dcc812bSGreg Roach    let markers = L.markerClusterGroup({
4729eb5762SGreg Roach      showCoverageOnHover: false,
483dcc812bSGreg Roach    });
493dcc812bSGreg Roach
503dcc812bSGreg Roach    let resetControl = L.Control.extend({
513dcc812bSGreg Roach      options: {
5229eb5762SGreg Roach        position: 'topleft',
533dcc812bSGreg Roach      },
543dcc812bSGreg Roach      onAdd: function (map) {
553dcc812bSGreg Roach        let container = L.DomUtil.create('div', 'leaflet-bar leaflet-control leaflet-control-custom');
563dcc812bSGreg Roach        container.onclick = function () {
57*c68bbde3SGreg Roach          map.flyToBounds(markers.getBounds(), { padding: [50, 30], maxZoom: 15 });
5829eb5762SGreg Roach          sidebar.scrollTo(sidebar.children(':first'));
5936409e74SGreg Roach
603dcc812bSGreg Roach          return false;
613dcc812bSGreg Roach        };
62c9c6f2ecSGreg Roach        let reset = config.i18n.reset;
633dcc812bSGreg Roach        let anchor = L.DomUtil.create('a', 'leaflet-control-reset', container);
6498579324SDavid Drury        anchor.setAttribute('aria-label', reset);
653dcc812bSGreg Roach        anchor.href = '#';
66a4321966SGreg Roach        anchor.title = reset;
673dcc812bSGreg Roach        anchor.role = 'button';
683dcc812bSGreg Roach        let image = L.DomUtil.create('i', 'fas fa-redo', anchor);
69a4321966SGreg Roach        image.alt = reset;
703dcc812bSGreg Roach
713dcc812bSGreg Roach        return container;
7229eb5762SGreg Roach      },
7398579324SDavid Drury    });
7498579324SDavid Drury
753dcc812bSGreg Roach    /**
763dcc812bSGreg Roach     * @private
773dcc812bSGreg Roach     */
783dcc812bSGreg Roach    let _drawMap = function () {
79c9c6f2ecSGreg Roach      map = webtrees.buildLeafletJsMap('osm-map', config)
80c9c6f2ecSGreg Roach        .addControl(new resetControl());
813dcc812bSGreg Roach    };
823dcc812bSGreg Roach
833dcc812bSGreg Roach    /**
843dcc812bSGreg Roach     * @private
853dcc812bSGreg Roach     */
8698579324SDavid Drury    let _buildMapData = function () {
870d123f04SDavid Drury      let sidebar_content = '';
8898579324SDavid Drury      let geoJson_data = <?= json_encode($data) ?>;
893dcc812bSGreg Roach
9098579324SDavid Drury      if (geoJson_data.features.length === 0) {
9198579324SDavid Drury        map.fitWorld();
9298579324SDavid Drury        sidebar_content += '<div class="bg-info text-white text-center">' + <?= json_encode(I18N::translate('Nothing to show')) ?> + '</div>';
9398579324SDavid Drury      } else {
9498579324SDavid Drury        let geoJsonLayer = L.geoJson(geoJson_data, {
953dcc812bSGreg Roach          pointToLayer: function (feature, latlng) {
963dcc812bSGreg Roach            return new L.Marker(latlng, {
973dcc812bSGreg Roach              icon: L.BeautifyIcon.icon({
983130efd4SGreg Roach                icon: 'bullseye fas',
993dcc812bSGreg Roach                borderColor: 'transparent',
1003130efd4SGreg Roach                backgroundColor: feature.properties.iconcolor,
1013dcc812bSGreg Roach                iconShape: 'marker',
1023130efd4SGreg Roach                textColor: 'white',
1033dcc812bSGreg Roach              }),
1043dcc812bSGreg Roach              title: feature.properties.tooltip,
1053dcc812bSGreg Roach              alt: feature.properties.tooltip,
10629eb5762SGreg Roach              id: feature.id,
1073dcc812bSGreg Roach            })
1083dcc812bSGreg Roach              .on('popupopen', function (e) {
10929eb5762SGreg Roach                let item = sidebar.children('.gchart[data-id=' + e.target.feature.id + ']');
1103dcc812bSGreg Roach                item.addClass('messagebox');
1113dcc812bSGreg Roach                sidebar.scrollTo(item);
1123dcc812bSGreg Roach              })
1133dcc812bSGreg Roach              .on('popupclose', function () {
11429eb5762SGreg Roach                sidebar.children('.gchart').removeClass('messagebox');
1153dcc812bSGreg Roach              });
1163dcc812bSGreg Roach          },
1173dcc812bSGreg Roach          onEachFeature: function (feature, layer) {
1183dcc812bSGreg Roach            if (feature.properties.polyline) {
1193dcc812bSGreg Roach              let pline = L.polyline(feature.properties.polyline.points, feature.properties.polyline.options);
1203dcc812bSGreg Roach              markers.addLayer(pline);
1213dcc812bSGreg Roach            }
1223dcc812bSGreg Roach            layer.bindPopup(feature.properties.summary);
1230d123f04SDavid Drury            sidebar_content += `<li class="gchart px-md-2" data-id=${feature.id}>${feature.properties.summary}</li>`;
12429eb5762SGreg Roach          },
1253dcc812bSGreg Roach        });
1263dcc812bSGreg Roach        markers.addLayer(geoJsonLayer);
12798579324SDavid Drury        map.addLayer(markers);
128*c68bbde3SGreg Roach        map.flyToBounds(markers.getBounds(), { padding: [50, 30], maxZoom: 15 });
1293dcc812bSGreg Roach      }
13098579324SDavid Drury      sidebar.append(sidebar_content);
1313dcc812bSGreg Roach    };
1323dcc812bSGreg Roach
1333dcc812bSGreg Roach    /**
1343dcc812bSGreg Roach     * @param   elem
1353dcc812bSGreg Roach     * @returns {$}
1363dcc812bSGreg Roach     */
1373dcc812bSGreg Roach    $.fn.scrollTo = function (elem) {
1383dcc812bSGreg Roach      let _this = $(this);
1393dcc812bSGreg Roach      _this.animate({
14029eb5762SGreg Roach        scrollTop: elem.offset().top - _this.offset().top + _this.scrollTop(),
1413dcc812bSGreg Roach      });
1423dcc812bSGreg Roach      return this;
1433dcc812bSGreg Roach    };
1443dcc812bSGreg Roach
1453dcc812bSGreg Roach    // Activate marker popup when sidebar entry clicked
1463dcc812bSGreg Roach    $(function () {
1470d123f04SDavid Drury      sidebar
1483dcc812bSGreg Roach        // open marker popup if sidebar event is clicked
1493dcc812bSGreg Roach        .on('click', '.gchart', function (e) {
1503dcc812bSGreg Roach          // first close any existing
1513dcc812bSGreg Roach          map.closePopup();
1523dcc812bSGreg Roach          let eventId = $(this).data('id');
1533dcc812bSGreg Roach          //find the marker corresponding to the clicked event
1543dcc812bSGreg Roach          let mkrLayer = markers.getLayers().filter(function (v) {
1553dcc812bSGreg Roach            return typeof (v.feature) !== 'undefined' && v.feature.id === eventId;
1563dcc812bSGreg Roach          });
1573dcc812bSGreg Roach          let mkr = mkrLayer.pop();
1583dcc812bSGreg Roach          // Unfortunately zoomToShowLayer zooms to maxZoom
1593dcc812bSGreg Roach          // when all marker in a cluster have exactly the
1603dcc812bSGreg Roach          // same co-ordinates
1613dcc812bSGreg Roach          markers.zoomToShowLayer(mkr, function (e) {
1623dcc812bSGreg Roach            mkr.openPopup();
1633dcc812bSGreg Roach          });
16498579324SDavid Drury
1653dcc812bSGreg Roach          return false;
1663dcc812bSGreg Roach        })
1673dcc812bSGreg Roach        .on('click', 'a', function (e) { // stop click on a person also opening the popup
1683dcc812bSGreg Roach          e.stopPropagation();
1693dcc812bSGreg Roach        });
1703dcc812bSGreg Roach    });
1713dcc812bSGreg Roach
1723dcc812bSGreg Roach    _drawMap();
17398579324SDavid Drury    _buildMapData();
1743dcc812bSGreg Roach
17529eb5762SGreg Roach    return 'Leaflet map interface for webtrees-2';
1763dcc812bSGreg Roach  })();
1773dcc812bSGreg Roach</script>
1783dcc812bSGreg Roach<?php View::endpush() ?>
179