xref: /webtrees/resources/views/modules/pedigree-map/chart.phtml (revision dc270d8cc5085ed29f3f419c99734ddd0960c624)
19ec21bfdSGreg Roach<?php
2d70512abSGreg Roach
39ec21bfdSGreg Roachuse Fisharebest\Webtrees\I18N;
49ec21bfdSGreg Roachuse Fisharebest\Webtrees\View;
59ec21bfdSGreg Roach
69ec21bfdSGreg Roach/**
7*dc270d8cSGreg Roach * @var array<mixed> $data
8*dc270d8cSGreg Roach * @var array<mixed> $provider
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 Roachwindow.WT_OSM = (function () {
3998579324SDavid Drury  const minZoom = 2;
403dcc812bSGreg Roach
413dcc812bSGreg Roach  let map      = null;
423dcc812bSGreg Roach  let zoom     = null;
430d123f04SDavid Drury  let sidebar  = $('.osm-sidebar');
4498579324SDavid Drury  let provider = <?= json_encode($provider) ?>;
4598579324SDavid Drury
4698579324SDavid Drury// Map components
473dcc812bSGreg Roach  let markers = L.markerClusterGroup({
4829eb5762SGreg Roach    showCoverageOnHover: false,
493dcc812bSGreg Roach  });
503dcc812bSGreg Roach
513dcc812bSGreg Roach  let resetControl = L.Control.extend({
523dcc812bSGreg Roach    options: {
5329eb5762SGreg Roach      position: 'topleft',
543dcc812bSGreg Roach    },
553dcc812bSGreg Roach    onAdd:   function (map) {
563dcc812bSGreg Roach      let container     = L.DomUtil.create('div', 'leaflet-bar leaflet-control leaflet-control-custom');
573dcc812bSGreg Roach      container.onclick = function () {
583dcc812bSGreg Roach        if (zoom) {
593dcc812bSGreg Roach          map.flyTo(markers.getBounds().getCenter(), zoom);
603dcc812bSGreg Roach        } else {
613dcc812bSGreg Roach          map.flyToBounds(markers.getBounds().pad(0.2));
623dcc812bSGreg Roach        }
6329eb5762SGreg Roach        sidebar.scrollTo(sidebar.children(':first'));
6436409e74SGreg Roach
653dcc812bSGreg Roach        return false;
663dcc812bSGreg Roach      };
6798579324SDavid Drury      let reset         = <?= json_encode(I18N::translate('Reload map')) ?>;
683dcc812bSGreg Roach      let anchor        = L.DomUtil.create('a', 'leaflet-control-reset', container);
6998579324SDavid Drury      anchor.setAttribute('aria-label', reset);
703dcc812bSGreg Roach      anchor.href  = '#';
71a4321966SGreg Roach      anchor.title = reset;
723dcc812bSGreg Roach      anchor.role  = 'button';
733dcc812bSGreg Roach      let image    = L.DomUtil.create('i', 'fas fa-redo', anchor);
74a4321966SGreg Roach      image.alt    = reset;
753dcc812bSGreg Roach
763dcc812bSGreg Roach      return container;
7729eb5762SGreg Roach    },
7898579324SDavid Drury  });
7998579324SDavid Drury
8098579324SDavid Drury// Zoom control with localised text
8198579324SDavid Drury  let newZoomControl = new L.control.zoom({
8298579324SDavid Drury    zoomInTitle: <?= json_encode(I18N::translate('Zoom in')) ?>,
8398579324SDavid Drury    zoomOutTitle: <?= json_encode(I18N::translate('Zoom out')) ?>,
843dcc812bSGreg Roach  });
853dcc812bSGreg Roach
863dcc812bSGreg Roach  /**
873dcc812bSGreg Roach   *
883dcc812bSGreg Roach   * @private
893dcc812bSGreg Roach   */
903dcc812bSGreg Roach  let _drawMap = function () {
913dcc812bSGreg Roach    map = L.map('osm-map', {
923dcc812bSGreg Roach      center:      [0, 0],
9398579324SDavid Drury      minZoom:     minZoom,   // maxZoom set by leaflet-providers.js
943dcc812bSGreg Roach      zoomControl: false,     // remove default
9598579324SDavid Drury    })
9698579324SDavid Drury    .addControl(new resetControl())
9798579324SDavid Drury    .addControl(newZoomControl)
982cbb0620SDavid Drury    .addLayer(L.tileLayer(provider.url, provider.options));
993dcc812bSGreg Roach  };
1003dcc812bSGreg Roach
1013dcc812bSGreg Roach  /**
1023dcc812bSGreg Roach   * @private
1033dcc812bSGreg Roach   */
10498579324SDavid Drury  let _buildMapData = function () {
1050d123f04SDavid Drury    let sidebar_content = '';
10698579324SDavid Drury    let geoJson_data    = <?= json_encode($data) ?>;
1073dcc812bSGreg Roach
10898579324SDavid Drury    if (geoJson_data.features.length === 0) {
10998579324SDavid Drury      map.fitWorld();
11098579324SDavid Drury      sidebar_content += '<div class="bg-info text-white text-center">' + <?= json_encode(I18N::translate('Nothing to show')) ?> +'</div>';
11198579324SDavid Drury    } else {
11298579324SDavid Drury      if (geoJson_data.features.length === 1) {
11398579324SDavid Drury        //fudge factor - maps zooms to maximum permitted otherwise
11498579324SDavid Drury        zoom = geoJson_data.features[0].properties.zoom;
1153dcc812bSGreg Roach      }
11698579324SDavid Drury      let geoJsonLayer = L.geoJson(geoJson_data, {
1173dcc812bSGreg Roach        pointToLayer:  function (feature, latlng) {
1183dcc812bSGreg Roach          return new L.Marker(latlng, {
1193dcc812bSGreg Roach            icon:  L.BeautifyIcon.icon({
1203130efd4SGreg Roach              icon:            'bullseye fas',
1213dcc812bSGreg Roach              borderColor:     'transparent',
1223130efd4SGreg Roach              backgroundColor: feature.properties.iconcolor,
1233dcc812bSGreg Roach              iconShape:       'marker',
1243130efd4SGreg Roach              textColor:       'white',
1253dcc812bSGreg Roach            }),
1263dcc812bSGreg Roach            title: feature.properties.tooltip,
1273dcc812bSGreg Roach            alt:   feature.properties.tooltip,
12829eb5762SGreg Roach            id:    feature.id,
1293dcc812bSGreg Roach          })
1303dcc812bSGreg Roach          .on('popupopen', function (e) {
13129eb5762SGreg Roach            let item = sidebar.children('.gchart[data-id=' + e.target.feature.id + ']');
1323dcc812bSGreg Roach            item.addClass('messagebox');
1333dcc812bSGreg Roach            sidebar.scrollTo(item);
1343dcc812bSGreg Roach          })
1353dcc812bSGreg Roach          .on('popupclose', function () {
13629eb5762SGreg Roach            sidebar.children('.gchart').removeClass('messagebox');
1373dcc812bSGreg Roach          });
1383dcc812bSGreg Roach        },
1393dcc812bSGreg Roach        onEachFeature: function (feature, layer) {
1403dcc812bSGreg Roach          if (feature.properties.polyline) {
1413dcc812bSGreg Roach            let pline = L.polyline(feature.properties.polyline.points, feature.properties.polyline.options);
1423dcc812bSGreg Roach            markers.addLayer(pline);
1433dcc812bSGreg Roach          }
1443dcc812bSGreg Roach          layer.bindPopup(feature.properties.summary);
1450d123f04SDavid Drury          sidebar_content += `<li class="gchart px-md-2" data-id=${feature.id}>${feature.properties.summary}</li>`;
14629eb5762SGreg Roach        },
1473dcc812bSGreg Roach      });
1483dcc812bSGreg Roach      markers.addLayer(geoJsonLayer);
14998579324SDavid Drury      map.addLayer(markers);
1503dcc812bSGreg Roach      if (zoom) {
1513dcc812bSGreg Roach        map.setView(markers.getBounds().getCenter(), zoom);
15298579324SDavid Drury      } else {
15345e60b72SGreg Roach        map.fitBounds(markers.getBounds(), {padding: [50, 30]});
1543dcc812bSGreg Roach      }
1553dcc812bSGreg Roach    }
15698579324SDavid Drury    sidebar.append(sidebar_content);
1573dcc812bSGreg Roach  };
1583dcc812bSGreg Roach
1593dcc812bSGreg Roach  /**
1603dcc812bSGreg Roach   * @param   elem
1613dcc812bSGreg Roach   * @returns {$}
1623dcc812bSGreg Roach   */
1633dcc812bSGreg Roach  $.fn.scrollTo = function (elem) {
1643dcc812bSGreg Roach    let _this = $(this);
1653dcc812bSGreg Roach    _this.animate({
16629eb5762SGreg Roach      scrollTop: elem.offset().top - _this.offset().top + _this.scrollTop(),
1673dcc812bSGreg Roach    });
1683dcc812bSGreg Roach    return this;
1693dcc812bSGreg Roach  };
1703dcc812bSGreg Roach
1713dcc812bSGreg Roach// Activate marker popup when sidebar entry clicked
1723dcc812bSGreg Roach  $(function () {
1730d123f04SDavid Drury    sidebar
1743dcc812bSGreg Roach    // open marker popup if sidebar event is clicked
1753dcc812bSGreg Roach    .on('click', '.gchart', function (e) {
1763dcc812bSGreg Roach      // first close any existing
1773dcc812bSGreg Roach      map.closePopup();
1783dcc812bSGreg Roach      let eventId  = $(this).data('id');
1793dcc812bSGreg Roach      //find the marker corresponding to the clicked event
1803dcc812bSGreg Roach      let mkrLayer = markers.getLayers().filter(function (v) {
1813dcc812bSGreg Roach        return typeof (v.feature) !== 'undefined' && v.feature.id === eventId;
1823dcc812bSGreg Roach      });
1833dcc812bSGreg Roach      let mkr      = mkrLayer.pop();
1843dcc812bSGreg Roach      // Unfortunately zoomToShowLayer zooms to maxZoom
1853dcc812bSGreg Roach      // when all marker in a cluster have exactly the
1863dcc812bSGreg Roach      // same co-ordinates
1873dcc812bSGreg Roach      markers.zoomToShowLayer(mkr, function (e) {
1883dcc812bSGreg Roach        mkr.openPopup();
1893dcc812bSGreg Roach      });
19098579324SDavid Drury
1913dcc812bSGreg Roach      return false;
1923dcc812bSGreg Roach    })
1933dcc812bSGreg Roach    .on('click', 'a', function (e) { // stop click on a person also opening the popup
1943dcc812bSGreg Roach      e.stopPropagation();
1953dcc812bSGreg Roach    });
1963dcc812bSGreg Roach  });
1973dcc812bSGreg Roach
1983dcc812bSGreg Roach  _drawMap();
19998579324SDavid Drury  _buildMapData();
2003dcc812bSGreg Roach
20129eb5762SGreg Roach  return 'Leaflet map interface for webtrees-2';
2023dcc812bSGreg Roach})();
2033dcc812bSGreg Roach</script>
2043dcc812bSGreg Roach<?php View::endpush() ?>
205