@raruto/leaflet-elevation 1.8.4 → 1.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/control.js CHANGED
@@ -17,7 +17,7 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
17
17
  __TOGEOJSON: 'https://unpkg.com/@tmcw/togeojson@4.3.0/dist/togeojson.umd.js',
18
18
  __LGEOMUTIL: 'https://unpkg.com/leaflet-geometryutil@0.9.3/src/leaflet.geometryutil.js',
19
19
  __LALMOSTOVER: 'https://unpkg.com/leaflet-almostover@1.0.1/src/leaflet.almostover.js',
20
- __LDISTANCEM: 'https://unpkg.com/@raruto/leaflet-elevation@1.8.4/libs/leaflet-distance-marker.min.js',
20
+ __LDISTANCEM: 'https://unpkg.com/@raruto/leaflet-elevation@1.8.5/libs/leaflet-distance-marker.min.js',
21
21
 
22
22
  /*
23
23
  * Add data to the diagram either from GPX or GeoJSON and update the axis domain and data
@@ -156,77 +156,62 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
156
156
  this._markedSegments = L.polyline([]);
157
157
  this._chartEnabled = true,
158
158
  this.track_info = {};
159
- this.options = _.deepMerge({}, this.options, options);
160
159
 
161
- if (this.options.followMarker) this._setMapView = L.Util.throttle(this._setMapView, 300, this);
162
- if (this.options.legend) this.options.margins.bottom += 30;
163
- if (this.options.theme) this.options.polylineSegments.className += ' ' + this.options.theme;
164
- if (this.options.wptIcons === true) this.options.wptIcons = Options.wptIcons;
160
+ L.setOptions(this, options);
161
+
162
+ if (this.options.followMarker) this._setMapView = L.Util.throttle(this._setMapView, 300, this);
163
+ if (this.options.legend) this.options.margins.bottom += 30;
164
+ if (this.options.theme) this.options.polylineSegments.className += ' ' + this.options.theme;
165
+ if (this.options.wptIcons === true) this.options.wptIcons = Options.wptIcons;
166
+ if (this.options.distanceMarkers === true) this.options.distanceMarkers = { lazy: true };
165
167
 
166
168
  this._markedSegments.setStyle(this.options.polylineSegments);
167
169
 
168
170
  // Leaflet canvas renderer colors
169
171
  L.extend(D3.Colors, this.options.colors || {});
172
+
173
+ // Various stuff
174
+ this._fixCanvasPaths();
175
+ this._fixTooltipSize();
170
176
  },
171
177
 
172
178
  /**
173
179
  * Javascript scripts downloader (lazy loader)
174
180
  */
175
- lazyLoad: function(src) {
176
- return _.lazyLoad(src, this);
181
+ lazyLoad: function(src, condition = false, loader = '') {
182
+ if (!this.options.lazyLoadJS) {
183
+ return Promise.resolve();
184
+ }
185
+ switch(src) {
186
+ case this.__D3:
187
+ loader = '_d3LazyLoader';
188
+ condition = typeof d3 !== 'object';
189
+ break;
190
+ case this.__TOGEOJSON:
191
+ loader = '_togeojsonLazyLoader';
192
+ condition = typeof toGeoJSON !== 'object';
193
+ break;
194
+ case this.__LGEOMUTIL:
195
+ loader = '_geomutilLazyLoader';
196
+ condition = typeof L.GeometryUtil !== 'object';
197
+ break;
198
+ case this.__LALMOSTOVER:
199
+ loader = '_almostoverLazyLoader';
200
+ condition = typeof L.Handler.AlmostOver !== 'function';
201
+ break;
202
+ case this.__LDISTANCEM:
203
+ loader = '_distanceMarkersLazyLoader';
204
+ condition = typeof L.DistanceMarkers !== 'function';
205
+ break;
206
+ }
207
+ return L.Control.Elevation[loader] = _.lazyLoader(src, condition, L.Control.Elevation[loader]);
177
208
  },
178
209
 
179
210
  /**
180
211
  * Load elevation data (GPX, GeoJSON or KML).
181
212
  */
182
213
  load: function(data) {
183
- if (_.isXMLDoc(data)) {
184
- this.loadXML(data);
185
- } else if (_.isJSONDoc(data)) {
186
- this.loadGeoJSON(data);
187
- } else {
188
- this.loadFile(data);
189
- }
190
- },
191
-
192
- /**
193
- * Load data from a remote url.
194
- */
195
- loadFile: function(url) {
196
- fetch(url)
197
- .then((response) => response.text())
198
- .then((data) => {
199
- this._downloadURL = url; // TODO: handle multiple urls?
200
- this.load(data);
201
- })
202
- .catch((err) => console.warn(err));
203
- },
204
-
205
- /**
206
- * Load raw GeoJSON data.
207
- */
208
- loadGeoJSON: function(data) {
209
- _.GeoJSONLoader(data, this);
210
- },
211
-
212
- /**
213
- * Load raw XML data.
214
- */
215
- loadXML: function(data) {
216
- this.lazyLoad(this.__TOGEOJSON)
217
- .then(() => {
218
- let xml = (new DOMParser()).parseFromString(data, "text/xml");
219
- let type = xml.documentElement.tagName.toLowerCase(); // "kml" or "gpx"
220
- if (!(type in toGeoJSON)) {
221
- type = xml.documentElement.tagName == "TrainingCenterDatabase" ? 'tcx' : 'gpx';
222
- }
223
- let geojson = toGeoJSON[type](xml);
224
- let name = xml.getElementsByTagName('name');
225
- if(name[0]) { geojson.name = name[0].innerHTML; }
226
- else if(this._downloadURL) { geojson.name = this._downloadURL.split('/').pop().split('#')[0].split('?')[0]; }
227
-
228
- return this.loadGeoJSON(geojson, this);
229
- });
214
+ this._parseFromString(data).then( geojson => geojson ? this._loadLayer(geojson) : this._loadFile(data));
230
215
  },
231
216
 
232
217
  /**
@@ -236,11 +221,8 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
236
221
  onAdd: function(map) {
237
222
  this._map = map;
238
223
 
239
- let container = this._container = _.create("div", "elevation-control elevation " + this.options.theme);
240
-
241
- if (!this.options.detached) {
242
- _.addClass(container, 'leaflet-control');
243
- }
224
+ let container = this._container = _.create("div", "elevation-control elevation " + this.options.theme + " " + (this.options.detached ? '' : 'leaflet-control'));
225
+
244
226
  this.lazyLoad(this.__D3)
245
227
  .then(() => {
246
228
  this._initButton(container);
@@ -256,8 +238,9 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
256
238
  .on('rotate', this._rotateMarker, this)
257
239
  .on('mousedown', this._resetDrag, this);
258
240
 
259
- _.on(map.getContainer(), 'mousewheel', this._resetDrag, this);
260
- _.on(map.getContainer(), 'touchstart', this._resetDrag, this);
241
+ _.on(map.getContainer(), 'mousewheel', this._resetDrag, this);
242
+ _.on(map.getContainer(), 'touchstart', this._resetDrag, this);
243
+ _.on(document, 'keydown', this._keydownHandler, this);
261
244
 
262
245
  this
263
246
  .on('eledata_added eledata_loaded', this._updateChart, this)
@@ -283,8 +266,9 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
283
266
  .off('resize', this._resizeChart, this)
284
267
  .off('mousedown', this._resetDrag, this);
285
268
 
286
- _.off(map.getContainer(), 'mousewheel', this._resetDrag, this);
287
- _.off(map.getContainer(), 'touchstart', this._resetDrag, this);
269
+ _.off(map.getContainer(), 'mousewheel', this._resetDrag, this);
270
+ _.off(map.getContainer(), 'touchstart', this._resetDrag, this);
271
+ _.off(document, 'keydown', this._keydownHandler, this);
288
272
 
289
273
  this
290
274
  .off('eledata_added eledata_loaded', this._updateChart, this)
@@ -387,12 +371,53 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
387
371
 
388
372
  _addLayer: function(layer) {
389
373
  if (layer) this._layers.addLayer(layer)
374
+ // Postpone adding the distance markers (lazy: true)
375
+ if (layer && this.options.distanceMarkers && this.options.distanceMarkers.lazy) {
376
+ layer.on('add remove', (e) => L.DistanceMarkers && e.target instanceof L.Polyline && e.target[e.type + 'DistanceMarkers']());
377
+ }
390
378
  },
391
379
 
392
380
  _addMarker: function(marker) {
393
381
  if (marker) this._markers.addLayer(marker)
394
382
  },
395
383
 
384
+ _bindPopup: function(marker) {
385
+ let popup = marker._popup;
386
+ if (popup) {
387
+ popup.options.className = 'elevation-popup';
388
+ if (popup._content) {
389
+ popup._content = decodeURI(popup._content);
390
+ popup.bindTooltip(popup._content, { direction: 'auto', sticky: true, opacity: 1, className: 'elevation-tooltip' }).openTooltip();
391
+ }
392
+ }
393
+ },
394
+
395
+ _initAlmostOverHandler: function(map, layer) {
396
+ if(!map || !this.options.almostOver) return;
397
+ this.lazyLoad(this.__LGEOMUTIL)
398
+ .then(() => this.lazyLoad(this.__LALMOSTOVER))
399
+ .then(() => {
400
+ map.addHandler('almostOver', L.Handler.AlmostOver)
401
+ if (L.GeometryUtil && map.almostOver && map.almostOver.enabled()) {
402
+ map.almostOver.addLayer(layer);
403
+ map
404
+ .on('almost:move', (e) => this._mousemoveLayerHandler(e))
405
+ .on('almost:out', (e) => this._mouseoutHandler(e));
406
+ }
407
+ });
408
+ },
409
+
410
+ _initDistanceMarkers: function(map, layer) {
411
+ if (!map) return;
412
+ if (this.options.distanceMarkers) {
413
+ this.lazyLoad(this.__LGEOMUTIL)
414
+ .then(() => this.lazyLoad(this.__LDISTANCEM))
415
+ .then(() => this.options.polyline && layer.addTo(map));
416
+ } else if (this.options.polyline) {
417
+ layer.addTo(map);
418
+ }
419
+ },
420
+
396
421
  /**
397
422
  * Adds the control to the given "detached" div.
398
423
  */
@@ -405,8 +430,7 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
405
430
  if (this.options.detached) {
406
431
  _.replaceClass(eleDiv, 'leaflet-control', 'elevation-detached');
407
432
  }
408
- this.eleDiv = eleDiv;
409
- return this.eleDiv;
433
+ return this.eleDiv = eleDiv;
410
434
  },
411
435
 
412
436
  /*
@@ -423,6 +447,58 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
423
447
  _.replaceClass(this._container, 'elevation-collapsed', 'elevation-expanded');
424
448
  },
425
449
 
450
+ /**
451
+ * Add some basic colors to leaflet canvas renderer (preferCanvas: true).
452
+ */
453
+ _fixCanvasPaths: function() {
454
+ let oldProto = L.Canvas.prototype._fillStroke;
455
+ let control = this;
456
+ L.Canvas.include({
457
+ _fillStroke: function(ctx, layer) {
458
+ if (control._layers.hasLayer(layer)) {
459
+
460
+ let theme = control.options.theme.replace('-theme', '');
461
+ let color = D3.Colors[theme] || {};
462
+ let options = layer.options;
463
+
464
+ options.color = color.line || color.area || theme;
465
+ options.stroke = !!options.color;
466
+
467
+ oldProto.call(this, ctx, layer);
468
+
469
+ if (options.stroke && options.weight !== 0) {
470
+ let oldVal = ctx.globalCompositeOperation || 'source-over';
471
+ ctx.globalCompositeOperation = 'destination-over'
472
+ ctx.strokeStyle = color.outline || '#FFF';
473
+ ctx.lineWidth = options.weight * 1.75;
474
+ ctx.stroke();
475
+ ctx.globalCompositeOperation = oldVal;
476
+ }
477
+
478
+ } else {
479
+ oldProto.call(this, ctx, layer);
480
+ }
481
+ }
482
+ });
483
+ },
484
+
485
+ /**
486
+ * Partial fix for initial tooltip size
487
+ *
488
+ * @link https://github.com/Raruto/leaflet-elevation/issues/81#issuecomment-713477050
489
+ */
490
+ _fixTooltipSize: function() {
491
+ this.on('elechart_init', () =>
492
+ this.once('elechart_change elechart_hover', e => {
493
+ if (this._chartEnabled) {
494
+ this._chart._showDiagramIndicator(e.data, e.xCoord);
495
+ this._chart._showDiagramIndicator(e.data, e.xCoord);
496
+ }
497
+ this._updateMarker(e.data);
498
+ })
499
+ );
500
+ },
501
+
426
502
  /*
427
503
  * Finds a data entry for the given LatLng
428
504
  */
@@ -522,7 +598,7 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
522
598
  },
523
599
 
524
600
  _initMarker: function(map) {
525
- let pane = map.getPane('elevationPane');
601
+ let pane = map.getPane('elevationPane');
526
602
  if (!pane) {
527
603
  pane = this._pane = map.createPane('elevationPane', map.getPane('norotatePane') || map.getPane('mapPane'));
528
604
  pane.style.zIndex = 625; // This pane is above markers but below popups.
@@ -530,8 +606,8 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
530
606
  }
531
607
 
532
608
  if (this._renderer) this._renderer.remove()
533
- this._renderer = L.svg({ pane: "elevationPane" }).addTo(this._map); // default leaflet svg renderer
534
- this._marker = new Marker(this.options);
609
+ this._renderer = L.svg({ pane: "elevationPane" }).addTo(this._map); // default leaflet svg renderer
610
+ this._marker = new Marker(this.options);
535
611
 
536
612
  this._fireEvt("elechart_marker");
537
613
  },
@@ -540,21 +616,13 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
540
616
  * Inspired by L.Control.Layers
541
617
  */
542
618
  _initButton: function(container) {
543
- //Makes this work on IE10 Touch devices by stopping it from firing a mouseout event when the touch is released
544
- container.setAttribute('aria-haspopup', true);
545
619
 
546
- if (!this.options.detached) {
620
+ if (L.Browser.mobile || !this.options.detached) {
547
621
  L.DomEvent
548
622
  .disableClickPropagation(container)
549
623
  .disableScrollPropagation(container);
550
624
  }
551
625
 
552
- if (L.Browser.mobile) {
553
- _.on(container, 'click', L.DomEvent.stopPropagation);
554
- }
555
-
556
- _.on(container, 'mousewheel', this._mousewheelHandler, this);
557
-
558
626
  if (!this.options.detached) {
559
627
  let link = this._button = _.create('a', "elevation-toggle elevation-toggle-icon" + (this.options.autohide ? "" : " close-button"), { href: '#', title: L._('Elevation') }, container);
560
628
 
@@ -571,21 +639,131 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
571
639
  _.on(link, 'focus', this._toggle, this);
572
640
 
573
641
  this._map.on('click', this._collapse, this);
574
- // TODO: keyboard accessibility
575
642
  }
576
- } else {
577
- // TODO: handle autohide when detached=true
578
643
  }
579
644
  },
580
645
 
581
646
  _initSummary: function(container) {
582
- let summary = this._summary = new Summary({ summary: this.options.summary }, this);
647
+ this._summary = new Summary({ summary: this.options.summary }, this);
583
648
 
584
- d3
585
- .select(container)
586
- .call(summary.render());
649
+ d3.select(container).call(this._summary.render());
650
+ },
587
651
 
588
- this.summaryDiv = this._summary._container;
652
+ _keydownHandler: function(e) {
653
+ if(!this.options.detached && e.key === "Escape"){
654
+ this._collapse()
655
+ };
656
+ },
657
+
658
+ /**
659
+ * Retrieve data from a remote url (HTTP).
660
+ */
661
+ _loadFile: function(url) {
662
+ fetch(url)
663
+ .then((response) => response.text())
664
+ .then((data) => {
665
+ this._downloadURL = url; // TODO: handle multiple urls?
666
+ this.load(data);
667
+ })
668
+ .catch((err) => console.warn(err));
669
+ },
670
+
671
+ /**
672
+ * Simple GeoJSON data loader (L.GeoJSON).
673
+ */
674
+ _loadLayer: function(geojson) {
675
+ let control = this;
676
+
677
+ let { wptIcons, wptLabels } = control.options;
678
+
679
+ let layer = L.geoJson(geojson, {
680
+ distanceMarkers: control.options.distanceMarkers,
681
+ style: (feature) => {
682
+ let style = L.extend({}, control.options.polyline);
683
+ if (control.options.theme) {
684
+ style.className += ' ' + control.options.theme;
685
+ }
686
+ return style;
687
+ },
688
+ pointToLayer: (feature, latlng) => {
689
+ if (!control.options.waypoints) return;
690
+
691
+ let prop = feature.properties;
692
+ let desc = prop.desc ?? '';
693
+ let name = prop.name ?? '';
694
+ let sym = (prop.sym ?? name).replace(' ', '-').replace('"', '').replace("'", '').toLowerCase();
695
+
696
+ // Handle chart waypoints (dots)
697
+ if ([true, 'dots'].includes(control.options.waypoints)) {
698
+ control._registerCheckPoint({
699
+ latlng: latlng,
700
+ label: ([true, 'dots'].includes(wptLabels) ? name : '')
701
+ });
702
+ }
703
+
704
+ // Handle map waypoints (markers)
705
+ if ([true, 'markers'].includes(control.options.waypoints) && wptIcons != false) {
706
+ // generate and cache appropriate icon symbol
707
+ if (!wptIcons.hasOwnProperty(sym)) {
708
+ wptIcons[sym] = L.divIcon(
709
+ L.extend({}, wptIcons[""].options, { html: '<i class="elevation-waypoint-icon ' + sym + '"></i>' } )
710
+ );
711
+ }
712
+ let marker = L.marker(latlng, { icon: wptIcons[sym] });
713
+ if ([true, 'markers'].includes(wptLabels) && (name || desc)) {
714
+ marker.bindPopup("<b>" + name + "</b>" + (desc.length > 0 ? '<br>' + desc : '')).openPopup();
715
+ }
716
+ control._addMarker(marker);
717
+ control._bindPopup(marker);
718
+ control.fire('waypoint_added', { point: marker, element: latlng, properties: prop });
719
+ return marker;
720
+ }
721
+ },
722
+ onEachFeature: (feature, layer) => {
723
+ if (feature.geometry && feature.geometry.type == 'Point') return;
724
+
725
+ // Standard GeoJSON --> doesn't handle "time"
726
+ // control.addData(feature, layer); // NB make use of "_addGeoJSONData"
727
+
728
+ // Extended GeoJSON --> rely on leaflet implementation
729
+ layer._latlngs.forEach((point, i) => {
730
+ // same properties as L.GPX layer
731
+ point.meta = { time: null, ele: null, hr: null, cad: null, atemp: null };
732
+ if("alt" in point) point.meta.ele = point.alt;
733
+ if(feature.properties) {
734
+ let prop = feature.properties;
735
+ if("coordTimes" in prop) point.meta.time = new Date(Date.parse(prop.coordTimes[i]));
736
+ else if("times" in prop) point.meta.time = new Date(Date.parse(prop.times[i]));
737
+ else if("time" in prop) point.meta.time = new Date(Date.parse((typeof prop.time === 'object' ? prop.time[i] : prop.time)));
738
+ if("heartRates" in prop) point.meta.hr = parseInt(prop.heartRates[i]);
739
+ else if("heartRate" in prop) point.meta.hr = parseInt((typeof prop.heartRate === 'object' ? prop.heartRate[i] : prop.heartRate));
740
+ // TODO: cadence, temperature
741
+ }
742
+ });
743
+ control.addData(layer); // NB make use of "_addGPXData"
744
+
745
+ control.track_info = L.extend({}, control.track_info, { name: geojson.name });
746
+ },
747
+ });
748
+
749
+ control.lazyLoad(control.__D3).then(() => {
750
+ let map = control._map;
751
+ if (map) {
752
+ map.once('layeradd', (e) => control.options.autofitBounds && control.fitBounds(layer.getBounds()));
753
+ if (!L.Browser.mobile) {
754
+ control._initAlmostOverHandler(map, layer);
755
+ control._initDistanceMarkers(map, layer);
756
+ } else if (control.options.polyline) {
757
+ layer.addTo(map);
758
+ }
759
+ } else {
760
+ console.warn("Undefined elevation map object");;
761
+ }
762
+
763
+ control._fireEvt("eledata_loaded", { data: geojson, layer: layer, name: control.track_info.name, track_info: control.track_info })
764
+ });
765
+
766
+ return layer;
589
767
  },
590
768
 
591
769
  _dragendHandler: function(e) {
@@ -657,19 +835,90 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
657
835
  this._fireEvt("elechart_leave");
658
836
  },
659
837
 
660
- /*
661
- * Handles the mouesewheel over the chart.
838
+ /**
839
+ * Simple GeoJSON Parser
662
840
  */
663
- _mousewheelHandler: function(e) {
664
- if (this._map.gestureHandling && this._map.gestureHandling._enabled) return;
665
- let ll = this._marker.getLatLng() || this._map.getCenter();
666
- let z = this._map.getZoom() + Math.sign(e.deltaY);
667
- this._resetDrag();
668
- this._map.flyTo(ll, z);
841
+ _parseFromGeoJSONString: function(data) {
842
+ try {
843
+ return JSON.parse(data);
844
+ } catch (e) { }
845
+ },
846
+
847
+ /**
848
+ * Attempt to parse raw response data (GeoJSON or XML > GeoJSON)
849
+ */
850
+ _parseFromString: function(data) {
851
+ return new Promise(resolve =>
852
+ this.lazyLoad(this.__TOGEOJSON).then(() => {
853
+ let geojson;
854
+ try {
855
+ geojson = this._parseFromXMLString(data.trim());
856
+ } catch (e) {
857
+ geojson = this._parseFromGeoJSONString(data.toString());
858
+ }
859
+ if (geojson) {
860
+ geojson = this._prepareMultiLineStrings(geojson);
861
+ geojson = this._prepareAdditionalProperties(geojson);
862
+ }
863
+ resolve(geojson);
864
+ })
865
+ );
866
+ },
867
+
868
+ /**
869
+ * Simple XML Parser (GPX, KML, TCX)
870
+ */
871
+ _parseFromXMLString: function(data) {
872
+ if (data.indexOf("<") != 0) {
873
+ throw 'Invalid XML';
874
+ }
875
+ let xml = (new DOMParser()).parseFromString(data, "text/xml");
876
+ let type = xml.documentElement.tagName.toLowerCase(); // "kml" or "gpx"
877
+ let name = xml.getElementsByTagName('name');
878
+ if (xml.getElementsByTagName('parsererror').length) {
879
+ throw 'Invalid XML';
880
+ }
881
+ if (!(type in toGeoJSON)) {
882
+ type = xml.documentElement.tagName == "TrainingCenterDatabase" ? 'tcx' : 'gpx';
883
+ }
884
+ let geojson = toGeoJSON[type](xml);
885
+ geojson.name = name.length > 0 ? Array.from(name).find(tag => tag.parentElement.tagName == "trk").textContent : '';
886
+ return geojson;
887
+ },
888
+
889
+ /**
890
+ * Extend GeoJSON properties (name, time, ...)
891
+ */
892
+ _prepareAdditionalProperties: function(geojson){
893
+ if (!geojson.name && this._downloadURL) {
894
+ geojson.name = this._downloadURL.split('/').pop().split('#')[0].split('?')[0];
895
+ }
896
+ return geojson;
669
897
  },
670
898
 
671
899
  /**
672
- * Add a waypoint marker to the diagram
900
+ * Just a temporary fix for MultiLineString data (trk > trkseg + trkseg),
901
+ * just split them into seperate LineStrings (trk > trkseg, trk > trkseg)
902
+ *
903
+ * @link https://github.com/Raruto/leaflet-elevation/issues/56
904
+ */
905
+ _prepareMultiLineStrings: function(geojson) {
906
+ geojson.features.forEach(feauture => {
907
+ if (feauture.geometry.type == "MultiLineString") {
908
+ feauture.geometry.coordinates.forEach(coords => {
909
+ geojson.features.push({
910
+ geometry: { type: 'LineString', coordinates: coords },
911
+ properties: feauture.properties,
912
+ type: 'Feature'
913
+ });
914
+ });
915
+ }
916
+ });
917
+ return geojson.features.filter(feauture => feauture.geometry.type != "MultiLineString");
918
+ },
919
+
920
+ /**
921
+ * Add a point of interest over the diagram
673
922
  */
674
923
  _registerCheckPoint: function(props) {
675
924
  this.on("elechart_updated", () => this._chart._registerCheckPoint(props));
@@ -887,9 +1136,14 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
887
1136
  this._fireEvt("elechart_summary");
888
1137
  }
889
1138
  if (this.options.downloadLink && this._downloadURL) { // TODO: generate dynamically file content instead of using static file urls.
890
- this.summaryDiv.innerHTML += '<span class="download"><a href="#">' + L._('Download') + '</a></span>'
891
- _.select('.download a', this.summaryDiv).onclick = (e) => {
1139
+ this._summary._container.innerHTML += '<span class="download"><a href="#">' + L._('Download') + '</a></span>'
1140
+ _.select('.download a', this._summary._container).onclick = (e) => {
892
1141
  e.preventDefault();
1142
+ if (e.downloadLink == 'modal' && typeof CustomEvent === "function") {
1143
+ document.dispatchEvent(new CustomEvent("eletrack_download", { detail: e }));
1144
+ } else if (e.downloadLink == 'link' || e.downloadLink === true) {
1145
+ e.confirm();
1146
+ }
893
1147
  this._fireEvt('eletrack_download', { downloadLink: this.options.downloadLink, confirm: _.saveFile.bind(this, this._downloadURL) });
894
1148
  };
895
1149
  };
@@ -921,125 +1175,4 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
921
1175
  return this.__yTicks || Math.round(this._height() / 30);
922
1176
  }
923
1177
 
924
- });
925
-
926
- /**
927
- * Attach here some useful elevation hooks.
928
- */
929
- Elevation.addInitHook(function() {
930
-
931
- // Alias deprecated functions
932
- this.enableDragging = this.enableBrush;
933
- this.disableDragging = this.disableBrush;
934
- this.loadChart = this.addTo;
935
- this.loadData = this.load;
936
- this.loadGPX = this.loadXML;
937
-
938
- this.on('waypoint_added', function(e) {
939
- let p = e.point,
940
- pop = p._popup;
941
- if (pop) {
942
- pop.options.className = 'elevation-popup';
943
- }
944
- if (pop && pop._content) {
945
- pop._content = decodeURI(pop._content);
946
- p.bindTooltip(pop._content, { direction: 'auto', sticky: true, opacity: 1, className: 'elevation-tooltip' }).openTooltip();
947
- }
948
- });
949
-
950
- this.on("eletrack_download", function(e) {
951
- if (e.downloadLink == 'modal' && typeof CustomEvent === "function") {
952
- document.dispatchEvent(new CustomEvent("eletrack_download", { detail: e }));
953
- } else if (e.downloadLink == 'link' || e.downloadLink === true) {
954
- e.confirm();
955
- }
956
- });
957
-
958
- this.on('eledata_loaded', function(e) {
959
- let map = this._map;
960
- let layer = e.layer;
961
- if (!map) {
962
- console.warn("Undefined elevation map object");
963
- return;
964
- }
965
- map.once('layeradd', (e) => this.options.autofitBounds && this.fitBounds(layer.getBounds()));
966
-
967
- if (L.Browser.mobile) {
968
-
969
- if (this.options.polyline) layer.addTo(map);
970
-
971
- } else {
972
-
973
- // leaflet-geometryutil
974
- this.lazyLoad(this.__LGEOMUTIL)
975
- .then(() => {
976
-
977
- // leaflet-almostover
978
- if (this.options.almostOver) {
979
- this.lazyLoad(this.__LALMOSTOVER)
980
- .then(() => {
981
- map.addHandler('almostOver', L.Handler.AlmostOver)
982
- if (L.GeometryUtil && map.almostOver && map.almostOver.enabled()) {
983
- map.almostOver.addLayer(layer);
984
- map
985
- .on('almost:move', (e) => this._mousemoveLayerHandler(e))
986
- .on('almost:out', (e) => this._mouseoutHandler(e));
987
- }
988
- });
989
- }
990
-
991
- // leaflet-distance-markers
992
- if (this.options.distanceMarkers) {
993
- this.lazyLoad(this.__LDISTANCEM)
994
- .then(() => this.options.polyline && layer.addTo(map));
995
- } else {
996
- if (this.options.polyline) layer.addTo(map);
997
- }
998
- });
999
- }
1000
-
1001
- });
1002
-
1003
- // Basic canvas renderer support.
1004
- let oldProto = L.Canvas.prototype._fillStroke;
1005
- let control = this;
1006
- L.Canvas.include({
1007
- _fillStroke: function(ctx, layer) {
1008
- if (control._layers.hasLayer(layer)) {
1009
-
1010
- let theme = control.options.theme.replace('-theme', '');
1011
- let color = D3.Colors[theme] || {};
1012
- let options = layer.options;
1013
-
1014
- options.color = color.line || color.area || theme;
1015
- options.stroke = !!options.color;
1016
-
1017
- oldProto.call(this, ctx, layer);
1018
-
1019
- if (options.stroke && options.weight !== 0) {
1020
- let oldVal = ctx.globalCompositeOperation || 'source-over';
1021
- ctx.globalCompositeOperation = 'destination-over'
1022
- ctx.strokeStyle = color.outline || '#FFF';
1023
- ctx.lineWidth = options.weight * 1.75;
1024
- ctx.stroke();
1025
- ctx.globalCompositeOperation = oldVal;
1026
- }
1027
-
1028
- } else {
1029
- oldProto.call(this, ctx, layer);
1030
- }
1031
- }
1032
- });
1033
-
1034
- // Partially fix: https://github.com/Raruto/leaflet-elevation/issues/81#issuecomment-713477050
1035
- this.on('elechart_init', function() {
1036
- this.once('elechart_change elechart_hover', function(e) {
1037
- if (this._chartEnabled) {
1038
- this._chart._showDiagramIndicator(e.data, e.xCoord);
1039
- this._chart._showDiagramIndicator(e.data, e.xCoord);
1040
- }
1041
- this._updateMarker(e.data);
1042
- });
1043
- });
1044
-
1045
- });
1178
+ });