Git Product home page Git Product logo

leaflet-gpx's Introduction

GPX plugin for Leaflet

CDNJS

Leaflet is a Javascript library for displaying interactive maps. This plugin, based on the work of Pavel Shramov and his 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.

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>
  <head>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.css" />
    <!-- ... -->
  </head>
  <body>
    <!-- ... -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-gpx/1.7.0/gpx.min.js"></script>
  </body>
</html>

Now, let's consider we have a Leaflet map:

var map = L.map('map');
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  attribution: 'Map data &copy; <a href="http://www.osm.org">OpenStreetMap</a>'
}).addTo(map);

Displaying a GPX track on it is as easy as:

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_speed_max(): returns the maximum speed in km per hour
  • 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
  • get_speed_max_imp(): returns the maximum speed in miles per hour

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_speed_data and get_speed_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:

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 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:

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:

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.

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. This also applies to named waypoints, but keep in mind that waypoint icons rules take precedence over point matchers.

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:

new L.GPX(app.params.gpx_url, async: true, {
  // 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);

Note that for your event listeners to be correctly triggered, you need to pass async: true to the L.GPX constructor; otherwise the parsing of the GPX happens synchronously in the constructor before you your event listeners get registered!

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 extension, and will extract styling information defined on routes and track segments to use for drawing the corresponding polyline.

<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>
      <linejoin>square</linejoin>
      <dasharray>0,10</dasharray>
      <dashoffset>3</dashoffset>
    </line>
  </extensions>
  <trkpt lat="..." lon="..."></trkpt>
</trkseg>

You can override the style of the lines by passing a polyline_options array into the options argument of the L.GPX constructor, each element of the array defines the style for the corresponding route and/or track in the file (in the same order).

new L.GPX(url, {
  polyline_options: [{
    color: 'green',
    opacity: 0.75,
    weight: 3,
    lineCap: 'round'
  },{
    color: 'blue',
    opacity: 0.75,
    weight: 1
  }]
}).on('loaded', function(e) {
  var gpx = e.target;
  map.fitToBounds(gpx.getBounds());
}).addTo(map);

If you have many routes or tracks in your GPX file and you want them to share the same styling, you can pass polyline_options as a single object rather than an array (this is also how leaflet-gpx worked before the introduction of the array):

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. 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:

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.

leaflet-gpx's People

Contributors

agorf avatar alessiogiambrone avatar astridx avatar brazacz avatar brotkrueml avatar burgalon avatar comptuzus avatar dave-p avatar dayofr avatar dj-bauer avatar f-fl0 avatar jeffstep avatar justb4 avatar kaueraal avatar kennynaoh avatar martinruenz avatar molnarm avatar mpetazzoni avatar mrothauer avatar peterdavehello avatar quelbs avatar rkusa avatar skogar42 avatar stefanclark avatar stefanocudini avatar velocat avatar ward avatar zeckfr avatar znegva avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

leaflet-gpx's Issues

Compatibility with leaflet 1.5.1

I've tried implementing the example code, but I use leaflet 1.5.1. I get an error when

this.callInitHooks()

is called (not defined error) after this.initialize && this.initialize.apply(this, arguments). I'm not well versed in Javascript or in the internals of leaflet, so I'm open to any idea on how to solve that issue. My input is directly the proper GPX data.

Expose points coordinates

Assuming that the gpx file is always composed of a single line.
How can I get the coordinates of the last point on the track?

Question regarding preview gpx on marker hover

I have a question regarding leaflet-gpx.

I am using Leaflet.markercluster for displaying many routes. What I am trying to achieve is that if a user 'mouse-over' an marker the GPX track is shown.

My code for displaying the clustering is:

    var markers = L.markerClusterGroup();
    for (var i = 0; i < markers_var.length; i++) {
        var a = markers_var[i];
        var title = a[3];
        var gpxfile= a[2];
  ` 
        var marker = L.marker(new L.LatLng(a[0], a[1]), {
        
            title: title
        });
      
        marker.bindPopup(title);
        markers.addLayer(marker);
  

        marker.on('mouseover', function (e)
{
*********How can I get the GPX (this is  **gpxfile= a[2];**  displayed?*******
  });

gpx color displayed

hello,
I got a map with several paths, I can't figure how to change the color
any pointers ?
thanks

Custom size for wpt

Hi team,

Thank you for your work with this great plugin. I'm building a trekking map and want to identify each track with a different icon mapped from GPX "sym" data. That was ok, but I would like to custom set the size of the wpt icon (green in the middle of the track) and I could´t, after trying in many ways. Can you help me with that? Thank you!!!! Hernán

http://southmedia.com.ar/mapselchaltentrekking/test-wpt.html

Trekking Map

Here is where I´m trying to set different color wpt icons:

	// Load GPX Tacks
	
		var tracks = [
			["/mapselchaltentrekking/maps/gpx/track-20.gpx", "#f48024", "4", "", "", ""],
			["/mapselchaltentrekking/maps/gpx/test-wpticon.gpx", "#f48024", "4", "", "", ""],
		];
				
		function loadGpx(item, index) {
			var g = new L.GPX(item[0], { 
				async: true,
				parseElements: ['track'],
				polyline_options: {
					weight: item[2],
					color: item[1],
					fillOpacity: 1
				},
				marker_options: {
					startIconUrl: item[4],
					endIconUrl: item[5],				
					iconSize: [40, 40],
					iconAnchor: [20, 40],
					shadowSize: [0, 0],
					shadowAnchor: [0, 0],
					wptIconUrls: {
					'green': '/mapselchaltentrekking/maps/iconos/sendero-green.png',
					}
				}
			});						
					

			g.on('loaded', function(e) {
				var gpx = e.target,
				name = gpx.get_name(),
				distM = gpx.get_distance(),
				distKm = distM / 1000,
				distKmRnd = distKm.toFixed(1),
				eleGain = gpx.get_elevation_gain().toFixed(0),
				eleLoss = gpx.get_elevation_loss().toFixed(0),
				eleDiff = gpx.get_elevation_max().toFixed(0) - gpx.get_elevation_min().toFixed(0);
				var info = "<b>" + name + "</b></br>" + "Distancia: <b>" + distKmRnd + " km </b></br>" + "Desnivel: <b>" + eleDiff + " m </b></br> <a target=" + "'" + "_parent" + "'" + "href=" + "'" + item[3] + "'"  + ">+ info</a>"

Trekking Map2

Below is html code:

<title>Trekking Map</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />

<!-- Stylesheet (CSS) -->

<link rel="stylesheet" href="/mapselchaltentrekking/maps/style/mapa-general.css" />

<!-- Font-Awesome (CSS) -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" />

<!-- Leaflet (JS/CSS) -->
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" />
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>

<!-- leaflet-geometryutil -->
<script src="https://unpkg.com/[email protected]/src/leaflet.geometryutil.js"></script>

<!-- Leaflet-fullscreen (JS/CSS) -->
<script src='https://api.mapbox.com/mapbox.js/plugins/leaflet-fullscreen/v1.0.1/Leaflet.fullscreen.min.js'></script>
<link href='https://api.mapbox.com/mapbox.js/plugins/leaflet-fullscreen/v1.0.1/leaflet.fullscreen.css' rel='stylesheet' />

<!-- D3.js (JS) -->
<script src="https://unpkg.com/[email protected]/build/d3.min.js" charset="utf-8"></script>

<!-- leaflet-gpx (JS) -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-gpx/1.4.0/gpx.js"></script>

<!-- leaflet-easyButton (JS/CSS) -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet-easybutton@2/src/easy-button.css">
<script src="https://cdn.jsdelivr.net/npm/leaflet-easybutton@2/src/easy-button.js"></script>

</head>
<body>
    <!-- Map div -->
    <div id="map" style="height: 100% !important;"></div>
    
    <!-- Main Script -->
    <script>
    
        // Map Setup
		var opts = {
    		map: {
	    		center: [-48.979325, -72.827558],
		    	zoom: 12.5,
				markerZoomAnimation: false,
    			zoomControl: true,
    			attributionControl: false
	    	},
			
    		osmLayer: {
			    url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
			    options: {
				    maxZoom: 18,
				    attribution: 'Map data: &copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
			    }
		    },
		    
		    otmLayer: {
			url: 'https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png',
			    options: {
				    maxZoom: 18,
				    attribution: 'Map data: &copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>, <a href="http://viewfinderpanoramas.org">SRTM</a> | Map style: &copy; <a href="https://opentopomap.org">OpenTopoMap</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)',
			    },
		    },
    
		    layersControl: {
			    options: {
			    	position: 'topright',
			    	collapsed: true,
		    	},
		    },
		    
		    scale: {
		        maxWidth: 100,
		        metric: true,
		        imperial: false,
		    },
		    
		    fullscreenControl: {
		        title: {
                    'false': 'Pantalla Completa',
                    'true': 'Salir de Pantalla Completa'
                 }
		    }
	    };
	    
	    // Define Icons
	    var iconSize = [20, 20];
	    var shadowSize = [34, 34];
		var iconAnchor = [10, 10];
		var shadowAnchor = [17, 17];

	<!-- Camping Area -->	
		var CampIcon = L.icon({
			iconUrl: '/mapselchaltentrekking/maps/iconos/camp.png',
			iconSize: [iconSize[0], iconSize[1]],
			iconAnchor: [iconAnchor[0], iconAnchor[1]],
			shadowUrl: '/mapselchaltentrekking/maps/iconos/icono-shadow.png',
			shadowSize: [shadowSize[0], shadowSize[1]],
			shadowAnchor: [shadowAnchor[0], shadowAnchor[1]]
		});	

	<!-- Gendarmeria -->	
		var GendaIcon = L.icon({
			iconUrl: '/mapselchaltentrekking/maps/iconos/genda.png',
			iconSize: [iconSize[0], iconSize[1]],
			iconAnchor: [iconAnchor[0], iconAnchor[1]],
			shadowUrl: '/mapselchaltentrekking/maps/iconos/icono-shadow.png',
			shadowSize: [shadowSize[0], shadowSize[1]],
			shadowAnchor: [shadowAnchor[0], shadowAnchor[1]]
		});				
		
	<!-- Internacional border-->	
		var PasointIcon = L.icon({
			iconUrl: '/mapselchaltentrekking/maps/iconos/pasoint.png',
			iconSize: [iconSize[0], iconSize[1]],
			iconAnchor: [iconAnchor[0], iconAnchor[1]],
			shadowUrl: '/mapselchaltentrekking/maps/iconos/icono-shadow.png',
			shadowSize: [shadowSize[0], shadowSize[1]],
			shadowAnchor: [shadowAnchor[0], shadowAnchor[1]]
		});	

	    
	// Load GPX Tacks
	
		var tracks = [
			["/mapselchaltentrekking/maps/gpx/track-20.gpx", "#f48024", "4", "", "", ""],
			["/mapselchaltentrekking/maps/gpx/test-wpticon.gpx", "#f48024", "4", "", "", ""],
		];
				
		function loadGpx(item, index) {
			var g = new L.GPX(item[0], { 
				async: true,
				parseElements: ['track'],
				polyline_options: {
					weight: item[2],
					color: item[1],
					fillOpacity: 1
				},
				marker_options: {
					startIconUrl: item[4],
					endIconUrl: item[5],				
					iconSize: [40, 40],
					iconAnchor: [20, 40],
					shadowSize: [0, 0],
					shadowAnchor: [0, 0],
					wptIconUrls: {
					'green': '/mapselchaltentrekking/maps/iconos/sendero-green.png',
					}
				}
			});						
					

			g.on('loaded', function(e) {
				var gpx = e.target,
				name = gpx.get_name(),
				distM = gpx.get_distance(),
				distKm = distM / 1000,
				distKmRnd = distKm.toFixed(1),
				eleGain = gpx.get_elevation_gain().toFixed(0),
				eleLoss = gpx.get_elevation_loss().toFixed(0),
				eleDiff = gpx.get_elevation_max().toFixed(0) - gpx.get_elevation_min().toFixed(0);
				var info = "<b>" + name + "</b></br>" + "Distancia: <b>" + distKmRnd + " km </b></br>" + "Desnivel: <b>" + eleDiff + " m </b></br> <a target=" + "'" + "_parent" + "'" + "href=" + "'" + item[3] + "'"  + ">+ info</a>"

				// Register popup on click
				gpx.getLayers()[0].bindPopup(info)
				
				// Mouseover Style;
				gpx.getLayers()[0].on('mouseover', function(e) {
					gpx.getLayers()[0].setStyle({
						weight: 4,
						color: '#71a0b4',
						fillOpacity: 0.8,
					});
					gpx.getLayers()[0].bringToFront();
				});
				gpx.getLayers()[0].on('mouseout', function(e) {
					gpx.getLayers()[0].setStyle({
						weight: 3,
						color: item[1],
						fillOpacity: 1
					});
				});
			});
			g.addTo(map);
		};

	// Define Map Elements
		var info = "Name: ";
		var map = new L.Map('map', opts.map);
		var baseLayers = {};
		baseLayers["Base"] = new L.TileLayer(opts.osmLayer.url, opts.osmLayer.options);
		baseLayers["Topografico"] = new L.TileLayer(opts.otmLayer.url, opts.otmLayer.options);
		var controlLayer = L.control.layers(baseLayers, null, opts.layersControl.options);
		var controlFullscreen = new L.Control.Fullscreen(opts.fullscreenControl)
		 
		// Load Map
		L.control.scale(opts.scale).addTo(map);
		controlFullscreen.addTo(map);
		controlLayer.addTo(map);
		L.easyButton('fa-home', function(btn, map){CenterMap(opts.map.center[0], opts.map.center[1], opts.map.zoom);}, 'Centrar').addTo(map);
		map.addLayer(baseLayers["Base"]);
		tracks.forEach(loadGpx);		

	// Load Pop-ups 
		<!-- Camping Punta Norte -->	
        var CampLocation = new L.LatLng(-48.999689, -72.838008);
        L.marker(CampLocation, {icon: CampIcon}).addTo(map).bindPopup("Campamento<br><b>Punta Norte</b>");

		<!-- Gendarmeria Punta Norte -->	               
        var GendaLocation = new L.LatLng(-48.998940, -72.839430);
        L.marker(GendaLocation, {icon: GendaIcon}).addTo(map).bindPopup("Gendarmería<br><b>Punta Norte</b>");			
		
		<!-- Paso Internacional Dos Lagunas-->			
        var PasointLocation = new L.LatLng(-48.960076, -72.815826);
        L.marker(PasointLocation, {icon: PasointIcon}).addTo(map).bindPopup("Paso Internacional<br><b>Dos Lagunas</b>");
		
	
    </script>
</body>

GPX Style extension should also be parsed from the <trk> element

I am fairly sure the placement of the color option parsing code is at the wrong tag:
https://github.com/mpetazzoni/leaflet-gpx#line-styling

unfortunately https://www.topografix.com/GPX/gpx_style/0/2 mandates no clear place where to put this

I arrived at this by analogy - have a look at some of the GPX files on github, eg

https://github.com/mapbox/togeojson/blob/72957d69545ed1f798d56618694473b603a0ba6f/test/data/style.gpx
https://github.com/hsnetzer/gpx-pinhoti/blob/76bdf95095ec0f42521a3c94dac29ceb7824aa3b/B.gpx

or search for https://github.com/search?q=www.topografix.com%2FGPX%2Fgpx_style%2F0%2F2+line+color+trk&type=Code for more examples

Ignore segments feature proposal

First of all, thank you for your great library :)

I have some GPX files with several segments (<trkseg></trkseg> tags), which results in several start and end icons being displayed on the map, and gaps in the displayed track.

Would it make sense to add an option that would only show one track, and with only one start icon (the start point of the first track segment) and one end icon on the map (the end point of the last track segment)? This option could be called like ignoreSegments (with the false value by default).

If you think this is overkill, feel free to close this issue, and I will edit my GPX files instead.
To the contrary, if you think that could be an interesting feature, I can open a PR implementing it.

Request: min-max altitude

Hi Mr Petazzoni,
thx for this wonderful plugin. I've a request, is possible to add 2 handlers, like get_elevation_max and get_elevation_min? For hiking is good to show a maxim and minium altitude for a path. Now i can see only elevation gain or loss, is good but not enough.
thank you

Not able to show the .gpx on the map

Hello, I cannot show a gpx on the map.

I installed your library in my project with npm i leaflet-gpx.

I donwloaded a london map (https://pogo.arspoofing.com/gpx/23-london-1-england-united-kingdom) and rename it as london.gpx.

My code:
map.component.ts:


import { AfterViewInit, Component, OnInit } from '@angular/core';
import * as L from 'leaflet-gpx';

@Component({
  selector: 'app-map',
  templateUrl: './map.component.html',
  styleUrls: ['./map.component.scss']
})

export class MapComponent implements OnInit {
  private map;
  constructor() { }

  ngOnInit() {
    var map = L.map('map').setView([51.505, -0.09], 13);
    L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      attribution: 'Map data &copy; <a href="http://www.osm.org">OpenStreetMap</a>'
    }).addTo(map);

    var gpx = 'C:/xampp/htdocs/leaflet-example/src/app/map/london.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);
    
    this.map = map;
  }
}

map.component.html

<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>
<div class="map-container">
    <div class="map-frame">
      <div id="map"></div>
    </div>
  </div>

But I am just able to see the map without the track.

mapWithoutTraking

Any idea?

Thanks a million

Show track "name" on marker click

Looking at the code, it seems that you can define marker_options and set clickable to true.

However, this doesn't appear to have any effect. I'd ideally want to be able to show the track (trk) name and maybe even more information about the track on mouse click.

Is this already possible? If not, how could this be added?

wptIcons is missing in _DEFAULT_MARKER_OPTS

Hi,

the wptIcons property is missing in the _DEFAULT_MARKER_OPTS, this leads to a js error if marker_options are specified without wptIcons and GPX track contains waypoints.

cheers,

There is no real error checking or file validation

When I try to give this a file which is not a gpx file (for example a jpeg or a cvs file) I get errors that show that no real validation is happening:

gpx.js:262 Uncaught DOMException: Failed to execute 'open' on 'XMLHttpRequest': Invalid URL
    at e._load_xml (http://test.localhost:8021/static/bow/leaflet-gpx/gpx.js:262:9)
    at e._parse (http://test.localhost:8021/static/bow/leaflet-gpx/gpx.js:291:12)
    at e.initialize (http://test.localhost:8021/static/bow/leaflet-gpx/gpx.js:91:12)
    at new e (http://test.localhost:8021/static/bow/leaflet/dist/leaflet.js:5:2745)
    at FileReader.<anonymous> (http://test.localhost:8021/kalendar/:600:19)
gpx.js:270 GET http://test.localhost:8021/kalendar/-----BEGIN%20PGP%20PUBLIC%20KEY%20BLOCK…gg70ajn5b5VHPvrw3poywoe/Q===Ct9S-----END%20PGP%20PUBLIC%20KEY%20BLOCK----- 414 (Request-URI Too Long)

Demo doesn't work

I tried the demo, yet it didn't work. Chrome inspector showed quite some errors.

working with geoJSON

Does anyone have experience using this with geoJSON? I suspect there are ways to convert geoJSON to CPX files.

It would a great feature if this plugin supported geoJSON. A specific object format would be great and then different use cases could provide their data into that format.

For example I have the following data:

{
    "time": "2014-05-12T16:55:02+0000",
    "location": {
      "type": "Point",
      "coordinates": [-70.222, 42.123]
    },
    "speed": 5400.0,
    "altitude": 14.67527198791504,
    "tripId": "1399913694471-c258e6ce-667e-4749-a3a4-ae93f00e56a6"
  }

Start-End icons obscuring map features

Even with a blank, transparent default png a large blank box remains on the map. I'm plotting multiple maps with common start-end points and the result is 10 overlapping empty boxes that obscure other map features. I'll log a pull request to add a feature to specify no start-end icons.

Very pleased with the results I've gotten with the extension.
Thank You!

GPX Tracks

Thr Leaflet plugin will not import this test gpx. Does the gpx track have to be formatted differently as I can read it on another gpx add-in?

Thanks



WGS84 Route 23/6/2016 11:42:54

00000000491
Point 1
Point 1: Pos: 48.374, 10.895


00000000490
Point 2
Point 2: Pos: 48.373, 10.893


00000000491
Point 3
Point 3: Pos: 48.372, 10.894


00000000489
Point 4
Point 4: Pos: 48.372, 10.894


00000000486
Point 5
Point 5: Pos: 48.372, 10.895


00000000487
Point 6
Point 6: Pos: 48.371, 10.895


00000000487
Point 7
Point 7: Pos: 48.371, 10.896


00000000484
Point 8
Point 8: Pos: 48.37, 10.896


00000000485
Point 9
Point 9: Pos: 48.37, 10.894


00000000490
Point 10
Point 10: Pos: 48.37, 10.893


00000000493
Point 11
Point 11: Pos: 48.368, 10.889


00000000496
Point 12
Point 12: Pos: 48.367, 10.889


00000000490
Point 13
Point 13: Pos: 48.367, 10.887


00000000488
Point 14
Point 14: Pos: 48.366, 10.887


Load event may get lost

The example code of the readme is:

new L.GPX(gpx, {async: true}).on('loaded', function(e) {
  map.fitBounds(e.target.getBounds());
}).addTo(map);

To me this looks like a race condition. If the constructor of L.GPX can load its data fast enough then the "loaded" event may get fired before the event handler is attached via on(..). I think you somehow try to work around that for the case when the XML is directly handed over (which would make it a blocking operation) by using setTimeout(..) without a delay value. But still, this doesn't solve the fundamental problem.

A possible way to solve this problem is to delay the loading until the object gets added to the map. This can be done by overloading the onAdd(map) method of the class and doing the loading there, essentially calling this._parse(gpx, options, this.options.async), and probably inside _parse calling the onAdd method of the parent class when done loading.

reload() error?

Hi. The function gpx.reload() in setInterval "(setInterval(function() { gpx.reload();}, 3000); " only works the first cycle, then runs continuously, is an error in my code? Thank you

loaded event not firing

I tried running the simple example in the readme, and also tried copying your demo file to my system (and to my remote site). In all cases the 'loaded' event of new 'L.GPX' doesn't get fired (I debugged with Chrome, and Firefox). Tried with my own gpx file and your demo one, all in same folder as index.html - same result each time. Yet it clearly does get fired when I run the demo on your own site.
Clearly I'm doing something fundamentally wrong but I can't see what!

GPX with Leaflet.PolylineOffset

Hi, is it possible to use PolylineOffset with a GPX track, because that plugin adds offset capabilities to a L.Polyline class.? I intend to add a parallel line to the track path. In that case, is there any code example o demo I can take a look to? Thank you!

GPX not display

Hello,

I encounter a problem with the plugin. When I start my html page, the gpx isn't display.
What can i do ?

Thanks in advance.

Default waypoint marker

When a waypoint is of unknown type a sane default icon should be used.

diff --git a/gpx.js b/gpx.js
index fcc4ce0..a6b57ca 100644
--- a/gpx.js
+++ b/gpx.js
@@ -342,6 +342,8 @@ L.GPX = L.FeatureGroup.extend({
         var symIcon;
         if (options.marker_options.wptIcons && options.marker_options.wptIcons[symKey]) {
           symIcon = options.marker_options.wptIcons[symKey];
+       } else if (options.marker_options.wptIcons && options.marker_options.wptIcons['']) {
+          symIcon = options.marker_options.wptIcons[''];
         } else if (options.marker_options.wptIconUrls && options.marker_options.wptIconUrls[symKey]) {
           symIcon = new L.GPXTrackIcon({iconUrl: options.marker_options.wptIconUrls[symKey]});
         } else {

Calculate max speed from gpx file

Hi team,

thank you for creating this perfect plugin. I like it, and its being used to display windsurfing and kitesurfing tracks of our registered users. The only thing which I'm missing is to be able to caluclate the max speed from the GPX data. Would it be please possible to add this calculation it into gpx.js?

Thank you!!
Martin

Release a new version?

Hi, are there any plans for a release anytime soon? The version available on the npm registry does not support gpx_options.joinTrackSegments.

get_elevation_gain / get_elevation_loss

Hi there!

I'm happily using this library for my routes (https://yamila-moreno.github.io/routes); I was using it to get the distance, which is very accurate.

Recently I wanted to add get_elevation_gain and loss to the description of my routes, and I found that the result of those functions is not the real gain or loss; I didn't find any consistency in the error (sometimes the given result is 4 times smaller than the real gain, and sometimes is 6 or other...). I tried to understand how is it calculated without any success.

This is the way I get the elevation:

var gain = (e.target.get_elevation_gain() / 10).toFixed(0);
var loss = (e.target.get_elevation_loss() / 10).toFixed(0);

is this correct? any help would be very appreciated. Thank you for your awesome library :)

Impossible to load not well-formed GPX

I want to show on the map a GPX, which is being recorded right now. This GPX does not have closing tags, of course. So I have a "XML Parsing Error: no root element found".

Demo cannot work with google chrome

Int the console report the following error :

Uncaught ReferenceError: global is not defined(anonymous function) @ gpx.js:41
(index):93 Uncaught TypeError: L.GPX is not a constructordisplay_gpx @ (index):93(anonymous function) @ (index):118

Support for multiple GPX tracks from the same file

Hi and thank you for your wonderful job.

I have some GPX files with two tracks inside. When I load them with your plugin, I have only one line drawn on the map, instead of two. That is odd because points of two tracks should not be connected.

What do you think ?

Distance from start to a point on the track

I would like to implement a feature in my own project where you can click on a point on the gpx track, and have a pop-up showing the cumulative distance up to that point, and maybe some point information like elevation.

I think this will require some changes in this library, and this is how I'm thinking of implementing it. I would appreciate any feedback you may have.

I can follow the same design as the _info.elevation._points, and have a new structure for the cumulative distance up to that point.

The Polyline onclick event returns the latlng of where it was clicked. I can lookup the _points array index in a Hashmap, which is generated when processing the trk data. The hashmap can have key = latlng and value = [array indexes]. It's possible that there could be multiple points at the same latlng, which is why the value is an array.

A new event on the GPX object should be triggered when the polyline onclick is triggered. It should also give the array indexes so that the user can lookup the relevant data from the arrays.

So the additions to the library would be:

  • cumulative_distance structure that at least stores a _pts array with the data and API to access the data
  • Hashmap to store array indexes given a latlng
  • handle Polyline onclick event and generate a new event with array indexes

Then in my own project, I can register on the GPX track click event, lookup the data with the array indexes, and generate a pop-up.

IE8 compatibility

On IE8 the XML isn't loaded into the responseXML object of the XMLHttpRequest but in response with the content type set to text/xml. The loading handler should be changed to something like this:

req.onreadystatechange = function() {
  if (req.readyState != 4) return;
  if (req.status == 200) {
      if (req.responseXML) {
          cb(req.responseXML, options);
      } else {
          try{
              var parser = new DOMParser();
              cb(parser.parseFromString(req.response, "text/xml"), options);
          } catch (e) {
              console.log(e);
          }
      }
  }
};

Show multiple GPX files

Is it possible to show an entire folder of GPX files in one map, instead of showing just one GPX?

Also, is it possible to dynamically remove and add tracks, depending on the date I pass to my function?

Question: Editing GPX

Could the GPX be edited by a draw control for example https://github.com/Leaflet/Leaflet.draw.

I tried the following code but it did not appear to work. The GPX displays fine but the draw control cannot edit it?

var gpxLayer = new L.GPX(gpx, {async: true});
        gpxLayer.on('loaded', function(e) { map.fitBounds(e.target.getBounds());}); 
        map.addLayer(gpxLayer);

    var options = {
        position: 'topleft',
        draw : {
            polygon: false,
            circle: false,
            rectangle: false,
            marker: false,
            line: false
        },

        edit: {
            featureGroup: gpxLayer,
            remove: false
        }
    };

    var drawControl = new L.Control.Draw(options);
    map.addControl(drawControl);

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"
I have the POIs file like this:

  <wpt lat="60.2068333" lon="25.7541667">
    <time>2011-11-08T20:32:40Z</time>
    <name>Aggskar</name>
    <sym>Beach</sym>
    <extensions>
      <gpxx:WaypointExtension xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3">
        <gpxx:DisplayMode>SymbolAndName</gpxx:DisplayMode>
      </gpxx:WaypointExtension>
    </extensions>
  </wpt>

  <wpt lat="55.9259326" lon="14.3052798">
    <time>2013-03-08T12:31:11Z</time>
    <name>Ahus</name>
    <cmt>150-200kr EWTDA Inet</cmt>
    <desc>150-200kr EWTDA Inet</desc>
    <sym>Marina</sym>
    <extensions>
      <gpxx:WaypointExtension xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3">
        <gpxx:DisplayMode>SymbolAndName</gpxx:DisplayMode>
      </gpxx:WaypointExtension>
    </extensions>
  </wpt>

First, the type of point are specified by <sym> </sym> tags.
Second, the custom marker are specified by

    <gpxx:WaypointExtension xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3">
       <gpxx:DisplayMode>SymbolAndName</gpxx:DisplayMode>
     </gpxx:WaypointExtension>

extension.

My question is:
Is it possible to match <sym> </sym> tags to create labeled markers?
and/or
Is it possible add support Garmin gpxx extensions?

Next question:
Is there a way to add a popup from <desc></desc> tags to labeled marker?

Is there a way to add a marker for every 1 km/ mile?

I would like to use Leafletjs and your plugin for our running club, and I have both leafletjs and your plugin running - I would like however to be able to display a numbered marker for every 1 km along the track.

Is this possible with Leafletjs and (or) your plugin?

KM markers?

Hi,
Thanks for your amazing work on this plugin, absolutely fantastic.

Not an issue so much as something I'm trying to figure out; I'd like to display an icon at every km (or mile or whatever). Is this possible at the moment? I know you've already got code to figure out the total distance so I was just wondering if that was made available as each point is plotted? Or if you'd have any tips on how to pull it off (happy to make a PR)

Track colors

Hi,
I have multiple GPX to show on maps. Is possibile? And can I choose the color for each track on map?

Thanks,
Marco

Distance off by factor 2, route drawn twice

I have a GPX file which contains data for a "route" three times: as <wpt>s, as <rte> and as <trk> with one <trkseg>. If I load and display this file, the same route is drawn twice (darker blue than usual) and the reported get_distance() is off by a factor of two, presumably because both <rtept>s and <trkpt>s are parsed. I 'fixed' this problem for me by removing the ['trkseg', 'trkpt'] bit from the tags variable. Would it be possible/worth it to handle this situation automatically?

[QUESTION] Integrate leaflet-gpx with leaflet-awesome-markers

Hi! I'm using this library for the first time. It's fantastic, thank you very much :D

I'm having troubles integrating leaflet-gpx marker with leaflet-awesome-markers. My goal is that the startIcon of the gpx can be a font-awesome-icon (with custom icons and so).

This is the code I'm trying to make work:

    var myIcon = L.AwesomeMarkers.icon({
        icon: 'coffee',
        prefix: 'fa',
        markerColor: 'blue',
        iconColor: 'white'
    }); 
    var gpx = new L.GPX(gpx, {
         async: false,
         marker_options: {
                    icon: myIcon,
                    startIconUrl: null,
                    endIconUrl: null,
                    shadowUrl: null
          }     
    }); 

Best

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.