@raruto/leaflet-elevation 2.0.1 → 2.0.2
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 +2 -1
- package/dist/leaflet-elevation.js +121 -158
- 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/libs/leaflet-distance-marker.js +97 -92
- package/libs/leaflet-distance-marker.min.js +1 -1
- package/package.json +1 -1
- package/src/control.js +119 -156
- package/src/handlers/altitude.js +4 -1
- package/src/utils.js +2 -2
|
@@ -143,102 +143,107 @@ L.DistanceMarkers = L.LayerGroup.extend({
|
|
|
143
143
|
// Get line coords as an array
|
|
144
144
|
let coords = typeof line.getLatLngs == 'function' ? line.getLatLngs() : line;
|
|
145
145
|
|
|
146
|
-
//
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
146
|
+
// Handle "MultiLineString" features
|
|
147
|
+
coords = L.LineUtil.isFlat(coords) ? [coords] : coords;
|
|
148
|
+
|
|
149
|
+
coords.forEach(latlngs => {
|
|
150
|
+
// Get accumulated line lengths as well as overall length
|
|
151
|
+
let accumulated = L.GeometryUtil.accumulatedLengths(latlngs);
|
|
152
|
+
let length = accumulated.length > 0 ? accumulated[accumulated.length - 1] : 0;
|
|
153
|
+
|
|
154
|
+
// count = Number of distance markers to be added
|
|
155
|
+
// j = Position in accumulated line length array
|
|
156
|
+
for (let i = 1, count = Math.floor(length / options.offset), j = 0; i <= count; ++i) {
|
|
157
|
+
|
|
158
|
+
let distance = options.offset * i;
|
|
159
|
+
|
|
160
|
+
// Find the first accumulated distance that is greater than the distance of this marker
|
|
161
|
+
while (j < accumulated.length - 1 && accumulated[j] < distance) ++j;
|
|
162
|
+
|
|
163
|
+
// Grab two nearest points either side marker position
|
|
164
|
+
let p1 = latlngs[j - 1];
|
|
165
|
+
let p2 = latlngs[j];
|
|
166
|
+
let m_line = L.polyline([p1, p2]);
|
|
167
|
+
|
|
168
|
+
// and create a simple line to interpolate on
|
|
169
|
+
let ratio = (distance - accumulated[j - 1]) / (accumulated[j] - accumulated[j - 1]);
|
|
170
|
+
let position = L.GeometryUtil.interpolateOnLine(map, m_line, ratio);
|
|
171
|
+
let delta = map.project(p2).subtract(map.project(p1));
|
|
172
|
+
let angle = Math.atan2(delta.y, delta.x);
|
|
173
|
+
|
|
174
|
+
// Generate distance marker label
|
|
175
|
+
let text = options.textFunction.call(this, distance, i, options.offset);
|
|
176
|
+
|
|
177
|
+
// Grouping layer of visible layers at zoom level (arrow + distance)
|
|
178
|
+
let zoom = this._minimumZoomLevelForItem(i, showAll);
|
|
179
|
+
let markers = this._zoomLayers[zoom] = this._zoomLayers[zoom] || L.layerGroup()
|
|
180
|
+
|
|
181
|
+
// create arrow markers
|
|
182
|
+
if (options.direction && ((options.distance && i % 2 == 1) || !options.distance)) {
|
|
183
|
+
if (preferCanvas) {
|
|
184
|
+
markers.addLayer(
|
|
185
|
+
new L.DistanceMarker(p1, {
|
|
186
|
+
radius: 0,
|
|
187
|
+
icon: {
|
|
188
|
+
url: options.arrowUrl, //image link
|
|
189
|
+
size: options.arrowSize, //image size ( default [40, 40] )
|
|
190
|
+
rotate: 0, //image base rotate ( default 0 )
|
|
191
|
+
offset: { x: 0, y: 0 }, //image offset ( default { x: 0, y: 0 } )
|
|
192
|
+
},
|
|
193
|
+
rotation: angle,
|
|
194
|
+
interactive: false,
|
|
195
|
+
// label: '⮞', //'➜',
|
|
196
|
+
// font: 'normal 20pt "Helvetica Neue", Arial, Helvetica, sans-serif',
|
|
197
|
+
// fillStyle: 'white',//'#3366CC',
|
|
198
|
+
// strokeStyle: 'black',
|
|
199
|
+
})
|
|
200
|
+
);
|
|
201
|
+
} else {
|
|
202
|
+
markers.addLayer(
|
|
203
|
+
L.marker(position.latLng, {
|
|
204
|
+
icon: L.icon({
|
|
205
|
+
iconUrl: options.arrowUrl,
|
|
206
|
+
iconSize: options.arrowSize,
|
|
207
|
+
}),
|
|
208
|
+
// NB the following option is added by "leaflet-rotate"
|
|
209
|
+
rotation: angle * L.DomUtil.RAD_TO_DEG,
|
|
210
|
+
interactive: false,
|
|
211
|
+
})
|
|
212
|
+
);
|
|
213
|
+
}
|
|
209
214
|
}
|
|
210
|
-
}
|
|
211
215
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
216
|
+
// create distance markers
|
|
217
|
+
if (options.distance && i % 2 == 0) {
|
|
218
|
+
if (preferCanvas) {
|
|
219
|
+
markers.addLayer(
|
|
220
|
+
new L.DistanceMarker(position.latLng, {
|
|
221
|
+
label: text, // TODO: handle text rotation (leaflet-rotate)
|
|
222
|
+
radius: 7,
|
|
223
|
+
fillColor: '#fff',
|
|
224
|
+
fillOpacity: 1,
|
|
225
|
+
fillStyle: 'black',
|
|
226
|
+
color: '#777',
|
|
227
|
+
weight: 1,
|
|
228
|
+
interactive: false,
|
|
229
|
+
})
|
|
230
|
+
);
|
|
231
|
+
} else {
|
|
232
|
+
markers.addLayer(
|
|
233
|
+
L.marker(position.latLng, {
|
|
234
|
+
title: text,
|
|
235
|
+
icon: L.divIcon({
|
|
236
|
+
className: options.cssClass,
|
|
237
|
+
html: text,
|
|
238
|
+
iconSize: options.iconSize
|
|
239
|
+
}),
|
|
240
|
+
interactive: false,
|
|
241
|
+
})
|
|
242
|
+
);
|
|
243
|
+
}
|
|
239
244
|
}
|
|
240
245
|
}
|
|
241
|
-
}
|
|
246
|
+
});
|
|
242
247
|
|
|
243
248
|
const updateMarkerVisibility = () => {
|
|
244
249
|
let oldZoom = this._lastZoomLevel || 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
L.DistanceMarker=L.CircleMarker.extend({_updatePath:function(){let ctx=this._renderer._ctx,p=this._point;if(this.options.rotation=this.options.rotation||0,this.options.radius&&this._renderer._updateCircle&&this._renderer._updateCircle(this),this.options.icon&&this.options.icon.url)if(this.options.icon.element){const icon=this.options.icon;let cx=p.x+icon.offset.x,cy=p.y+icon.offset.y;ctx.save(),icon.rotate&&(ctx.translate(p.x,p.y),ctx.rotate(icon.rotate),cx=0,cy=0),ctx.drawImage(icon.element,cx-icon.size[0]/2,cy-icon.size[1]/2,icon.size[0],icon.size[1]),ctx.restore()}else{const icon=document.createElement("img");this.options.icon=L.extend({rotate:0,size:[40,40],offset:{x:0,y:0}},this.options.icon),this.options.icon.rotate+=this.options.rotation,this.options.icon.element=icon,icon.src=this.options.icon.url,icon.onload=()=>this.redraw(),icon.onerror=()=>this.options.icon=null}if(this.options.label){let cx=p.x,cy=p.y;ctx.save(),ctx.font=this.options.font||'normal 7pt "Helvetica Neue", Arial, Helvetica, sans-serif',ctx.textAlign="center",ctx.textBaseline="middle",ctx.fillStyle=this.options.fillStyle||"black",this.options.rotation&&(ctx.translate(p.x,p.y),ctx.rotate(this.options.rotation),cx=0,cy=0),this._map.getZoom()>17&&(ctx.fillStyle=this.options.strokeStyle||"black"),ctx.fillText(this.options.label,cx,cy),this.options.strokeStyle&&this._map.getZoom()<=17&&(ctx.strokeStyle=this.options.strokeStyle,ctx.strokeText(this.options.label,cx,cy)),ctx.restore()}}}),L.DistanceMarkers=L.LayerGroup.extend({options:{cssClass:"dist-marker",iconSize:[12,12],arrowSize:[10,10],arrowUrl:"data:image/svg+xml,%3Csvg transform='rotate(90)' xmlns='http://www.w3.org/2000/svg' width='560px' height='560px' viewBox='0 0 560 560'%3E%3Cpath stroke-width='35' fill='%23000' stroke='%23FFF' d='M280,40L522,525L280,420L38,525z'/%3E%3C/svg%3E",offset:1e3,showAll:12,textFunction:(distance,i,offset)=>i,distance:!0,direction:!0},initialize:function(line,map,options){this._layers={},this._zoomLayers={},options=L.setOptions(this,options);let preferCanvas=map.options.preferCanvas,showAll=Math.min(map.getMaxZoom(),options.showAll);preferCanvas||map.options.rotate||console.warn('Missing dependency: "leaflet-rotate"');let coords="function"==typeof line.getLatLngs?line.getLatLngs():line,accumulated=L.GeometryUtil.accumulatedLengths(
|
|
1
|
+
L.DistanceMarker=L.CircleMarker.extend({_updatePath:function(){let ctx=this._renderer._ctx,p=this._point;if(this.options.rotation=this.options.rotation||0,this.options.radius&&this._renderer._updateCircle&&this._renderer._updateCircle(this),this.options.icon&&this.options.icon.url)if(this.options.icon.element){const icon=this.options.icon;let cx=p.x+icon.offset.x,cy=p.y+icon.offset.y;ctx.save(),icon.rotate&&(ctx.translate(p.x,p.y),ctx.rotate(icon.rotate),cx=0,cy=0),ctx.drawImage(icon.element,cx-icon.size[0]/2,cy-icon.size[1]/2,icon.size[0],icon.size[1]),ctx.restore()}else{const icon=document.createElement("img");this.options.icon=L.extend({rotate:0,size:[40,40],offset:{x:0,y:0}},this.options.icon),this.options.icon.rotate+=this.options.rotation,this.options.icon.element=icon,icon.src=this.options.icon.url,icon.onload=()=>this.redraw(),icon.onerror=()=>this.options.icon=null}if(this.options.label){let cx=p.x,cy=p.y;ctx.save(),ctx.font=this.options.font||'normal 7pt "Helvetica Neue", Arial, Helvetica, sans-serif',ctx.textAlign="center",ctx.textBaseline="middle",ctx.fillStyle=this.options.fillStyle||"black",this.options.rotation&&(ctx.translate(p.x,p.y),ctx.rotate(this.options.rotation),cx=0,cy=0),this._map.getZoom()>17&&(ctx.fillStyle=this.options.strokeStyle||"black"),ctx.fillText(this.options.label,cx,cy),this.options.strokeStyle&&this._map.getZoom()<=17&&(ctx.strokeStyle=this.options.strokeStyle,ctx.strokeText(this.options.label,cx,cy)),ctx.restore()}}}),L.DistanceMarkers=L.LayerGroup.extend({options:{cssClass:"dist-marker",iconSize:[12,12],arrowSize:[10,10],arrowUrl:"data:image/svg+xml,%3Csvg transform='rotate(90)' xmlns='http://www.w3.org/2000/svg' width='560px' height='560px' viewBox='0 0 560 560'%3E%3Cpath stroke-width='35' fill='%23000' stroke='%23FFF' d='M280,40L522,525L280,420L38,525z'/%3E%3C/svg%3E",offset:1e3,showAll:12,textFunction:(distance,i,offset)=>i,distance:!0,direction:!0},initialize:function(line,map,options){this._layers={},this._zoomLayers={},options=L.setOptions(this,options);let preferCanvas=map.options.preferCanvas,showAll=Math.min(map.getMaxZoom(),options.showAll);preferCanvas||map.options.rotate||console.warn('Missing dependency: "leaflet-rotate"');let coords="function"==typeof line.getLatLngs?line.getLatLngs():line;coords=L.LineUtil.isFlat(coords)?[coords]:coords,coords.forEach(latlngs=>{let accumulated=L.GeometryUtil.accumulatedLengths(latlngs),length=accumulated.length>0?accumulated[accumulated.length-1]:0;for(let i=1,count=Math.floor(length/options.offset),j=0;i<=count;++i){let distance=options.offset*i;for(;j<accumulated.length-1&&accumulated[j]<distance;)++j;let p1=latlngs[j-1],p2=latlngs[j],m_line=L.polyline([p1,p2]),ratio=(distance-accumulated[j-1])/(accumulated[j]-accumulated[j-1]),position=L.GeometryUtil.interpolateOnLine(map,m_line,ratio),delta=map.project(p2).subtract(map.project(p1)),angle=Math.atan2(delta.y,delta.x),text=options.textFunction.call(this,distance,i,options.offset),zoom=this._minimumZoomLevelForItem(i,showAll),markers=this._zoomLayers[zoom]=this._zoomLayers[zoom]||L.layerGroup();options.direction&&(options.distance&&i%2==1||!options.distance)&&(preferCanvas?markers.addLayer(new L.DistanceMarker(p1,{radius:0,icon:{url:options.arrowUrl,size:options.arrowSize,rotate:0,offset:{x:0,y:0}},rotation:angle,interactive:!1})):markers.addLayer(L.marker(position.latLng,{icon:L.icon({iconUrl:options.arrowUrl,iconSize:options.arrowSize}),rotation:angle*L.DomUtil.RAD_TO_DEG,interactive:!1}))),options.distance&&i%2==0&&(preferCanvas?markers.addLayer(new L.DistanceMarker(position.latLng,{label:text,radius:7,fillColor:"#fff",fillOpacity:1,fillStyle:"black",color:"#777",weight:1,interactive:!1})):markers.addLayer(L.marker(position.latLng,{title:text,icon:L.divIcon({className:options.cssClass,html:text,iconSize:options.iconSize}),interactive:!1})))}});const updateMarkerVisibility=()=>{let oldZoom=this._lastZoomLevel||0,newZoom=map.getZoom();if(newZoom>oldZoom)for(let i=oldZoom+1;i<=newZoom;++i)void 0!==this._zoomLayers[i]&&this.addLayer(this._zoomLayers[i]);else if(newZoom<oldZoom)for(let i=oldZoom;i>newZoom;--i)void 0!==this._zoomLayers[i]&&this.removeLayer(this._zoomLayers[i]);this._lastZoomLevel=newZoom};map.on("zoomend",updateMarkerVisibility),updateMarkerVisibility()},_minimumZoomLevelForItem:function(i,zoom){for(;i>0&&i%2==0;)--zoom,i=Math.floor(i/2);return zoom}}),L.Polyline.include({_originalOnAdd:L.Polyline.prototype.onAdd,_originalOnRemove:L.Polyline.prototype.onRemove,addDistanceMarkers:function(){this._map&&this._distanceMarkers&&this._map.addLayer(this._distanceMarkers)},removeDistanceMarkers:function(){this._map&&this._distanceMarkers&&this._map.removeLayer(this._distanceMarkers)},onAdd:function(map){this._originalOnAdd(map);let opts=this.options.distanceMarkers||{};this.options.distanceMarkers&&(this._distanceMarkers=this._distanceMarkers||new L.DistanceMarkers(this,map,opts)),void 0!==opts.lazy&&!1!==opts.lazy||this.addDistanceMarkers()},onRemove:function(map){this.removeDistanceMarkers(),this._originalOnRemove(map)}});
|
package/package.json
CHANGED
package/src/control.js
CHANGED
|
@@ -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
|
-
|
|
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 });
|
|
@@ -296,51 +294,44 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
|
|
|
296
294
|
return;
|
|
297
295
|
}
|
|
298
296
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
this._addGeoJSONData(geom.coordinates);
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
break;
|
|
312
|
-
|
|
313
|
-
default:
|
|
314
|
-
return console.warn('Unsopperted GeoJSON feature geometry type:' + geom.type);
|
|
297
|
+
// Standard GeoJSON
|
|
298
|
+
if (d.type === "FeatureCollection" ) {
|
|
299
|
+
return _.each(d.features, feature => this._addData(feature));
|
|
300
|
+
} else if (d.type === "Feature") {
|
|
301
|
+
let geom = d.geometry;
|
|
302
|
+
if (geom) {
|
|
303
|
+
switch (geom.type) {
|
|
304
|
+
case 'LineString': return this._addGeoJSONData(geom.coordinates, d.properties);
|
|
305
|
+
case 'MultiLineString': return _.each(geom.coordinates, (coords, i) => this._addGeoJSONData(coords, d.properties, i));
|
|
306
|
+
case 'Point':
|
|
307
|
+
default: return console.warn('Unsopperted GeoJSON feature geometry type:' + geom.type);
|
|
308
|
+
}
|
|
315
309
|
}
|
|
316
310
|
}
|
|
317
|
-
if (d.type === "FeatureCollection") {
|
|
318
|
-
_.each(d.features, feature => this._addData(feature));
|
|
319
|
-
}
|
|
320
311
|
|
|
321
|
-
|
|
322
|
-
* Extended GeoJSON --> rely on leaflet implementation
|
|
323
|
-
*/
|
|
312
|
+
// Fallback for leaflet layers (eg. L.Gpx)
|
|
324
313
|
if (d._latlngs) {
|
|
325
|
-
this._addGeoJSONData(d._latlngs, d.feature && d.feature.properties);
|
|
314
|
+
return this._addGeoJSONData(d._latlngs, d.feature && d.feature.properties);
|
|
326
315
|
}
|
|
316
|
+
|
|
327
317
|
},
|
|
328
318
|
|
|
329
319
|
/*
|
|
330
320
|
* Parsing of GeoJSON data lines and their elevation in z-coordinate
|
|
331
321
|
*/
|
|
332
|
-
_addGeoJSONData: function(coords, properties) {
|
|
322
|
+
_addGeoJSONData: function(coords, properties, nestingLevel) {
|
|
323
|
+
|
|
324
|
+
// "coordinateProperties" property is generated inside "@tmcw/toGeoJSON"
|
|
325
|
+
let props = (properties && properties.coordinateProperties) || properties;
|
|
326
|
+
|
|
333
327
|
coords.forEach((point, i) => {
|
|
334
328
|
|
|
335
329
|
// GARMIN_EXTENSIONS = ["hr", "cad", "atemp", "wtemp", "depth", "course", "bearing"];
|
|
336
330
|
point.meta = point.meta ?? { time: null, ele: null };
|
|
337
331
|
|
|
338
|
-
// "coordinateProperties" property is generated inside "@tmcw/toGeoJSON"
|
|
339
|
-
let props = (properties && properties.coordinateProperties) || properties;
|
|
340
|
-
|
|
341
332
|
point.prev = (attr) => (attr ? this._data[i > 0 ? i - 1 : 0][attr] : this._data[i > 0 ? i - 1 : 0]);
|
|
342
333
|
|
|
343
|
-
this.fire("elepoint_init", { point: point, props: props, id: i });
|
|
334
|
+
this.fire("elepoint_init", { point: point, props: props, id: i, isMulti: nestingLevel });
|
|
344
335
|
|
|
345
336
|
this._addPoint(
|
|
346
337
|
point.lat ?? point[1],
|
|
@@ -380,10 +371,12 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
|
|
|
380
371
|
if (layer && this.options.distanceMarkers && this.options.distanceMarkers.lazy) {
|
|
381
372
|
layer.on('add remove', ({target, type}) => L.DistanceMarkers && target instanceof L.Polyline && target[type + 'DistanceMarkers']());
|
|
382
373
|
}
|
|
374
|
+
return layer;
|
|
383
375
|
},
|
|
384
376
|
|
|
385
377
|
_addMarker: function(marker) {
|
|
386
378
|
if (marker) this._markers.addLayer(marker)
|
|
379
|
+
return marker;
|
|
387
380
|
},
|
|
388
381
|
|
|
389
382
|
/**
|
|
@@ -716,7 +709,7 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
|
|
|
716
709
|
*/
|
|
717
710
|
_loadModules: function(handlers) {
|
|
718
711
|
// First map known classnames (eg. "Altitude" --> L.Control.Elevation.Altitude)
|
|
719
|
-
handlers = handlers.map((h) => typeof h === 'string' && typeof
|
|
712
|
+
handlers = handlers.map((h) => typeof h === 'string' && typeof Elevation[h] !== "undefined" ? Elevation[h] : h);
|
|
720
713
|
// Then load optional classes and custom imports (eg. "Cadence" --> import('../src/handlers/cadence.js'))
|
|
721
714
|
Promise.
|
|
722
715
|
all(
|
|
@@ -727,8 +720,8 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
|
|
|
727
720
|
.then((m) => {
|
|
728
721
|
_.each(m, (exported) => {
|
|
729
722
|
let fn = Object.keys(exported)[0];
|
|
730
|
-
if (fn && typeof
|
|
731
|
-
handlers[fn] =
|
|
723
|
+
if (fn && typeof Elevation[fn] === "undefined" ) {
|
|
724
|
+
handlers[fn] = Elevation[fn] = exported[fn];
|
|
732
725
|
|
|
733
726
|
}
|
|
734
727
|
});
|
|
@@ -740,65 +733,48 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
|
|
|
740
733
|
* Simple GeoJSON data loader (L.GeoJSON).
|
|
741
734
|
*/
|
|
742
735
|
_loadLayer: function(geojson) {
|
|
743
|
-
let
|
|
736
|
+
let { polyline, theme, waypoints, wptIcons, wptLabels, distanceMarkers } = this.options;
|
|
737
|
+
let style = L.extend({}, polyline);
|
|
744
738
|
|
|
745
|
-
|
|
739
|
+
if (theme) {
|
|
740
|
+
style.className += ' ' + theme;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
if (geojson.name) {
|
|
744
|
+
this.track_info.name = geojson.name;
|
|
745
|
+
}
|
|
746
746
|
|
|
747
747
|
let layer = L.geoJson(geojson, {
|
|
748
|
-
distanceMarkers:
|
|
749
|
-
style:
|
|
750
|
-
let style = L.extend({}, control.options.polyline);
|
|
751
|
-
if (control.options.theme) {
|
|
752
|
-
style.className += ' ' + control.options.theme;
|
|
753
|
-
}
|
|
754
|
-
return style;
|
|
755
|
-
},
|
|
748
|
+
distanceMarkers: distanceMarkers,
|
|
749
|
+
style: style,
|
|
756
750
|
pointToLayer: (feature, latlng) => {
|
|
757
|
-
if (
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
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
|
-
);
|
|
751
|
+
if (waypoints) {
|
|
752
|
+
let { desc, name, sym } = feature.properties;
|
|
753
|
+
desc = desc || '';
|
|
754
|
+
name = name || '';
|
|
755
|
+
// Handle chart waypoints (dots)
|
|
756
|
+
if ([true, 'dots'].includes(waypoints)) {
|
|
757
|
+
this._registerCheckPoint({
|
|
758
|
+
latlng: latlng,
|
|
759
|
+
label : ([true, 'dots'].includes(wptLabels) ? name : '')
|
|
760
|
+
});
|
|
779
761
|
}
|
|
780
|
-
|
|
781
|
-
if ([true, 'markers'].includes(
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
762
|
+
// Handle map waypoints (markers)
|
|
763
|
+
if ([true, 'markers'].includes(waypoints) && wptIcons != false) {
|
|
764
|
+
return this._registerMarker({
|
|
765
|
+
latlng : latlng,
|
|
766
|
+
sym : (sym ?? name).replace(' ', '-').replace('"', '').replace("'", '').toLowerCase(),
|
|
767
|
+
content: [true, 'markers'].includes(wptLabels) && (name || desc) && decodeURI("<b>" + name + "</b>" + (desc.length > 0 ? '<br>' + desc : ''))
|
|
768
|
+
});
|
|
785
769
|
}
|
|
786
|
-
control._addMarker(marker);
|
|
787
|
-
control.fire('waypoint_added', { point: marker, element: latlng, properties: prop });
|
|
788
|
-
return marker;
|
|
789
770
|
}
|
|
790
771
|
},
|
|
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
|
-
},
|
|
772
|
+
onEachFeature: (feature, layer) => feature.geometry && feature.geometry.type != 'Point' && this.addData(feature, layer),
|
|
797
773
|
});
|
|
798
774
|
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
775
|
+
this.import(this.__D3).then(() => {
|
|
776
|
+
this._initMapIntegrations(this, layer);
|
|
777
|
+
this._fireEvt("eledata_loaded", { data: geojson, layer: layer, name: this.track_info.name, track_info: this.track_info });
|
|
802
778
|
});
|
|
803
779
|
|
|
804
780
|
return layer;
|
|
@@ -929,8 +905,7 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
|
|
|
929
905
|
geojson = this._parseFromGeoJSONString(data.toString());
|
|
930
906
|
}
|
|
931
907
|
if (geojson) {
|
|
932
|
-
geojson = this.
|
|
933
|
-
geojson = this._prepareAdditionalProperties(geojson);
|
|
908
|
+
geojson.name = geojson.name || (this._downloadURL || '').split('/').pop().split('#')[0].split('?')[0];
|
|
934
909
|
}
|
|
935
910
|
resolve(geojson);
|
|
936
911
|
})
|
|
@@ -958,37 +933,6 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
|
|
|
958
933
|
return geojson;
|
|
959
934
|
},
|
|
960
935
|
|
|
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
936
|
/**
|
|
993
937
|
* Add chart profile to diagram
|
|
994
938
|
*/
|
|
@@ -1106,60 +1050,79 @@ export const Elevation = L.Control.Elevation = L.Control.extend({
|
|
|
1106
1050
|
return this._registerHandler(props.call(this));
|
|
1107
1051
|
}
|
|
1108
1052
|
|
|
1053
|
+
let {
|
|
1054
|
+
name,
|
|
1055
|
+
attr,
|
|
1056
|
+
required,
|
|
1057
|
+
skipNull,
|
|
1058
|
+
deltaMax,
|
|
1059
|
+
clampRange,
|
|
1060
|
+
decimals,
|
|
1061
|
+
meta,
|
|
1062
|
+
unit,
|
|
1063
|
+
coordinateProperties,
|
|
1064
|
+
coordPropsToMeta,
|
|
1065
|
+
pointToAttr,
|
|
1066
|
+
onPointAdded,
|
|
1067
|
+
stats,
|
|
1068
|
+
statsName,
|
|
1069
|
+
grid,
|
|
1070
|
+
scale,
|
|
1071
|
+
path,
|
|
1072
|
+
tooltip,
|
|
1073
|
+
summary
|
|
1074
|
+
} = props;
|
|
1075
|
+
|
|
1109
1076
|
// eg. "altitude" == true
|
|
1110
|
-
if (this.options[
|
|
1077
|
+
if (this.options[name] || required) {
|
|
1111
1078
|
|
|
1112
1079
|
this._registerDataAttribute({
|
|
1113
|
-
name
|
|
1114
|
-
attr
|
|
1115
|
-
skipNull
|
|
1116
|
-
deltaMax
|
|
1117
|
-
clampRange
|
|
1118
|
-
decimals
|
|
1119
|
-
coordPropsToMeta: _.coordPropsToMeta(
|
|
1120
|
-
pointToAttr
|
|
1121
|
-
onPointAdded
|
|
1122
|
-
stats
|
|
1123
|
-
statsName
|
|
1080
|
+
name,
|
|
1081
|
+
attr,
|
|
1082
|
+
skipNull,
|
|
1083
|
+
deltaMax,
|
|
1084
|
+
clampRange,
|
|
1085
|
+
decimals,
|
|
1086
|
+
coordPropsToMeta: _.coordPropsToMeta(coordinateProperties, meta || name, coordPropsToMeta),
|
|
1087
|
+
pointToAttr,
|
|
1088
|
+
onPointAdded,
|
|
1089
|
+
stats,
|
|
1090
|
+
statsName,
|
|
1124
1091
|
});
|
|
1125
1092
|
|
|
1126
|
-
if (
|
|
1127
|
-
|
|
1128
|
-
this._registerAxisGrid(props.grid);
|
|
1093
|
+
if (grid) {
|
|
1094
|
+
this._registerAxisGrid(L.extend({ name }, grid));
|
|
1129
1095
|
}
|
|
1130
1096
|
|
|
1131
|
-
if (this.options[
|
|
1132
|
-
if (
|
|
1133
|
-
|
|
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
|
-
}
|
|
1097
|
+
if (this.options[name] !== "summary") {
|
|
1098
|
+
if (scale) this._registerAxisScale(L.extend({ name, label: unit }, scale));
|
|
1099
|
+
if (path) this._registerAreaPath(L.extend({ name }, path));
|
|
1141
1100
|
}
|
|
1142
1101
|
|
|
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)
|
|
1102
|
+
if (tooltip || props.tooltips) {
|
|
1103
|
+
_.each([tooltip, ...(props.tooltips || [])], t => t && this._registerTooltip(L.extend({ name }, t)));
|
|
1153
1104
|
}
|
|
1154
1105
|
|
|
1155
|
-
if (
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
}
|
|
1159
|
-
this._registerSummary(props.summary);
|
|
1106
|
+
if (summary) {
|
|
1107
|
+
_.each(summary, (s, k) => summary[k] = L.extend({ unit }, s));
|
|
1108
|
+
this._registerSummary(summary);
|
|
1160
1109
|
}
|
|
1161
1110
|
}
|
|
1162
1111
|
},
|
|
1112
|
+
|
|
1113
|
+
_registerMarker({latlng, sym, content}) {
|
|
1114
|
+
let { wptIcons } = this.options;
|
|
1115
|
+
// generate and cache appropriate icon symbol
|
|
1116
|
+
if (!wptIcons.hasOwnProperty(sym)) {
|
|
1117
|
+
wptIcons[sym] = L.divIcon(L.extend({}, wptIcons[""].options, { html: '<i class="elevation-waypoint-icon ' + sym + '"></i>' } ));
|
|
1118
|
+
}
|
|
1119
|
+
let marker = L.marker(latlng, { icon: wptIcons[sym] });
|
|
1120
|
+
if (content) {
|
|
1121
|
+
marker.bindPopup(content, { className: 'elevation-popup', keepInView: true }).openPopup();
|
|
1122
|
+
marker.bindTooltip(content, { className: 'elevation-tooltip', direction: 'auto', sticky: true, opacity: 1 }).openTooltip();
|
|
1123
|
+
}
|
|
1124
|
+
return this._addMarker(marker)
|
|
1125
|
+
},
|
|
1163
1126
|
|
|
1164
1127
|
/**
|
|
1165
1128
|
* Add chart or marker tooltip info
|
package/src/handlers/altitude.js
CHANGED
|
@@ -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: (
|
|
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",
|
package/src/utils.js
CHANGED
|
@@ -88,11 +88,11 @@ export function formatTime(t) {
|
|
|
88
88
|
* Loop and extract GPX Extensions handled by "@tmcw/toGeoJSON" (eg. "coordinateProperties" > "times")
|
|
89
89
|
*/
|
|
90
90
|
export function coordPropsToMeta(coordProps, name, parser) {
|
|
91
|
-
return coordProps && (({props, point, id}) => {
|
|
91
|
+
return coordProps && (({props, point, id, isMulti }) => {
|
|
92
92
|
if (props) {
|
|
93
93
|
for (const key of coordProps) {
|
|
94
94
|
if (key in props) {
|
|
95
|
-
point.meta[name] = (parser || parseInt).call(this, props[key], id);
|
|
95
|
+
point.meta[name] = (parser || parseInt).call(this, (isMulti ? props[key][isMulti] : props[key]), id);
|
|
96
96
|
break;
|
|
97
97
|
}
|
|
98
98
|
}
|