From 003e94ae11f2b9f35f93b7dc1b280fb3c0bb9267 Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Sat, 18 Apr 2015 17:41:36 +0200 Subject: [PATCH 01/11] Fix L.Polyline._flat returning true for a nested empty array --- spec/suites/layer/vector/PolylineSpec.js | 25 ++++++++++++++++++++++++ src/layer/vector/Polyline.js | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/spec/suites/layer/vector/PolylineSpec.js b/spec/suites/layer/vector/PolylineSpec.js index 49349897..8ab42b1b 100644 --- a/spec/suites/layer/vector/PolylineSpec.js +++ b/spec/suites/layer/vector/PolylineSpec.js @@ -88,4 +88,29 @@ describe('Polyline', function () { }); + describe('#_flat', function () { + var layer = L.polyline([]); + + it('should return true for an array of LatLngs', function () { + expect(layer._flat([L.latLng([0, 0])])).to.be(true); + }); + + it('should return true for an array of LatLngs arrays', function () { + expect(layer._flat([[0, 0]])).to.be(true); + }); + + it('should return true for an empty array', function () { + expect(layer._flat([])).to.be(true); + }); + + it('should return false for a nested array of LatLngs', function () { + expect(layer._flat([[L.latLng([0, 0])]])).to.be(false); + }); + + it('should return false for a nested empty array', function () { + expect(layer._flat([[]])).to.be(false); + }); + + }); + }); diff --git a/src/layer/vector/Polyline.js b/src/layer/vector/Polyline.js index e548447d..d49ca27e 100644 --- a/src/layer/vector/Polyline.js +++ b/src/layer/vector/Polyline.js @@ -131,7 +131,7 @@ L.Polyline = L.Path.extend({ _flat: function (latlngs) { // true if it's a flat array of latlngs; false if nested - return !L.Util.isArray(latlngs[0]) || typeof latlngs[0][0] !== 'object'; + return !L.Util.isArray(latlngs[0]) || (typeof latlngs[0][0] !== 'object' && typeof latlngs[0][0] !== 'undefined'); }, _project: function () { From 097128cfa782f53f670ae7deb09aa8857805838a Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Tue, 21 Apr 2015 15:52:44 +0200 Subject: [PATCH 02/11] Add LatLng.clone --- spec/suites/geo/LatLngSpec.js | 21 +++++++++++++++++++++ src/geo/LatLng.js | 4 ++++ 2 files changed, 25 insertions(+) diff --git a/spec/suites/geo/LatLngSpec.js b/spec/suites/geo/LatLngSpec.js index 3b8bce0e..b229c87c 100644 --- a/spec/suites/geo/LatLngSpec.js +++ b/spec/suites/geo/LatLngSpec.js @@ -116,4 +116,25 @@ describe('LatLng', function () { expect(L.latLng({lat: 50, lon: 30, alt: 100})).to.eql(new L.LatLng(50, 30, 100)); }); }); + + describe('#clone', function () { + + it('should clone attributes', function () { + var a = new L.LatLng(50.5, 30.5, 100); + var b = a.clone(); + + expect(b.lat).to.equal(50.5); + expect(b.lng).to.equal(30.5); + expect(b.alt).to.equal(100); + }); + + it('should create another reference', function () { + var a = new L.LatLng(50.5, 30.5, 100); + var b = a.clone(); + + expect(a === b).to.be(false); + }); + + }); + }); diff --git a/src/geo/LatLng.js b/src/geo/LatLng.js index f040cb62..83a44568 100644 --- a/src/geo/LatLng.js +++ b/src/geo/LatLng.js @@ -49,6 +49,10 @@ L.LatLng.prototype = { return L.latLngBounds( [this.lat - latAccuracy, this.lng - lngAccuracy], [this.lat + latAccuracy, this.lng + lngAccuracy]); + }, + + clone: function () { + return new L.LatLng(this.lat, this.lng, this.alt); } }; From 4d70fe09a7b9fcd5524ca96d378ae2810d2437d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20S=C3=A1nchez=20Ortega?= Date: Wed, 22 Apr 2015 00:22:52 +0200 Subject: [PATCH 03/11] Implement L.Map.flyToBounds(), #3391 --- src/map/Map.js | 12 ++++++++++-- src/map/anim/Map.FlyTo.js | 5 +++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/map/Map.js b/src/map/Map.js index ee2a411d..9d2cb376 100644 --- a/src/map/Map.js +++ b/src/map/Map.js @@ -88,7 +88,7 @@ L.Map = L.Evented.extend({ return this.setView(newCenter, zoom, {zoom: options}); }, - fitBounds: function (bounds, options) { + _getBoundsCenterZoom: function (bounds, options) { options = options || {}; bounds = bounds.getBounds ? bounds.getBounds() : L.latLngBounds(bounds); @@ -106,7 +106,15 @@ L.Map = L.Evented.extend({ nePoint = this.project(bounds.getNorthEast(), zoom), center = this.unproject(swPoint.add(nePoint).divideBy(2).add(paddingOffset), zoom); - return this.setView(center, zoom, options); + return { + center: center, + zoom: zoom + }; + }, + + fitBounds: function (bounds, options) { + var target = this._getBoundsCenterZoom(bounds, options); + return this.setView(target.center, target.zoom, options); }, fitWorld: function (options) { diff --git a/src/map/anim/Map.FlyTo.js b/src/map/anim/Map.FlyTo.js index 81128f1a..d55c3eeb 100644 --- a/src/map/anim/Map.FlyTo.js +++ b/src/map/anim/Map.FlyTo.js @@ -56,5 +56,10 @@ L.Map.include({ this.fire('zoomstart'); frame.call(this); + }, + + flyToBounds: function(bounds, options) { + var target = this._getBoundsCenterZoom(bounds, options); + return this.flyTo(target.center, target.zoom); } }); From c3575be344e754a3152180ae47e0413d0a5e929f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20S=C3=A1nchez=20Ortega?= Date: Thu, 23 Apr 2015 09:18:59 +0200 Subject: [PATCH 04/11] Implement options in L.Map.flyTo() --- debug/map/zoompan.html | 3 +++ src/map/anim/Map.FlyTo.js | 12 +++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/debug/map/zoompan.html b/debug/map/zoompan.html index 3016a1dd..9c0e0f11 100644 --- a/debug/map/zoompan.html +++ b/debug/map/zoompan.html @@ -27,6 +27,7 @@ --> + @@ -36,6 +37,7 @@ london = [51.51, -0.12], sf = [37.77, -122.42], dc = [38.91, -77.04]; + trd = [63.41, 10.41]; var map = L.map('map').setView(dc, 10); @@ -51,6 +53,7 @@ document.getElementById('dc').onclick = function () { map.flyTo(dc, 10); }; document.getElementById('sf').onclick = function () { map.flyTo(sf, 10); }; + document.getElementById('trd').onclick = function () { map.flyTo(trd, 10, {duration: 20}); }; document.getElementById('stop').onclick = function () { map.stop(); }; // document.getElementById('london').onclick = function () { map.flyTo(london); }; // document.getElementById('kyiv').onclick = function () { map.flyTo(kyiv); }; diff --git a/src/map/anim/Map.FlyTo.js b/src/map/anim/Map.FlyTo.js index d55c3eeb..e7dda3f3 100644 --- a/src/map/anim/Map.FlyTo.js +++ b/src/map/anim/Map.FlyTo.js @@ -1,6 +1,11 @@ L.Map.include({ - flyTo: function (targetCenter, targetZoom) { + flyTo: function (targetCenter, targetZoom, options) { + + options = options || {}; + if (options.animate === false) { + return this.setView(targetCenter, targetZoom, options); + } this.stop(); @@ -36,7 +41,7 @@ L.Map.include({ var start = Date.now(), S = (r(1) - r0) / rho, - duration = 1000 * S * 0.8; + duration = options.duration ? 1000 * options.duration : 1000 * S * 0.8; function frame() { var t = (Date.now() - start) / duration, @@ -56,10 +61,11 @@ L.Map.include({ this.fire('zoomstart'); frame.call(this); + return this; }, flyToBounds: function(bounds, options) { var target = this._getBoundsCenterZoom(bounds, options); - return this.flyTo(target.center, target.zoom); + return this.flyTo(target.center, target.zoom, options); } }); From 6abcdb97510e66c5aed3b661c99a64ca266b5f9f Mon Sep 17 00:00:00 2001 From: Steve Date: Thu, 23 Apr 2015 13:59:38 -0500 Subject: [PATCH 05/11] Fix ESRI Imagery 404s --- FAQ.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FAQ.md b/FAQ.md index 47f24966..aa0ee75b 100644 --- a/FAQ.md +++ b/FAQ.md @@ -30,7 +30,7 @@ with over seventy different layers to choose from. Popular commercial options, free up to a particular number of requests, include [MapBox](http://mapbox.com), [Bing Maps](http://www.microsoft.com/maps/choose-your-bing-maps-API.aspx) (using a [plugin](https://github.com/shramov/leaflet-plugins)), -[Esri ArcGIS](http://www.arcgis.com/features/maps/imagery.html) ([official plugin](https://github.com/Esri/esri-leaflet)) +[Esri ArcGIS](http://www.esri.com/software/arcgis/arcgisonline/maps/maps-and-map-layers) ([official plugin](https://github.com/Esri/esri-leaflet)) and [Nokia Here](http://developer.here.com/web-experiences). A notable exception is [MapQuest Open](http://developer.mapquest.com/web/products/open/map), which is free for any number of requests. @@ -40,7 +40,7 @@ Always be sure to **read the terms of use** of a chosen tile provider, **know it [MapBox](http://mapbox.com), [Bing Maps](http://www.microsoft.com/maps/choose-your-bing-maps-API.aspx), -[ArcGIS](http://www.arcgis.com/features/maps/imagery.html) +[ArcGIS](http://www.esri.com/software/arcgis/arcgisonline/maps/maps-and-map-layers) and [MapQuest Open](http://developer.mapquest.com/web/products/open/map) provide satellite imagery among others. #### I want to use Google Maps API tiles with Leaflet, can I do that? From 71f93c44efc9c974f7d2c6294e71d146721fbb06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20S=C3=A1nchez=20Ortega?= Date: Mon, 27 Apr 2015 09:42:54 +0200 Subject: [PATCH 06/11] Fix leaflet/Leaflet#3404 --- src/map/ext/Map.Geolocation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/map/ext/Map.Geolocation.js b/src/map/ext/Map.Geolocation.js index 05fe552a..bf728a7a 100644 --- a/src/map/ext/Map.Geolocation.js +++ b/src/map/ext/Map.Geolocation.js @@ -16,7 +16,7 @@ L.Map.include({ options = this._locateOptions = L.extend({}, this._defaultLocateOptions, options); - if (!navigator.geolocation) { + if (!('geolocation' in navigator)) { this._handleGeolocationError({ code: 0, message: 'Geolocation not supported.' From 286f192ca963135ef769649b62830528c95ae3ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20S=C3=A1nchez=20Ortega?= Date: Wed, 29 Apr 2015 11:02:51 +0200 Subject: [PATCH 07/11] Prevent recursion on map.setMaxBounds --- debug/map/max-bounds.html | 2 ++ src/map/Map.js | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/debug/map/max-bounds.html b/debug/map/max-bounds.html index d1a5a583..345b813f 100644 --- a/debug/map/max-bounds.html +++ b/debug/map/max-bounds.html @@ -33,6 +33,8 @@ var latlngs = L.rectangle(bounds).getLatLngs(); L.polyline(latlngs.concat([latlngs[0]])).addTo(map); + map.setMaxBounds(bounds); // Should not enter infinite recursion + diff --git a/src/map/Map.js b/src/map/Map.js index 9d2cb376..87df569b 100644 --- a/src/map/Map.js +++ b/src/map/Map.js @@ -138,12 +138,14 @@ L.Map = L.Evented.extend({ setMaxBounds: function (bounds) { bounds = L.latLngBounds(bounds); - this.options.maxBounds = bounds; - if (!bounds) { return this.off('moveend', this._panInsideMaxBounds); + } else if (this.options.maxBounds) { + this.off('moveend', this._panInsideMaxBounds); } + this.options.maxBounds = bounds; + if (this._loaded) { this._panInsideMaxBounds(); } From ea680ce21af1e36b136c6108c0d51962e220b9a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20S=C3=A1nchez=20Ortega?= Date: Thu, 30 Apr 2015 12:58:46 +0200 Subject: [PATCH 08/11] Detect Firefox for Android as L.Browser.mobile --- src/core/Browser.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/core/Browser.js b/src/core/Browser.js index 8fe06ac5..599ff325 100644 --- a/src/core/Browser.js +++ b/src/core/Browser.js @@ -13,8 +13,9 @@ phantomjs = ua.indexOf('phantom') !== -1, android23 = ua.search('android [23]') !== -1, chrome = ua.indexOf('chrome') !== -1, + gecko = ua.indexOf('gecko') !== -1 && !webkit && !window.opera && !ie, - mobile = typeof orientation !== 'undefined', + mobile = typeof orientation !== 'undefined' || ua.indexOf('mobile') !== -1, msPointer = navigator.msPointerEnabled && navigator.msMaxTouchPoints && !window.PointerEvent, pointer = (window.PointerEvent && navigator.pointerEnabled && navigator.maxTouchPoints) || msPointer, @@ -30,7 +31,7 @@ ie: ie, ielt9: ie && !document.addEventListener, webkit: webkit, - gecko: (ua.indexOf('gecko') !== -1) && !webkit && !window.opera && !ie, + gecko: gecko, android: ua.indexOf('android') !== -1, android23: android23, chrome: chrome, @@ -46,6 +47,7 @@ mobileWebkit: mobile && webkit, mobileWebkit3d: mobile && webkit3d, mobileOpera: mobile && window.opera, + mobileGecko: mobile && gecko, touch: !!touch, msPointer: !!msPointer, From 8f3a353d84909f7b6cf27d6a37b162af01cc2dc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20S=C3=A1nchez=20Ortega?= Date: Thu, 30 Apr 2015 16:38:48 +0200 Subject: [PATCH 09/11] LatLng.wrap shall not drop altitude, closes #3420 --- spec/suites/geo/CRSSpec.js | 8 ++++++++ src/geo/crs/CRS.js | 5 +++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/spec/suites/geo/CRSSpec.js b/spec/suites/geo/CRSSpec.js index d252b6bc..a75efb92 100644 --- a/spec/suites/geo/CRSSpec.js +++ b/spec/suites/geo/CRSSpec.js @@ -63,6 +63,14 @@ describe("CRS.EPSG3857", function () { expect(crs.wrapLatLng(new L.LatLng(0, 180)).lng).to.eql(180); }); + it("does not drop altitude", function () { + expect(crs.wrapLatLng(new L.LatLng(0, 190, 1234)).lng).to.eql(-170); + expect(crs.wrapLatLng(new L.LatLng(0, 190, 1234)).alt).to.eql(1234); + + expect(crs.wrapLatLng(new L.LatLng(0, 380, 1234)).lng).to.eql(20); + expect(crs.wrapLatLng(new L.LatLng(0, 380, 1234)).alt).to.eql(1234); + }); + }); }); diff --git a/src/geo/crs/CRS.js b/src/geo/crs/CRS.js index 74efb7c3..e7288df4 100644 --- a/src/geo/crs/CRS.js +++ b/src/geo/crs/CRS.js @@ -56,8 +56,9 @@ L.CRS = { // wraps geo coords in certain ranges if applicable wrapLatLng: function (latlng) { var lng = this.wrapLng ? L.Util.wrapNum(latlng.lng, this.wrapLng, true) : latlng.lng, - lat = this.wrapLat ? L.Util.wrapNum(latlng.lat, this.wrapLat, true) : latlng.lat; + lat = this.wrapLat ? L.Util.wrapNum(latlng.lat, this.wrapLat, true) : latlng.lat, + alt = latlng.alt; - return L.latLng(lat, lng); + return L.latLng(lat, lng, alt); } }; From 19d6008dfc2d382f70598e6a320140f300b3dc25 Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Fri, 8 May 2015 11:52:00 +0200 Subject: [PATCH 10/11] Make L.Polyline._flat a static method --- spec/suites/layer/vector/PolylineSpec.js | 10 +++++----- src/layer/GeoJSON.js | 6 +++--- src/layer/vector/Polyline.js | 16 ++++++++++------ 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/spec/suites/layer/vector/PolylineSpec.js b/spec/suites/layer/vector/PolylineSpec.js index 8ab42b1b..177f7370 100644 --- a/spec/suites/layer/vector/PolylineSpec.js +++ b/spec/suites/layer/vector/PolylineSpec.js @@ -92,23 +92,23 @@ describe('Polyline', function () { var layer = L.polyline([]); it('should return true for an array of LatLngs', function () { - expect(layer._flat([L.latLng([0, 0])])).to.be(true); + expect(L.Polyline._flat([L.latLng([0, 0])])).to.be(true); }); it('should return true for an array of LatLngs arrays', function () { - expect(layer._flat([[0, 0]])).to.be(true); + expect(L.Polyline._flat([[0, 0]])).to.be(true); }); it('should return true for an empty array', function () { - expect(layer._flat([])).to.be(true); + expect(L.Polyline._flat([])).to.be(true); }); it('should return false for a nested array of LatLngs', function () { - expect(layer._flat([[L.latLng([0, 0])]])).to.be(false); + expect(L.Polyline._flat([[L.latLng([0, 0])]])).to.be(false); }); it('should return false for a nested empty array', function () { - expect(layer._flat([[]])).to.be(false); + expect(L.Polyline._flat([[]])).to.be(false); }); }); diff --git a/src/layer/GeoJSON.js b/src/layer/GeoJSON.js index cb29d8de..871bd111 100644 --- a/src/layer/GeoJSON.js +++ b/src/layer/GeoJSON.js @@ -190,7 +190,7 @@ L.Circle.include(PointToGeoJSON); L.CircleMarker.include(PointToGeoJSON); L.Polyline.prototype.toGeoJSON = function () { - var multi = !this._flat(this._latlngs); + var multi = !L.Polyline._flat(this._latlngs); var coords = L.GeoJSON.latLngsToCoords(this._latlngs, multi ? 1 : 0); @@ -201,8 +201,8 @@ L.Polyline.prototype.toGeoJSON = function () { }; L.Polygon.prototype.toGeoJSON = function () { - var holes = !this._flat(this._latlngs), - multi = holes && !this._flat(this._latlngs[0]); + var holes = !L.Polyline._flat(this._latlngs), + multi = holes && !L.Polyline._flat(this._latlngs[0]); var coords = L.GeoJSON.latLngsToCoords(this._latlngs, multi ? 2 : holes ? 1 : 0, true); diff --git a/src/layer/vector/Polyline.js b/src/layer/vector/Polyline.js index d49ca27e..06171d72 100644 --- a/src/layer/vector/Polyline.js +++ b/src/layer/vector/Polyline.js @@ -115,7 +115,7 @@ L.Polyline = L.Path.extend({ // recursively convert latlngs input into actual LatLng instances; calculate bounds along the way _convertLatLngs: function (latlngs) { var result = [], - flat = this._flat(latlngs); + flat = L.Polyline._flat(latlngs); for (var i = 0, len = latlngs.length; i < len; i++) { if (flat) { @@ -129,11 +129,6 @@ L.Polyline = L.Path.extend({ return result; }, - _flat: function (latlngs) { - // true if it's a flat array of latlngs; false if nested - return !L.Util.isArray(latlngs[0]) || (typeof latlngs[0][0] !== 'object' && typeof latlngs[0][0] !== 'undefined'); - }, - _project: function () { this._rings = []; this._projectLatlngs(this._latlngs, this._rings); @@ -228,3 +223,12 @@ L.Polyline = L.Path.extend({ L.polyline = function (latlngs, options) { return new L.Polyline(latlngs, options); }; + +L.extend(L.Polyline, { + + _flat: function (latlngs) { + // true if it's a flat array of latlngs; false if nested + return !L.Util.isArray(latlngs[0]) || (typeof latlngs[0][0] !== 'object' && typeof latlngs[0][0] !== 'undefined'); + } + +}); From d53d958e815089f7829bef513a4f7b4687ed81f2 Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Fri, 8 May 2015 12:01:22 +0200 Subject: [PATCH 11/11] Simpler approach for static method --- src/layer/vector/Polyline.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/layer/vector/Polyline.js b/src/layer/vector/Polyline.js index 06171d72..41c04ee8 100644 --- a/src/layer/vector/Polyline.js +++ b/src/layer/vector/Polyline.js @@ -224,11 +224,7 @@ L.polyline = function (latlngs, options) { return new L.Polyline(latlngs, options); }; -L.extend(L.Polyline, { - - _flat: function (latlngs) { - // true if it's a flat array of latlngs; false if nested - return !L.Util.isArray(latlngs[0]) || (typeof latlngs[0][0] !== 'object' && typeof latlngs[0][0] !== 'undefined'); - } - -}); +L.Polyline._flat = function (latlngs) { + // true if it's a flat array of latlngs; false if nested + return !L.Util.isArray(latlngs[0]) || (typeof latlngs[0][0] !== 'object' && typeof latlngs[0][0] !== 'undefined'); +};