diff --git a/CHANGELOG.md b/CHANGELOG.md
index dcc9b9bb..d668d750 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,13 +4,16 @@ Leaflet Changelog
## 0.2 (master)
* Added **WMS support** (`TileLayer.WMS`), currently EPSG:3857 only.
+ * Added `TileLayer.Canvas` for easy creation of canvas-based tile layers.
* `Circle` is now zoom-dependent (with radius in meters); circle of a permanent size is now called `L.CircleMarker`.
* Added `mouseover` and `mouseout` events to map, markers and paths; added map `mousemove` event.
* Added `setLatLngs`, `spliceLatLngs`, `addLatLng`, `getLatLngs` methods to polylines and polygons.
* `LatLngBounds contains` method now accepts `LatLng` in addition to `LatLngBounds`, the same for `Bounds contains` and `Point`
+ * Added TMS tile numbering support through `TileLayer` `scheme: 'tms'` option (by [@tmcw](https://github.com/tmcw)).
* Added `opacity` option for tile layers.
* Added `setLatLng` method to `L.Marker`.
* Added `maxZoom` argument to `map.locateAndSetView` method.
+ * Added `DomEvent.getTarget` method.
* Improved geolocation error handling: better error messages, explicit timeout, set world view on locateAndSetView failure. [#61](http://github.com/CloudMade/Leaflet/issues/61)
* Disabled zoom animation on Android by default because it's buggy on some devices (will be enabled back when it's stable enough). [#32](http://github.com/CloudMade/Leaflet/issues/32)
* Fixed a bug where map would occasionally break while multi-touch-zooming on iOS. [#32](http://github.com/CloudMade/Leaflet/issues/32)
diff --git a/build/Makefile b/build/Makefile
new file mode 100644
index 00000000..cba4f1d4
--- /dev/null
+++ b/build/Makefile
@@ -0,0 +1,54 @@
+../dist/leaflet.js: Makefile
+ java -jar ../lib/closure-compiler/compiler.jar \
+ --js ../src/Leaflet.js \
+ --js ../src/core/Util.js \
+ --js ../src/core/Class.js \
+ --js ../src/core/Events.js \
+ --js ../src/core/Browser.js \
+ --js ../src/geometry/Point.js \
+ --js ../src/geometry/Bounds.js \
+ --js ../src/geometry/Transformation.js \
+ --js ../src/geometry/LineUtil.js \
+ --js ../src/geometry/PolyUtil.js \
+ --js ../src/dom/DomEvent.js \
+ --js ../src/dom/DomEvent.DoubleTap.js \
+ --js ../src/dom/DomUtil.js \
+ --js ../src/dom/Draggable.js \
+ --js ../src/dom/transition/Transition.js \
+ --js ../src/dom/transition/Transition.Native.js \
+ --js ../src/dom/transition/Transition.Timer.js \
+ --js ../src/geo/LatLng.js \
+ --js ../src/geo/LatLngBounds.js \
+ --js ../src/geo/Projection.js \
+ --js ../src/layer/tile/TileLayer.js \
+ --js ../src/layer/tile/TileLayer.WMS.js \
+ --js ../src/layer/tile/TileLayer.Canvas.js \
+ --js ../src/layer/ImageOverlay.js \
+ --js ../src/layer/Popup.js \
+ --js ../src/layer/marker/Icon.js \
+ --js ../src/layer/marker/Marker.js \
+ --js ../src/layer/marker/Marker.Popup.js \
+ --js ../src/layer/vector/Path.js \
+ --js ../src/layer/vector/Path.VML.js \
+ --js ../src/layer/vector/Path.Popup.js \
+ --js ../src/layer/vector/Polyline.js \
+ --js ../src/layer/vector/Polygon.js \
+ --js ../src/layer/vector/Circle.js \
+ --js ../src/layer/vector/CircleMarker.js \
+ --js ../src/handler/Handler.js \
+ --js ../src/handler/MapDrag.js \
+ --js ../src/handler/TouchZoom.js \
+ --js ../src/handler/ScrollWheelZoom.js \
+ --js ../src/handler/DoubleClickZoom.js \
+ --js ../src/handler/ShiftDragZoom.js \
+ --js ../src/handler/MarkerDrag.js \
+ --js ../src/control/Control.js \
+ --js ../src/control/Control.Zoom.js \
+ --js ../src/control/Control.Attribution.js \
+ --js ../src/map/Map.js \
+ --js ../src/map/ext/Map.Geolocation.js \
+ --js ../src/map/ext/Map.Popup.js \
+ --js ../src/map/ext/Map.PanAnimation.js \
+ --js ../src/map/ext/Map.ZoomAnimation.js \
+ --js ../src/map/ext/Map.Control.js \
+ --js_output_file ../dist/leaflet.js
diff --git a/build/build.bat b/build/build.bat
index 29232526..72302b83 100644
--- a/build/build.bat
+++ b/build/build.bat
@@ -20,8 +20,9 @@ java -jar ../lib/closure-compiler/compiler.jar ^
--js ../src/geo/LatLng.js ^
--js ../src/geo/LatLngBounds.js ^
--js ../src/geo/Projection.js ^
---js ../src/layer/TileLayer.js ^
---js ../src/layer/TileLayer.WMS.js ^
+--js ../src/layer/tile/TileLayer.js ^
+--js ../src/layer/tile/TileLayer.WMS.js ^
+--js ../src/layer/tile/TileLayer.Canvas.js ^
--js ../src/layer/ImageOverlay.js ^
--js ../src/layer/Popup.js ^
--js ../src/layer/marker/Icon.js ^
diff --git a/build/deps.js b/build/deps.js
index 2e91222f..27ede35b 100644
--- a/build/deps.js
+++ b/build/deps.js
@@ -18,17 +18,23 @@ var deps = {
TileLayer: {
- src: ['layer/TileLayer.js'],
+ src: ['layer/tile/TileLayer.js'],
desc: 'The base class for displaying tile layers on the map.',
heading: 'Layers'
},
TileLayerWMS: {
- src: ['layer/TileLayer.WMS.js'],
+ src: ['layer/tile/TileLayer.WMS.js'],
desc: 'WMS tile layer, currently only supports EPSG:3857.',
deps: ['TileLayer']
},
+ TileLayerCanvas: {
+ src: ['layer/tile/TileLayer.Canvas.js'],
+ desc: 'Tile layer made from canvases (for custom drawing purposes).',
+ deps: ['TileLayer']
+ },
+
ImageOverlay: {
src: ['layer/ImageOverlay.js'],
desc: 'Used to display an image over a particular rectangular area of the map.'
diff --git a/debug/include.js b/debug/include.js
index f231a1a3..275f0029 100644
--- a/debug/include.js
+++ b/debug/include.js
@@ -27,8 +27,9 @@
'geo/LatLngBounds.js',
'geo/Projection.js',
- 'layer/TileLayer.js',
- 'layer/TileLayer.WMS.js',
+ 'layer/tile/TileLayer.js',
+ 'layer/tile/TileLayer.WMS.js',
+ 'layer/tile/TileLayer.Canvas.js',
'layer/ImageOverlay.js',
'layer/Popup.js',
diff --git a/debug/map/canvas.html b/debug/map/canvas.html
new file mode 100644
index 00000000..6f6fab8c
--- /dev/null
+++ b/debug/map/canvas.html
@@ -0,0 +1,46 @@
+
+
+
+ Leaflet debug page
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dist/leaflet.js b/dist/leaflet.js
index 8bfd4c07..8e970d29 100644
--- a/dist/leaflet.js
+++ b/dist/leaflet.js
@@ -17,8 +17,8 @@ b,d.y);else if(c&4)return new L.Point(a.x+e*(f.y-a.y)/b,f.y);else if(c&2)return
0)return this._sqDist(a,b);if(f>1)return this._sqDist(a,c);b=new L.Point(b.x+d*f,b.y+e*f);return this._sqDist(a,b)}};L.PolyUtil={};L.PolyUtil.clipPolygon=function(a,b){var c,d=[1,4,2,8],e,f,g,h,i,j,k=L.LineUtil;e=0;for(i=a.length;e0&&c<=h;f=b}}function e(){if(g)i.type="dblclick",b(i),f=null}var f,g=!1,h=250,i;a["_leaflet_touchstart"+c]=d;a["_leaflet_touchend"+c]=e;a.addEventListener("touchstart",d,!1);a.addEventListener("touchend",e,!1)},removeDoubleTapListener:function(a,b){a.removeEventListener(a,a["_leaflet_touchstart"+b],!1);a.removeEventListener(a,a["_leaflet_touchend"+b],
+"mousedown",L.DomEvent.stopPropagation);L.DomEvent.addListener(a,"click",L.DomEvent.stopPropagation);L.DomEvent.addListener(a,"dblclick",L.DomEvent.stopPropagation)},preventDefault:function(a){a.preventDefault?a.preventDefault():a.returnValue=!1},getTarget:function(a){if((a=a.target||a.srcElement)&&a.nodeType==3)a=a.parentNode;return a},getMousePosition:function(a,b){var c=new L.Point(a.pageX?a.pageX:a.clientX+document.body.scrollLeft+document.documentElement.scrollLeft,a.pageY?a.pageY:a.clientY+
+document.body.scrollTop+document.documentElement.scrollTop);return b?c.subtract(L.DomUtil.getCumulativeOffset(b)):c},getWheelDelta:function(a){var b=0;a.wheelDelta&&(b=a.wheelDelta/120);a.detail&&(b=-a.detail/3);return b}};L.Util.extend(L.DomEvent,{addDoubleTapListener:function(a,b,c){function d(a){if(a.touches.length==1){var b=Date.now(),c=b-(f||b);i=a.touches[0];g=c>0&&c<=h;f=b}}function e(){if(g)i.type="dblclick",b(i),f=null}var f,g=!1,h=250,i;a["_leaflet_touchstart"+c]=d;a["_leaflet_touchend"+c]=e;a.addEventListener("touchstart",d,!1);a.addEventListener("touchend",e,!1)},removeDoubleTapListener:function(a,b){a.removeEventListener(a,a["_leaflet_touchstart"+b],!1);a.removeEventListener(a,a["_leaflet_touchend"+b],
!1)}});L.DomUtil={get:function(a){return typeof a=="string"?document.getElementById(a):a},getStyle:function(a,b){var c=a.style[b];typeof c=="undefined"&&a.currentStyle&&(c=a.currentStyle[b]);typeof c=="undefined"&&(c=(c=document.defaultView.getComputedStyle(a,null))?c[b]:null);return c=="auto"?null:c},getCumulativeOffset:function(a){var b=0,c=0;do b+=a.offsetTop||0,c+=a.offsetLeft||0,a=a.offsetParent;while(a);return new L.Point(c,b)},create:function(a,b,c){a=document.createElement(a);a.className=b;c&&c.appendChild(a);
return a},disableTextSelection:function(){document.selection&&document.selection.empty&&document.selection.empty();if(!this._onselectstart)this._onselectstart=document.onselectstart,document.onselectstart=L.Util.falseFn},enableTextSelection:function(){document.onselectstart=this._onselectstart;this._onselectstart=null},CLASS_RE:/(\\s|^)'+cls+'(\\s|$)/,hasClass:function(a,b){return a.className.length>0&&RegExp("(^|\\s)"+b+"(\\s|$)").test(a.className)},addClass:function(a,b){L.DomUtil.hasClass(a,b)||
(a.className+=(a.className?" ":"")+b)},setOpacity:function(a,b){L.Browser.ie?a.style.filter="alpha(opacity="+Math.round(b*100)+")":a.style.opacity=b},testProp:function(a){for(var b=document.documentElement.style,c=0;c=b.lat&&a.lat<=c.lat&&d.lng>=b.lng&&a.lng<=c.lng}});L.Projection={};L.Projection.Mercator={MAX_LATITUDE:function(){var a=Math.exp(2*Math.PI);return Math.asin((a-1)/(a+1))*L.LatLng.RAD_TO_DEG}(),project:function(a){var b=L.LatLng.DEG_TO_RAD,c=L.Projection.Mercator.MAX_LATITUDE,d=a.lng*b,a=Math.max(Math.min(c,a.lat),-c)*b,a=Math.log(Math.tan(Math.PI/4+a/2));return new L.Point(d,a)},unproject:function(a,b){var c=L.LatLng.RAD_TO_DEG;return new L.LatLng((2*Math.atan(Math.exp(a.y))-Math.PI/2)*c,a.x*c,b)}};L.TileLayer=L.Class.extend({includes:L.Mixin.Events,options:{minZoom:0,maxZoom:18,tileSize:256,subdomains:"abc",errorTileUrl:"",attribution:"",opacity:1,unloadInvisibleTiles:L.Browser.mobileWebkit,updateWhenIdle:L.Browser.mobileWebkit},initialize:function(a,b){L.Util.setOptions(this,b);this._url=a;if(typeof this.options.subdomains=="string")this.options.subdomains=this.options.subdomains.split("")},onAdd:function(a){this._map=a;this._initContainer();this._tileImg=L.DomUtil.create("img","leaflet-tile");
-this._tileImg.galleryimg="no";var b=this.options.tileSize;this._tileImg.style.width=b+"px";this._tileImg.style.height=b+"px";a.on("viewreset",this._reset,this);if(this.options.updateWhenIdle)a.on("moveend",this._update,this);else this._limitedUpdate=L.Util.limitExecByInterval(this._update,100,this),a.on("move",this._limitedUpdate,this);this._reset();this._update()},onRemove:function(){this._map.getPanes().tilePane.removeChild(this._container);this._map.off("viewreset",this._reset);this.options.updateWhenIdle?
-this._map.off("moveend",this._update):this._map.off("move",this._limitedUpdate)},getAttribution:function(){return this.options.attribution},_initContainer:function(){var a=this._map.getPanes().tilePane;if(!this._container||a.empty)this._container=L.DomUtil.create("div","leaflet-layer",a),this.options.opacity<1&&L.DomUtil.setOpacity(this._container,this.options.opacity)},_reset:function(){this._tiles={};this._initContainer();this._container.innerHTML=""},_update:function(){var a=this._map.getPixelBounds(),
-b=this.options.tileSize,c=new L.Point(Math.floor(a.min.x/b),Math.floor(a.min.y/b)),a=new L.Point(Math.floor(a.max.x/b),Math.floor(a.max.y/b)),c=new L.Bounds(c,a);this._loadTilesFromCenterOut(c);this.options.unloadInvisibleTiles&&this._unloadOtherTiles(c)},getTileUrl:function(a,b){return this._url.replace("{s}",this.options.subdomains[(a.x+a.y)%this.options.subdomains.length]).replace("{z}",b).replace("{x}",a.x).replace("{y}",a.y)},_loadTilesFromCenterOut:function(a){for(var b=[],c=a.getCenter(),d=
-a.min.y;d<=a.max.y;d++)for(var e=a.min.x;e<=a.max.x;e++)e+":"+d in this._tiles||b.push(new L.Point(e,d));b.sort(function(a,b){return a.distanceTo(c)-b.distanceTo(c)});this._tilesToLoad=b.length;a=0;for(d=this._tilesToLoad;aa.max.x||ba.max.y))this._tiles[d].parentNode==this._container&&this._container.removeChild(this._tiles[d]),
-delete this._tiles[d]},_loadTile:function(a){var b=this._map.getPixelOrigin(),b=a.multiplyBy(this.options.tileSize).subtract(b),c=this._map.getZoom(),d=1<=d))d=this._tileImg.cloneNode(!1),L.DomUtil.setPosition(d,b),this._tiles[a.x+":"+a.y]=d,d._leaflet_layer=this,d.onload=this._tileOnLoad,d.onerror=this._tileOnError,d.onselectstart=d.onmousemove=L.Util.falseFn,d.src=this.getTileUrl(a,c),this._container.appendChild(d)},_tileOnLoad:function(){this.className+=" leaflet-tile-loaded";
-var a=this._leaflet_layer;a.fire("tileload",{tile:this,url:this.src});a._tilesToLoad--;a._tilesToLoad||a.fire("load")},_tileOnError:function(){this._leaflet_layer.fire("tileerror",{tile:this,url:this.src});var a=this._leaflet_layer.options.errorTileUrl;if(a)this.src=a}});L.TileLayer.WMS=L.TileLayer.extend({defaultWmsParams:{service:"WMS",request:"GetMap",version:"1.1.1",layers:"",styles:"",format:"image/jpeg",transparent:!1},initialize:function(a,b){this._url=a;this.wmsParams=L.Util.extend({},this.defaultWmsParams);this.wmsParams.width=this.wmsParams.height=this.options.tileSize;for(var c in b)this.options.hasOwnProperty(c)||(this.wmsParams[c]=b[c]);this.wmsParams[parseFloat(this.wmsParams.version)>=1.3?"crs":"srs"]="EPSG:3857";L.Util.setOptions(this,b)},getTileUrl:function(a){var b=
-this.options.tileSize,a=a.multiplyBy(b),b=a.add(new L.Point(b,b)),a=this._map.unproject(a),b=this._map.unproject(b),a=L.Projection.Mercator.project(a).multiplyBy(6378137),b=L.Projection.Mercator.project(b).multiplyBy(6378137),b=[a.x,b.y,b.x,a.y].join(",");return this._url+L.Util.getParamString(this.wmsParams)+"&bbox="+b}});L.ImageOverlay=L.Class.extend({includes:L.Mixin.Events,initialize:function(a,b){this._url=a;this._bounds=b},onAdd:function(a){this._map=a;this._image||this._initImage();a.getPanes().overlayPane.appendChild(this._image);a.on("viewreset",this._reset,this);this._reset()},onRemove:function(a){a.getPanes().overlayPane.removeChild(this._image);a.off("viewreset",this._reset,this)},_initImage:function(){this._image=L.DomUtil.create("img","leaflet-image-layer");this._image.style.visibility="hidden";L.Util.extend(this._image,
+a=a.getNorthEast()):d=a;return d.lat>=b.lat&&a.lat<=c.lat&&d.lng>=b.lng&&a.lng<=c.lng}});L.Projection={};L.Projection.Mercator={MAX_LATITUDE:function(){var a=Math.exp(2*Math.PI);return Math.asin((a-1)/(a+1))*L.LatLng.RAD_TO_DEG}(),project:function(a){var b=L.LatLng.DEG_TO_RAD,c=L.Projection.Mercator.MAX_LATITUDE,d=a.lng*b,a=Math.max(Math.min(c,a.lat),-c)*b,a=Math.log(Math.tan(Math.PI/4+a/2));return new L.Point(d,a)},unproject:function(a,b){var c=L.LatLng.RAD_TO_DEG;return new L.LatLng((2*Math.atan(Math.exp(a.y))-Math.PI/2)*c,a.x*c,b)}};L.TileLayer=L.Class.extend({includes:L.Mixin.Events,options:{minZoom:0,maxZoom:18,tileSize:256,subdomains:"abc",errorTileUrl:"",attribution:"",opacity:1,scheme:"xyz",unloadInvisibleTiles:L.Browser.mobileWebkit,updateWhenIdle:L.Browser.mobileWebkit},initialize:function(a,b){L.Util.setOptions(this,b);this._url=a;if(typeof this.options.subdomains=="string")this.options.subdomains=this.options.subdomains.split("")},onAdd:function(a){this._map=a;this._initContainer();this._createTileProto();a.on("viewreset",
+this._reset,this);if(this.options.updateWhenIdle)a.on("moveend",this._update,this);else this._limitedUpdate=L.Util.limitExecByInterval(this._update,100,this),a.on("move",this._limitedUpdate,this);this._reset();this._update()},onRemove:function(){this._map.getPanes().tilePane.removeChild(this._container);this._map.off("viewreset",this._reset);this.options.updateWhenIdle?this._map.off("moveend",this._update):this._map.off("move",this._limitedUpdate)},getAttribution:function(){return this.options.attribution},
+_initContainer:function(){var a=this._map.getPanes().tilePane;if(!this._container||a.empty)this._container=L.DomUtil.create("div","leaflet-layer",a),this.options.opacity<1&&L.DomUtil.setOpacity(this._container,this.options.opacity)},_reset:function(){this._tiles={};this._initContainer();this._container.innerHTML=""},_update:function(){var a=this._map.getPixelBounds(),b=this.options.tileSize,c=new L.Point(Math.floor(a.min.x/b),Math.floor(a.min.y/b)),a=new L.Point(Math.floor(a.max.x/b),Math.floor(a.max.y/
+b)),c=new L.Bounds(c,a);this._addTilesFromCenterOut(c);this.options.unloadInvisibleTiles&&this._removeOtherTiles(c)},_addTilesFromCenterOut:function(a){for(var b=[],c=a.getCenter(),d=a.min.y;d<=a.max.y;d++)for(var e=a.min.x;e<=a.max.x;e++)e+":"+d in this._tiles||b.push(new L.Point(e,d));b.sort(function(a,b){return a.distanceTo(c)-b.distanceTo(c)});this._tilesToLoad=b.length;a=0;for(d=this._tilesToLoad;aa.max.x||ba.max.y))this._tiles[d].parentNode==this._container&&this._container.removeChild(this._tiles[d]),delete this._tiles[d]},_addTile:function(a){var b=this._getTilePos(a);zoom=this._map.getZoom();var c=1<=c||(c=this._createTile(),L.DomUtil.setPosition(c,b),this._tiles[a.x+":"+a.y]=c,this._loadTile(c,a,zoom),this._container.appendChild(c))},
+_getTilePos:function(a){var b=this._map.getPixelOrigin();return a.multiplyBy(this.options.tileSize).subtract(b)},getTileUrl:function(a,b){return this._url.replace("{s}",this.options.subdomains[(a.x+a.y)%this.options.subdomains.length]).replace("{z}",b).replace("{x}",a.x).replace("{y}",a.y)},_createTileProto:function(){this._tileImg=L.DomUtil.create("img","leaflet-tile");this._tileImg.galleryimg="no";var a=this.options.tileSize;this._tileImg.style.width=a+"px";this._tileImg.style.height=a+"px"},_createTile:function(){var a=
+this._tileImg.cloneNode(!1);a.onselectstart=a.onmousemove=L.Util.falseFn;return a},_loadTile:function(a,b,c){a.onload=L.Util.bind(this._tileOnLoad,this);a.onerror=L.Util.bind(this._tileOnError,this);a.src=this.getTileUrl(b,c)},_tileOnLoad:function(a){a=L.DomEvent.getTarget(a);a.className+=" leaflet-tile-loaded";this.fire("tileload",{tile:a,url:a.src});this._tilesToLoad--;this._tilesToLoad||this.fire("load")},_tileOnError:function(a){a=L.DomEvent.getTarget(a);this.fire("tileerror",{tile:a,url:a.src});
+var b=this.options.errorTileUrl;if(b)a.src=b}});L.TileLayer.WMS=L.TileLayer.extend({defaultWmsParams:{service:"WMS",request:"GetMap",version:"1.1.1",layers:"",styles:"",format:"image/jpeg",transparent:!1},initialize:function(a,b){this._url=a;this.wmsParams=L.Util.extend({},this.defaultWmsParams);this.wmsParams.width=this.wmsParams.height=this.options.tileSize;for(var c in b)this.options.hasOwnProperty(c)||(this.wmsParams[c]=b[c]);this.wmsParams[parseFloat(this.wmsParams.version)>=1.3?"crs":"srs"]="EPSG:3857";L.Util.setOptions(this,b)},getTileUrl:function(a){var b=
+this.options.tileSize,a=a.multiplyBy(b),b=a.add(new L.Point(b,b)),a=this._map.unproject(a),b=this._map.unproject(b),a=L.Projection.Mercator.project(a).multiplyBy(6378137),b=L.Projection.Mercator.project(b).multiplyBy(6378137),b=[a.x,b.y,b.x,a.y].join(",");return this._url+L.Util.getParamString(this.wmsParams)+"&bbox="+b}});L.TileLayer.Canvas=L.TileLayer.extend({initialize:function(a){L.Util.setOptions(this,a)},_createTileProto:function(){this._canvasProto=L.DomUtil.create("canvas","leaflet-tile");var a=this.options.tileSize;this._canvasProto.width=a;this._canvasProto.height=a},_createTile:function(){var a=this._canvasProto.cloneNode(!1);a.onselectstart=a.onmousemove=L.Util.falseFn;return a},_loadTile:function(a,b,c){this.drawTile(a,b,c);this._tileOnLoad({target:a})},drawTile:function(){}});L.ImageOverlay=L.Class.extend({includes:L.Mixin.Events,initialize:function(a,b){this._url=a;this._bounds=b},onAdd:function(a){this._map=a;this._image||this._initImage();a.getPanes().overlayPane.appendChild(this._image);a.on("viewreset",this._reset,this);this._reset()},onRemove:function(a){a.getPanes().overlayPane.removeChild(this._image);a.off("viewreset",this._reset,this)},_initImage:function(){this._image=L.DomUtil.create("img","leaflet-image-layer");this._image.style.visibility="hidden";L.Util.extend(this._image,
{galleryimg:"no",onselectstart:L.Util.falseFn,onmousemove:L.Util.falseFn,onload:this._onImageLoad,src:this._url})},_reset:function(){var a=this._map.latLngToLayerPoint(this._bounds.getNorthWest()),b=this._map.latLngToLayerPoint(this._bounds.getSouthEast()).subtract(a);L.DomUtil.setPosition(this._image,a);this._image.style.width=b.x+"px";this._image.style.height=b.y+"px"},_onImageLoad:function(){this.style.visibility=""}});L.Popup=L.Class.extend({includes:L.Mixin.Events,options:{maxWidth:300,autoPan:!0,closeButton:!0,offset:new L.Point(0,2),autoPanPadding:new L.Point(5,5)},initialize:function(a){L.Util.setOptions(this,a)},onAdd:function(a){this._map=a;this._container||this._initLayout();this._updateContent();this._container.style.opacity="0";this._map._panes.popupPane.appendChild(this._container);this._map.on("viewreset",this._updatePosition,this);if(this._map.options.closePopupOnClick)this._map.on("preclick",this._close,
this);this._update();this._container.style.opacity="1";this._opened=!0},onRemove:function(a){a._panes.popupPane.removeChild(this._container);a.off("viewreset",this._updatePosition,this);a.off("click",this._close,this);this._container.style.opacity="0";this._opened=!1},setLatLng:function(a){this._latlng=a;this._opened&&this._update();return this},setContent:function(a){this._content=a;this._opened&&this._update();return this},_close:function(){this._opened&&this._map.removeLayer(this)},_initLayout:function(){this._container=
L.DomUtil.create("div","leaflet-popup");this._closeButton=L.DomUtil.create("a","leaflet-popup-close-button",this._container);this._closeButton.href="#close";this._closeButton.onclick=L.Util.bind(this._onCloseButtonClick,this);this._wrapper=L.DomUtil.create("div","leaflet-popup-content-wrapper",this._container);L.DomEvent.disableClickPropagation(this._wrapper);this._contentNode=L.DomUtil.create("div","leaflet-popup-content",this._wrapper);this._tipContainer=L.DomUtil.create("div","leaflet-popup-tip-container",
diff --git a/src/dom/DomEvent.js b/src/dom/DomEvent.js
index a07e9f60..c185de88 100644
--- a/src/dom/DomEvent.js
+++ b/src/dom/DomEvent.js
@@ -106,6 +106,16 @@ L.DomEvent = {
}
},
+ getTarget: function(e) {
+ var target = e.target || e.srcElement;
+
+ if (target && target.nodeType == 3) {
+ target = target.parentNode;
+ }
+
+ return target;
+ },
+
getMousePosition: function(e, container) {
var x = e.pageX ? e.pageX : e.clientX +
document.body.scrollLeft + document.documentElement.scrollLeft,
diff --git a/src/layer/tile/TileLayer.Canvas.js b/src/layer/tile/TileLayer.Canvas.js
new file mode 100644
index 00000000..a3d3833b
--- /dev/null
+++ b/src/layer/tile/TileLayer.Canvas.js
@@ -0,0 +1,28 @@
+L.TileLayer.Canvas = L.TileLayer.extend({
+ initialize: function(options) {
+ L.Util.setOptions(this, options);
+ },
+
+ _createTileProto: function() {
+ this._canvasProto = L.DomUtil.create('canvas', 'leaflet-tile');
+
+ var tileSize = this.options.tileSize;
+ this._canvasProto.width = tileSize;
+ this._canvasProto.height = tileSize;
+ },
+
+ _createTile: function() {
+ var tile = this._canvasProto.cloneNode(false);
+ tile.onselectstart = tile.onmousemove = L.Util.falseFn;
+ return tile;
+ },
+
+ _loadTile: function(tile, tilePoint, zoom) {
+ this.drawTile(tile, tilePoint, zoom);
+ this._tileOnLoad({target: tile});
+ },
+
+ drawTile: function(tile, tilePoint, zoom) {
+ // override with rendering code
+ }
+});
\ No newline at end of file
diff --git a/src/layer/TileLayer.WMS.js b/src/layer/tile/TileLayer.WMS.js
similarity index 100%
rename from src/layer/TileLayer.WMS.js
rename to src/layer/tile/TileLayer.WMS.js
diff --git a/src/layer/TileLayer.js b/src/layer/tile/TileLayer.js
similarity index 73%
rename from src/layer/TileLayer.js
rename to src/layer/tile/TileLayer.js
index e1f3f96e..57f9b2fc 100644
--- a/src/layer/TileLayer.js
+++ b/src/layer/tile/TileLayer.js
@@ -13,6 +13,7 @@ L.TileLayer = L.Class.extend({
errorTileUrl: '',
attribution: '',
opacity: 1,
+ scheme: 'xyz',
unloadInvisibleTiles: L.Browser.mobileWebkit,
updateWhenIdle: L.Browser.mobileWebkit
@@ -35,12 +36,7 @@ L.TileLayer = L.Class.extend({
this._initContainer();
// create an image to clone for tiles
- this._tileImg = L.DomUtil.create('img', 'leaflet-tile');
- this._tileImg.galleryimg = 'no';
-
- var tileSize = this.options.tileSize;
- this._tileImg.style.width = tileSize + 'px';
- this._tileImg.style.height = tileSize + 'px';
+ this._createTileProto();
// set up events
map.on('viewreset', this._reset, this);
@@ -102,25 +98,14 @@ L.TileLayer = L.Class.extend({
Math.floor(bounds.max.y / tileSize)),
tileBounds = new L.Bounds(nwTilePoint, seTilePoint);
- this._loadTilesFromCenterOut(tileBounds);
+ this._addTilesFromCenterOut(tileBounds);
if (this.options.unloadInvisibleTiles) {
- this._unloadOtherTiles(tileBounds);
+ this._removeOtherTiles(tileBounds);
}
},
- getTileUrl: function(tilePoint, zoom) {
- var subdomains = this.options.subdomains,
- s = this.options.subdomains[(tilePoint.x + tilePoint.y) % subdomains.length];
-
- return this._url
- .replace('{s}', s)
- .replace('{z}', zoom)
- .replace('{x}', tilePoint.x)
- .replace('{y}', tilePoint.y);
- },
-
- _loadTilesFromCenterOut: function(bounds) {
+ _addTilesFromCenterOut: function(bounds) {
var queue = [],
center = bounds.getCenter();
@@ -138,11 +123,11 @@ L.TileLayer = L.Class.extend({
this._tilesToLoad = queue.length;
for (var k = 0, len = this._tilesToLoad; k < len; k++) {
- this._loadTile(queue[k]);
+ this._addTile(queue[k]);
}
},
- _unloadOtherTiles: function(bounds) {
+ _removeOtherTiles: function(bounds) {
var kArr, x, y, key;
for (key in this._tiles) {
@@ -162,54 +147,89 @@ L.TileLayer = L.Class.extend({
}
},
- _loadTile: function(tilePoint) {
- var origin = this._map.getPixelOrigin(),
- tileSize = this.options.tileSize,
- tilePos = tilePoint.multiplyBy(tileSize).subtract(origin),
+ _addTile: function(tilePoint) {
+ var tilePos = this._getTilePos(tilePoint);
zoom = this._map.getZoom();
// wrap tile coordinates
var tileLimit = (1 << zoom);
tilePoint.x = ((tilePoint.x % tileLimit) + tileLimit) % tileLimit;
+ if (this.options.scheme == 'tms') tilePoint.y = tileLimit - tilePoint.y - 1;
if (tilePoint.y < 0 || tilePoint.y >= tileLimit) { return; }
// create tile
- var tile = this._tileImg.cloneNode(false);
-
+ var tile = this._createTile();
L.DomUtil.setPosition(tile, tilePos);
this._tiles[tilePoint.x + ':' + tilePoint.y] = tile;
- tile._leaflet_layer = this;
- tile.onload = this._tileOnLoad;
- tile.onerror = this._tileOnError;
- tile.onselectstart = tile.onmousemove = L.Util.falseFn;
-
- tile.src = this.getTileUrl(tilePoint, zoom);
+ this._loadTile(tile, tilePoint, zoom);
this._container.appendChild(tile);
},
- _tileOnLoad: function() {
- this.className += ' leaflet-tile-loaded'; //TODO DomEvent#addListener target
+ _getTilePos: function(tilePoint) {
+ var origin = this._map.getPixelOrigin(),
+ tileSize = this.options.tileSize;
+
+ return tilePoint.multiplyBy(tileSize).subtract(origin);
+ },
+
+ // image-specific code (override to implement e.g. Canvas or SVG tile layer)
+
+ getTileUrl: function(tilePoint, zoom) {
+ var subdomains = this.options.subdomains,
+ s = this.options.subdomains[(tilePoint.x + tilePoint.y) % subdomains.length];
- var layer = this._leaflet_layer;
+ return this._url
+ .replace('{s}', s)
+ .replace('{z}', zoom)
+ .replace('{x}', tilePoint.x)
+ .replace('{y}', tilePoint.y);
+ },
+
+ _createTileProto: function() {
+ this._tileImg = L.DomUtil.create('img', 'leaflet-tile');
+ this._tileImg.galleryimg = 'no';
- layer.fire('tileload', {tile: this, url: this.src});
+ var tileSize = this.options.tileSize;
+ this._tileImg.style.width = tileSize + 'px';
+ this._tileImg.style.height = tileSize + 'px';
+ },
+
+ _createTile: function() {
+ var tile = this._tileImg.cloneNode(false);
+ tile.onselectstart = tile.onmousemove = L.Util.falseFn;
+ return tile;
+ },
+
+ _loadTile: function(tile, tilePoint, zoom) {
+ tile.onload = L.Util.bind(this._tileOnLoad, this);
+ tile.onerror = L.Util.bind(this._tileOnError, this);
+ tile.src = this.getTileUrl(tilePoint, zoom);
+ },
+
+ _tileOnLoad: function(e) {
+ var tile = L.DomEvent.getTarget(e);
- layer._tilesToLoad--;
- if (!layer._tilesToLoad) {
- layer.fire('load');
+ tile.className += ' leaflet-tile-loaded';
+
+ this.fire('tileload', {tile: tile, url: tile.src});
+
+ this._tilesToLoad--;
+ if (!this._tilesToLoad) {
+ this.fire('load');
}
},
- _tileOnError: function() {
- this._leaflet_layer.fire('tileerror', {tile: this, url: this.src});
+ _tileOnError: function(e) {
+ var tile = L.DomEvent.getTarget(e);
- var newUrl = this._leaflet_layer.options.errorTileUrl;
+ this.fire('tileerror', {tile: tile, url: tile.src});
+
+ var newUrl = this.options.errorTileUrl;
if (newUrl) {
- this.src = newUrl;
+ tile.src = newUrl;
}
-
}
-});
\ No newline at end of file
+});