Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
+396
@@ -0,0 +1,396 @@
|
||||
# GPX plugin for Leaflet
|
||||
|
||||
[](https://cdnjs.com/libraries/leaflet-gpx)
|
||||
|
||||
[Leaflet](http://www.leafletjs.com) is a Javascript library for displaying
|
||||
interactive maps. This plugin, based on the work of [Pavel
|
||||
Shramov](http://github.com/shramov) and his
|
||||
[leaflet-plugins](http://github.com/shramov/leaflet-plugins), it allows for the
|
||||
analysis and parsing of a GPX track in order to display it as a Leaflet map
|
||||
layer. As it parses the GPX data, it will record information about the recorded
|
||||
track, including total time, moving time, total distance, elevation stats and
|
||||
heart-rate.
|
||||
|
||||
GPX parsing will automatically handle pauses in the track with a default
|
||||
tolerance interval of 15 seconds between points. You can configure this
|
||||
interval by setting `max_point_interval`, in milliseconds, in the options
|
||||
passed to the `GPX` constructor.
|
||||
|
||||
I've put together a complete example as a
|
||||
[demo](http://mpetazzoni.github.com/leaflet-gpx/).
|
||||
|
||||
## License
|
||||
|
||||
`leaflet-gpx` is under the *BSD 2-clause license*. Please refer to the
|
||||
attached LICENSE file and/or to the copyright header in gpx.js for more
|
||||
information.
|
||||
|
||||
## Usage
|
||||
|
||||
Usage is very simple. First, include the Leaflet.js and Leaflet-GPX
|
||||
scripts in your HTML page:
|
||||
|
||||
```html
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.1/leaflet.css" />
|
||||
<!-- ... -->
|
||||
</head>
|
||||
<body>
|
||||
<!-- ... -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.3.1/leaflet.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-gpx/1.4.0/gpx.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
Now, let's consider we have a Leaflet map:
|
||||
|
||||
```javascript
|
||||
var map = L.map('map');
|
||||
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
attribution: 'Map data © <a href="http://www.osm.org">OpenStreetMap</a>'
|
||||
}).addTo(map);
|
||||
```
|
||||
|
||||
Displaying a GPX track on it is as easy as:
|
||||
|
||||
```javascript
|
||||
var gpx = '...'; // URL to your GPX file or the GPX itself
|
||||
new L.GPX(gpx, {async: true}).on('loaded', function(e) {
|
||||
map.fitBounds(e.target.getBounds());
|
||||
}).addTo(map);
|
||||
```
|
||||
|
||||
Some GPX tracks contain the actual route/track twice, both the `<trk>` and
|
||||
`<rte>` elements are used. You can tell `leaflet-gpx` which tag to use or to
|
||||
use both (which is the default setting for backwards compatibility) with the
|
||||
`gpx_options` object in the second argument of the constructor. The member
|
||||
`parseElements` controls this behavior, it should be an array that contains
|
||||
`'route'` and/or `'track'`.
|
||||
|
||||
### Available functions
|
||||
|
||||
If you want to display additional information about the GPX track, you can do
|
||||
so in the 'loaded' event handler, calling one of the following methods on the
|
||||
`GPX` object `e.target`:
|
||||
|
||||
* `get_name()`: returns the name of the GPX track
|
||||
* `get_distance()`: returns the total track distance, in meters
|
||||
* `get_start_time()`: returns a Javascript `Date` object representing the
|
||||
starting time
|
||||
* `get_end_time()`: returns a Javascript `Date` object representing when the
|
||||
last point was recorded
|
||||
* `get_moving_time()`: returns the moving time, in milliseconds
|
||||
* `get_total_time()`: returns the total track time, in milliseconds
|
||||
* `get_moving_pace()`: returns the average moving pace in milliseconds per km
|
||||
* `get_moving_speed()`: returns the average moving speed in km per hour
|
||||
* `get_total_speed()`: returns the average total speed in km per hour
|
||||
* `get_elevation_min()`: returns the lowest elevation, in meters
|
||||
* `get_elevation_max()`: returns the highest elevation, in meters
|
||||
* `get_elevation_gain()`: returns the cumulative elevation gain, in meters
|
||||
* `get_elevation_loss()`: returns the cumulative elevation loss, in meters
|
||||
* `get_average_hr()`: returns the average heart rate (if available)
|
||||
* `get_average_cadence()`: returns the average cadence (if available)
|
||||
* `get_average_temp()`: returns the average of the temperature (if available)
|
||||
|
||||
If you're not a fan of the metric system, you also have the following methods
|
||||
at your disposal:
|
||||
|
||||
* `get_distance_imp()`: returns the total track distance in miles
|
||||
* `get_moving_pace_imp()`: returns the average moving pace in milliseconds per
|
||||
hour
|
||||
* `get_moving_speed_imp()`: returns the average moving speed in miles per hour
|
||||
* `get_total_speed_imp()`: returns the average total speed in miles per hour
|
||||
* `get_elevation_min_imp()`: returns the lowest elevation, in feet
|
||||
* `get_elevation_max_imp()`: returns the highest elevation, in feet
|
||||
* `get_elevation_gain_imp()`: returns the cumulative elevation gain, in feet
|
||||
* `get_elevation_loss_imp()`: returns the cumulative elevation loss, in feet
|
||||
|
||||
The reason why these methods return milliseconds is that you have at your
|
||||
disposal nice helper methods to format a duration in milliseconds into a cool
|
||||
string:
|
||||
|
||||
* `get_duration_string(duration, hidems)` format to a string like `3:07'48"`
|
||||
or `59'32.431`, where `duration` is in
|
||||
milliseconds and `hidems` is an optional boolean you can use to request never
|
||||
to display millisecond precision.
|
||||
* `get_duration_string_iso(duration, hidems)` formats to an ISO like
|
||||
representation like `3:07:48` or `59:32.431`, where `duration` is in
|
||||
milliseconds and `hidems` is an optional boolean you can use to request never
|
||||
to display millisecond precision.
|
||||
|
||||
You can also get full elevation, heartrate, cadence and temperature data with:
|
||||
|
||||
* `get_elevation_data()` and `get_elevation_data_imp()`
|
||||
* `get_heartrate_data()` and `get_heartrate_data_imp()`
|
||||
* `get_cadence_data()` and `get_cadence_data_imp()`
|
||||
* `get_temp_data()` and `get_temp_data_imp()`
|
||||
|
||||
These methods all return an array of points `[distance, value, tooltip]` where
|
||||
the distance is either in kilometers or in miles and the elevation in meters or
|
||||
feet, depending on whether you use the `_imp` variant or not. Heart rate,
|
||||
obviously, doesn't change.
|
||||
|
||||
### Reloading
|
||||
|
||||
You can make `leaflet-gpx` reload the source GPX file by calling the
|
||||
`reload()` method. For example, to trigger a reload every 5 seconds, you
|
||||
can do:
|
||||
|
||||
```javascript
|
||||
var gpx = new L.GPX(gpxFile);
|
||||
setInterval(function() {
|
||||
gpx.reload();
|
||||
}, 5000);
|
||||
```
|
||||
|
||||
## About marker icons
|
||||
|
||||
By default `gpx.js` will use `pin-icon-start.png`, `pin-icon-end.png` and
|
||||
`pin-shadow.png` as the marker icons URLs for, respectively, the start marker,
|
||||
the end marker and their drop shadow. Since it might not be convenient that
|
||||
these images have to reside under the same directory as your HTML page, it is
|
||||
possible to override the marker icon URLs and sizes by passing a
|
||||
`marker_options` object to the `GPX` options object.
|
||||
|
||||
The field names are the same as for custom Leaflet icons, as explained in the
|
||||
[Markers with custom icons](http://leafletjs.com/examples/custom-icons.html)
|
||||
page in Leaflet's documentation. The only difference is that instead of
|
||||
`iconUrl` you should specify `startIconUrl` and `endIconUrl` for the start and
|
||||
end markers, respectively.
|
||||
|
||||
Note that you do not need to override all the marker icon options as `gpx.js`
|
||||
will use sensible defaults with sizes matching the provided icon images. Here
|
||||
is how you would override the URL of the provided icons if you decided to place
|
||||
them in an `images/` directory:
|
||||
|
||||
```javascript
|
||||
var url = '...'; // URL to your GPX file
|
||||
new L.GPX(url, {
|
||||
async: true,
|
||||
marker_options: {
|
||||
startIconUrl: 'images/pin-icon-start.png',
|
||||
endIconUrl: 'images/pin-icon-end.png',
|
||||
shadowUrl: 'images/pin-shadow.png'
|
||||
}
|
||||
}).on('loaded', function(e) {
|
||||
map.fitBounds(e.target.getBounds());
|
||||
}).addTo(map);
|
||||
```
|
||||
|
||||
## About waypoints
|
||||
|
||||
By default `gpx.js` will parse Waypoints from a GPX file. This may also
|
||||
be steered via the value `waypoint` in `gpx_options`, e.g.
|
||||
`parseElements: ['track', 'route', 'waypoint']`.
|
||||
|
||||
Waypoint icons: by default the `pin-icon-wpt.png` icon is shown for each
|
||||
waypoint. This can be overridden by setting `marker_options.wptIconUrls`
|
||||
in the `L.GPX` constructor options, as a mapping from the waypoint "SYM"
|
||||
name to a user-supplied icon file or URL. The empty string `''` is used
|
||||
by the waypoint tag does not define a "SYM" name. See the example below:
|
||||
|
||||
```javascript
|
||||
new L.GPX(app.params.gpx_url, {
|
||||
async: true,
|
||||
marker_options: {
|
||||
wptIconUrls: {
|
||||
'': 'img/gpx/default-waypoint.png',
|
||||
'Geocache Found': 'img/gpx/geocache.png',
|
||||
'Park': 'img/gpx/tree.png'
|
||||
},
|
||||
...
|
||||
shadowUrl: 'http://github.com/mpetazzoni/leaflet-gpx/raw/master/pin-shadow.png'
|
||||
}
|
||||
}).on('loaded', function (e) {
|
||||
var gpx = e.target;
|
||||
map.fitBounds(gpx.getBounds());
|
||||
}).addTo(map);
|
||||
```
|
||||
|
||||
## Custom markers
|
||||
|
||||
You can also use your own icons/markers if you want to use custom
|
||||
markers, for example from `leaflet-awesome-markers`. To specify you own
|
||||
markers, set `startIcon`, `endIcon`, and a map of `wptIcons` by waypoint
|
||||
symbol (see above). Those should be marker icon objects usable by
|
||||
Leaflet as the `icon` property of a `L.Marker` object.
|
||||
|
||||
```javascript
|
||||
new L.GPX(app.params.gpx_url, {
|
||||
async: true,
|
||||
marker_options: {
|
||||
wptIcons: {
|
||||
'Coffee shop': new L.AwesomeMarkers.icon({
|
||||
icon: 'coffee',
|
||||
prefix: 'fa',
|
||||
markerColor: 'blue',
|
||||
iconColor: 'white'
|
||||
})
|
||||
}
|
||||
}
|
||||
}).on('loaded', function (e) {
|
||||
var gpx = e.target;
|
||||
map.fitBounds(gpx.getBounds());
|
||||
}).addTo(map);
|
||||
```
|
||||
|
||||
## Named points
|
||||
|
||||
GPX points can be named, for example to denote certain POIs (points of
|
||||
interest). You can setup rules to match point names to create labeled
|
||||
markers for those points by providing a `pointMatchers` array in the
|
||||
`marker_options`. Each element in this array must define a `regex` to
|
||||
match the point's name and an `icon` object (any `L.Marker` or
|
||||
for example an `L.AwesomeMarkers.icon` as shown above in _Custom
|
||||
markers_).
|
||||
|
||||
Each named point in the GPX track is evaluated against those rules and
|
||||
a marker is created with the point's name as label from the first
|
||||
matching rule.
|
||||
|
||||
```javascript
|
||||
new L.GPX(app.params.gpx_url, {
|
||||
async: true,
|
||||
marker_options: {
|
||||
pointMatchers: [
|
||||
{
|
||||
regex: /Coffee/,
|
||||
icon: new L.AwesomeMarkers.icon({
|
||||
icon: 'coffee',
|
||||
markerColor: 'blue',
|
||||
iconColor: 'white'
|
||||
}),
|
||||
},
|
||||
{
|
||||
regex: /Home/,
|
||||
icon: new L.AwesomeMarkers.icon({
|
||||
icon: 'home',
|
||||
markerColor: 'green',
|
||||
iconColor: 'white'
|
||||
}),
|
||||
}
|
||||
]
|
||||
}
|
||||
}).on('loaded', function(e) {
|
||||
var gpx = e.target;
|
||||
map.fitToBounds(gpx.getBounds());
|
||||
}).addTo(map);
|
||||
```
|
||||
|
||||
## Events
|
||||
|
||||
Events are fired on the `L.GPX` object as the GPX data is being parsed
|
||||
and the map layers generated. You can listen for those events by
|
||||
attaching the corresponding event listener on the `L.GPX` object:
|
||||
|
||||
```javascript
|
||||
new L.GPX(app.params.gpx_url, {
|
||||
// options
|
||||
}).on('addpoint', function(e) {
|
||||
console.log('Added ' + e.point_type + ' point: ' + e.point);
|
||||
}).on('loaded', function(e) {
|
||||
var gpx = e.target;
|
||||
map.fitToBounds(gpx.getBounds());
|
||||
}).on('error', function(e) {
|
||||
console.log('Error loading file: ' + e.err);
|
||||
}).addTo(map);
|
||||
```
|
||||
|
||||
`addpoint` events are fired for every marker added to the map, in
|
||||
particular for the start and end points, all the waypoints, and all the
|
||||
named points that matched `pointMatchers` rules. Each `addpoint` event
|
||||
contains the following properties:
|
||||
|
||||
- `point`: the marker object itself, from which you can get or modify
|
||||
the latitude and longitude of the point and any other attribute of the
|
||||
marker.
|
||||
- `point_type`: one of `start`, `end`, `waypoint` or `label`, allowing
|
||||
you to identify what type of point the marker is for.
|
||||
- `element`: the track point element the marker was created for.
|
||||
|
||||
One use case for those events is for example to attach additional
|
||||
content or behavior to the markers that were generated (popups, etc).
|
||||
|
||||
`error` events are fired when no layers of the type(s) specified in
|
||||
`options.gpx_options.parseElements` can be parsed out of the given
|
||||
file. For instance, `error` would be fired if a file with no waypoints
|
||||
was attempted to be loaded with `parseElements` set to `['waypoint']`.
|
||||
Each `error` event contains the following property:
|
||||
|
||||
- `err`: a message with details about the error that occurred.
|
||||
|
||||
## Line styling
|
||||
|
||||
`leaflet-gpx` understands the [GPX
|
||||
Style](http://www.topografix.com/GPX/gpx_style/0/2) extension, and will
|
||||
extract styling information defined on routes and track segments to use
|
||||
for drawing the corresponding polyline.
|
||||
|
||||
```xml
|
||||
<trkseg>
|
||||
<extensions>
|
||||
<line xmlns="http://www.topografix.com/GPX/gpx_style/0/2">
|
||||
<color>FF0000</color>
|
||||
<opacity>0.5</opacity>
|
||||
<weight>1</weight>
|
||||
<linecap>square</linecap>
|
||||
</line>
|
||||
</extensions>
|
||||
<trkpt lat="..." lon="..."></trkpt>
|
||||
</trkseg>
|
||||
```
|
||||
|
||||
You can override the style of the lines by passing a `polyline_options`
|
||||
object into the `options` argument of the `L.GPX` constructor:
|
||||
|
||||
```javascript
|
||||
new L.GPX(url, {
|
||||
polyline_options: {
|
||||
color: 'green',
|
||||
opacity: 0.75,
|
||||
weight: 3,
|
||||
lineCap: 'round'
|
||||
}
|
||||
}).on('loaded', function(e) {
|
||||
var gpx = e.target;
|
||||
map.fitToBounds(gpx.getBounds());
|
||||
}).addTo(map);
|
||||
```
|
||||
|
||||
For more information on the available polyline styling options, refer to
|
||||
the [Leaflet documentation on
|
||||
Polyline](https://leafletjs.com/reference-1.3.0.html#polyline). By
|
||||
default, if no styling is available, the line will be drawn in _blue_.
|
||||
|
||||
## GPX parsing options
|
||||
|
||||
### Multiple track segments within each track
|
||||
|
||||
GPX file may contain multiple tracks represented by `<trk>` elements,
|
||||
each track possibly composed of multiple segments with `<trkseg>`
|
||||
elements. Although this plugin will always represent each GPX route and
|
||||
each GPX track as distinct entities with their own start and end
|
||||
markers, track segments will by default be joined into a single line.
|
||||
|
||||
You can disable this behavior by setting the `joinTrackSegments` flag to
|
||||
`false` in the `gpx_options`:
|
||||
|
||||
```javascript
|
||||
new L.GPX(url, {
|
||||
gpx_options: {
|
||||
joinTrackSegments: false
|
||||
}
|
||||
}).on('loaded', function(e) {
|
||||
map.fitBounds(e.target.getBounds());
|
||||
}).addTo(map);
|
||||
```
|
||||
|
||||
## Caveats
|
||||
|
||||
* Distance calculation is relatively accurate, but elevation change
|
||||
calculation is not topographically adjusted, so the total elevation
|
||||
gain/loss/change might appear inaccurate in some situations.
|
||||
* Currently doesn't seem to work in IE8/9. See #9 and #11 for
|
||||
discussion.
|
||||
Reference in new issue
Block a user