@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.
@@ -135,11 +135,11 @@
135
135
  * Loop and extract GPX Extensions handled by "@tmcw/toGeoJSON" (eg. "coordinateProperties" > "times")
136
136
  */
137
137
  function coordPropsToMeta(coordProps, name, parser) {
138
- return coordProps && (({props, point, id}) => {
138
+ return coordProps && (({props, point, id, isMulti }) => {
139
139
  if (props) {
140
140
  for (const key of coordProps) {
141
141
  if (key in props) {
142
- point.meta[name] = (parser || parseInt).call(this, props[key], id);
142
+ point.meta[name] = (parser || parseInt).call(this, (isMulti ? props[key][isMulti] : props[key]), id);
143
143
  break;
144
144
  }
145
145
  }
@@ -186,9 +186,9 @@
186
186
  /**
187
187
  * Alias for some leaflet core functions
188
188
  */
189
- const { on, off } = L.DomEvent;
190
- const { throttle } = L.Util;
191
- const { hasClass } = L.DomUtil;
189
+ const { on, off } = L.DomEvent;
190
+ const { throttle, wrapNum } = L.Util;
191
+ const { hasClass } = L.DomUtil;
192
192
 
193
193
  /**
194
194
  * Limit floating point precision
@@ -236,6 +236,7 @@
236
236
  on: on,
237
237
  off: off,
238
238
  throttle: throttle,
239
+ wrapNum: wrapNum,
239
240
  hasClass: hasClass,
240
241
  round: round,
241
242
  clamp: clamp,
@@ -244,10 +245,11 @@
244
245
 
245
246
  var Options = {
246
247
  autofitBounds: true,
247
- autohide: !L.Browser.mobile,
248
+ autohide: false,
248
249
  autohideMarker: true,
249
250
  almostover: true,
250
251
  altitude: true,
252
+ closeBtn: true,
251
253
  collapsed: false,
252
254
  detached: true,
253
255
  distance: true,
@@ -308,7 +310,13 @@
308
310
  zFollow: false,
309
311
  zooming: !L.Browser.Mobile,
310
312
 
311
- // Quite uncommon and undocumented options (quite useless)
313
+ // Quite uncommon and undocumented options
314
+ margins: { top: 30, right: 30, bottom: 30, left: 40 },
315
+ height: (screen.height * 0.3) || 200,
316
+ width: (screen.width * 0.6) || 600,
317
+ xTicks: undefined,
318
+ yTicks: undefined,
319
+
312
320
  decimalsX: 2,
313
321
  decimalsY: 0,
314
322
  forceAxisBounds: false,
@@ -316,13 +324,6 @@
316
324
  skipNullZCoords: false,
317
325
  yAxisMax: undefined,
318
326
  yAxisMin: undefined,
319
-
320
- // Probably no longer functional as expected (internally overwritten)
321
- margins: { top: 30, right: 30, bottom: 30, left: 40 },
322
- height: 200,
323
- width: 600,
324
- xTicks: undefined,
325
- yTicks: undefined,
326
327
  };
327
328
 
328
329
  const Elevation = L.Control.Elevation = L.Control.extend({
@@ -330,8 +331,8 @@
330
331
  includes: L.Evented ? L.Evented.prototype : L.Mixin.Events,
331
332
 
332
333
  options: Options,
333
- __mileFactor: 0.621371, // 1 km = (0.621371 mi)
334
- __footFactor: 3.28084, // 1 m = (3.28084 ft)
334
+ __mileFactor: 0.621371, // 1 km = (0.621371 mi)
335
+ __footFactor: 3.28084, // 1 m = (3.28084 ft)
335
336
  __D3: 'https://unpkg.com/d3@6.5.0/dist/d3.min.js',
336
337
  __TOGEOJSON: 'https://unpkg.com/@tmcw/togeojson@4.6.0/dist/togeojson.umd.js',
337
338
  __LGEOMUTIL: 'https://unpkg.com/leaflet-geometryutil@0.9.3/src/leaflet.geometryutil.js',
@@ -348,9 +349,7 @@
348
349
  addData: function(d, layer) {
349
350
  this.import(this.__D3)
350
351
  .then(() => {
351
- if (typeof layer === "undefined" && d.on) {
352
- layer = d;
353
- }
352
+ layer = layer ?? (d.on && d);
354
353
  this._addData(d);
355
354
  this._addLayer(layer);
356
355
  this._fireEvt("eledata_added", { data: d, layer: layer, track_info: this.track_info });
@@ -362,9 +361,9 @@
362
361
  */
363
362
  addTo: function(map) {
364
363
  if (this.options.detached) {
365
- let eleDiv = this._initElevationDiv();
366
- if (!eleDiv.isConnected) insert(map.getContainer(), eleDiv, 'afterend');
367
- append(eleDiv, this.onAdd(map));
364
+ let parent = select(this.options.elevationDiv);
365
+ let eleDiv = this.onAdd(map);
366
+ parent ? append(parent, eleDiv) : insert(map.getContainer(), eleDiv, 'afterend');
368
367
  } else {
369
368
  L.Control.prototype.addTo.call(this, map);
370
369
  }
@@ -546,7 +545,9 @@
546
545
  onAdd: function(map) {
547
546
  this._map = map;
548
547
 
549
- let container = this._container = create("div", "elevation-control elevation " + this.options.theme + " " + (this.options.detached ? '' : 'leaflet-control'));
548
+ let container = this._container = create("div", "elevation-control " + this.options.theme + " " + (this.options.detached ? 'elevation-detached' : 'leaflet-control'), this.options.detached ? { id: 'elevation-' + randomId() } : {});
549
+
550
+ if (!this.eleDiv) this.eleDiv = container;
550
551
 
551
552
  let modules = [
552
553
  "Distance",
@@ -619,51 +620,44 @@
619
620
  return;
620
621
  }
621
622
 
622
- /**
623
- * Standard GeoJSON --> doesn't handle "time", "heart", …
624
- */
625
- let geom = d.geometry;
626
- if (geom) {
627
- switch (geom.type) {
628
- case 'LineString':
629
- this._addGeoJSONData(geom.coordinates);
630
- break;
631
-
632
- case 'MultiLineString':
633
- each(geom.coordinates, coords => this._addGeoJSONData(coords));
634
- break;
635
-
636
- default:
637
- return console.warn('Unsopperted GeoJSON feature geometry type:' + geom.type);
623
+ // Standard GeoJSON
624
+ if (d.type === "FeatureCollection" ) {
625
+ return each(d.features, feature => this._addData(feature));
626
+ } else if (d.type === "Feature") {
627
+ let geom = d.geometry;
628
+ if (geom) {
629
+ switch (geom.type) {
630
+ case 'LineString': return this._addGeoJSONData(geom.coordinates, d.properties);
631
+ case 'MultiLineString': return each(geom.coordinates, (coords, i) => this._addGeoJSONData(coords, d.properties, i));
632
+ case 'Point':
633
+ default: return console.warn('Unsopperted GeoJSON feature geometry type:' + geom.type);
634
+ }
638
635
  }
639
636
  }
640
- if (d.type === "FeatureCollection") {
641
- each(d.features, feature => this._addData(feature));
642
- }
643
637
 
644
- /**
645
- * Extended GeoJSON --> rely on leaflet implementation
646
- */
638
+ // Fallback for leaflet layers (eg. L.Gpx)
647
639
  if (d._latlngs) {
648
- this._addGeoJSONData(d._latlngs, d.feature && d.feature.properties);
640
+ return this._addGeoJSONData(d._latlngs, d.feature && d.feature.properties);
649
641
  }
642
+
650
643
  },
651
644
 
652
645
  /*
653
646
  * Parsing of GeoJSON data lines and their elevation in z-coordinate
654
647
  */
655
- _addGeoJSONData: function(coords, properties) {
648
+ _addGeoJSONData: function(coords, properties, nestingLevel) {
649
+
650
+ // "coordinateProperties" property is generated inside "@tmcw/toGeoJSON"
651
+ let props = (properties && properties.coordinateProperties) || properties;
652
+
656
653
  coords.forEach((point, i) => {
657
654
 
658
655
  // GARMIN_EXTENSIONS = ["hr", "cad", "atemp", "wtemp", "depth", "course", "bearing"];
659
656
  point.meta = point.meta ?? { time: null, ele: null };
660
657
 
661
- // "coordinateProperties" property is generated inside "@tmcw/toGeoJSON"
662
- let props = (properties && properties.coordinateProperties) || properties;
663
-
664
658
  point.prev = (attr) => (attr ? this._data[i > 0 ? i - 1 : 0][attr] : this._data[i > 0 ? i - 1 : 0]);
665
659
 
666
- this.fire("elepoint_init", { point: point, props: props, id: i });
660
+ this.fire("elepoint_init", { point: point, props: props, id: i, isMulti: nestingLevel });
667
661
 
668
662
  this._addPoint(
669
663
  point.lat ?? point[1],
@@ -703,10 +697,12 @@
703
697
  if (layer && this.options.distanceMarkers && this.options.distanceMarkers.lazy) {
704
698
  layer.on('add remove', ({target, type}) => L.DistanceMarkers && target instanceof L.Polyline && target[type + 'DistanceMarkers']());
705
699
  }
700
+ return layer;
706
701
  },
707
702
 
708
703
  _addMarker: function(marker) {
709
704
  if (marker) this._markers.addLayer(marker);
705
+ return marker;
710
706
  },
711
707
 
712
708
  /**
@@ -743,21 +739,6 @@
743
739
  }
744
740
  },
745
741
 
746
- /**
747
- * Adds the control to the given "detached" div.
748
- */
749
- _initElevationDiv: function() {
750
- let eleDiv = select(this.options.elevationDiv);
751
- if (!eleDiv) {
752
- this.options.elevationDiv = '#elevation-div_' + randomId();
753
- eleDiv = create('div', 'leaflet-control elevation elevation-div', { id: this.options.elevationDiv.substr(1) });
754
- }
755
- if (this.options.detached) {
756
- replaceClass(eleDiv, 'leaflet-control', 'elevation-detached');
757
- }
758
- return this.eleDiv = eleDiv;
759
- },
760
-
761
742
  /**
762
743
  * Initialize "L.AlmostOver" and "L.DistanceMarkers"
763
744
  */
@@ -776,6 +757,7 @@
776
757
  } else if (control.options.polyline) {
777
758
  layer.addTo(map);
778
759
  }
760
+ map.invalidateSize();
779
761
  } else {
780
762
  console.warn("Undefined elevation map object"); }
781
763
  },
@@ -801,7 +783,7 @@
801
783
  let oldProto = L.Canvas.prototype._fillStroke;
802
784
  let control = this;
803
785
 
804
- let theme = this.options.theme.replace('-theme', '');
786
+ let theme = this.options.theme.split(' ')[0].replace('-theme', '');
805
787
  let color = Colors[theme] || {};
806
788
 
807
789
  L.Canvas.include({
@@ -922,10 +904,6 @@
922
904
  .on('margins_updated', this._resizeChart, this);
923
905
 
924
906
 
925
- this.fire("elechart_axis");
926
-
927
- if (this.options.legend) this.fire("elechart_legend");
928
-
929
907
  this.fire("elechart_init");
930
908
 
931
909
  map
@@ -990,23 +968,19 @@
990
968
  .disableScrollPropagation(container);
991
969
  }
992
970
 
993
- if (!this.options.detached) {
994
- let link = this._button = create('a', "elevation-toggle elevation-toggle-icon" + (this.options.autohide ? "" : " close-button"), { href: '#', title: L._('Elevation') }, container);
971
+ this.options.collapsed ? this._collapse() : this._expand();
995
972
 
996
- if (this.options.collapsed) {
997
- this._collapse();
998
- if (this.options.autohide) {
999
- on(container, 'mouseover', this._expand, this);
1000
- on(container, 'mouseout', this._collapse, this);
1001
- } else {
1002
- on(link, 'click', L.DomEvent.stop);
1003
- on(link, 'click', this._toggle, this);
1004
- }
1005
-
1006
- on(link, 'focus', this._toggle, this);
973
+ if (this.options.autohide) {
974
+ on(container, 'mouseover', this._expand, this);
975
+ on(container, 'mouseout', this._collapse, this);
976
+ this._map.on('click', this._collapse, this);
977
+ }
1007
978
 
1008
- this._map.on('click', this._collapse, this);
1009
- }
979
+ if (this.options.closeBtn) {
980
+ let link = this._button = create('a', "elevation-toggle-icon", { href: '#', title: L._('Elevation'), }, container);
981
+ on(link, 'click', L.DomEvent.stop);
982
+ on(link, 'click', this._toggle, this);
983
+ on(link, 'focus', this._toggle, this);
1010
984
  }
1011
985
  },
1012
986
 
@@ -1038,7 +1012,7 @@
1038
1012
  */
1039
1013
  _loadModules: function(handlers) {
1040
1014
  // First map known classnames (eg. "Altitude" --> L.Control.Elevation.Altitude)
1041
- handlers = handlers.map((h) => typeof h === 'string' && typeof L.Control.Elevation[h] !== "undefined" ? L.Control.Elevation[h] : h);
1015
+ handlers = handlers.map((h) => typeof h === 'string' && typeof Elevation[h] !== "undefined" ? Elevation[h] : h);
1042
1016
  // Then load optional classes and custom imports (eg. "Cadence" --> import('../src/handlers/cadence.js'))
1043
1017
  Promise.
1044
1018
  all(
@@ -1049,8 +1023,8 @@
1049
1023
  .then((m) => {
1050
1024
  each(m, (exported) => {
1051
1025
  let fn = Object.keys(exported)[0];
1052
- if (fn && typeof L.Control.Elevation[fn] === "undefined" ) {
1053
- handlers[fn] = L.Control.Elevation[fn] = exported[fn];
1026
+ if (fn && typeof Elevation[fn] === "undefined" ) {
1027
+ handlers[fn] = Elevation[fn] = exported[fn];
1054
1028
 
1055
1029
  }
1056
1030
  });
@@ -1062,65 +1036,48 @@
1062
1036
  * Simple GeoJSON data loader (L.GeoJSON).
1063
1037
  */
1064
1038
  _loadLayer: function(geojson) {
1065
- let control = this;
1039
+ let { polyline, theme, waypoints, wptIcons, wptLabels, distanceMarkers } = this.options;
1040
+ let style = L.extend({}, polyline);
1066
1041
 
1067
- let { wptIcons, wptLabels } = control.options;
1042
+ if (theme) {
1043
+ style.className += ' ' + theme;
1044
+ }
1045
+
1046
+ if (geojson.name) {
1047
+ this.track_info.name = geojson.name;
1048
+ }
1068
1049
 
1069
1050
  let layer = L.geoJson(geojson, {
1070
- distanceMarkers: control.options.distanceMarkers,
1071
- style: (feature) => {
1072
- let style = L.extend({}, control.options.polyline);
1073
- if (control.options.theme) {
1074
- style.className += ' ' + control.options.theme;
1075
- }
1076
- return style;
1077
- },
1051
+ distanceMarkers: distanceMarkers,
1052
+ style: style,
1078
1053
  pointToLayer: (feature, latlng) => {
1079
- if (!control.options.waypoints) return;
1080
-
1081
- let prop = feature.properties;
1082
- let desc = prop.desc ?? '';
1083
- let name = prop.name ?? '';
1084
- let sym = (prop.sym ?? name).replace(' ', '-').replace('"', '').replace("'", '').toLowerCase();
1085
-
1086
- // Handle chart waypoints (dots)
1087
- if ([true, 'dots'].includes(control.options.waypoints)) {
1088
- control._registerCheckPoint({
1089
- latlng: latlng,
1090
- label: ([true, 'dots'].includes(wptLabels) ? name : '')
1091
- });
1092
- }
1093
-
1094
- // Handle map waypoints (markers)
1095
- if ([true, 'markers'].includes(control.options.waypoints) && wptIcons != false) {
1096
- // generate and cache appropriate icon symbol
1097
- if (!wptIcons.hasOwnProperty(sym)) {
1098
- wptIcons[sym] = L.divIcon(
1099
- L.extend({}, wptIcons[""].options, { html: '<i class="elevation-waypoint-icon ' + sym + '"></i>' } )
1100
- );
1054
+ if (waypoints) {
1055
+ let { desc, name, sym } = feature.properties;
1056
+ desc = desc || '';
1057
+ name = name || '';
1058
+ // Handle chart waypoints (dots)
1059
+ if ([true, 'dots'].includes(waypoints)) {
1060
+ this._registerCheckPoint({
1061
+ latlng: latlng,
1062
+ label : ([true, 'dots'].includes(wptLabels) ? name : '')
1063
+ });
1101
1064
  }
1102
- let marker = L.marker(latlng, { icon: wptIcons[sym] });
1103
- if ([true, 'markers'].includes(wptLabels) && (name || desc)) {
1104
- let content = decodeURI("<b>" + name + "</b>" + (desc.length > 0 ? '<br>' + desc : ''));
1105
- marker.bindPopup(content, { className: 'elevation-popup', keepInView: true }).openPopup();
1106
- marker.bindTooltip(content, { className: 'elevation-tooltip', direction: 'auto', sticky: true, opacity: 1 }).openTooltip();
1065
+ // Handle map waypoints (markers)
1066
+ if ([true, 'markers'].includes(waypoints) && wptIcons != false) {
1067
+ return this._registerMarker({
1068
+ latlng : latlng,
1069
+ sym : (sym ?? name).replace(' ', '-').replace('"', '').replace("'", '').toLowerCase(),
1070
+ content: [true, 'markers'].includes(wptLabels) && (name || desc) && decodeURI("<b>" + name + "</b>" + (desc.length > 0 ? '<br>' + desc : ''))
1071
+ });
1107
1072
  }
1108
- control._addMarker(marker);
1109
- control.fire('waypoint_added', { point: marker, element: latlng, properties: prop });
1110
- return marker;
1111
1073
  }
1112
1074
  },
1113
- onEachFeature: (feature, layer) => {
1114
- if (feature.geometry && feature.geometry.type != 'Point') {
1115
- control.addData(layer);
1116
- control.track_info = L.extend({}, control.track_info, { name: geojson.name });
1117
- }
1118
- },
1075
+ onEachFeature: (feature, layer) => feature.geometry && feature.geometry.type != 'Point' && this.addData(feature, layer),
1119
1076
  });
1120
1077
 
1121
- control.import(control.__D3).then(() => {
1122
- control._initMapIntegrations(control, layer);
1123
- control._fireEvt("eledata_loaded", { data: geojson, layer: layer, name: control.track_info.name, track_info: control.track_info });
1078
+ this.import(this.__D3).then(() => {
1079
+ this._initMapIntegrations(this, layer);
1080
+ this._fireEvt("eledata_loaded", { data: geojson, layer: layer, name: this.track_info.name, track_info: this.track_info });
1124
1081
  });
1125
1082
 
1126
1083
  return layer;
@@ -1250,8 +1207,7 @@
1250
1207
  geojson = this._parseFromGeoJSONString(data.toString());
1251
1208
  }
1252
1209
  if (geojson) {
1253
- geojson = this._prepareMultiLineStrings(geojson);
1254
- geojson = this._prepareAdditionalProperties(geojson);
1210
+ geojson.name = geojson.name || (this._downloadURL || '').split('/').pop().split('#')[0].split('?')[0];
1255
1211
  }
1256
1212
  resolve(geojson);
1257
1213
  })
@@ -1279,37 +1235,6 @@
1279
1235
  return geojson;
1280
1236
  },
1281
1237
 
1282
- /**
1283
- * Extend GeoJSON properties (name, time, ...)
1284
- */
1285
- _prepareAdditionalProperties: function(geojson) {
1286
- if (!geojson.name && this._downloadURL) {
1287
- geojson.name = this._downloadURL.split('/').pop().split('#')[0].split('?')[0];
1288
- }
1289
- return geojson;
1290
- },
1291
-
1292
- /**
1293
- * Just a temporary fix for MultiLineString data (trk > trkseg + trkseg),
1294
- * just split them into seperate LineStrings (trk > trkseg, trk > trkseg)
1295
- *
1296
- * @link https://github.com/Raruto/leaflet-elevation/issues/56
1297
- */
1298
- _prepareMultiLineStrings: function(geojson) {
1299
- geojson.features.forEach(feauture => {
1300
- if (feauture.geometry.type == "MultiLineString") {
1301
- feauture.geometry.coordinates.forEach(coords => {
1302
- geojson.features.push({
1303
- geometry: { type: 'LineString', coordinates: coords },
1304
- properties: feauture.properties,
1305
- type: 'Feature'
1306
- });
1307
- });
1308
- }
1309
- });
1310
- return geojson.features.filter(feauture => feauture.geometry.type != "MultiLineString");
1311
- },
1312
-
1313
1238
  /**
1314
1239
  * Add chart profile to diagram
1315
1240
  */
@@ -1427,60 +1352,79 @@
1427
1352
  return this._registerHandler(props.call(this));
1428
1353
  }
1429
1354
 
1355
+ let {
1356
+ name,
1357
+ attr,
1358
+ required,
1359
+ skipNull,
1360
+ deltaMax,
1361
+ clampRange,
1362
+ decimals,
1363
+ meta,
1364
+ unit,
1365
+ coordinateProperties,
1366
+ coordPropsToMeta: coordPropsToMeta$1,
1367
+ pointToAttr,
1368
+ onPointAdded,
1369
+ stats,
1370
+ statsName,
1371
+ grid,
1372
+ scale,
1373
+ path,
1374
+ tooltip,
1375
+ summary
1376
+ } = props;
1377
+
1430
1378
  // eg. "altitude" == true
1431
- if (this.options[props.name] || props.required) {
1379
+ if (this.options[name] || required) {
1432
1380
 
1433
1381
  this._registerDataAttribute({
1434
- name: props.name,
1435
- attr: props.attr,
1436
- skipNull: props.skipNull,
1437
- deltaMax: props.deltaMax,
1438
- clampRange: props.clampRange,
1439
- decimals: props.decimals,
1440
- coordPropsToMeta: coordPropsToMeta(props.coordinateProperties, props.meta || props.name, props.coordPropsToMeta),
1441
- pointToAttr: props.pointToAttr,
1442
- onPointAdded: props.onPointAdded,
1443
- stats: props.stats,
1444
- statsName: props.statsName,
1382
+ name,
1383
+ attr,
1384
+ skipNull,
1385
+ deltaMax,
1386
+ clampRange,
1387
+ decimals,
1388
+ coordPropsToMeta: coordPropsToMeta(coordinateProperties, meta || name, coordPropsToMeta$1),
1389
+ pointToAttr,
1390
+ onPointAdded,
1391
+ stats,
1392
+ statsName,
1445
1393
  });
1446
1394
 
1447
- if (props.grid) {
1448
- props.grid.name = props.grid.name || props.name;
1449
- this._registerAxisGrid(props.grid);
1395
+ if (grid) {
1396
+ this._registerAxisGrid(L.extend({ name }, grid));
1450
1397
  }
1451
1398
 
1452
- if (this.options[props.name] !== "summary") {
1453
- if (props.scale) {
1454
- props.scale.name = props.scale.name || props.name;
1455
- props.scale.label = props.scale.label || props.unit;
1456
- this._registerAxisScale(props.scale);
1457
- }
1458
- if (props.path) {
1459
- props.path.name = props.path.name || props.name;
1460
- this._registerAreaPath(props.path);
1461
- }
1399
+ if (this.options[name] !== "summary") {
1400
+ if (scale) this._registerAxisScale(L.extend({ name, label: unit }, scale));
1401
+ if (path) this._registerAreaPath(L.extend({ name }, path));
1462
1402
  }
1463
1403
 
1464
- if (props.tooltips) {
1465
- each(props.tooltips, t => {
1466
- if (t) {
1467
- t.name = t.name || props.name;
1468
- this._registerTooltip(t);
1469
- }
1470
- });
1471
- } else if (props.tooltip) {
1472
- props.tooltip.name = props.tooltip.name || props.name;
1473
- this._registerTooltip(props.tooltip);
1404
+ if (tooltip || props.tooltips) {
1405
+ each([tooltip, ...(props.tooltips || [])], t => t && this._registerTooltip(L.extend({ name }, t)));
1474
1406
  }
1475
1407
 
1476
- if (props.summary) {
1477
- for (const key in props.summary) {
1478
- props.summary[key].unit = props.summary[key].unit || props.unit;
1479
- }
1480
- this._registerSummary(props.summary);
1408
+ if (summary) {
1409
+ each(summary, (s, k) => summary[k] = L.extend({ unit }, s));
1410
+ this._registerSummary(summary);
1481
1411
  }
1482
1412
  }
1483
1413
  },
1414
+
1415
+ _registerMarker({latlng, sym, content}) {
1416
+ let { wptIcons } = this.options;
1417
+ // generate and cache appropriate icon symbol
1418
+ if (!wptIcons.hasOwnProperty(sym)) {
1419
+ wptIcons[sym] = L.divIcon(L.extend({}, wptIcons[""].options, { html: '<i class="elevation-waypoint-icon ' + sym + '"></i>' } ));
1420
+ }
1421
+ let marker = L.marker(latlng, { icon: wptIcons[sym] });
1422
+ if (content) {
1423
+ marker.bindPopup(content, { className: 'elevation-popup', keepInView: true }).openPopup();
1424
+ marker.bindTooltip(content, { className: 'elevation-tooltip', direction: 'auto', sticky: true, opacity: 1 }).openTooltip();
1425
+ }
1426
+ return this._addMarker(marker)
1427
+ },
1484
1428
 
1485
1429
  /**
1486
1430
  * Add chart or marker tooltip info
@@ -1563,7 +1507,6 @@
1563
1507
  _updateChart: function() {
1564
1508
  if (this._chart && this._container) {
1565
1509
  this.fire("elechart_axis");
1566
- this.fire("elechart_area");
1567
1510
 
1568
1511
  this._chart.update({ data: this._data, options: this.options });
1569
1512
 
@@ -1611,27 +1554,27 @@
1611
1554
  * Update chart summary.
1612
1555
  */
1613
1556
  _updateSummary: function() {
1614
- if (!this._summary) return;
1615
-
1616
- this._summary.reset();
1617
-
1618
- if (this.options.summary) {
1619
- this.fire("elechart_summary");
1620
- this._summary.update();
1557
+ if (this._summary) {
1558
+ this._summary.reset();
1559
+ if (this.options.summary) {
1560
+ this.fire("elechart_summary");
1561
+ this._summary.update();
1562
+ }
1563
+ if (this.options.downloadLink && this._downloadURL) { // TODO: generate dynamically file content instead of using static file urls.
1564
+ this._summary._container.innerHTML += '<span class="download"><a href="#">' + L._('Download') + '</a></span>';
1565
+ select('.download a', this._summary._container).onclick = ({preventDefault}) => {
1566
+ preventDefault();
1567
+ let event = { downloadLink: this.options.downloadLink, confirm: saveFile.bind(this, this._downloadURL) };
1568
+ if (this.options.downloadLink == 'modal' && typeof CustomEvent === "function") {
1569
+ document.dispatchEvent(new CustomEvent("eletrack_download", { detail: event }));
1570
+ } else if (this.options.downloadLink == 'link' || this.options.downloadLink === true) {
1571
+ event.confirm();
1572
+ }
1573
+ this.fire('eletrack_download', event);
1574
+ };
1575
+ }
1621
1576
  }
1622
- if (this.options.downloadLink && this._downloadURL) { // TODO: generate dynamically file content instead of using static file urls.
1623
- this._summary._container.innerHTML += '<span class="download"><a href="#">' + L._('Download') + '</a></span>';
1624
- select('.download a', this._summary._container).onclick = ({preventDefault}) => {
1625
- preventDefault();
1626
- let event = { downloadLink: this.options.downloadLink, confirm: saveFile.bind(this, this._downloadURL) };
1627
- if (this.options.downloadLink == 'modal' && typeof CustomEvent === "function") {
1628
- document.dispatchEvent(new CustomEvent("eletrack_download", { detail: event }));
1629
- } else if (this.options.downloadLink == 'link' || this.options.downloadLink === true) {
1630
- event.confirm();
1631
- }
1632
- this.fire('eletrack_download', event);
1633
- };
1634
- } },
1577
+ },
1635
1578
 
1636
1579
 
1637
1580
  /**