mpetazzoni / leaflet-gpx

A GPX track plugin for Leaflet.js
http://mpetazzoni.github.io/leaflet-gpx
BSD 2-Clause "Simplified" License
545 stars 118 forks source link

Zoom to GPX tracks #104

Closed mjut closed 3 years ago

mjut commented 3 years ago

I have multiple gpx-tracks loaded into a map. I place all of them (in a for each loop) with this:

gpxTrack.addTo(map);

It is working as expected. Now, I want to center the map to show all the tracks. I know, there is this:

on('loaded', function(e) {
    var gpxTrack = e.target;
    map.fitToBounds(gpxTrack.getBounds());
});

But this is not working, as I have multiple gpx-tracks.

My code looks like this:

var init = function() {

    var map = new L.Map('map', {
        crs: L.CRS.EPSG900913,
        continuousWorld: true,
        worldCopyJump: false,
        center: [52.2639817,9.49812629450324],
        zoom: 13,
    }),

    osmWms = L.tileLayer.grayscale('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
        attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
    });
    osmWms.addTo(map);

////////
// Tracks

            // Trail-Grade
            var easy = "#00998a"; //green
            var intermediate = "#42a6ba"; //blue
            var hard = "#89242a"; //red
            var wow = "#25252b"; //black

            var grade = easy; // easy / intermediate / hard / wow

            var pathGpxTrack = '/site/assets/files/1093/track1.gpx',
                markerOptions = {
                    startIconUrl: "/site/templates/js/pins/play-circle-regular.svg",
                    endIconUrl: null,
                    shadowUrl: null,
                };

            // bring track to map
            var url = '/site/assets/files/1093/track1.gpx'; // URL to your GPX file

            var gpxTrack = new L.GPX('/site/assets/files/1093/track1.gpx', {
                async: true,
                max_point_interval: 120000,
                polyline_options: {
                    color: grade,
                    weight: 4,
                    lineCap: "round",
                },
                marker_options: {
                    startIconUrl: "/site/templates/js/pins/play-circle-regular.svg",
                    endIconUrl: null,
                    shadowUrl: null,
                },
            });
            // add the gpx layer to the map
            gpxTrack.addTo(map);

            // register popups on click
            // set initial zoom
            gpxTrack.on("loaded", function (e) {
                var gpx = e.target,
                    distM = gpx.get_distance(),
                    distKm = distM / 1000,
                    distKmRnd = distKm.toFixed(1),
                    eleGain = gpx.get_elevation_gain().toFixed(),
                    eleLoss = gpx.get_elevation_loss().toFixed(),
                    name = gpx.get_name();

                gpx
                    .getLayers()[0]
                    .bindPopup(
                        "<h5>Jägermeister 1</h5>" +
                        "Strecke " + distKmRnd + " km </br>" +
                        "Höhenmeter " + eleGain + " m </br>" +
                        "Tiefenmeter " + eleLoss +  " m"
                    );
            });

            // Trail-Grade
            var easy = "#00998a"; //green
            var intermediate = "#42a6ba"; //blue
            var hard = "#89242a"; //red
            var wow = "#25252b"; //black

            var grade = easy; // easy / intermediate / hard / wow

            var pathGpxTrack = '/site/assets/files/1094/track2.gpx',
                markerOptions = {
                    startIconUrl: "/site/templates/js/pins/play-circle-regular.svg",
                    endIconUrl: null,
                    shadowUrl: null,
                };

            // bring track to map
            var url = '/site/assets/files/1094/track2.gpx'; // URL to your GPX file

            var gpxTrack = new L.GPX('/site/assets/files/1094/track2.gpx', {
                async: true,
                max_point_interval: 120000,
                polyline_options: {
                    color: grade,
                    weight: 4,
                    lineCap: "round",
                },
                marker_options: {
                    startIconUrl: "/site/templates/js/pins/play-circle-regular.svg",
                    endIconUrl: null,
                    shadowUrl: null,
                },
            });
            // add the gpx layer to the map
            gpxTrack.addTo(map);

            // register popups on click
            // set initial zoom
            gpxTrack.on("loaded", function (e) {
                var gpx = e.target,
                    distM = gpx.get_distance(),
                    distKm = distM / 1000,
                    distKmRnd = distKm.toFixed(1),
                    eleGain = gpx.get_elevation_gain().toFixed(),
                    eleLoss = gpx.get_elevation_loss().toFixed(),
                    name = gpx.get_name();

                gpx
                    .getLayers()[0]
                    .bindPopup(
                        "<h5>Title</h5>" +
                        "Strecke " + distKmRnd + " km </br>" +
                        "Höhenmeter " + eleGain + " m </br>" +
                        "Tiefenmeter " + eleLoss +  " m"
                    );
            });

// configure and add a layer-switcher
var overlays = {
},
background = {
};

// This is not working:
//on('loaded', function(e) {
//  var gpxTrack = e.target;
//  map.fitToBounds(gpxTrack.getBounds());
//});

}

This is two tracks loading into the map. But the position and zoom of the map is hard coded. My aim is to automatically zoom and position the map to the tracks.

Any suggestions or hints that lead me into the right direction?

Thanks a lot for your help,

Stephan

ibrierley commented 3 years ago

Is this the sort of thing you mean https://mappy.dabbles.info/ ? This is a little site I do for my walks, and it dynamically sizes/zooms to the range.

If so, feel free to dig through the code, I think the main bit is...

// outside of loop
var maxBounds = L.bounds();

//inside loop

   var myBounds = e.target.getBounds();

   if(typeof maxBounds == 'undefined' ) {
   maxBounds = e.target.getBounds();
   }
    
   if( (typeof maxBounds.getSouthWest().lat == 'undefined') || myBounds.getSouthWest().lat < maxBounds.getSouthWest().lat ) {
     maxBounds._southWest['lat'] = myBounds._southWest.lat;
   }
   if( (typeof maxBounds.getSouthWest().lng == 'undefined') || myBounds.getSouthWest().lng < maxBounds.getSouthWest().lng ) {
     maxBounds._southWest['lng'] = myBounds._southWest.lng;
   }
   if( (typeof maxBounds.getNorthEast().lat == 'undefined') || myBounds.getNorthEast().lat > maxBounds.getNorthEast().lat ) {
     maxBounds._northEast['lat'] = myBounds._northEast.lat;
   }
   if( (typeof maxBounds.getNorthEast().lng == 'undefined') || myBounds.getNorthEast().lng > maxBounds.getNorthEast().lng ) {
     maxBounds._northEast['lng'] = myBounds._northEast.lng;
   }
   if( showOnly || (loaded >= urls.length) ) { // last one, or move after loop
     mymap.fitBounds( maxBounds );
   }
ibrierley commented 3 years ago

Ops, forgot url :D

mjut commented 3 years ago

Thanks a lot @ibrierley !! I need to dig into this. But I am no Java expert, this might take some time. (I am learning) But this looks very good! =) Cheers!

mjut commented 3 years ago

I think, I am going to rewrite my code completely. I like your approach much better and cleaner:

window.onload = function() {
    var clickTimer = null;
    var timer = 0;
    var delay = 1000;
    var prevent = false;
    var maxBounds = L.bounds();//{ _southWest: {}, _northEast: {}};
    var urls = [
        { url: 'Amberley%20Burgh.gpx', color: '#0040ff' },
        { url: 'Lancing%20SouthDownsWay.gpx', color: '#ff0000' },
        { url: 'MileOak%20Truleight%2012k.gpx', color: 'darkblue' },
        { url: 'MileOakCarPk%20Southdowns%20West.gpx', color: 'darkslateblue' },
        { url: 'Woodingdean%20Castle%20Hill.gpx', color: 'maroon' },

This is very good! Thanks again!

ibrierley commented 3 years ago

Cool, if it's useful I may put it on a Git repo sometime, then people can improve.

mjut commented 3 years ago

@ibrierley with your suggestions, you made me change the whole code for the better. Take a look at this: https://github.com/mjut/trailmap It is still a draft, but I am going to work more on this. Cheers-

ibrierley commented 3 years ago

You're welcome, it looks like you've grasped it all (there's not that much really), but any questions, feel free to ping me at ians.coding at gmail.com.

mpetazzoni commented 3 years ago

@ibrierley A slightly easier way to accomplish this is to use LatLngBounds.extend(...):

var maxBounds = L.latLngBounds();
tracks.forEach(function(track) {
  maxBounds.extend(track.getBounds());
});
map.fitBounds(maxBounds);
ibrierley commented 3 years ago

Ah thank you!