@raruto/leaflet-elevation 1.9.5 → 2.0.1

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.
@@ -0,0 +1,64 @@
1
+ export function Acceleration() {
2
+
3
+ const _ = L.Control.Elevation.Utils;
4
+
5
+ let opts = this.options;
6
+ let acceleration = {};
7
+
8
+ acceleration.label = opts.accelerationLabel || L._(opts.imperial ? 'ft/s²' : 'm/s²');
9
+ opts.accelerationFactor = opts.accelerationFactor || 1;
10
+
11
+ return {
12
+ name: 'acceleration',
13
+ unit: acceleration.label,
14
+ deltaMax: this.options.accelerationDeltaMax,
15
+ clampRange: this.options.accelerationRange,
16
+ decimals: 2,
17
+ pointToAttr: (_, i) => {
18
+ let dv = (this._data[i].speed - this._data[i > 0 ? i - 1 : i].speed) * (1000 / opts.timeFactor);
19
+ let dt = (this._data[i].time - this._data[i > 0 ? i - 1 : i].time) / 1000;
20
+ return dt > 0 ? Math.abs((dv / dt)) * opts.accelerationFactor : 0;
21
+ },
22
+ stats: { max: _.iMax, min: _.iMin, avg: _.iAvg },
23
+ scale: {
24
+ axis : "y",
25
+ position : "right",
26
+ scale : { min: 0, max: +1 },
27
+ tickPadding: 16,
28
+ labelX : 25,
29
+ labelY : -8,
30
+ },
31
+ path: {
32
+ label : 'Acceleration',
33
+ yAttr : 'acceleration',
34
+ scaleX : 'distance',
35
+ scaleY : 'acceleration',
36
+ color : '#050402',
37
+ strokeColor : '#000',
38
+ strokeOpacity: "0.5",
39
+ fillOpacity : "0.25",
40
+ },
41
+ tooltip: {
42
+ chart: (item) => L._("a: ") + item.acceleration + " " + acceleration.label,
43
+ marker: (item) => Math.round(item.acceleration) + " " + acceleration.label,
44
+ order: 60,
45
+ },
46
+ summary: {
47
+ "minacceleration" : {
48
+ label: "Min Acceleration: ",
49
+ value: (track, unit) => Math.round(track.acceleration_min || 0) + ' ' + unit,
50
+ order: 60
51
+ },
52
+ "maxacceleration" : {
53
+ label: "Max Acceleration: ",
54
+ value: (track, unit) => Math.round(track.acceleration_max || 0) + ' ' + unit,
55
+ order: 61
56
+ },
57
+ "avgacceleration": {
58
+ label: "Avg Acceleration: ",
59
+ value: (track, unit) => Math.round(track.acceleration_avg || 0) + ' ' + unit,
60
+ order: 62
61
+ },
62
+ }
63
+ };
64
+ }
@@ -0,0 +1,76 @@
1
+ export function Altitude() {
2
+
3
+ const _ = L.Control.Elevation.Utils;
4
+
5
+ let opts = this.options;
6
+ let altitude = {};
7
+
8
+ let theme = opts.theme.replace('-theme', '');
9
+ let color = _.Colors[theme] || {};
10
+
11
+ opts.altitudeFactor = opts.imperial ? this.__footFactor : (opts.altitudeFactor || 1); // 1 m = (1 m)
12
+ altitude.label = opts.imperial ? "ft" : opts.yLabel;
13
+
14
+ return {
15
+ name: 'altitude',
16
+ required: this.options.slope,
17
+ meta: 'z',
18
+ unit: altitude.label,
19
+ statsName: 'elevation',
20
+ skipNull: this.options.skipNullZCoords,
21
+ deltaMax: this.options.altitudeDeltaMax,
22
+ clampRange: this.options.altitudeRange,
23
+ // init: ({point}) => {
24
+ // // "alt" property is generated inside "leaflet"
25
+ // if ("alt" in point) point.meta.ele = point.alt;
26
+ // },
27
+ pointToAttr: (_, i) => this._data[i].z * opts.altitudeFactor,
28
+ stats: { max: _.iMax, min: _.iMin, avg: _.iAvg },
29
+ grid: {
30
+ axis : "y",
31
+ position : "left",
32
+ scale : "y" // this._chart._y,
33
+ },
34
+ scale: {
35
+ axis : "y",
36
+ position: "left",
37
+ scale : "y", // this._chart._y,
38
+ labelX : -3,
39
+ labelY : -8,
40
+ },
41
+ path: {
42
+ label : 'Altitude',
43
+ scaleX : 'distance',
44
+ scaleY : 'altitude',
45
+ className : 'area',
46
+ color : color.area || theme,
47
+ strokeColor : opts.detached ? color.stroke : '#000',
48
+ strokeOpacity: "1",
49
+ fillOpacity : opts.detached ? (color.alpha || '0.8') : 1,
50
+ preferCanvas : opts.preferCanvas,
51
+ },
52
+ tooltip: {
53
+ name: 'y',
54
+ chart: (item) => L._("y: ") + _.round(item[opts.yAttr], opts.decimalsY) + " " + altitude.label,
55
+ marker: (item) => _.round(item[opts.yAttr], opts.decimalsY) + " " + altitude.label,
56
+ order: 10,
57
+ },
58
+ summary: {
59
+ "minele" : {
60
+ label: "Min Elevation: ",
61
+ value: (track, unit) => (track.elevation_min || 0).toFixed(2) + ' ' + unit,
62
+ order: 30,
63
+ },
64
+ "maxele" : {
65
+ label: "Max Elevation: ",
66
+ value: (track, unit) => (track.elevation_max || 0).toFixed(2) + ' ' + unit,
67
+ order: 31,
68
+ },
69
+ "avgele" : {
70
+ label: "Avg Elevation: ",
71
+ value: (track, unit) => (track.elevation_avg || 0).toFixed(2) + ' ' + unit,
72
+ order: 32,
73
+ },
74
+ }
75
+ };
76
+ }
@@ -0,0 +1,54 @@
1
+ export function Cadence() {
2
+
3
+ const _ = L.Control.Elevation.Utils;
4
+
5
+ return {
6
+ name: 'cadence', // <-- Your custom option name (eg. "cadence: true")
7
+ unit: 'rpm',
8
+ meta: 'cad', // <-- point.meta.cad
9
+ coordinateProperties: ["cads", "cadences", "cad", "cadence"], // List of GPX Extensions ("coordinateProperties") to be handled by "@tmcw/toGeoJSON"
10
+ pointToAttr: (point, i) => (point.cad ?? point.meta.cad ?? point.prev('cadence')) || 0,
11
+ stats: { max: _.iMax, min: _.iMin, avg: _.iAvg },
12
+ scale: {
13
+ axis : "y",
14
+ position : "right",
15
+ scale : { min: -1, max: +1 },
16
+ tickPadding: 16,
17
+ labelX : 25,
18
+ labelY : -8,
19
+ },
20
+ path: {
21
+ label : 'RPM',
22
+ yAttr : 'cadence',
23
+ scaleX : 'distance',
24
+ scaleY : 'cadence',
25
+ color : '#FFF',
26
+ strokeColor : 'blue',
27
+ strokeOpacity: "0.85",
28
+ fillOpacity : "0.1",
29
+ },
30
+ tooltip: {
31
+ name: 'cadence',
32
+ chart: (item) => L._("cad: ") + item.cadence + " " + 'rpm',
33
+ marker: (item) => Math.round(item.cadence) + " " + 'rpm',
34
+ order: 1
35
+ },
36
+ summary: {
37
+ "minrpm": {
38
+ label: "Min RPM: ",
39
+ value: (track, unit) => Math.round(track.cadence_min || 0) + '&nbsp;' + unit,
40
+ // order: 30
41
+ },
42
+ "maxrpm": {
43
+ label: "Max RPM: ",
44
+ value: (track, unit) => Math.round(track.cadence_max || 0) + '&nbsp;' + unit,
45
+ // order: 30
46
+ },
47
+ "avgrpm": {
48
+ label: "Avg RPM: ",
49
+ value: (track, unit) => Math.round(track.cadence_avg || 0) + '&nbsp;' + unit,
50
+ // order: 20
51
+ },
52
+ }
53
+ };
54
+ }
@@ -0,0 +1,45 @@
1
+ export function Distance() {
2
+
3
+ const _ = L.Control.Elevation.Utils;
4
+
5
+ let opts = this.options;
6
+ let distance = {};
7
+
8
+ opts.distanceFactor = opts.imperial ? this.__mileFactor : (opts.distanceFactor || 1); // 1 km = (1000 m)
9
+ distance.label = opts.imperial ? "mi" : opts.xLabel;
10
+
11
+ return {
12
+ name: 'distance',
13
+ attr: 'dist',
14
+ unit: distance.label,
15
+ decimals: 5,
16
+ pointToAttr: (_, i) => (i > 0 ? this._data[i - 1].dist : 0) + (this._data[i].latlng.distanceTo(this._data[i > 0 ? i - 1 : i].latlng) * opts.distanceFactor) / 1000, // convert back km to meters
17
+ // stats: { total: _.iSum },
18
+ onPointAdded: (distance, i) => this.track_info.distance = distance,
19
+ scale: {
20
+ axis : "x",
21
+ position: "bottom",
22
+ scale : "x", // this._chart._x,
23
+ labelY : 25,
24
+ labelX : () => this._width() + 6,
25
+ ticks : () => _.clamp(this._chart._xTicks() / 2, [4, +Infinity]),
26
+ },
27
+ grid: {
28
+ axis : "x",
29
+ position : "bottom",
30
+ scale : "x" // this._chart._x,
31
+ },
32
+ tooltip: {
33
+ name: 'x',
34
+ chart: (item) => L._("x: ") + _.round(item[opts.xAttr], opts.decimalsX) + " " + distance.label,
35
+ order: 20
36
+ },
37
+ summary: {
38
+ "totlen" : {
39
+ label: "Total Length: ",
40
+ value: (track) => (track.distance || 0).toFixed(2) + '&nbsp;' + distance.label,
41
+ order: 10
42
+ }
43
+ }
44
+ };
45
+ }
@@ -0,0 +1,53 @@
1
+ export function Heart() {
2
+
3
+ const _ = L.Control.Elevation.Utils;
4
+
5
+ return {
6
+ name: 'heart', // <-- Your custom option name (eg. "heart: true")
7
+ unit: 'bpm',
8
+ meta: 'hr', // <-- point.meta.hr
9
+ coordinateProperties: ["heart", "heartRates", "heartRate"], // List of GPX Extensions ("coordinateProperties") to be handled by "@tmcw/toGeoJSON"
10
+ pointToAttr: (point, i) => (point.hr ?? point.meta.hr ?? point.prev('heart')) || 0,
11
+ stats: { max: _.iMax, min: _.iMin, avg: _.iAvg },
12
+ scale: {
13
+ axis : "y",
14
+ position : "left",
15
+ scale : { min: -1, max: +1 },
16
+ tickPadding: 16,
17
+ labelX : -18,
18
+ labelY : -8,
19
+ },
20
+ path: {
21
+ label : 'ECG',
22
+ yAttr : 'heart',
23
+ scaleX : 'distance',
24
+ scaleY : 'heart',
25
+ color : 'white',
26
+ strokeColor : 'red',
27
+ strokeOpacity: "0.85",
28
+ fillOpacity : "0.1",
29
+ },
30
+ tooltip: {
31
+ chart: (item) => L._("hr: ") + item.heart + " " + 'bpm',
32
+ marker: (item) => Math.round(item.heart) + " " + 'bpm',
33
+ order: 1
34
+ },
35
+ summary: {
36
+ "minbpm": {
37
+ label: "Min BPM: ",
38
+ value: (track, unit) => Math.round(track.heart_min || 0) + '&nbsp;' + unit,
39
+ // order: 30
40
+ },
41
+ "maxbpm": {
42
+ label: "Max BPM: ",
43
+ value: (track, unit) => Math.round(track.heart_min || 0) + '&nbsp;' + unit,
44
+ // order: 30
45
+ },
46
+ "avgbpm": {
47
+ label: "Avg BPM: ",
48
+ value: (track, unit) => Math.round(track.heart_avg || 0) + '&nbsp;' + unit,
49
+ // order: 20
50
+ },
51
+ }
52
+ };
53
+ };
@@ -0,0 +1,79 @@
1
+ export function Slope() {
2
+
3
+ const _ = L.Control.Elevation.Utils;
4
+
5
+ let opts = this.options;
6
+ let slope = {};
7
+
8
+ slope.label = opts.slopeLabel || '%';
9
+
10
+ return {
11
+ name: 'slope',
12
+ meta: 'slope',
13
+ unit: slope.label,
14
+ deltaMax: this.options.slopedDeltaMax,
15
+ clampRange: this.options.slopeRange,
16
+ decimals: 2,
17
+ pointToAttr: (_, i) => { // slope in % = ( dy / dx ) * 100;
18
+ let dx = (this._data[i].dist - this._data[i > 0 ? i - 1 : i].dist) * 1000;
19
+ let dy = this._data[i][this.options.yAttr] - this._data[i > 0 ? i - 1 : i][this.options.yAttr];
20
+ return (!isNaN(dy) && dx !== 0) ? (dy / dx) * 100 : 0;
21
+ },
22
+ onPointAdded: (_, i) => {
23
+ let dz = this._data[i][this.options.yAttr] - this._data[i > 0 ? i - 1 : i][this.options.yAttr];
24
+ if (dz > 0) this.track_info.ascent = (this.track_info.ascent || 0) + dz; // Total Ascent
25
+ else if (dz < 0) this.track_info.descent = (this.track_info.descent || 0) - dz; // Total Descent
26
+ },
27
+ stats: { max: _.iMax, min: _.iMin, avg: _.iAvg, },
28
+ scale: {
29
+ axis : "y",
30
+ position : "right",
31
+ scale : { min: -1, max: +1 },
32
+ tickPadding: 16,
33
+ labelX : 25,
34
+ labelY : -8,
35
+ },
36
+ path: {
37
+ label : 'Slope',
38
+ yAttr : 'slope',
39
+ scaleX : 'distance',
40
+ scaleY : 'slope',
41
+ color : '#F00',
42
+ strokeColor : '#000',
43
+ strokeOpacity: "0.5",
44
+ fillOpacity : "0.25",
45
+ },
46
+ tooltip: {
47
+ chart: (item) => L._("m: ") + item.slope + slope.label,
48
+ marker: (item) => Math.round(item.slope) + slope.label,
49
+ order: 40,
50
+ },
51
+ summary: {
52
+ "minslope": {
53
+ label: "Min Slope: ",
54
+ value: (track, unit) => Math.round(track.slope_min || 0) + '&nbsp;' + unit,
55
+ order: 40
56
+ },
57
+ "maxslope": {
58
+ label: "Max Slope: ",
59
+ value: (track, unit) => Math.round(track.slope_max || 0) + '&nbsp;' + unit,
60
+ order: 41
61
+ },
62
+ "avgslope": {
63
+ label: "Avg Slope: ",
64
+ value: (track, unit) => Math.round(track.slope_avg || 0) + '&nbsp;' + unit,
65
+ order: 42
66
+ },
67
+ "ascent" : {
68
+ label: "Total Ascent: ",
69
+ value: (track, unit) => Math.round(track.ascent || 0) + '&nbsp;' + (this.options.imperial ? 'ft' : 'm'),
70
+ order: 43
71
+ },
72
+ "descent" : {
73
+ label: "Total Descent: ",
74
+ value: (track, unit) => Math.round(track.descent || 0) + '&nbsp;' + (this.options.imperial ? 'ft' : 'm'),
75
+ order: 45
76
+ },
77
+ }
78
+ };
79
+ }
@@ -0,0 +1,66 @@
1
+ export function Speed() {
2
+
3
+ const _ = L.Control.Elevation.Utils;
4
+
5
+ let opts = this.options;
6
+ let speed = {};
7
+
8
+ speed.label = opts.speedLabel || L._(opts.imperial ? 'mph' : 'km/h');
9
+ opts.speedFactor = opts.speedFactor || 1;
10
+
11
+ return {
12
+ name: 'speed',
13
+ required: (this.options.acceleration),
14
+ unit: speed.label,
15
+ deltaMax: this.options.speedDeltaMax,
16
+ clampRange: this.options.speedRange,
17
+ decimals: 2,
18
+ pointToAttr: (_, i) => {
19
+ let dx = (this._data[i].dist - this._data[i > 0 ? i - 1 : i].dist) * 1000;
20
+ let dt = this._data[i].time - this._data[ i > 0 ? i - 1 : i].time;
21
+ return dt > 0 ? Math.abs((dx / dt) * opts.timeFactor) * opts.speedFactor : 0;
22
+ },
23
+ stats: { max: _.iMax, min: _.iMin, avg: _.iAvg },
24
+ scale : (this.options.speed && this.options.speed != "summary") && {
25
+ axis : "y",
26
+ position : "right",
27
+ scale : { min : 0, max : +1 },
28
+ tickPadding: 16,
29
+ labelX : 25,
30
+ labelY : -8,
31
+ },
32
+ path: (this.options.speed && this.options.speed != "summary") && {
33
+ // name : 'speed',
34
+ label : 'Speed',
35
+ yAttr : "speed",
36
+ scaleX : 'distance',
37
+ scaleY : 'speed',
38
+ color : '#03ffff',
39
+ strokeColor : '#000',
40
+ strokeOpacity: "0.5",
41
+ fillOpacity : "0.25",
42
+ },
43
+ tooltip: (this.options.speed) && {
44
+ chart: (item) => L._('v: ') + item.speed + " " + speed.label,
45
+ marker: (item) => Math.round(item.speed) + " " + speed.label,
46
+ order: 50,
47
+ },
48
+ summary: (this.options.speed) && {
49
+ "minspeed" : {
50
+ label: "Min Speed: ",
51
+ value: (track, unit) => Math.round(track.speed_min || 0) + '&nbsp;' + unit,
52
+ order: 51
53
+ },
54
+ "maxspeed" : {
55
+ label: "Max Speed: ",
56
+ value: (track, unit) => Math.round(track.speed_max || 0) + '&nbsp;' + unit,
57
+ order: 51
58
+ },
59
+ "avgspeed": {
60
+ label: "Avg Speed: ",
61
+ value: (track, unit) => Math.round(track.speed_avg || 0) + '&nbsp;' + unit,
62
+ order: 52
63
+ },
64
+ }
65
+ };
66
+ }
@@ -1,9 +1,6 @@
1
- import 'leaflet-i18n';
2
- import * as _ from './utils';
3
- import * as D3 from './components';
4
- import { Elevation } from './control';
1
+ export function Time() {
5
2
 
6
- Elevation.addInitHook(function() {
3
+ const _ = L.Control.Elevation.Utils;
7
4
 
8
5
  let opts = this.options;
9
6
  let time = {};
@@ -33,45 +30,31 @@ Elevation.addInitHook(function() {
33
30
 
34
31
  opts.xTimeFormat = opts.xTimeFormat || ((t) => _.formatTime(t).split("'")[0]);
35
32
 
36
- this._registerDataAttribute({
33
+ return {
37
34
  name: 'time',
38
- init: function({ point, props, id }) {
39
- // "coordinateProperties" property is generated inside "@tmcw/toGeoJSON"
40
- if (props) {
41
- if("coordTimes" in props) point.meta.time = new Date(Date.parse(props.coordTimes[id]));
42
- else if("times" in props) point.meta.time = new Date(Date.parse(props.times[id]));
43
- else if("time" in props) point.meta.time = new Date(Date.parse((typeof props.time === 'object' ? props.time[id] : props.time)));
44
- }
45
- },
46
- fetch: function(i, point) {
35
+ required: (this.options.speed || this.options.acceleration || this.options.timestamps),
36
+ coordinateProperties: ["coordTimes", "times", "time"],
37
+ coordPropsToMeta: _.parseDate,
38
+ pointToAttr: function(point, i) {
47
39
  // Add missing timestamps (see: options.timeAVGSpeed)
48
40
  if (!point.meta || !point.meta.time) {
49
41
  point.meta = point.meta || {};
50
42
  if(i > 0) {
51
43
  let dx = (this._data[i].dist - this._data[i - 1].dist);
52
44
  let t0 = this._data[i - 1].time.getTime();
53
- let dt = ( dx / this._timeAVGSpeed) * this.options.timeFactor * 1000;
54
- point.meta.time = new Date(t0 + dt);
45
+ point.meta.time = new Date(t0 + ( dx / this._timeAVGSpeed) * this.options.timeFactor * 1000);
55
46
  } else {
56
47
  point.meta.time = new Date(Date.now())
57
48
  }
58
49
  }
59
50
  // Handle timezone offset
60
- if (point.meta.time.getTime() - point.meta.time.getTimezoneOffset() * 60 * 1000 === 0) {
61
- point.meta.time = 0;
62
- }
63
- return point.meta.time.getTime();
51
+ let time = (point.meta.time.getTime() - point.meta.time.getTimezoneOffset() * 60 * 1000 !== 0) ? point.meta.time : 0;
52
+ // Update duration
53
+ this._data[i].duration = i > 0 ? (this._data[i - 1].duration || 0) + Math.abs(time - this._data[i - 1].time) : 0;
54
+ return time;
64
55
  },
65
- update: function(time, i) {
66
- this.track_info.time = (this.track_info.time || 0) + Math.abs(this._data[i].time - this._data[i > 0 ? i - 1 : i].time);
67
- this._data[i].duration = this.track_info.time;
68
- return new Date(time);
69
- }
70
- });
71
-
72
- if (opts.time && opts.time != "summary" && !L.Browser.mobile) {
73
-
74
- this._registerAxisScale({
56
+ onPointAdded: (_, i) => this.track_info.time = this._data[i].duration,
57
+ scale: (opts.time && opts.time != "summary" && !L.Browser.mobile) && {
75
58
  axis : "x",
76
59
  position : "top",
77
60
  scale : {
@@ -82,6 +65,7 @@ Elevation.addInitHook(function() {
82
65
  labelY : -10,
83
66
  labelX : () => this._width(),
84
67
  name : "time",
68
+ ticks : () => _.clamp(this._chart._xTicks() / 2, [4, +Infinity]),
85
69
  tickFormat : (d) => (d == 0 ? '' : opts.xTimeFormat(d)),
86
70
  onAxisMount: axis => {
87
71
  axis.select(".domain")
@@ -95,31 +79,25 @@ Elevation.addInitHook(function() {
95
79
  .attr('stroke-dasharray', 2)
96
80
  .attr('opacity', 0.75);
97
81
  }
98
- });
99
-
100
- }
101
-
102
- if (this.options.timestamps) {
103
- this._registerTooltip({
104
- name: 'date',
105
- chart: (item) => L._("t: ") + this.options.timeFormat(item.time),
106
- order: 20,
107
- });
108
- }
109
-
110
- if (this.options.time) {
111
- this._registerTooltip({
112
- name: 'time',
113
- chart: (item) => L._("T: ") + _.formatTime(item.duration || 0),
114
- order: 20
115
- });
116
- this._registerSummary({
82
+ },
83
+ tooltips: [
84
+ (this.options.time) && {
85
+ name: 'time',
86
+ chart: (item) => L._("T: ") + _.formatTime(item.duration || 0),
87
+ order: 20
88
+ },
89
+ (this.options.timestamps) && {
90
+ name: 'date',
91
+ chart: (item) => L._("t: ") + this.options.timeFormat(item.time),
92
+ order: 21,
93
+ }
94
+ ],
95
+ summary: (this.options.time) && {
117
96
  "tottime" : {
118
97
  label: "Total Time: ",
119
98
  value: (track) => _.formatTime(track.time || 0),
120
99
  order: 20
121
100
  }
122
- });
123
- }
124
-
125
- });
101
+ }
102
+ };
103
+ }