-
Notifications
You must be signed in to change notification settings - Fork 86
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Multiple tracks and <trk> segments #56
Comments
Hi velocat,
Based on your example, it could be such a thing: var filteringFunc = this._area.defined();
var filteredData = this._data.filter(filteringFunc),
svg.append("path")
.datum(filteredData)
.attr("fill", "#eee")
.attr("d", area);
Try reading this article to better understand how it works: https://bocoup.com/blog/showing-missing-data-in-line-charts
An "intermediate" solution already exists: leaflet-elevation/src/leaflet-elevation.js Line 595 in f0a2de6
But at the moment this library doesn't support multi-track segments, anyway pull requests are welcome. Happy further investigations, |
As you can see from the picture above, I still adapted the multi-track like this: loadTrace = function(id) {
var Maintrace = {};
$.ajax({
//dataType: "xml",
url: "aljax2.php",
data: {
mode: "getcontent",
id: id
},
success: function(xml) {
Maintrace.gpx = new L.GPX(xml, {
async: true,
joinTrackSegments: true,
joinTracks: false,
marker_options: {
wptIcons: arrayIcons,
startIconUrl: null, //'images/map/icon-start.png' ,
endIconUrl: null, //'images/map/icon-end.png' ,
iconSize: [13, 13],
iconAnchor: [6, 13],
shadowUrl: ''
},
polyline_options: {
color: colors[countColor],
stroke: '#000',
opacity: 0.75,
weight: 4,
lineCap: 'round',
}
}).on('loaded', function(e) {
if (Tracks.length > 1) {
controlLayer.addTo(mymap);
controlLayer.addBaseLayer(e.target, "Все участки");
MainTrack_id = e.target._leaflet_id;
}
var i = 0;
for (var track in Tracks) {
loadTrack(track, i++)
}
allLayers = e.layers;
waypoints.addTo(mymap);
}).on("addline", function(e) {
var line = e.line;
line.options.distanceMarkers = {
lazy: true
};
if (!Maintrace.gpx.lines) {
Maintrace.gpx.lines = []
}
Maintrace.gpx.line = line;
Maintrace.gpx.lines.push(line)
Tracks.push(e.element);
}).on('addpoint', function(e) {
waypoints.addLayer(e.point);
});
traces.push(Maintrace);
}
});
}
function loadTrack(track, i) {
var trace = {};
var XMLTrack = xmlToString(Tracks[track]);
trace.gpx = new L.GPX(XMLTrack, {
async: true,
index: i,
marker_options: {
wptIcons: arrayIcons,
startIconUrl: 'images/map/icon-start.png',
endIconUrl: 'images/map/icon-end.png',
iconSize: [13, 13],
iconAnchor: [6, 13],
shadowUrl: ''
},
polyline_options: {
color: colors[countColor],
stroke: '#000',
opacity: 0.75,
weight: 4,
lineCap: 'round',
}
});
trace.gpx.on('loaded', function(e) {
controlLayer.addBaseLayer(e.target, e.target.get_name());
if (e.target.options.index == 0) {
setElevationTrack(0);
} else {
mymap.removeLayer(e.target);
}
})
trace.gpx.on("addline", function(e) {
var line = e.line;
line.options.distanceMarkers = {
lazy: true
};
trace.gpx.line = line;
})
trace.gpx.on("click", function(e) {
//console.log(i)
})
trace.gpx.addTo(mymap);
traces.push(trace);
} The function that you indicated works great and that is why there is a flat line of heights from the end of one segment to the beginning of a new one. It is only necessary to paint over it :)) In general, it remains to deal with the paths in svg. If I find a solution, I will definitely share it. |
I can't see it in your code, but I think you solved this problem by calling the
In your tests, you can avoid editing library code and access to the var controlElevation = L.control.elevation( ... ); // leaflet.js chart object
// ...
var svg = d3.select(controlElevation.getContainer()).select("svg"); // d3.js object
var area = controlElevation._area;
var data = controlElevation._data;
Ok thanks, if it can help try to check this pull too: MrMufflon/Leaflet.Elevation#84 Have a nice day, |
I did not write code so that there was no long text, but if interested, then here it is: setElevationTrack = function(index) {
var trace = traces[index + 1]; // +1 i.e. 0=Main
controlElevation.clear();
if (index == -1) {
var Lines = trace.gpx.lines;
Lines.forEach(function(line, i, arr) {
controlElevation.addData(line);
controlElevation.hide(); //remove()
line.setStyle({
color: colors[countColor],
weight: 4,
});
if (triggerDM == true) {
line.addDistanceMarkers();
} else {
line.removeDistanceMarkers();
}
});
viewMain = true;
} else {
controlElevation.addData(trace.gpx.line);
trace.gpx.setStyle({
color: colors[countColor],
weight: 4,
});
if (triggerDM == true) {
trace.gpx.line.addDistanceMarkers();
} else {
trace.gpx.line.removeDistanceMarkers();
}
viewMain = false;
}
set_info(trace);
mymap.fitBounds(trace.gpx.getBounds());
} |
Hi velocat, I took a better look at the following example: Basically it works because where you have the Unlike your dataset where you are also missing the <gpx>
<trk> .... </trk>
<trk> .... </trk>
</gpx> So, i think that to achieve a result like in the following example: The As usual, pull requests are welcome... Have a nice day, |
I've been doing some research, since multi segment tracks were working for me, and I've just realized that in version 1.5.6 (and below), multi segment tracks are working as expected. However, from version 1.6.0 and above, it doesn't work. I guess that this change might have something to do with it: 0df53e9#diff-3274f1a37032fb0ae4e2823def0007c634e869ae0dfc304ff6a12c36513c3a52L138-L172 I can see that the library stopped using the leaflet-gpx library. And that library has support for multi segment tracks. Now they work like a charm. Do you think that it'll be possible to revert this change? I find it quite important, since there are a lot of GPX tracks with several segments in it. It's not about loading several tracks, it's just the same track, with different segments. |
Hi Carlos, theoretically this library should still be somehow backwards compatible with what produced by MrMufflon: // https://github.com/MrMufflon/Leaflet.Elevation#how-to-use
var el = L.control.elevation();
el.addTo(map);
var g=new L.GPX("./mytrack.gpx", {async: true});
g.on("addline",function(e){
el.addData(e.line);
});
g.addTo(map); obviously taking care to include the necessary dependencies: ...
<!-- leaflet-gpx -->
<script src="https://unpkg.com/[email protected]/gpx.js"></script>
<!-- leaflet-elevation -->
<script src="https://unpkg.com/@raruto/[email protected]/dist/leaflet-elevation.min.js"></script>
... and possibly integrating it with some changes from that function: /**
* Simple GPX data loader.
*/
function GPXLoader(data, control) {
control = control || this;
control.options.gpxOptions.polyline_options = L.extend({}, control.options.polyline, control.options.gpxOptions.polyline_options);
if (control.options.theme) {
control.options.gpxOptions.polyline_options.className += ' ' + control.options.theme;
}
let layer = new L.GPX(data, control.options.gpxOptions);
// similar to L.GeoJSON.pointToLayer
layer.on('addpoint', (e) => {
control.fire("waypoint_added", e);
});
// similar to L.GeoJSON.onEachFeature
layer.on("addline", (e) => {
control.addData(e.line /*, layer*/ ); // NB uses "_addGPXData"
control.track_info = L.extend({}, control.track_info, { type: "gpx", name: layer.get_name() });
});
// unlike the L.GeoJSON, L.GPX parsing is async
layer.once('loaded', (e) => {
L.Control.Elevation._d3LazyLoader.then(() => {
control._fireEvt("eledata_loaded", { data: data, layer: layer, name: control.track_info.name, track_info: control.track_info });
});
});
return layer;
} Anyway, have you checked if this library parses them natively? https://github.com/tmcw/togeojson
I understand this would be great, but personally I have no resources to devote to this feature... (anyway, pull requests and or recommendations are always welcome). Have a nice day, |
I can share my experience: I upload tracks via fileloader, even if they are on the server. In it, as a handler, they use their own parser "importGeojson", in which I sort through the segments separately, create layers for them and add them to the array of segments. Next, I just switch between these layers, and each time I switch, I display the height profile for this segment, thereby always up-to-date information on the screen and there are no "gaps", as described above. If I want to show all the segment layers at the same time, I just disable the height profile. |
@velocat @carlos-mg89 if it interests you here you can find what I have already tried to do in the past: as you can see the geojson segments are already managed natively (the only problem is to find a way to split the chart profiles): var opts = {
map: {
center: [41.4583, 12.7059],
zoom: 5,
fullscreenControl: false,
resizerControl: true,
preferCanvas: true,
rotate: true,
bearing: 15,
rotateControl: {
closeOnZeroBearing: false
},
},
elevationControl: {
url: 'multi.gpx',
options: {
preferCanvas: false,
theme: "lightblue-theme",
collapsed: false,
autohide: false,
autofitBounds: true,
position: "bottomleft",
detached: true,
summary: "inline",
imperial: false,
altitude: true, //"summary",
distance: true, //"summary",
slope: true, //"disabled",
speed: "disabled",
acceleration: "disabled",
time: true, //"summary",
timestamps: true,
legend: true,
followMarker: true,
// zFollow: 13,
ruler: true,
// polyline: false,
// marker: 'position-marker',
// dragging: true,
distanceMarkers: true,
waypoints: true,
wptIcons: true,
wptLabels: true,
almostOver: true,
},
},
layersControl: {
options: {
collapsed: false,
},
},
};
var map = new L.Map('map', opts.map);
var controlElevation = L.control.elevation(opts.elevationControl.options);
var controlLayer = L.control.layers(null, null, opts.layersControl.options);
controlElevation.clear();
controlElevation.redraw();
map.on('eledata_loaded', function(e) {
if (!controlLayer._map) controlLayer.addTo(map);
controlElevation._gaps = controlElevation._data.reduce(function(array, item ) {
if (item.trkEnd) array.push([]);
if (array.length && (item.trkStart || item.trkEnd)) array[array.length-1].push(item);
return array;
}, []);
e.layer.eachLayer((trkseg) => {
if(trkseg.feature.geometry.type != "Point") {
controlLayer.addOverlay(trkseg, trkseg.feature.properties.name);
}
});
// console.log('eledata_loaded');
// console.log(e);
});
controlElevation.on('eletrack_added', function(e) {
this._data[0].trkStart = true;
this._data[this._data.length-1].trkEnd = true;
this.once('eledata_updated', function(e){
this._data[this._data.length-1].trkStart = true;
});
// console.log('eletrack_added');
// console.log(this._data[this._data.length-1], e);
});
controlElevation.load(opts.elevationControl.url);
controlElevation.addTo(map); for those wishing to try, clone this repository into your localhost folder and inside move to the leaflet-elevation folder
After that you can start developing inside the Have a nice day, |
Patch released in version 1.8.1 Below a simple example of how to use this in conjunction with L.Control.Layers: var map = new L.Map('map', opts.map);
var controlElevation = L.control.elevation(opts.elevationControl.options);
var controlLayer = L.control.layers(null, null, opts.layersControl.options);
// Optional
controlElevation.clear();
controlElevation.redraw();
// Add individual "multi-track" segments to layers control
map.on('eledata_loaded', function(e) {
if (!controlLayer._map) controlLayer.addTo(map);
e.layer.eachLayer((trkseg) => {
if (trkseg.feature.geometry.type != "Point") {
controlLayer.addOverlay(trkseg, trkseg.feature.properties.name);
}
});
});
controlElevation.load(opts.elevationControl.url);
controlElevation.addTo(map); Heartily, |
@Raruto I tried with the 1.8.x versions but didn't make it work. There were some issues. However, I've just tried it with the 1.9.6 release, and now it works like a charm. Thanks a lot!!! |
Sometimes users can download gpx of this kind:
It contains several tracks, and they are not necessarily an extension of each other.
The ability to create such multitracks is provided by MapSource and BaseCamp - the basic programs for working with tracks.
It would be nice to use the
area.defined
feature to correctly display these codes:https://observablehq.com/@d3/area-with-missing-data
But I just can’t figure out how to apply the filter to SVG, like this:
I just did not quite understand the principle of building SVG.
Can you tell me a thought?
In general, it seems to me that it would not be bad to add this to the general code :)
The text was updated successfully, but these errors were encountered: