@raruto/leaflet-elevation 2.0.1 → 2.0.4

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
@@ -7,8 +7,8 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
7
7
  includes: L.Evented ? L.Evented.prototype : L.Mixin.Events,
8
8
 
9
9
  options: Options,
10
- __mileFactor: 0.621371, // 1 km = (0.621371 mi)
11
- __footFactor: 3.28084, // 1 m = (3.28084 ft)
10
+ __mileFactor: 0.621371, // 1 km = (0.621371 mi)
11
+ __footFactor: 3.28084, // 1 m = (3.28084 ft)
12
12
  __D3: 'https://unpkg.com/d3@6.5.0/dist/d3.min.js',
13
13
  __TOGEOJSON: 'https://unpkg.com/@tmcw/togeojson@4.6.0/dist/togeojson.umd.js',
14
14
  __LGEOMUTIL: 'https://unpkg.com/leaflet-geometryutil@0.9.3/src/leaflet.geometryutil.js',
@@ -25,9 +25,7 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
25
25
  addData: function(d, layer) {
26
26
  this.import(this.__D3)
27
27
  .then(() => {
28
- if (typeof layer === "undefined" && d.on) {
29
- layer = d;
30
- }
28
+ layer = layer ?? (d.on && d);
31
29
  this._addData(d);
32
30
  this._addLayer(layer);
33
31
  this._fireEvt("eledata_added", { data: d, layer: layer, track_info: this.track_info });
@@ -39,9 +37,9 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
39
37
  */
40
38
  addTo: function(map) {
41
39
  if (this.options.detached) {
42
- let eleDiv = this._initElevationDiv();
43
- if (!eleDiv.isConnected) _.insert(map.getContainer(), eleDiv, 'afterend');
44
- _.append(eleDiv, this.onAdd(map));
40
+ let parent = _.select(this.options.elevationDiv);
41
+ let eleDiv = this.onAdd(map);
42
+ parent ? _.append(parent, eleDiv) : _.insert(map.getContainer(), eleDiv, 'afterend');
45
43
  } else {
46
44
  L.Control.prototype.addTo.call(this, map);
47
45
  }
@@ -223,7 +221,9 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
223
221
  onAdd: function(map) {
224
222
  this._map = map;
225
223
 
226
- let container = this._container = _.create("div", "elevation-control elevation " + this.options.theme + " " + (this.options.detached ? '' : 'leaflet-control'));
224
+ let container = this._container = _.create("div", "elevation-control " + this.options.theme + " " + (this.options.detached ? 'elevation-detached' : 'leaflet-control'), this.options.detached ? { id: 'elevation-' + _.randomId() } : {});
225
+
226
+ if (!this.eleDiv) this.eleDiv = container;
227
227
 
228
228
  let modules = [
229
229
  "Distance",
@@ -296,51 +296,44 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
296
296
  return;
297
297
  }
298
298
 
299
- /**
300
- * Standard GeoJSON --> doesn't handle "time", "heart", …
301
- */
302
- let geom = d.geometry;
303
- if (geom) {
304
- switch (geom.type) {
305
- case 'LineString':
306
- this._addGeoJSONData(geom.coordinates);
307
- break;
308
-
309
- case 'MultiLineString':
310
- _.each(geom.coordinates, coords => this._addGeoJSONData(coords));
311
- break;
312
-
313
- default:
314
- return console.warn('Unsopperted GeoJSON feature geometry type:' + geom.type);
299
+ // Standard GeoJSON
300
+ if (d.type === "FeatureCollection" ) {
301
+ return _.each(d.features, feature => this._addData(feature));
302
+ } else if (d.type === "Feature") {
303
+ let geom = d.geometry;
304
+ if (geom) {
305
+ switch (geom.type) {
306
+ case 'LineString': return this._addGeoJSONData(geom.coordinates, d.properties);
307
+ case 'MultiLineString': return _.each(geom.coordinates, (coords, i) => this._addGeoJSONData(coords, d.properties, i));
308
+ case 'Point':
309
+ default: return console.warn('Unsopperted GeoJSON feature geometry type:' + geom.type);
310
+ }
315
311
  }
316
312
  }
317
- if (d.type === "FeatureCollection") {
318
- _.each(d.features, feature => this._addData(feature));
319
- }
320
313
 
321
- /**
322
- * Extended GeoJSON --> rely on leaflet implementation
323
- */
314
+ // Fallback for leaflet layers (eg. L.Gpx)
324
315
  if (d._latlngs) {
325
- this._addGeoJSONData(d._latlngs, d.feature && d.feature.properties);
316
+ return this._addGeoJSONData(d._latlngs, d.feature && d.feature.properties);
326
317
  }
318
+
327
319
  },
328
320
 
329
321
  /*
330
322
  * Parsing of GeoJSON data lines and their elevation in z-coordinate
331
323
  */
332
- _addGeoJSONData: function(coords, properties) {
324
+ _addGeoJSONData: function(coords, properties, nestingLevel) {
325
+
326
+ // "coordinateProperties" property is generated inside "@tmcw/toGeoJSON"
327
+ let props = (properties && properties.coordinateProperties) || properties;
328
+
333
329
  coords.forEach((point, i) => {
334
330
 
335
331
  // GARMIN_EXTENSIONS = ["hr", "cad", "atemp", "wtemp", "depth", "course", "bearing"];
336
332
  point.meta = point.meta ?? { time: null, ele: null };
337
333
 
338
- // "coordinateProperties" property is generated inside "@tmcw/toGeoJSON"
339
- let props = (properties && properties.coordinateProperties) || properties;
340
-
341
334
  point.prev = (attr) => (attr ? this._data[i > 0 ? i - 1 : 0][attr] : this._data[i > 0 ? i - 1 : 0]);
342
335
 
343
- this.fire("elepoint_init", { point: point, props: props, id: i });
336
+ this.fire("elepoint_init", { point: point, props: props, id: i, isMulti: nestingLevel });
344
337
 
345
338
  this._addPoint(
346
339
  point.lat ?? point[1],
@@ -380,10 +373,12 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
380
373
  if (layer && this.options.distanceMarkers && this.options.distanceMarkers.lazy) {
381
374
  layer.on('add remove', ({target, type}) => L.DistanceMarkers && target instanceof L.Polyline && target[type + 'DistanceMarkers']());
382
375
  }
376
+ return layer;
383
377
  },
384
378
 
385
379
  _addMarker: function(marker) {
386
380
  if (marker) this._markers.addLayer(marker)
381
+ return marker;
387
382
  },
388
383
 
389
384
  /**
@@ -420,21 +415,6 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
420
415
  }
421
416
  },
422
417
 
423
- /**
424
- * Adds the control to the given "detached" div.
425
- */
426
- _initElevationDiv: function() {
427
- let eleDiv = _.select(this.options.elevationDiv);
428
- if (!eleDiv) {
429
- this.options.elevationDiv = '#elevation-div_' + _.randomId();
430
- eleDiv = _.create('div', 'leaflet-control elevation elevation-div', { id: this.options.elevationDiv.substr(1) });
431
- }
432
- if (this.options.detached) {
433
- _.replaceClass(eleDiv, 'leaflet-control', 'elevation-detached');
434
- }
435
- return this.eleDiv = eleDiv;
436
- },
437
-
438
418
  /**
439
419
  * Initialize "L.AlmostOver" and "L.DistanceMarkers"
440
420
  */
@@ -453,6 +433,7 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
453
433
  } else if (control.options.polyline) {
454
434
  layer.addTo(map);
455
435
  }
436
+ map.invalidateSize();
456
437
  } else {
457
438
  console.warn("Undefined elevation map object");;
458
439
  }
@@ -479,7 +460,7 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
479
460
  let oldProto = L.Canvas.prototype._fillStroke;
480
461
  let control = this;
481
462
 
482
- let theme = this.options.theme.replace('-theme', '');
463
+ let theme = this.options.theme.split(' ')[0].replace('-theme', '');
483
464
  let color = _.Colors[theme] || {};
484
465
 
485
466
  L.Canvas.include({
@@ -600,10 +581,6 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
600
581
  .on('margins_updated', this._resizeChart, this);
601
582
 
602
583
 
603
- this.fire("elechart_axis");
604
-
605
- if (this.options.legend) this.fire("elechart_legend");
606
-
607
584
  this.fire("elechart_init");
608
585
 
609
586
  map
@@ -668,23 +645,19 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
668
645
  .disableScrollPropagation(container);
669
646
  }
670
647
 
671
- if (!this.options.detached) {
672
- let link = this._button = _.create('a', "elevation-toggle elevation-toggle-icon" + (this.options.autohide ? "" : " close-button"), { href: '#', title: L._('Elevation') }, container);
673
-
674
- if (this.options.collapsed) {
675
- this._collapse();
676
- if (this.options.autohide) {
677
- _.on(container, 'mouseover', this._expand, this);
678
- _.on(container, 'mouseout', this._collapse, this);
679
- } else {
680
- _.on(link, 'click', L.DomEvent.stop);
681
- _.on(link, 'click', this._toggle, this);
682
- }
648
+ this.options.collapsed ? this._collapse() : this._expand();
683
649
 
684
- _.on(link, 'focus', this._toggle, this);
650
+ if (this.options.autohide) {
651
+ _.on(container, 'mouseover', this._expand, this);
652
+ _.on(container, 'mouseout', this._collapse, this);
653
+ this._map.on('click', this._collapse, this);
654
+ }
685
655
 
686
- this._map.on('click', this._collapse, this);
687
- }
656
+ if (this.options.closeBtn) {
657
+ let link = this._button = _.create('a', "elevation-toggle-icon", { href: '#', title: L._('Elevation'), }, container);
658
+ _.on(link, 'click', L.DomEvent.stop);
659
+ _.on(link, 'click', this._toggle, this);
660
+ _.on(link, 'focus', this._toggle, this);
688
661
  }
689
662
  },
690
663
 
@@ -716,7 +689,7 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
716
689
  */
717
690
  _loadModules: function(handlers) {
718
691
  // First map known classnames (eg. "Altitude" --> L.Control.Elevation.Altitude)
719
- handlers = handlers.map((h) => typeof h === 'string' && typeof L.Control.Elevation[h] !== "undefined" ? L.Control.Elevation[h] : h);
692
+ handlers = handlers.map((h) => typeof h === 'string' && typeof Elevation[h] !== "undefined" ? Elevation[h] : h);
720
693
  // Then load optional classes and custom imports (eg. "Cadence" --> import('../src/handlers/cadence.js'))
721
694
  Promise.
722
695
  all(
@@ -727,8 +700,8 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
727
700
  .then((m) => {
728
701
  _.each(m, (exported) => {
729
702
  let fn = Object.keys(exported)[0];
730
- if (fn && typeof L.Control.Elevation[fn] === "undefined" ) {
731
- handlers[fn] = L.Control.Elevation[fn] = exported[fn];
703
+ if (fn && typeof Elevation[fn] === "undefined" ) {
704
+ handlers[fn] = Elevation[fn] = exported[fn];
732
705
 
733
706
  }
734
707
  });
@@ -740,65 +713,48 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
740
713
  * Simple GeoJSON data loader (L.GeoJSON).
741
714
  */
742
715
  _loadLayer: function(geojson) {
743
- let control = this;
716
+ let { polyline, theme, waypoints, wptIcons, wptLabels, distanceMarkers } = this.options;
717
+ let style = L.extend({}, polyline);
718
+
719
+ if (theme) {
720
+ style.className += ' ' + theme;
721
+ }
744
722
 
745
- let { wptIcons, wptLabels } = control.options;
723
+ if (geojson.name) {
724
+ this.track_info.name = geojson.name;
725
+ }
746
726
 
747
727
  let layer = L.geoJson(geojson, {
748
- distanceMarkers: control.options.distanceMarkers,
749
- style: (feature) => {
750
- let style = L.extend({}, control.options.polyline);
751
- if (control.options.theme) {
752
- style.className += ' ' + control.options.theme;
753
- }
754
- return style;
755
- },
728
+ distanceMarkers: distanceMarkers,
729
+ style: style,
756
730
  pointToLayer: (feature, latlng) => {
757
- if (!control.options.waypoints) return;
758
-
759
- let prop = feature.properties;
760
- let desc = prop.desc ?? '';
761
- let name = prop.name ?? '';
762
- let sym = (prop.sym ?? name).replace(' ', '-').replace('"', '').replace("'", '').toLowerCase();
763
-
764
- // Handle chart waypoints (dots)
765
- if ([true, 'dots'].includes(control.options.waypoints)) {
766
- control._registerCheckPoint({
767
- latlng: latlng,
768
- label: ([true, 'dots'].includes(wptLabels) ? name : '')
769
- });
770
- }
771
-
772
- // Handle map waypoints (markers)
773
- if ([true, 'markers'].includes(control.options.waypoints) && wptIcons != false) {
774
- // generate and cache appropriate icon symbol
775
- if (!wptIcons.hasOwnProperty(sym)) {
776
- wptIcons[sym] = L.divIcon(
777
- L.extend({}, wptIcons[""].options, { html: '<i class="elevation-waypoint-icon ' + sym + '"></i>' } )
778
- );
731
+ if (waypoints) {
732
+ let { desc, name, sym } = feature.properties;
733
+ desc = desc || '';
734
+ name = name || '';
735
+ // Handle chart waypoints (dots)
736
+ if ([true, 'dots'].includes(waypoints)) {
737
+ this._registerCheckPoint({
738
+ latlng: latlng,
739
+ label : ([true, 'dots'].includes(wptLabels) ? name : '')
740
+ });
779
741
  }
780
- let marker = L.marker(latlng, { icon: wptIcons[sym] });
781
- if ([true, 'markers'].includes(wptLabels) && (name || desc)) {
782
- let content = decodeURI("<b>" + name + "</b>" + (desc.length > 0 ? '<br>' + desc : ''));
783
- marker.bindPopup(content, { className: 'elevation-popup', keepInView: true }).openPopup();
784
- marker.bindTooltip(content, { className: 'elevation-tooltip', direction: 'auto', sticky: true, opacity: 1 }).openTooltip();
742
+ // Handle map waypoints (markers)
743
+ if ([true, 'markers'].includes(waypoints) && wptIcons != false) {
744
+ return this._registerMarker({
745
+ latlng : latlng,
746
+ sym : (sym ?? name).replace(' ', '-').replace('"', '').replace("'", '').toLowerCase(),
747
+ content: [true, 'markers'].includes(wptLabels) && (name || desc) && decodeURI("<b>" + name + "</b>" + (desc.length > 0 ? '<br>' + desc : ''))
748
+ });
785
749
  }
786
- control._addMarker(marker);
787
- control.fire('waypoint_added', { point: marker, element: latlng, properties: prop });
788
- return marker;
789
750
  }
790
751
  },
791
- onEachFeature: (feature, layer) => {
792
- if (feature.geometry && feature.geometry.type != 'Point') {
793
- control.addData(layer);
794
- control.track_info = L.extend({}, control.track_info, { name: geojson.name });
795
- }
796
- },
752
+ onEachFeature: (feature, layer) => feature.geometry && feature.geometry.type != 'Point' && this.addData(feature, layer),
797
753
  });
798
754
 
799
- control.import(control.__D3).then(() => {
800
- control._initMapIntegrations(control, layer);
801
- control._fireEvt("eledata_loaded", { data: geojson, layer: layer, name: control.track_info.name, track_info: control.track_info });
755
+ this.import(this.__D3).then(() => {
756
+ this._initMapIntegrations(this, layer);
757
+ this._fireEvt("eledata_loaded", { data: geojson, layer: layer, name: this.track_info.name, track_info: this.track_info });
802
758
  });
803
759
 
804
760
  return layer;
@@ -929,8 +885,7 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
929
885
  geojson = this._parseFromGeoJSONString(data.toString());
930
886
  }
931
887
  if (geojson) {
932
- geojson = this._prepareMultiLineStrings(geojson);
933
- geojson = this._prepareAdditionalProperties(geojson);
888
+ geojson.name = geojson.name || (this._downloadURL || '').split('/').pop().split('#')[0].split('?')[0];
934
889
  }
935
890
  resolve(geojson);
936
891
  })
@@ -958,37 +913,6 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
958
913
  return geojson;
959
914
  },
960
915
 
961
- /**
962
- * Extend GeoJSON properties (name, time, ...)
963
- */
964
- _prepareAdditionalProperties: function(geojson) {
965
- if (!geojson.name && this._downloadURL) {
966
- geojson.name = this._downloadURL.split('/').pop().split('#')[0].split('?')[0];
967
- }
968
- return geojson;
969
- },
970
-
971
- /**
972
- * Just a temporary fix for MultiLineString data (trk > trkseg + trkseg),
973
- * just split them into seperate LineStrings (trk > trkseg, trk > trkseg)
974
- *
975
- * @link https://github.com/Raruto/leaflet-elevation/issues/56
976
- */
977
- _prepareMultiLineStrings: function(geojson) {
978
- geojson.features.forEach(feauture => {
979
- if (feauture.geometry.type == "MultiLineString") {
980
- feauture.geometry.coordinates.forEach(coords => {
981
- geojson.features.push({
982
- geometry: { type: 'LineString', coordinates: coords },
983
- properties: feauture.properties,
984
- type: 'Feature'
985
- });
986
- });
987
- }
988
- });
989
- return geojson.features.filter(feauture => feauture.geometry.type != "MultiLineString");
990
- },
991
-
992
916
  /**
993
917
  * Add chart profile to diagram
994
918
  */
@@ -1106,60 +1030,79 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
1106
1030
  return this._registerHandler(props.call(this));
1107
1031
  }
1108
1032
 
1033
+ let {
1034
+ name,
1035
+ attr,
1036
+ required,
1037
+ skipNull,
1038
+ deltaMax,
1039
+ clampRange,
1040
+ decimals,
1041
+ meta,
1042
+ unit,
1043
+ coordinateProperties,
1044
+ coordPropsToMeta,
1045
+ pointToAttr,
1046
+ onPointAdded,
1047
+ stats,
1048
+ statsName,
1049
+ grid,
1050
+ scale,
1051
+ path,
1052
+ tooltip,
1053
+ summary
1054
+ } = props;
1055
+
1109
1056
  // eg. "altitude" == true
1110
- if (this.options[props.name] || props.required) {
1057
+ if (this.options[name] || required) {
1111
1058
 
1112
1059
  this._registerDataAttribute({
1113
- name: props.name,
1114
- attr: props.attr,
1115
- skipNull: props.skipNull,
1116
- deltaMax: props.deltaMax,
1117
- clampRange: props.clampRange,
1118
- decimals: props.decimals,
1119
- coordPropsToMeta: _.coordPropsToMeta(props.coordinateProperties, props.meta || props.name, props.coordPropsToMeta),
1120
- pointToAttr: props.pointToAttr,
1121
- onPointAdded: props.onPointAdded,
1122
- stats: props.stats,
1123
- statsName: props.statsName,
1060
+ name,
1061
+ attr,
1062
+ skipNull,
1063
+ deltaMax,
1064
+ clampRange,
1065
+ decimals,
1066
+ coordPropsToMeta: _.coordPropsToMeta(coordinateProperties, meta || name, coordPropsToMeta),
1067
+ pointToAttr,
1068
+ onPointAdded,
1069
+ stats,
1070
+ statsName,
1124
1071
  });
1125
1072
 
1126
- if (props.grid) {
1127
- props.grid.name = props.grid.name || props.name;
1128
- this._registerAxisGrid(props.grid);
1073
+ if (grid) {
1074
+ this._registerAxisGrid(L.extend({ name }, grid));
1129
1075
  }
1130
1076
 
1131
- if (this.options[props.name] !== "summary") {
1132
- if (props.scale) {
1133
- props.scale.name = props.scale.name || props.name;
1134
- props.scale.label = props.scale.label || props.unit;
1135
- this._registerAxisScale(props.scale);
1136
- }
1137
- if (props.path) {
1138
- props.path.name = props.path.name || props.name;
1139
- this._registerAreaPath(props.path);
1140
- }
1077
+ if (this.options[name] !== "summary") {
1078
+ if (scale) this._registerAxisScale(L.extend({ name, label: unit }, scale));
1079
+ if (path) this._registerAreaPath(L.extend({ name }, path));
1141
1080
  }
1142
1081
 
1143
- if (props.tooltips) {
1144
- _.each(props.tooltips, t => {
1145
- if (t) {
1146
- t.name = t.name || props.name;
1147
- this._registerTooltip(t)
1148
- }
1149
- });
1150
- } else if (props.tooltip) {
1151
- props.tooltip.name = props.tooltip.name || props.name;
1152
- this._registerTooltip(props.tooltip)
1082
+ if (tooltip || props.tooltips) {
1083
+ _.each([tooltip, ...(props.tooltips || [])], t => t && this._registerTooltip(L.extend({ name }, t)));
1153
1084
  }
1154
1085
 
1155
- if (props.summary) {
1156
- for (const key in props.summary) {
1157
- props.summary[key].unit = props.summary[key].unit || props.unit;
1158
- }
1159
- this._registerSummary(props.summary);
1086
+ if (summary) {
1087
+ _.each(summary, (s, k) => summary[k] = L.extend({ unit }, s));
1088
+ this._registerSummary(summary);
1160
1089
  }
1161
1090
  }
1162
1091
  },
1092
+
1093
+ _registerMarker({latlng, sym, content}) {
1094
+ let { wptIcons } = this.options;
1095
+ // generate and cache appropriate icon symbol
1096
+ if (!wptIcons.hasOwnProperty(sym)) {
1097
+ wptIcons[sym] = L.divIcon(L.extend({}, wptIcons[""].options, { html: '<i class="elevation-waypoint-icon ' + sym + '"></i>' } ));
1098
+ }
1099
+ let marker = L.marker(latlng, { icon: wptIcons[sym] });
1100
+ if (content) {
1101
+ marker.bindPopup(content, { className: 'elevation-popup', keepInView: true }).openPopup();
1102
+ marker.bindTooltip(content, { className: 'elevation-tooltip', direction: 'auto', sticky: true, opacity: 1 }).openTooltip();
1103
+ }
1104
+ return this._addMarker(marker)
1105
+ },
1163
1106
 
1164
1107
  /**
1165
1108
  * Add chart or marker tooltip info
@@ -1242,7 +1185,6 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
1242
1185
  _updateChart: function() {
1243
1186
  if (this._chart && this._container) {
1244
1187
  this.fire("elechart_axis");
1245
- this.fire("elechart_area");
1246
1188
 
1247
1189
  this._chart.update({ data: this._data, options: this.options });
1248
1190
 
@@ -1290,27 +1232,26 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
1290
1232
  * Update chart summary.
1291
1233
  */
1292
1234
  _updateSummary: function() {
1293
- if (!this._summary) return;
1294
-
1295
- this._summary.reset();
1296
-
1297
- if (this.options.summary) {
1298
- this.fire("elechart_summary");
1299
- this._summary.update();
1235
+ if (this._summary) {
1236
+ this._summary.reset();
1237
+ if (this.options.summary) {
1238
+ this.fire("elechart_summary");
1239
+ this._summary.update();
1240
+ }
1241
+ if (this.options.downloadLink && this._downloadURL) { // TODO: generate dynamically file content instead of using static file urls.
1242
+ this._summary._container.innerHTML += '<span class="download"><a href="#">' + L._('Download') + '</a></span>'
1243
+ _.select('.download a', this._summary._container).onclick = ({preventDefault}) => {
1244
+ preventDefault();
1245
+ let event = { downloadLink: this.options.downloadLink, confirm: _.saveFile.bind(this, this._downloadURL) };
1246
+ if (this.options.downloadLink == 'modal' && typeof CustomEvent === "function") {
1247
+ document.dispatchEvent(new CustomEvent("eletrack_download", { detail: event }));
1248
+ } else if (this.options.downloadLink == 'link' || this.options.downloadLink === true) {
1249
+ event.confirm();
1250
+ }
1251
+ this.fire('eletrack_download', event);
1252
+ };
1253
+ }
1300
1254
  }
1301
- if (this.options.downloadLink && this._downloadURL) { // TODO: generate dynamically file content instead of using static file urls.
1302
- this._summary._container.innerHTML += '<span class="download"><a href="#">' + L._('Download') + '</a></span>'
1303
- _.select('.download a', this._summary._container).onclick = ({preventDefault}) => {
1304
- preventDefault();
1305
- let event = { downloadLink: this.options.downloadLink, confirm: _.saveFile.bind(this, this._downloadURL) };
1306
- if (this.options.downloadLink == 'modal' && typeof CustomEvent === "function") {
1307
- document.dispatchEvent(new CustomEvent("eletrack_download", { detail: event }));
1308
- } else if (this.options.downloadLink == 'link' || this.options.downloadLink === true) {
1309
- event.confirm();
1310
- }
1311
- this.fire('eletrack_download', event);
1312
- };
1313
- };
1314
1255
  },
1315
1256
 
1316
1257
 
@@ -5,7 +5,7 @@ export function Altitude() {
5
5
  let opts = this.options;
6
6
  let altitude = {};
7
7
 
8
- let theme = opts.theme.replace('-theme', '');
8
+ let theme = opts.theme.split(' ')[0].replace('-theme', '');
9
9
  let color = _.Colors[theme] || {};
10
10
 
11
11
  opts.altitudeFactor = opts.imperial ? this.__footFactor : (opts.altitudeFactor || 1); // 1 m = (1 m)
@@ -24,7 +24,10 @@ export function Altitude() {
24
24
  // // "alt" property is generated inside "leaflet"
25
25
  // if ("alt" in point) point.meta.ele = point.alt;
26
26
  // },
27
- pointToAttr: (_, i) => this._data[i].z * opts.altitudeFactor,
27
+ pointToAttr: (point, i) => {
28
+ if ("alt" in point) point.meta.ele = point.alt; // "alt" property is generated inside "leaflet"
29
+ return this._data[i].z * opts.altitudeFactor;
30
+ },
28
31
  stats: { max: _.iMax, min: _.iMin, avg: _.iAvg },
29
32
  grid: {
30
33
  axis : "y",
@@ -13,8 +13,8 @@ export function Heart() {
13
13
  axis : "y",
14
14
  position : "left",
15
15
  scale : { min: -1, max: +1 },
16
- tickPadding: 16,
17
- labelX : -18,
16
+ tickPadding: 25,
17
+ labelX : -30,
18
18
  labelY : -8,
19
19
  },
20
20
  path: {