@raruto/leaflet-elevation 2.0.8 → 2.2.0
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/README.md +29 -8
- package/dist/leaflet-elevation.js +1619 -1682
- package/dist/leaflet-elevation.js.map +1 -1
- package/dist/leaflet-elevation.min.js +1 -1
- package/dist/leaflet-elevation.min.js.map +1 -1
- package/package.json +10 -7
- package/src/components/chart.js +1 -1
- package/src/components/d3.js +1 -1
- package/src/control.js +19 -30
- package/src/handlers/heart.js +52 -52
- package/src/handlers/pace.js +65 -0
- package/src/index.js +0 -12
- package/src/options.js +2 -2
- package/src/utils.js +6 -6
package/src/control.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import 'leaflet-i18n';
|
|
2
1
|
import * as _ from './utils';
|
|
3
2
|
import { Options } from './options';
|
|
4
3
|
|
|
4
|
+
// "leaflet-i18n" fallback
|
|
5
|
+
if (!L._ || !L.i18n) {
|
|
6
|
+
L._ = L.i18n = (string, data) => string;
|
|
7
|
+
}
|
|
8
|
+
|
|
5
9
|
export const Elevation = L.Control.Elevation = L.Control.extend({
|
|
6
10
|
|
|
7
11
|
includes: L.Evented ? L.Evented.prototype : L.Mixin.Events,
|
|
@@ -228,17 +232,7 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
|
|
|
228
232
|
|
|
229
233
|
if (!this.eleDiv) this.eleDiv = container;
|
|
230
234
|
|
|
231
|
-
|
|
232
|
-
"Distance",
|
|
233
|
-
"Time",
|
|
234
|
-
"Altitude",
|
|
235
|
-
"Slope",
|
|
236
|
-
"Speed",
|
|
237
|
-
"Acceleration",
|
|
238
|
-
...this.options.handlers
|
|
239
|
-
].filter(m => false !== this.options[typeof m == "string" && m.toLowerCase()]);
|
|
240
|
-
|
|
241
|
-
this._loadModules(modules).then(() => { // Inject here required modules (data handlers)
|
|
235
|
+
this._loadModules(this.options.handlers).then(() => { // Inject here required modules (data handlers)
|
|
242
236
|
this._initChart(container);
|
|
243
237
|
this._initButton(container);
|
|
244
238
|
this._initSummary(container);
|
|
@@ -578,14 +572,15 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
|
|
|
578
572
|
* Generate "svg" chart (DOM element).
|
|
579
573
|
*/
|
|
580
574
|
_initChart: function(container) {
|
|
581
|
-
let opts
|
|
575
|
+
let opts = this.options;
|
|
576
|
+
let map = this._map;
|
|
582
577
|
|
|
583
578
|
if (opts.detached) {
|
|
584
579
|
let { offsetWidth, offsetHeight} = this.eleDiv;
|
|
585
580
|
if (offsetWidth > 0) opts.width = offsetWidth;
|
|
586
581
|
if (offsetHeight > 20) opts.height = offsetHeight - 20; // 20 = horizontal scrollbar size.
|
|
587
582
|
} else {
|
|
588
|
-
let { clientWidth } =
|
|
583
|
+
let { clientWidth } = map.getContainer();
|
|
589
584
|
opts._maxWidth = opts._maxWidth > opts.width ? opts._maxWidth : opts.width;
|
|
590
585
|
this._container.style.maxWidth = opts._maxWidth + 'px';
|
|
591
586
|
if (opts._maxWidth > clientWidth) opts.width = clientWidth - 30;
|
|
@@ -725,22 +720,16 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
|
|
|
725
720
|
// First map known classnames (eg. "Altitude" --> L.Control.Elevation.Altitude)
|
|
726
721
|
handlers = handlers.map((h) => typeof h === 'string' && typeof Elevation[h] !== "undefined" ? Elevation[h] : h);
|
|
727
722
|
// Then load optional classes and custom imports (eg. "Cadence" --> import('../src/handlers/cadence.js'))
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
_.each(m, (exported) => {
|
|
736
|
-
let fn = Object.keys(exported)[0];
|
|
737
|
-
if (fn && typeof Elevation[fn] === "undefined" ) {
|
|
738
|
-
handlers[fn] = Elevation[fn] = exported[fn];
|
|
739
|
-
|
|
740
|
-
}
|
|
741
|
-
});
|
|
742
|
-
_.each(handlers, h => this._registerHandler(h));
|
|
723
|
+
let modules = handlers.map(file => (typeof file === 'string' && this.import(this.__modulesFolder + file.toLowerCase() + '.js')) || (file instanceof Promise && file) || Promise.resolve());
|
|
724
|
+
return Promise.all(modules).then((m) => {
|
|
725
|
+
_.each(m, (exported, i) => {
|
|
726
|
+
let fn = exported && Object.keys(exported)[0];
|
|
727
|
+
if (fn) {
|
|
728
|
+
handlers[i] = Elevation[fn] = (Elevation[fn] ?? exported[fn]);
|
|
729
|
+
}
|
|
743
730
|
});
|
|
731
|
+
_.each(handlers, h => ["function", "object"].includes(typeof h) && this._registerHandler(h));
|
|
732
|
+
});
|
|
744
733
|
},
|
|
745
734
|
|
|
746
735
|
/**
|
|
@@ -1030,7 +1019,7 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
|
|
|
1030
1019
|
if (props.stats) {
|
|
1031
1020
|
for (const key in props.stats) {
|
|
1032
1021
|
let sname = (props.statsName || attr) + (key != '' ? '_' : '');
|
|
1033
|
-
this.track_info[sname + key] = props.stats[key].call(this, curr[attr], this.track_info[sname + key]);
|
|
1022
|
+
this.track_info[sname + key] = props.stats[key].call(this, curr[attr], this.track_info[sname + key], index);
|
|
1034
1023
|
}
|
|
1035
1024
|
}
|
|
1036
1025
|
|
package/src/handlers/heart.js
CHANGED
|
@@ -1,53 +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: 25,
|
|
17
|
-
labelX : -30,
|
|
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) + ' ' + unit,
|
|
39
|
-
// order: 30
|
|
40
|
-
},
|
|
41
|
-
"maxbpm": {
|
|
42
|
-
label: "Max BPM: ",
|
|
43
|
-
value: (track, unit) => Math.round(track.
|
|
44
|
-
// order: 30
|
|
45
|
-
},
|
|
46
|
-
"avgbpm": {
|
|
47
|
-
label: "Avg BPM: ",
|
|
48
|
-
value: (track, unit) => Math.round(track.heart_avg || 0) + ' ' + unit,
|
|
49
|
-
// order: 20
|
|
50
|
-
},
|
|
51
|
-
}
|
|
52
|
-
};
|
|
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: 25,
|
|
17
|
+
labelX : -30,
|
|
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) + ' ' + unit,
|
|
39
|
+
// order: 30
|
|
40
|
+
},
|
|
41
|
+
"maxbpm": {
|
|
42
|
+
label: "Max BPM: ",
|
|
43
|
+
value: (track, unit) => Math.round(track.heart_max || 0) + ' ' + unit,
|
|
44
|
+
// order: 30
|
|
45
|
+
},
|
|
46
|
+
"avgbpm": {
|
|
47
|
+
label: "Avg BPM: ",
|
|
48
|
+
value: (track, unit) => Math.round(track.heart_avg || 0) + ' ' + unit,
|
|
49
|
+
// order: 20
|
|
50
|
+
},
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
53
|
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export function Pace() {
|
|
2
|
+
|
|
3
|
+
const _ = L.Control.Elevation.Utils;
|
|
4
|
+
|
|
5
|
+
let opts = this.options;
|
|
6
|
+
let pace = {};
|
|
7
|
+
|
|
8
|
+
pace.label = opts.paceLabel || L._(opts.imperial ? 'min/mi' : 'min/km');
|
|
9
|
+
opts.paceFactor = opts.paceFactor || 60; // 1 min = 60 sec
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
name: 'pace',
|
|
13
|
+
unit: pace.label,
|
|
14
|
+
deltaMax: this.options.paceDeltaMax,
|
|
15
|
+
clampRange: this.options.paceRange,
|
|
16
|
+
decimals: 2,
|
|
17
|
+
pointToAttr: (_, i) => {
|
|
18
|
+
let dx = (this._data[i].dist - this._data[i > 0 ? i - 1 : i].dist) * 1000;
|
|
19
|
+
let dt = this._data[i].time - this._data[ i > 0 ? i - 1 : i].time;
|
|
20
|
+
return dx > 0 ? Math.abs((dt / dx) / opts.paceFactor) : 0;
|
|
21
|
+
},
|
|
22
|
+
stats: { max: _.iMax, min: _.iMin, avg: _.iAvg },
|
|
23
|
+
scale : (this.options.pace && this.options.pace != "summary") && {
|
|
24
|
+
axis : "y",
|
|
25
|
+
position : "right",
|
|
26
|
+
scale : { min : 0, max : +1 },
|
|
27
|
+
tickPadding: 16,
|
|
28
|
+
labelX : 25,
|
|
29
|
+
labelY : -8,
|
|
30
|
+
},
|
|
31
|
+
path: (this.options.pace && this.options.pace != "summary") && {
|
|
32
|
+
// name : 'pace',
|
|
33
|
+
label : 'Pace',
|
|
34
|
+
yAttr : "pace",
|
|
35
|
+
scaleX : 'distance',
|
|
36
|
+
scaleY : 'pace',
|
|
37
|
+
color : '#03ffff',
|
|
38
|
+
strokeColor : '#000',
|
|
39
|
+
strokeOpacity: "0.5",
|
|
40
|
+
fillOpacity : "0.25",
|
|
41
|
+
},
|
|
42
|
+
tooltip: (this.options.pace) && {
|
|
43
|
+
chart: (item) => L._('pace: ') + item.pace + " " + pace.label,
|
|
44
|
+
marker: (item) => Math.round(item.pace) + " " + pace.label,
|
|
45
|
+
order: 50,
|
|
46
|
+
},
|
|
47
|
+
summary: (this.options.pace) && {
|
|
48
|
+
"minpace" : {
|
|
49
|
+
label: "Min Pace: ",
|
|
50
|
+
value: (track, unit) => Math.round(track.pace_min || 0) + ' ' + unit,
|
|
51
|
+
order: 51
|
|
52
|
+
},
|
|
53
|
+
"maxpace" : {
|
|
54
|
+
label: "Max Pace: ",
|
|
55
|
+
value: (track, unit) => Math.round(track.pace_max || 0) + ' ' + unit,
|
|
56
|
+
order: 51
|
|
57
|
+
},
|
|
58
|
+
"avgpace": {
|
|
59
|
+
label: "Avg Pace: ",
|
|
60
|
+
value: (track, unit) => Math.round(track.pace_avg || 0) + ' ' + unit,
|
|
61
|
+
order: 52
|
|
62
|
+
},
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
package/src/index.js
CHANGED
|
@@ -34,21 +34,9 @@
|
|
|
34
34
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
35
35
|
*/
|
|
36
36
|
|
|
37
|
-
import 'leaflet-i18n';
|
|
38
37
|
import * as _ from './utils';
|
|
39
38
|
import { Elevation } from './control';
|
|
40
39
|
|
|
41
40
|
Elevation.Utils = _;
|
|
42
41
|
|
|
43
|
-
/* Temporary fix for empty values evaluated as false (leaflet-i18n v0.3.1) */
|
|
44
|
-
(function(){
|
|
45
|
-
let proto = L.i18n.bind({});
|
|
46
|
-
L.i18n = L._ = (string, data) => {
|
|
47
|
-
if (L.locale && L.locales[L.locale] && L.locales[L.locale][string] == "") {
|
|
48
|
-
L.locales[L.locale][string] = "\u200B";
|
|
49
|
-
}
|
|
50
|
-
return proto.call(null, string, data);
|
|
51
|
-
};
|
|
52
|
-
})();
|
|
53
|
-
|
|
54
42
|
L.control.elevation = (options) => new Elevation(options);
|
package/src/options.js
CHANGED
|
@@ -17,7 +17,7 @@ export var Options = {
|
|
|
17
17
|
followMarker: true,
|
|
18
18
|
imperial: false,
|
|
19
19
|
legend: true,
|
|
20
|
-
handlers: [],
|
|
20
|
+
handlers: ["Distance", "Time", "Altitude", "Slope", "Speed", "Acceleration"],
|
|
21
21
|
hotline: 'elevation',
|
|
22
22
|
marker: 'elevation-line',
|
|
23
23
|
markerIcon: L.divIcon({
|
|
@@ -46,7 +46,7 @@ export var Options = {
|
|
|
46
46
|
summary: 'inline',
|
|
47
47
|
slope: false,
|
|
48
48
|
speed: false,
|
|
49
|
-
time:
|
|
49
|
+
time: true,
|
|
50
50
|
timeFactor: 3600,
|
|
51
51
|
timestamps: false,
|
|
52
52
|
trkStart: L.circleMarker([0,0], { className: 'start-marker', radius: 6, weight: 2, color: '#fff', fillColor: '#00d800', fillOpacity: 1, interactive: false }),
|
package/src/utils.js
CHANGED
|
@@ -92,7 +92,7 @@ export function coordPropsToMeta(coordProps, name, parser) {
|
|
|
92
92
|
if (props) {
|
|
93
93
|
for (const key of coordProps) {
|
|
94
94
|
if (key in props) {
|
|
95
|
-
point.meta[name] = (parser ||
|
|
95
|
+
point.meta[name] = (parser || parseNumeric).call(this, (isMulti ? props[key][isMulti] : props[key]), id);
|
|
96
96
|
break;
|
|
97
97
|
}
|
|
98
98
|
}
|
|
@@ -103,7 +103,7 @@ export function coordPropsToMeta(coordProps, name, parser) {
|
|
|
103
103
|
/**
|
|
104
104
|
* Extract numeric property (id) from GeoJSON object
|
|
105
105
|
*/
|
|
106
|
-
export const
|
|
106
|
+
export const parseNumeric = (property, id) => parseInt((typeof property === 'object' ? property[id] : property));
|
|
107
107
|
|
|
108
108
|
/**
|
|
109
109
|
* Extract datetime property (id) from GeoJSON object
|
|
@@ -131,10 +131,10 @@ export const randomId = () => Math.random().toString(36).
|
|
|
131
131
|
/**
|
|
132
132
|
* TODO: use generators instead? (ie. "yield")
|
|
133
133
|
*/
|
|
134
|
-
export const iMax = (iVal, max) => (iVal > max ? iVal : max)
|
|
135
|
-
export const iMin = (iVal, min) => (iVal < min ? iVal : min)
|
|
136
|
-
export const iAvg = (iVal, avg) => (iVal +
|
|
137
|
-
export const iSum = (iVal, sum) => iVal +
|
|
134
|
+
export const iMax = (iVal, max = -Infinity) => (iVal > max ? iVal : max);
|
|
135
|
+
export const iMin = (iVal, min = +Infinity) => (iVal < min ? iVal : min);
|
|
136
|
+
export const iAvg = (iVal, avg = 0, idx = 1) => (iVal + avg * (idx - 1)) / idx;
|
|
137
|
+
export const iSum = (iVal, sum = 0) => iVal + sum;
|
|
138
138
|
|
|
139
139
|
/**
|
|
140
140
|
* Alias for some leaflet core functions
|