@raruto/leaflet-elevation 1.8.5 → 1.8.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raruto/leaflet-elevation",
3
- "version": "1.8.5",
3
+ "version": "1.8.8",
4
4
  "description": "A Leaflet plugin that allows to add elevation profiles using d3js",
5
5
  "main": "dist/leaflet-elevation.min.js",
6
6
  "module": "src/index.js",
package/src/components.js CHANGED
@@ -496,8 +496,8 @@ export const Chart = ({
496
496
  const panes = {
497
497
  grid : g.append("g").attr("class", "grid"),
498
498
  area : g.append('g').attr("class", "area"),
499
- point : g.append('g').attr("class", "point"),
500
499
  axis : g.append('g').attr("class", "axis"),
500
+ point : g.append('g').attr("class", "point"),
501
501
  brush : g.append("g").attr("class", "brush"),
502
502
  tooltip: g.append("g").attr("class", "tooltip").attr('display', 'none'),
503
503
  ruler : g.append('g').attr('class', 'ruler'),
package/src/control.js CHANGED
@@ -14,10 +14,10 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
14
14
  __mileFactor: 0.621371,
15
15
  __footFactor: 3.28084,
16
16
  __D3: 'https://unpkg.com/d3@6.5.0/dist/d3.min.js',
17
- __TOGEOJSON: 'https://unpkg.com/@tmcw/togeojson@4.3.0/dist/togeojson.umd.js',
17
+ __TOGEOJSON: 'https://unpkg.com/@tmcw/togeojson@4.5.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.5/libs/leaflet-distance-marker.min.js',
20
+ __LDISTANCEM: 'https://unpkg.com/@raruto/leaflet-elevation@1.8.8/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
@@ -304,6 +304,9 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
304
304
  return;
305
305
  }
306
306
 
307
+ /**
308
+ * Standard GeoJSON --> doesn't handle "time", "heart", …
309
+ */
307
310
  let geom = d.geometry;
308
311
  if (geom) {
309
312
  switch (geom.type) {
@@ -319,35 +322,47 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
319
322
  console.warn('Unsopperted GeoJSON feature geometry type:' + geom.type);
320
323
  }
321
324
  }
322
-
323
325
  if (d.type === "FeatureCollection") {
324
326
  _.each(d.features, feature => this._addData(feature));
325
327
  }
326
328
 
329
+ /**
330
+ * Extended GeoJSON --> rely on leaflet implementation
331
+ */
327
332
  if (d._latlngs) {
328
- this._addGPXData(d._latlngs);
333
+ this._addGeoJSONData(d._latlngs, d.feature && d.feature.properties);
329
334
  }
330
335
  },
331
336
 
332
337
  /*
333
338
  * Parsing of GeoJSON data lines and their elevation in z-coordinate
334
339
  */
335
- _addGeoJSONData: function(coords) {
336
- _.each(coords, point => {
337
- this._addPoint(point[1], point[0], point[2]);
338
- this._fireEvt("elepoint_added", { point: point, index: this._data.length - 1 });
339
- });
340
- this._fireEvt("eletrack_added", { coords: coords, index: this._data.length - 1 });
341
- },
340
+ _addGeoJSONData: function(coords, properties) {
341
+ coords.forEach((point, i) => {
342
+
343
+ // Inspired by L.GPX layer properties
344
+ point.meta = point.meta ?? { time: null, ele: null, hr: null, cad: null, atemp: null };
345
+
346
+ // "alt" property is generated inside "leaflet"
347
+ if ("alt" in point) point.meta.ele = point.alt;
348
+
349
+ // "coordinateProperties" property is generated inside "@tmcw/toGeoJSON"
350
+ if (properties.coordinateProperties) {
351
+ let props = properties.coordinateProperties;
352
+ if("times" in props) point.meta.time = new Date(Date.parse(props.times[i]));
353
+ if("heart" in props) point.meta.hr = parseInt(props.heart[i]);
354
+ // TODO: ask to "@tmcw/toGeoJSON" for "cadence" and "temperature" implementation
355
+ }
356
+
357
+ this._addPoint(
358
+ point.lat ?? point[1],
359
+ point.lng ?? point[0],
360
+ point.alt ?? point.meta.ele ?? point[2]
361
+ );
342
362
 
343
- /*
344
- * Parsing function for GPX data and their elevation in z-coordinate
345
- */
346
- _addGPXData: function(coords) {
347
- _.each(coords, point => {
348
- this._addPoint(point.lat, point.lng, point.alt ?? point.meta.ele);
349
363
  this._fireEvt("elepoint_added", { point: point, index: this._data.length - 1 });
350
364
  });
365
+
351
366
  this._fireEvt("eletrack_added", { coords: coords, index: this._data.length - 1 });
352
367
  },
353
368
 
@@ -392,6 +407,9 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
392
407
  }
393
408
  },
394
409
 
410
+ /**
411
+ * Initialize "L.AlmostOver" integration
412
+ */
395
413
  _initAlmostOverHandler: function(map, layer) {
396
414
  if(!map || !this.options.almostOver) return;
397
415
  this.lazyLoad(this.__LGEOMUTIL)
@@ -407,6 +425,9 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
407
425
  });
408
426
  },
409
427
 
428
+ /**
429
+ * Initialize "L.DistanceMarkers" integration
430
+ */
410
431
  _initDistanceMarkers: function(map, layer) {
411
432
  if (!map) return;
412
433
  if (this.options.distanceMarkers) {
@@ -433,6 +454,24 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
433
454
  return this.eleDiv = eleDiv;
434
455
  },
435
456
 
457
+ /**
458
+ * Initialize "L.AlmostOver" and "L.DistanceMarkers"
459
+ */
460
+ _initMapIntegrations: function(control, layer) {
461
+ let map = control._map;
462
+ if (control._map) {
463
+ map.once('layeradd', (e) => control.options.autofitBounds && control.fitBounds(layer.getBounds()));
464
+ if (!L.Browser.mobile) {
465
+ control._initAlmostOverHandler(map, layer);
466
+ control._initDistanceMarkers(map, layer);
467
+ } else if (control.options.polyline) {
468
+ layer.addTo(map);
469
+ }
470
+ } else {
471
+ console.warn("Undefined elevation map object");;
472
+ }
473
+ },
474
+
436
475
  /*
437
476
  * Collapse current chart control.
438
477
  */
@@ -663,9 +702,9 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
663
702
  .then((response) => response.text())
664
703
  .then((data) => {
665
704
  this._downloadURL = url; // TODO: handle multiple urls?
666
- this.load(data);
667
- })
668
- .catch((err) => console.warn(err));
705
+ this._parseFromString(data)
706
+ .then( geojson => geojson && this._loadLayer(geojson));
707
+ }).catch((err) => console.warn(err));
669
708
  },
670
709
 
671
710
  /**
@@ -720,46 +759,15 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
720
759
  }
721
760
  },
722
761
  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 });
762
+ if (feature.geometry && feature.geometry.type != 'Point') {
763
+ control.addData(layer);
764
+ control.track_info = L.extend({}, control.track_info, { name: geojson.name });
765
+ }
746
766
  },
747
767
  });
748
768
 
749
769
  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
-
770
+ control._initMapIntegrations(control, layer);
763
771
  control._fireEvt("eledata_loaded", { data: geojson, layer: layer, name: control.track_info.name, track_info: control.track_info })
764
772
  });
765
773
 
@@ -881,15 +889,15 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
881
889
  if (!(type in toGeoJSON)) {
882
890
  type = xml.documentElement.tagName == "TrainingCenterDatabase" ? 'tcx' : 'gpx';
883
891
  }
884
- let geojson = toGeoJSON[type](xml);
885
- geojson.name = name.length > 0 ? Array.from(name).find(tag => tag.parentElement.tagName == "trk").textContent : '';
892
+ let geojson = toGeoJSON[type](xml);
893
+ geojson.name = name.length > 0 ? (Array.from(name).find(tag => tag.parentElement.tagName == "trk") ?? name[0]).textContent : '';
886
894
  return geojson;
887
895
  },
888
896
 
889
897
  /**
890
898
  * Extend GeoJSON properties (name, time, ...)
891
899
  */
892
- _prepareAdditionalProperties: function(geojson){
900
+ _prepareAdditionalProperties: function(geojson) {
893
901
  if (!geojson.name && this._downloadURL) {
894
902
  geojson.name = this._downloadURL.split('/').pop().split('#')[0].split('?')[0];
895
903
  }
@@ -948,7 +956,7 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
948
956
  /**
949
957
  * Add chart or marker tooltip info
950
958
  */
951
- _registerTooltip: function(props) {
959
+ _registerTooltip: function(props) {
952
960
  if (props.chart) {
953
961
  let label = L.extend({}, props, { value: props.chart });
954
962
  this.on("elechart_init", () => this._chart._registerTooltip(label));
@@ -1055,16 +1063,12 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
1055
1063
  * Toggle chart data on legend click
1056
1064
  */
1057
1065
  _toggleChartHandler: function(e) {
1058
- let { path, name, enabled } = e;
1066
+ let { name, enabled } = e;
1059
1067
 
1060
1068
  this._chartEnabled = this._chart._hasActiveLayers();
1061
1069
 
1062
1070
  // toggle layer visibility on empty chart
1063
- this._layers.eachLayer(layer => {
1064
- let node = layer.getElement && layer.getElement();
1065
- _.toggleClass(node, this.options.polyline.className + ' ' + this.options.theme, this._chartEnabled);
1066
- }
1067
- );
1071
+ this._layers.eachLayer(layer => _.toggleClass(layer.getElement && layer.getElement(), this.options.polyline.className + ' ' + this.options.theme, this._chartEnabled));
1068
1072
 
1069
1073
  // toggle option value (eg. altitude = { 'disabled' || 'disabled' })
1070
1074
  this.options[name] = !enabled && this.options[name] == 'disabled' ? 'enabled' : 'disabled';
package/src/index.js CHANGED
@@ -63,14 +63,16 @@ Elevation.Chart = Chart;
63
63
 
64
64
  // Alias deprecated functions
65
65
  Elevation.addInitHook(function() {
66
- this.enableDragging = this.enableBrush;
67
- this.disableDragging = this.disableBrush;
68
- this.loadChart = this.addTo;
69
- this.loadData = this.load;
70
- this.loadGPX = this.load;
71
- this.loadGeoJSON = this.load;
72
- this.loadXML = this.load;
73
- this.loadFile = this.load;
66
+ this.enableDragging = this.enableBrush;
67
+ this.disableDragging = this.disableBrush;
68
+ this.loadChart = this.addTo;
69
+ this.loadData = this.load;
70
+ this.loadGPX = this.load;
71
+ this.loadGeoJSON = this.load;
72
+ this.loadXML = this.load;
73
+ this.loadFile = this.load;
74
+ this._addGPXData = this._addGeoJSONData;
75
+ this._registerFocusLabel = this._registerTooltip;
74
76
  });
75
77
 
76
78
  L.control.elevation = (options) => new Elevation(options);
@@ -1,107 +0,0 @@
1
- /*
2
- * Copyright (c) 2020, GPL-3.0+ Project, Gérald Niel, Raruto
3
- *
4
- * This file is free software: you may copy, redistribute and/or modify it
5
- * under the terms of the GNU General Public License as published by the
6
- * Free Software Foundation, either version 2 of the License, or (at your
7
- * option) any later version.
8
- *
9
- * This file is distributed in the hope that it will be useful, but
10
- * WITHOUT ANY WARRANTY; without even the implied warranty of
11
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
- * General Public License for more details.
13
- *
14
- * You should have received a copy of the GNU General Public License
15
- * along with this program. If not, see .
16
- */
17
-
18
- L.Control.Elevation.addInitHook(function() {
19
-
20
- this.on("eledata_updated", function(e) {
21
- let data = this._data;
22
- let i = e.index;
23
- let z = data[i].z;
24
-
25
- let curr = data[i].latlng;
26
- let prev = i > 0 ? data[i - 1].latlng : curr;
27
-
28
- let delta = curr.distanceTo(prev) * this._distanceFactor;
29
-
30
- // Slope / Gain
31
- let tAsc = this._tAsc || 0; // Total Ascent
32
- let tDes = this._tDes || 0; // Total Descent
33
- let sMax = this._sMax || 0; // Slope Max
34
- let sMin = this._sMin || 0; // Slope Min
35
- let diff = 0;
36
- let slope = 0;
37
-
38
- if (!isNaN(z)) {
39
- // diff height between actual and previous point
40
- diff = i > 0 ? z - data[i - 1].z : 0;
41
- if (diff > 0) tAsc += diff;
42
- if (diff < 0) tDes -= diff;
43
- // slope in % = ( height / length ) * 100
44
- slope = delta !== 0 ? Math.round((diff / delta) * 10000) / 100 : 0;
45
- // apply slope to the previous point because we will
46
- // ascent or desent, so the slope is in the fist point
47
- if (i > 0) data[i - 1].slope = slope;
48
- sMax = slope > sMax ? slope : sMax;
49
- sMin = slope < sMin ? slope : sMin;
50
- }
51
-
52
- data[i].slope = slope;
53
-
54
- this.track_info = this.track_info || {};
55
- this.track_info.ascent = this._tAsc = tAsc;
56
- this.track_info.descent = this._tDes = tDes;
57
- this.track_info.slope_max = this._sMax = sMax;
58
- this.track_info.slope_min = this._sMin = sMin;
59
- });
60
-
61
- if (!this.options.extendedUI) return;
62
-
63
- this.on("elechart_change", function(e) {
64
- let item = e.data;
65
- let xCoordinate = e.xCoord;
66
-
67
- if (!this._focuslabelSlope || !this._focuslabelSlope.property('isConnected')) {
68
- this._focuslabelSlope = this._focuslabeltext.insert("svg:tspan", ".mouse-focus-label-x")
69
- .attr("class", "mouse-focus-label-slope")
70
- .attr("dy", "1.5em");
71
- }
72
-
73
- this._focuslabelSlope.text(item.slope + "%");
74
-
75
- if (!this._mouseSlopeFocusLabel) {
76
- this._mouseSlopeFocusLabel = this._mouseHeightFocusLabel.append("svg:tspan")
77
- .attr("class", "height-focus-slope ");
78
- }
79
-
80
- this._mouseHeightFocusLabelY
81
- .attr("dy", "-1.5em");
82
- this._focuslabelX
83
- .attr("dy", "1.5em");
84
-
85
- this._mouseSlopeFocusLabel
86
- .attr("dy", "1.5em")
87
- .text(Math.round(item.slope) + "%");
88
-
89
- });
90
-
91
- this.on("elechart_summary", function() {
92
- this.summaryDiv.querySelector('.minele').insertAdjacentHTML('afterend', '<span class="ascent"><span class="summarylabel">' + L._("Total Ascent: ") + '</span><span class="summaryvalue">' + Math.round(this.track_info.ascent) + '&nbsp;' +
93
- this._yLabel +
94
- '</span></span>' + '<span class="descent"><span class="summarylabel">' + L._("Total Descent: ") + '</span><span class="summaryvalue">' + Math.round(this.track_info.descent) + '&nbsp;' + this._yLabel +
95
- '</span></span>' + '<span class="minslope"><span class="summarylabel">' + L._("Min Slope: ") + '</span><span class="summaryvalue">' + this.track_info.slope_min + '&nbsp;' + '%' +
96
- '</span></span>' + '<span class="maxslope"><span class="summarylabel">' + L._("Max Slope: ") + '</span><span class="summaryvalue">' + this.track_info.slope_max + '&nbsp;' + '%' +
97
- '</span></span>');
98
- });
99
-
100
- this.on("eledata_clear", function() {
101
- this._sMax = null;
102
- this._sMin = null;
103
- this._tAsc = null;
104
- this._tDes = null;
105
- });
106
-
107
- });
@@ -1,5 +0,0 @@
1
- 'use strict';L.Control.Elevation.addInitHook(function(){this.on("eledata_updated",function(e){let data=this._data;let i=e.index;let z=data[i].z;let curr=data[i].latlng;let prev=i>0?data[i-1].latlng:curr;let delta=curr.distanceTo(prev)*this._distanceFactor;let tAsc=this._tAsc||0;let tDes=this._tDes||0;let sMax=this._sMax||0;let sMin=this._sMin||0;let diff=0;let slope=0;if(!isNaN(z)){diff=i>0?z-data[i-1].z:0;if(diff>0)tAsc+=diff;if(diff<0)tDes-=diff;slope=delta!==0?Math.round(diff/delta*1E4)/100:0;
2
- if(i>0)data[i-1].slope=slope;sMax=slope>sMax?slope:sMax;sMin=slope<sMin?slope:sMin}data[i].slope=slope;this.track_info=this.track_info||{};this.track_info.ascent=this._tAsc=tAsc;this.track_info.descent=this._tDes=tDes;this.track_info.slope_max=this._sMax=sMax;this.track_info.slope_min=this._sMin=sMin});if(!this.options.extendedUI)return;this.on("elechart_change",function(e){let item=e.data;let xCoordinate=e.xCoord;if(!this._focuslabelSlope||!this._focuslabelSlope.property("isConnected"))this._focuslabelSlope=
3
- this._focuslabeltext.insert("svg:tspan",".mouse-focus-label-x").attr("class","mouse-focus-label-slope").attr("dy","1.5em");this._focuslabelSlope.text(item.slope+"%");if(!this._mouseSlopeFocusLabel)this._mouseSlopeFocusLabel=this._mouseHeightFocusLabel.append("svg:tspan").attr("class","height-focus-slope ");this._mouseHeightFocusLabelY.attr("dy","-1.5em");this._focuslabelX.attr("dy","1.5em");this._mouseSlopeFocusLabel.attr("dy","1.5em").text(Math.round(item.slope)+"%")});this.on("elechart_summary",
4
- function(){this.summaryDiv.querySelector(".minele").insertAdjacentHTML("afterend",'<span class="ascent"><span class="summarylabel">'+L._("Total Ascent: ")+'</span><span class="summaryvalue">'+Math.round(this.track_info.ascent)+"&nbsp;"+this._yLabel+"</span></span>"+'<span class="descent"><span class="summarylabel">'+L._("Total Descent: ")+'</span><span class="summaryvalue">'+Math.round(this.track_info.descent)+"&nbsp;"+this._yLabel+"</span></span>"+'<span class="minslope"><span class="summarylabel">'+
5
- L._("Min Slope: ")+'</span><span class="summaryvalue">'+this.track_info.slope_min+"&nbsp;"+"%"+"</span></span>"+'<span class="maxslope"><span class="summarylabel">'+L._("Max Slope: ")+'</span><span class="summaryvalue">'+this.track_info.slope_max+"&nbsp;"+"%"+"</span></span>")});this.on("eledata_clear",function(){this._sMax=null;this._sMin=null;this._tAsc=null;this._tDes=null})});