leaflet-ruby 0.3.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. data/CHANGELOG.rdoc +5 -0
  2. data/LICENSE +21 -0
  3. data/README.rdoc +55 -0
  4. data/Rakefile +15 -0
  5. data/leaflet-ruby.gemspec +24 -0
  6. data/lib/leaflet-ruby.rb +18 -0
  7. data/lib/leaflet/CHANGELOG.md +181 -0
  8. data/lib/leaflet/Jakefile.js +65 -0
  9. data/lib/leaflet/LICENSE +22 -0
  10. data/lib/leaflet/README.md +32 -0
  11. data/lib/leaflet/build/build.html +243 -0
  12. data/lib/leaflet/build/build.js +79 -0
  13. data/lib/leaflet/build/deps.js +231 -0
  14. data/lib/leaflet/build/hint.js +30 -0
  15. data/lib/leaflet/build/hintrc.js +44 -0
  16. data/lib/leaflet/debug/control/control-layers.html +47 -0
  17. data/lib/leaflet/debug/control/map-control.html +29 -0
  18. data/lib/leaflet/debug/css/mobile.css +6 -0
  19. data/lib/leaflet/debug/css/screen.css +5 -0
  20. data/lib/leaflet/debug/geojson/geojson-sample.js +53 -0
  21. data/lib/leaflet/debug/geojson/geojson.html +56 -0
  22. data/lib/leaflet/debug/leaflet-include.js +120 -0
  23. data/lib/leaflet/debug/map/canvas.html +46 -0
  24. data/lib/leaflet/debug/map/map-mobile.html +42 -0
  25. data/lib/leaflet/debug/map/map.html +54 -0
  26. data/lib/leaflet/debug/map/max-bounds.html +36 -0
  27. data/lib/leaflet/debug/map/scroll.html +35 -0
  28. data/lib/leaflet/debug/map/wms-marble.html +30 -0
  29. data/lib/leaflet/debug/map/wms.html +37 -0
  30. data/lib/leaflet/debug/vector/editable.html +43 -0
  31. data/lib/leaflet/debug/vector/route.js +1 -0
  32. data/lib/leaflet/debug/vector/vector-bounds.html +69 -0
  33. data/lib/leaflet/debug/vector/vector-canvas.html +92 -0
  34. data/lib/leaflet/debug/vector/vector-mobile.html +38 -0
  35. data/lib/leaflet/debug/vector/vector-simple.html +63 -0
  36. data/lib/leaflet/debug/vector/vector.html +38 -0
  37. data/lib/leaflet/dist/images/layers.png +0 -0
  38. data/lib/leaflet/dist/images/marker-shadow.png +0 -0
  39. data/lib/leaflet/dist/images/marker.png +0 -0
  40. data/lib/leaflet/dist/images/popup-close.png +0 -0
  41. data/lib/leaflet/dist/images/zoom-in.png +0 -0
  42. data/lib/leaflet/dist/images/zoom-out.png +0 -0
  43. data/lib/leaflet/dist/leaflet-src.js +5537 -0
  44. data/lib/leaflet/dist/leaflet.css +323 -0
  45. data/lib/leaflet/dist/leaflet.ie.css +48 -0
  46. data/lib/leaflet/dist/leaflet.js +6 -0
  47. data/lib/leaflet/lib/jasmine/jasmine-html.js +182 -0
  48. data/lib/leaflet/lib/jasmine/jasmine.css +166 -0
  49. data/lib/leaflet/lib/jasmine/jasmine.js +2421 -0
  50. data/lib/leaflet/spec/runner.html +57 -0
  51. data/lib/leaflet/spec/suites/LeafletSpec.js +15 -0
  52. data/lib/leaflet/spec/suites/SpecHelper.js +28 -0
  53. data/lib/leaflet/spec/suites/core/ClassSpec.js +153 -0
  54. data/lib/leaflet/spec/suites/core/EventsSpec.js +110 -0
  55. data/lib/leaflet/spec/suites/core/UtilSpec.js +63 -0
  56. data/lib/leaflet/spec/suites/dom/DomEventSpec.js +102 -0
  57. data/lib/leaflet/spec/suites/dom/DomUtilSpec.js +59 -0
  58. data/lib/leaflet/spec/suites/geo/LatLngBoundsSpec.js +1 -0
  59. data/lib/leaflet/spec/suites/geo/LatLngSpec.js +76 -0
  60. data/lib/leaflet/spec/suites/geo/ProjectionSpec.js +42 -0
  61. data/lib/leaflet/spec/suites/geometry/BoundsSpec.js +53 -0
  62. data/lib/leaflet/spec/suites/geometry/PointSpec.js +45 -0
  63. data/lib/leaflet/spec/suites/geometry/TransformationSpec.js +19 -0
  64. data/lib/leaflet/spec/suites/layer/TileLayerSpec.js +1 -0
  65. data/lib/leaflet/spec/suites/layer/vector/PolylineGeometrySpec.js +35 -0
  66. data/lib/leaflet/spec/suites/map/MapSpec.js +1 -0
  67. data/lib/leaflet/src/Leaflet.js +33 -0
  68. data/lib/leaflet/src/control/Control.Attribution.js +66 -0
  69. data/lib/leaflet/src/control/Control.Layers.js +167 -0
  70. data/lib/leaflet/src/control/Control.Zoom.js +36 -0
  71. data/lib/leaflet/src/control/Control.js +9 -0
  72. data/lib/leaflet/src/core/Browser.js +53 -0
  73. data/lib/leaflet/src/core/Class.js +66 -0
  74. data/lib/leaflet/src/core/Events.js +62 -0
  75. data/lib/leaflet/src/core/Handler.js +29 -0
  76. data/lib/leaflet/src/core/Util.js +108 -0
  77. data/lib/leaflet/src/dom/DomEvent.DoubleTap.js +43 -0
  78. data/lib/leaflet/src/dom/DomEvent.js +154 -0
  79. data/lib/leaflet/src/dom/DomUtil.js +155 -0
  80. data/lib/leaflet/src/dom/Draggable.js +147 -0
  81. data/lib/leaflet/src/dom/transition/Transition.Native.js +102 -0
  82. data/lib/leaflet/src/dom/transition/Transition.Timer.js +126 -0
  83. data/lib/leaflet/src/dom/transition/Transition.js +28 -0
  84. data/lib/leaflet/src/geo/LatLng.js +44 -0
  85. data/lib/leaflet/src/geo/LatLngBounds.js +86 -0
  86. data/lib/leaflet/src/geo/crs/CRS.EPSG3395.js +13 -0
  87. data/lib/leaflet/src/geo/crs/CRS.EPSG3857.js +17 -0
  88. data/lib/leaflet/src/geo/crs/CRS.EPSG4326.js +7 -0
  89. data/lib/leaflet/src/geo/crs/CRS.js +17 -0
  90. data/lib/leaflet/src/geo/projection/Projection.LonLat.js +10 -0
  91. data/lib/leaflet/src/geo/projection/Projection.Mercator.js +51 -0
  92. data/lib/leaflet/src/geo/projection/Projection.SphericalMercator.js +23 -0
  93. data/lib/leaflet/src/geo/projection/Projection.js +5 -0
  94. data/lib/leaflet/src/geometry/Bounds.js +50 -0
  95. data/lib/leaflet/src/geometry/LineUtil.js +194 -0
  96. data/lib/leaflet/src/geometry/Point.js +66 -0
  97. data/lib/leaflet/src/geometry/PolyUtil.js +59 -0
  98. data/lib/leaflet/src/geometry/Transformation.js +31 -0
  99. data/lib/leaflet/src/layer/FeatureGroup.js +40 -0
  100. data/lib/leaflet/src/layer/GeoJSON.js +104 -0
  101. data/lib/leaflet/src/layer/ImageOverlay.js +58 -0
  102. data/lib/leaflet/src/layer/LayerGroup.js +74 -0
  103. data/lib/leaflet/src/layer/Popup.js +179 -0
  104. data/lib/leaflet/src/layer/marker/Icon.js +58 -0
  105. data/lib/leaflet/src/layer/marker/Marker.Drag.js +57 -0
  106. data/lib/leaflet/src/layer/marker/Marker.Popup.js +42 -0
  107. data/lib/leaflet/src/layer/marker/Marker.js +142 -0
  108. data/lib/leaflet/src/layer/tile/TileLayer.Canvas.js +41 -0
  109. data/lib/leaflet/src/layer/tile/TileLayer.WMS.js +47 -0
  110. data/lib/leaflet/src/layer/tile/TileLayer.js +310 -0
  111. data/lib/leaflet/src/layer/vector/Circle.js +68 -0
  112. data/lib/leaflet/src/layer/vector/CircleMarker.js +25 -0
  113. data/lib/leaflet/src/layer/vector/MultiPoly.js +34 -0
  114. data/lib/leaflet/src/layer/vector/Path.Popup.js +24 -0
  115. data/lib/leaflet/src/layer/vector/Path.SVG.js +138 -0
  116. data/lib/leaflet/src/layer/vector/Path.VML.js +93 -0
  117. data/lib/leaflet/src/layer/vector/Path.js +88 -0
  118. data/lib/leaflet/src/layer/vector/Polygon.js +64 -0
  119. data/lib/leaflet/src/layer/vector/Polyline.js +146 -0
  120. data/lib/leaflet/src/layer/vector/canvas/Circle.Canvas.js +18 -0
  121. data/lib/leaflet/src/layer/vector/canvas/Path.Canvas.js +146 -0
  122. data/lib/leaflet/src/layer/vector/canvas/Polygon.Canvas.js +34 -0
  123. data/lib/leaflet/src/layer/vector/canvas/Polyline.Canvas.js +27 -0
  124. data/lib/leaflet/src/map/Map.js +613 -0
  125. data/lib/leaflet/src/map/anim/Map.PanAnimation.js +70 -0
  126. data/lib/leaflet/src/map/anim/Map.ZoomAnimation.js +133 -0
  127. data/lib/leaflet/src/map/ext/Map.Control.js +50 -0
  128. data/lib/leaflet/src/map/ext/Map.Geolocation.js +86 -0
  129. data/lib/leaflet/src/map/ext/Map.Popup.js +20 -0
  130. data/lib/leaflet/src/map/handler/Map.BoxZoom.js +73 -0
  131. data/lib/leaflet/src/map/handler/Map.DoubleClickZoom.js +18 -0
  132. data/lib/leaflet/src/map/handler/Map.Drag.js +81 -0
  133. data/lib/leaflet/src/map/handler/Map.ScrollWheelZoom.js +55 -0
  134. data/lib/leaflet/src/map/handler/Map.TouchZoom.js +93 -0
  135. data/lib/zerista/CRS.Cartesian.js +20 -0
  136. data/lib/zerista/Projection.Identity.js +11 -0
  137. data/lib/zerista/zerista_layer.js +97 -0
  138. data/vendor/assets/javascripts/leaflet.js +139 -0
  139. data/vendor/assets/stylesheets/leaflet.css +1 -0
  140. data/vendor/assets/stylesheets/leaflet.ie.css +1 -0
  141. metadata +185 -0
@@ -0,0 +1,58 @@
1
+ L.Icon = L.Class.extend({
2
+ iconUrl: L.ROOT_URL + 'images/marker.png',
3
+ shadowUrl: L.ROOT_URL + 'images/marker-shadow.png',
4
+
5
+ iconSize: new L.Point(25, 41),
6
+ shadowSize: new L.Point(41, 41),
7
+
8
+ iconAnchor: new L.Point(13, 41),
9
+ popupAnchor: new L.Point(0, -33),
10
+
11
+ initialize: function (iconUrl) {
12
+ if (iconUrl) {
13
+ this.iconUrl = iconUrl;
14
+ }
15
+ },
16
+
17
+ createIcon: function () {
18
+ return this._createIcon('icon');
19
+ },
20
+
21
+ createShadow: function () {
22
+ return this._createIcon('shadow');
23
+ },
24
+
25
+ _createIcon: function (name) {
26
+ var size = this[name + 'Size'],
27
+ src = this[name + 'Url'],
28
+ img = this._createImg(src);
29
+
30
+ if (!src) {
31
+ return null;
32
+ }
33
+
34
+ img.className = 'leaflet-marker-' + name;
35
+
36
+ img.style.marginLeft = (-this.iconAnchor.x) + 'px';
37
+ img.style.marginTop = (-this.iconAnchor.y) + 'px';
38
+
39
+ if (size) {
40
+ img.style.width = size.x + 'px';
41
+ img.style.height = size.y + 'px';
42
+ }
43
+
44
+ return img;
45
+ },
46
+
47
+ _createImg: function (src) {
48
+ var el;
49
+ if (!L.Browser.ie6) {
50
+ el = document.createElement('img');
51
+ el.src = src;
52
+ } else {
53
+ el = document.createElement('div');
54
+ el.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + src + '")';
55
+ }
56
+ return el;
57
+ }
58
+ });
@@ -0,0 +1,57 @@
1
+ /*
2
+ * L.Handler.MarkerDrag is used internally by L.Marker to make the markers draggable.
3
+ */
4
+
5
+ L.Handler.MarkerDrag = L.Handler.extend({
6
+ initialize: function (marker) {
7
+ this._marker = marker;
8
+ },
9
+
10
+ addHooks: function () {
11
+ var icon = this._marker._icon;
12
+ if (!this._draggable) {
13
+ this._draggable = new L.Draggable(icon, icon);
14
+
15
+ this._draggable
16
+ .on('dragstart', this._onDragStart, this)
17
+ .on('drag', this._onDrag, this)
18
+ .on('dragend', this._onDragEnd, this);
19
+ }
20
+ this._draggable.enable();
21
+ },
22
+
23
+ removeHooks: function () {
24
+ this._draggable.disable();
25
+ },
26
+
27
+ moved: function () {
28
+ return this._draggable && this._draggable._moved;
29
+ },
30
+
31
+ _onDragStart: function (e) {
32
+ this._marker
33
+ .closePopup()
34
+ .fire('movestart')
35
+ .fire('dragstart');
36
+ },
37
+
38
+ _onDrag: function (e) {
39
+ // update shadow position
40
+ var iconPos = L.DomUtil.getPosition(this._marker._icon);
41
+ if (this._marker._shadow) {
42
+ L.DomUtil.setPosition(this._marker._shadow, iconPos);
43
+ }
44
+
45
+ this._marker._latlng = this._marker._map.layerPointToLatLng(iconPos);
46
+
47
+ this._marker
48
+ .fire('move')
49
+ .fire('drag');
50
+ },
51
+
52
+ _onDragEnd: function () {
53
+ this._marker
54
+ .fire('moveend')
55
+ .fire('dragend');
56
+ }
57
+ });
@@ -0,0 +1,42 @@
1
+ /*
2
+ * Popup extension to L.Marker, adding openPopup & bindPopup methods.
3
+ */
4
+
5
+ L.Marker.include({
6
+ openPopup: function () {
7
+ this._popup.setLatLng(this._latlng);
8
+ if (this._map) {
9
+ this._map.openPopup(this._popup);
10
+ }
11
+
12
+ return this;
13
+ },
14
+
15
+ closePopup: function () {
16
+ if (this._popup) {
17
+ this._popup._close();
18
+ }
19
+ return this;
20
+ },
21
+
22
+ bindPopup: function (content, options) {
23
+ options = L.Util.extend({offset: this.options.icon.popupAnchor}, options);
24
+
25
+ if (!this._popup) {
26
+ this.on('click', this.openPopup, this);
27
+ }
28
+
29
+ this._popup = new L.Popup(options, this);
30
+ this._popup.setContent(content);
31
+
32
+ return this;
33
+ },
34
+
35
+ unbindPopup: function () {
36
+ if (this._popup) {
37
+ this._popup = null;
38
+ this.off('click', this.openPopup);
39
+ }
40
+ return this;
41
+ }
42
+ });
@@ -0,0 +1,142 @@
1
+ /*
2
+ * L.Marker is used to display clickable/draggable icons on the map.
3
+ */
4
+
5
+ L.Marker = L.Class.extend({
6
+
7
+ includes: L.Mixin.Events,
8
+
9
+ options: {
10
+ icon: new L.Icon(),
11
+ title: '',
12
+ clickable: true,
13
+ draggable: false,
14
+ zIndexOffset: 0
15
+ },
16
+
17
+ initialize: function (latlng, options) {
18
+ L.Util.setOptions(this, options);
19
+ this._latlng = latlng;
20
+ },
21
+
22
+ onAdd: function (map) {
23
+ this._map = map;
24
+
25
+ this._initIcon();
26
+
27
+ map.on('viewreset', this._reset, this);
28
+ this._reset();
29
+ },
30
+
31
+ onRemove: function (map) {
32
+ this._removeIcon();
33
+
34
+ // TODO move to Marker.Popup.js
35
+ if (this.closePopup) {
36
+ this.closePopup();
37
+ }
38
+
39
+ this._map = null;
40
+
41
+ map.off('viewreset', this._reset, this);
42
+ },
43
+
44
+ getLatLng: function () {
45
+ return this._latlng;
46
+ },
47
+
48
+ setLatLng: function (latlng) {
49
+ this._latlng = latlng;
50
+ if (this._icon) {
51
+ this._reset();
52
+
53
+ if (this._popup) {
54
+ this._popup.setLatLng(this._latlng);
55
+ }
56
+ }
57
+ },
58
+
59
+ setIcon: function (icon) {
60
+ if (this._map) {
61
+ this._removeIcon();
62
+ }
63
+
64
+ this.options.icon = icon;
65
+
66
+ if (this._map) {
67
+ this._initIcon();
68
+ this._reset();
69
+ }
70
+ },
71
+
72
+ _initIcon: function () {
73
+ if (!this._icon) {
74
+ this._icon = this.options.icon.createIcon();
75
+
76
+ if (this.options.title) {
77
+ this._icon.title = this.options.title;
78
+ }
79
+
80
+ this._initInteraction();
81
+ }
82
+ if (!this._shadow) {
83
+ this._shadow = this.options.icon.createShadow();
84
+ }
85
+
86
+ this._map._panes.markerPane.appendChild(this._icon);
87
+ if (this._shadow) {
88
+ this._map._panes.shadowPane.appendChild(this._shadow);
89
+ }
90
+ },
91
+
92
+ _removeIcon: function () {
93
+ this._map._panes.markerPane.removeChild(this._icon);
94
+ if (this._shadow) {
95
+ this._map._panes.shadowPane.removeChild(this._shadow);
96
+ }
97
+ this._icon = this._shadow = null;
98
+ },
99
+
100
+ _reset: function () {
101
+ var pos = this._map.latLngToLayerPoint(this._latlng).round();
102
+
103
+ L.DomUtil.setPosition(this._icon, pos);
104
+ if (this._shadow) {
105
+ L.DomUtil.setPosition(this._shadow, pos);
106
+ }
107
+
108
+ this._icon.style.zIndex = pos.y + this.options.zIndexOffset;
109
+ },
110
+
111
+ _initInteraction: function () {
112
+ if (this.options.clickable) {
113
+ this._icon.className += ' leaflet-clickable';
114
+
115
+ L.DomEvent.addListener(this._icon, 'click', this._onMouseClick, this);
116
+
117
+ var events = ['dblclick', 'mousedown', 'mouseover', 'mouseout'];
118
+ for (var i = 0; i < events.length; i++) {
119
+ L.DomEvent.addListener(this._icon, events[i], this._fireMouseEvent, this);
120
+ }
121
+ }
122
+
123
+ if (L.Handler.MarkerDrag) {
124
+ this.dragging = new L.Handler.MarkerDrag(this);
125
+
126
+ if (this.options.draggable) {
127
+ this.dragging.enable();
128
+ }
129
+ }
130
+ },
131
+
132
+ _onMouseClick: function (e) {
133
+ L.DomEvent.stopPropagation(e);
134
+ if (this.dragging && this.dragging.moved()) { return; }
135
+ this.fire(e.type);
136
+ },
137
+
138
+ _fireMouseEvent: function (e) {
139
+ this.fire(e.type);
140
+ L.DomEvent.stopPropagation(e);
141
+ }
142
+ });
@@ -0,0 +1,41 @@
1
+ L.TileLayer.Canvas = L.TileLayer.extend({
2
+ options: {
3
+ async: false
4
+ },
5
+
6
+ initialize: function (options) {
7
+ L.Util.setOptions(this, options);
8
+ },
9
+
10
+ _createTileProto: function () {
11
+ this._canvasProto = L.DomUtil.create('canvas', 'leaflet-tile');
12
+
13
+ var tileSize = this.options.tileSize;
14
+ this._canvasProto.width = tileSize;
15
+ this._canvasProto.height = tileSize;
16
+ },
17
+
18
+ _createTile: function () {
19
+ var tile = this._canvasProto.cloneNode(false);
20
+ tile.onselectstart = tile.onmousemove = L.Util.falseFn;
21
+ return tile;
22
+ },
23
+
24
+ _loadTile: function (tile, tilePoint, zoom) {
25
+ tile._layer = this;
26
+
27
+ this.drawTile(tile, tilePoint, zoom);
28
+
29
+ if (!this.options.async) {
30
+ this.tileDrawn(tile);
31
+ }
32
+ },
33
+
34
+ drawTile: function (tile, tilePoint, zoom) {
35
+ // override with rendering code
36
+ },
37
+
38
+ tileDrawn: function (tile) {
39
+ this._tileOnLoad.call(tile);
40
+ }
41
+ });
@@ -0,0 +1,47 @@
1
+ L.TileLayer.WMS = L.TileLayer.extend({
2
+ defaultWmsParams: {
3
+ service: 'WMS',
4
+ request: 'GetMap',
5
+ version: '1.1.1',
6
+ layers: '',
7
+ styles: '',
8
+ format: 'image/jpeg',
9
+ transparent: false
10
+ },
11
+
12
+ initialize: function (/*String*/ url, /*Object*/ options) {
13
+ this._url = url;
14
+
15
+ this.wmsParams = L.Util.extend({}, this.defaultWmsParams);
16
+ this.wmsParams.width = this.wmsParams.height = this.options.tileSize;
17
+
18
+ for (var i in options) {
19
+ // all keys that are not TileLayer options go to WMS params
20
+ if (!this.options.hasOwnProperty(i)) {
21
+ this.wmsParams[i] = options[i];
22
+ }
23
+ }
24
+
25
+ L.Util.setOptions(this, options);
26
+ },
27
+
28
+ onAdd: function (map) {
29
+ var projectionKey = (parseFloat(this.wmsParams.version) >= 1.3 ? 'crs' : 'srs');
30
+ this.wmsParams[projectionKey] = map.options.crs.code;
31
+
32
+ L.TileLayer.prototype.onAdd.call(this, map);
33
+ },
34
+
35
+ getTileUrl: function (/*Point*/ tilePoint, /*Number*/ zoom)/*-> String*/ {
36
+ var tileSize = this.options.tileSize,
37
+ nwPoint = tilePoint.multiplyBy(tileSize),
38
+ sePoint = nwPoint.add(new L.Point(tileSize, tileSize)),
39
+ nwMap = this._map.unproject(nwPoint, this._zoom, true),
40
+ seMap = this._map.unproject(sePoint, this._zoom, true),
41
+ nw = this._map.options.crs.project(nwMap),
42
+ se = this._map.options.crs.project(seMap),
43
+ bbox = [nw.x, se.y, se.x, nw.y].join(',');
44
+
45
+ return this._url + L.Util.getParamString(this.wmsParams) + "&bbox=" + bbox;
46
+ }
47
+ });
@@ -0,0 +1,310 @@
1
+ /*
2
+ * L.TileLayer is used for standard xyz-numbered tile layers.
3
+ */
4
+
5
+ L.TileLayer = L.Class.extend({
6
+ includes: L.Mixin.Events,
7
+
8
+ options: {
9
+ minZoom: 0,
10
+ maxZoom: 18,
11
+ tileSize: 256,
12
+ subdomains: 'abc',
13
+ errorTileUrl: '',
14
+ attribution: '',
15
+ opacity: 1,
16
+ scheme: 'xyz',
17
+ continuousWorld: false,
18
+ noWrap: false,
19
+ zoomOffset: 0,
20
+
21
+ unloadInvisibleTiles: L.Browser.mobile,
22
+ updateWhenIdle: L.Browser.mobile
23
+ },
24
+
25
+ initialize: function (url, options, urlParams) {
26
+ L.Util.setOptions(this, options);
27
+
28
+ this._url = url;
29
+ this._urlParams = urlParams;
30
+
31
+ if (typeof this.options.subdomains === 'string') {
32
+ this.options.subdomains = this.options.subdomains.split('');
33
+ }
34
+ },
35
+
36
+ onAdd: function (map, insertAtTheBottom) {
37
+ this._map = map;
38
+ this._insertAtTheBottom = insertAtTheBottom;
39
+
40
+ // create a container div for tiles
41
+ this._initContainer();
42
+
43
+ // create an image to clone for tiles
44
+ this._createTileProto();
45
+
46
+ // set up events
47
+ map.on('viewreset', this._resetCallback, this);
48
+
49
+ if (this.options.updateWhenIdle) {
50
+ map.on('moveend', this._update, this);
51
+ } else {
52
+ this._limitedUpdate = L.Util.limitExecByInterval(this._update, 150, this);
53
+ map.on('move', this._limitedUpdate, this);
54
+ }
55
+
56
+ this._reset();
57
+ this._update();
58
+ },
59
+
60
+ onRemove: function (map) {
61
+ this._map.getPanes().tilePane.removeChild(this._container);
62
+ this._container = null;
63
+
64
+ this._map.off('viewreset', this._resetCallback, this);
65
+
66
+ if (this.options.updateWhenIdle) {
67
+ this._map.off('moveend', this._update, this);
68
+ } else {
69
+ this._map.off('move', this._limitedUpdate, this);
70
+ }
71
+ },
72
+
73
+ getAttribution: function () {
74
+ return this.options.attribution;
75
+ },
76
+
77
+ setOpacity: function (opacity) {
78
+ this.options.opacity = opacity;
79
+
80
+ this._setOpacity(opacity);
81
+
82
+ // stupid webkit hack to force redrawing of tiles
83
+ if (L.Browser.webkit) {
84
+ for (var i in this._tiles) {
85
+ if (this._tiles.hasOwnProperty(i)) {
86
+ this._tiles[i].style.webkitTransform += ' translate(0,0)';
87
+ }
88
+ }
89
+ }
90
+ },
91
+
92
+ _setOpacity: function (opacity) {
93
+ if (opacity < 1) {
94
+ L.DomUtil.setOpacity(this._container, opacity);
95
+ }
96
+ },
97
+
98
+ _initContainer: function () {
99
+ var tilePane = this._map.getPanes().tilePane,
100
+ first = tilePane.firstChild;
101
+
102
+ if (!this._container || tilePane.empty) {
103
+ this._container = L.DomUtil.create('div', 'leaflet-layer');
104
+
105
+ if (this._insertAtTheBottom && first) {
106
+ tilePane.insertBefore(this._container, first);
107
+ } else {
108
+ tilePane.appendChild(this._container);
109
+ }
110
+
111
+ this._setOpacity(this.options.opacity);
112
+ }
113
+ },
114
+
115
+ _resetCallback: function (e) {
116
+ this._reset(e.hard);
117
+ },
118
+
119
+ _reset: function (clearOldContainer) {
120
+ var key;
121
+ for (key in this._tiles) {
122
+ if (this._tiles.hasOwnProperty(key)) {
123
+ this.fire("tileunload", {tile: this._tiles[key]});
124
+ }
125
+ }
126
+ this._tiles = {};
127
+
128
+ if (clearOldContainer && this._container) {
129
+ this._container.innerHTML = "";
130
+ }
131
+ this._initContainer();
132
+ },
133
+
134
+ _update: function () {
135
+ var bounds = this._map.getPixelBounds(),
136
+ tileSize = this.options.tileSize;
137
+
138
+ var nwTilePoint = new L.Point(
139
+ Math.floor(bounds.min.x / tileSize),
140
+ Math.floor(bounds.min.y / tileSize)),
141
+ seTilePoint = new L.Point(
142
+ Math.floor(bounds.max.x / tileSize),
143
+ Math.floor(bounds.max.y / tileSize)),
144
+ tileBounds = new L.Bounds(nwTilePoint, seTilePoint);
145
+
146
+ this._addTilesFromCenterOut(tileBounds);
147
+
148
+ if (this.options.unloadInvisibleTiles) {
149
+ this._removeOtherTiles(tileBounds);
150
+ }
151
+ },
152
+
153
+ _addTilesFromCenterOut: function (bounds) {
154
+ var queue = [],
155
+ center = bounds.getCenter();
156
+
157
+ for (var j = bounds.min.y; j <= bounds.max.y; j++) {
158
+ for (var i = bounds.min.x; i <= bounds.max.x; i++) {
159
+ if ((i + ':' + j) in this._tiles) {
160
+ continue;
161
+ }
162
+ queue.push(new L.Point(i, j));
163
+ }
164
+ }
165
+
166
+ // load tiles in order of their distance to center
167
+ queue.sort(function (a, b) {
168
+ return a.distanceTo(center) - b.distanceTo(center);
169
+ });
170
+
171
+ var fragment = document.createDocumentFragment();
172
+
173
+ this._tilesToLoad = queue.length;
174
+ for (var k = 0, len = this._tilesToLoad; k < len; k++) {
175
+ this._addTile(queue[k], fragment);
176
+ }
177
+
178
+ this._container.appendChild(fragment);
179
+ },
180
+
181
+ _removeOtherTiles: function (bounds) {
182
+ var kArr, x, y, key, tile;
183
+
184
+ for (key in this._tiles) {
185
+ if (this._tiles.hasOwnProperty(key)) {
186
+ kArr = key.split(':');
187
+ x = parseInt(kArr[0], 10);
188
+ y = parseInt(kArr[1], 10);
189
+
190
+ // remove tile if it's out of bounds
191
+ if (x < bounds.min.x || x > bounds.max.x || y < bounds.min.y || y > bounds.max.y) {
192
+
193
+ tile = this._tiles[key];
194
+ this.fire("tileunload", {tile: tile, url: tile.src});
195
+
196
+ // evil, don't do this! crashes Android 3, produces load errors, doesn't solve memory leaks
197
+ // this._tiles[key].src = '';
198
+
199
+ if (tile.parentNode === this._container) {
200
+ this._container.removeChild(tile);
201
+ }
202
+ delete this._tiles[key];
203
+ }
204
+ }
205
+ }
206
+ },
207
+
208
+ _addTile: function (tilePoint, container) {
209
+ var tilePos = this._getTilePos(tilePoint),
210
+ zoom = this._map.getZoom(),
211
+ key = tilePoint.x + ':' + tilePoint.y,
212
+ tileLimit = Math.pow(2, (zoom + this.options.zoomOffset));
213
+
214
+ // wrap tile coordinates
215
+ if (!this.options.continuousWorld) {
216
+ if (!this.options.noWrap) {
217
+ tilePoint.x = ((tilePoint.x % tileLimit) + tileLimit) % tileLimit;
218
+ } else if (tilePoint.x < 0 || tilePoint.x >= tileLimit) {
219
+ this._tilesToLoad--;
220
+ return;
221
+ }
222
+
223
+ if (tilePoint.y < 0 || tilePoint.y >= tileLimit) {
224
+ this._tilesToLoad--;
225
+ return;
226
+ }
227
+ }
228
+
229
+ // create tile
230
+ var tile = this._createTile();
231
+ L.DomUtil.setPosition(tile, tilePos);
232
+
233
+ this._tiles[key] = tile;
234
+
235
+ if (this.options.scheme === 'tms') {
236
+ tilePoint.y = tileLimit - tilePoint.y - 1;
237
+ }
238
+
239
+ this._loadTile(tile, tilePoint, zoom);
240
+
241
+ container.appendChild(tile);
242
+ },
243
+
244
+ _getTilePos: function (tilePoint) {
245
+ var origin = this._map.getPixelOrigin(),
246
+ tileSize = this.options.tileSize;
247
+
248
+ return tilePoint.multiplyBy(tileSize).subtract(origin);
249
+ },
250
+
251
+ // image-specific code (override to implement e.g. Canvas or SVG tile layer)
252
+
253
+ getTileUrl: function (tilePoint, zoom) {
254
+ var subdomains = this.options.subdomains,
255
+ s = this.options.subdomains[(tilePoint.x + tilePoint.y) % subdomains.length];
256
+
257
+ return L.Util.template(this._url, L.Util.extend({
258
+ s: s,
259
+ z: zoom + this.options.zoomOffset,
260
+ x: tilePoint.x,
261
+ y: tilePoint.y
262
+ }, this._urlParams));
263
+ },
264
+
265
+ _createTileProto: function () {
266
+ this._tileImg = L.DomUtil.create('img', 'leaflet-tile');
267
+ this._tileImg.galleryimg = 'no';
268
+
269
+ var tileSize = this.options.tileSize;
270
+ this._tileImg.style.width = tileSize + 'px';
271
+ this._tileImg.style.height = tileSize + 'px';
272
+ },
273
+
274
+ _createTile: function () {
275
+ var tile = this._tileImg.cloneNode(false);
276
+ tile.onselectstart = tile.onmousemove = L.Util.falseFn;
277
+ return tile;
278
+ },
279
+
280
+ _loadTile: function (tile, tilePoint, zoom) {
281
+ tile._layer = this;
282
+ tile.onload = this._tileOnLoad;
283
+ tile.onerror = this._tileOnError;
284
+ tile.src = this.getTileUrl(tilePoint, zoom);
285
+ },
286
+
287
+ _tileOnLoad: function (e) {
288
+ var layer = this._layer;
289
+
290
+ this.className += ' leaflet-tile-loaded';
291
+
292
+ layer.fire('tileload', {tile: this, url: this.src});
293
+
294
+ layer._tilesToLoad--;
295
+ if (!layer._tilesToLoad) {
296
+ layer.fire('load');
297
+ }
298
+ },
299
+
300
+ _tileOnError: function (e) {
301
+ var layer = this._layer;
302
+
303
+ layer.fire('tileerror', {tile: this, url: this.src});
304
+
305
+ var newUrl = layer.options.errorTileUrl;
306
+ if (newUrl) {
307
+ this.src = newUrl;
308
+ }
309
+ }
310
+ });