I'm using Leaflet maps together with "Plugins by Pavel Shramov", which allows google usage and GPX file use.
This bit was easy enough, but trying now to use markerClusterer. I've spent a few hours playing around with things but complete stabs in the dark, and no joy yet.
Most of the examples I'm seeing are JSON, not GPX, and I don't think are really relevant?
My test page is up here: http://www.talesfromthesaddle.com/mapproject/map.html
If anyone knows of similar usage examples, please let me know so I can take a look. Or, if you want to head over to the test page and give me a few pointers, also welcome!
This is the GPX parser, which might provide some insight:
L.GPX = L.FeatureGroup.extend({
initialize: function(gpx, options) {
L.Util.setOptions(this, options);
this._gpx = gpx;
this._layers = {};
if (gpx) {
this.addGPX(gpx, options, this.options.async);
}
},
loadXML: function(url, cb, options, async) {
if (async === undefined) async = this.options.async;
if (options === undefined) options = this.options;
var req = new window.XMLHttpRequest();
req.open('GET', url, async);
try {
req.overrideMimeType('text/xml'); // unsupported by IE
} catch(e) {}
req.onreadystatechange = function() {
if (req.readyState !== 4) return;
if(req.status === 200) cb(req.responseXML, options);
};
req.send(null);
},
_humanLen: function(l) {
if (l < 2000)
return l.toFixed(0) + ' m';
else
return (l/1000).toFixed(1) + ' km';
},
_polylineLen: function(line)//line is a L.Polyline()
{
var ll = line._latlngs;
var d = 0, p = null;
for (var i = 0; i < ll.length; i++)
{
if(i && p)
d += p.distanceTo(ll[i]);
p = ll[i];
}
return d;
},
addGPX: function(url, options, async) {
var _this = this;
var cb = function(gpx, options) { _this._addGPX(gpx, options); };
this.loadXML(url, cb, options, async);
},
_addGPX: function(gpx, options) {
var layers = this.parseGPX(gpx, options);
if (!layers) return;
this.addLayer(layers);
this.fire('loaded');
},
parseGPX: function(xml, options) {
var j, i, el, layers = [];
var named = false, tags = [['rte','rtept'], ['trkseg','trkpt']];
for (j = 0; j < tags.length; j++) {
el = xml.getElementsByTagName(tags[j][0]);
for (i = 0; i < el.length; i++) {
var l = this.parse_trkseg(el[i], xml, options, tags[j][1]);
for (var k = 0; k < l.length; k++) {
if (this.parse_name(el[i], l[k])) named = true;
layers.push(l[k]);
}
}
}
el = xml.getElementsByTagName('wpt');
if (options.display_wpt !== false) {
for (i = 0; i < el.length; i++) {
var marker = this.parse_wpt(el[i], xml, options);
if (!marker) continue;
if (this.parse_name(el[i], marker)) named = true;
layers.push(marker);
}
}
if (!layers.length) return;
var layer = layers[0];
if (layers.length > 1)
layer = new L.FeatureGroup(layers);
if (!named) this.parse_name(xml, layer);
return layer;
},
parse_name: function(xml, layer) {
var i, el, txt='', name, descr='', len=0;
el = xml.getElementsByTagName('name');
if (el.length)
name = el[0].childNodes[0].nodeValue;
el = xml.getElementsByTagName('desc');
for (i = 0; i < el.length; i++) {
for (var j = 0; j < el[i].childNodes.length; j++)
descr = descr + el[i].childNodes[j].nodeValue;
}
if(layer instanceof L.Path)
len = this._polylineLen(layer);
if (name) txt += '<h2>' + name + '</h2>' + descr;
if (len) txt += '<p>' + this._humanLen(len) + '</p>';
if (layer && layer._popup === undefined) layer.bindPopup(txt);
return txt;
},
parse_trkseg: function(line, xml, options, tag) {
var el = line.getElementsByTagName(tag);
if (!el.length) return [];
var coords = [];
for (var i = 0; i < el.length; i++) {
var ll = new L.LatLng(el[i].getAttribute('lat'),
el[i].getAttribute('lon'));
ll.meta = {};
for (var j in el[i].childNodes) {
var e = el[i].childNodes[j];
if (!e.tagName) continue;
ll.meta[e.tagName] = e.textContent;
}
coords.push(ll);
}
var l = [new L.Polyline(coords, options)];
this.fire('addline', {line:l});
return l;
},
parse_wpt: function(e, xml, options) {
var m = new L.Marker(new L.LatLng(e.getAttribute('lat'),
e.getAttribute('lon')), options);
this.fire('addpoint', {point:m});
return m;
} });
Best Answer
GeoJSON or GPX doesn't really matter, you just need a way to construct a marker from each coordinate pair, and add it to a MarkerCluster group.
Here is the start of a solution; ugly as it is, it works (for clustering the hundreds of gpx points), and it should point you in the right direction to a cleaner solution.
Add a max zoom to the map. Not sure why, but L.MarkerCluster complains if you don't
var map = new L.Map('map', {center: new L.LatLng(45, 0), zoom: 2, maxZoom:12});
Create a marker cluster group before you start parsing the gpx
var markerClusters = new L.MarkerClusterGroup();
Drop the on.('loaded') function from this line
var track = new L.GPX("./map.gpx", {async: true});
Don't add the 'track' to the map. Instead, get GPX.js to add the markers to the marker cluster group, by changing the parseWPT() function as shown below. (Basically, use the existing methods in the GPX.js plugin to construct markers from the lat and log attributes, and add them to the clusters)
parse_wpt: function(e, xml, options) { var m = new L.Marker(new L.LatLng(e.getAttribute('lat'), e.getAttribute('lon')), options); markerClusters.addLayer(m); }
Finally, add the markerCluster to the map
map.addLayer(markerClusters)
Note, this is not adding your tracks to the map. If you need these, I suggest separating the points from the tracks in your gpx file, and working from there, with a second call to GPX.js.