proj4leaflet.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. (function (factory) {
  2. var L, proj4;
  3. if (typeof define === 'function' && define.amd) {
  4. // AMD
  5. define(['leaflet', 'proj4'], factory);
  6. } else if (typeof module !== 'undefined') {
  7. // Node/CommonJS
  8. L = require('leaflet');
  9. proj4 = require('proj4');
  10. module.exports = factory(L, proj4);
  11. } else {
  12. // Browser globals
  13. if (typeof window.L === 'undefined' || typeof window.proj4 === 'undefined')
  14. throw 'Leaflet and proj4 must be loaded first';
  15. factory(window.L, window.proj4);
  16. }
  17. }(function (L, proj4) {
  18. L.Proj = {};
  19. L.Proj._isProj4Obj = function(a) {
  20. return (typeof a.inverse !== 'undefined' &&
  21. typeof a.forward !== 'undefined');
  22. };
  23. L.Proj.ScaleDependantTransformation = function(scaleTransforms) {
  24. this.scaleTransforms = scaleTransforms;
  25. };
  26. L.Proj.ScaleDependantTransformation.prototype.transform = function(point, scale) {
  27. return this.scaleTransforms[scale].transform(point, scale);
  28. };
  29. L.Proj.ScaleDependantTransformation.prototype.untransform = function(point, scale) {
  30. return this.scaleTransforms[scale].untransform(point, scale);
  31. };
  32. L.Proj.Projection = L.Class.extend({
  33. initialize: function(a, def) {
  34. if (L.Proj._isProj4Obj(a)) {
  35. this._proj = a;
  36. } else {
  37. var code = a;
  38. if (def) {
  39. proj4.defs(code, def);
  40. } else if (proj4.defs[code] === undefined) {
  41. var urn = code.split(':');
  42. if (urn.length > 3) {
  43. code = urn[urn.length - 3] + ':' + urn[urn.length - 1];
  44. }
  45. if (proj4.defs[code] === undefined) {
  46. throw 'No projection definition for code ' + code;
  47. }
  48. }
  49. this._proj = proj4(code);
  50. }
  51. },
  52. project: function (latlng) {
  53. var point = this._proj.forward([latlng.lng, latlng.lat]);
  54. return new L.Point(point[0], point[1]);
  55. },
  56. unproject: function (point, unbounded) {
  57. var point2 = this._proj.inverse([point.x, point.y]);
  58. return new L.LatLng(point2[1], point2[0], unbounded);
  59. }
  60. });
  61. L.Proj.CRS = L.Class.extend({
  62. includes: L.CRS,
  63. options: {
  64. transformation: new L.Transformation(1, 0, -1, 0)
  65. },
  66. initialize: function(a, b, c) {
  67. var code, proj, def, options;
  68. if (L.Proj._isProj4Obj(a)) {
  69. proj = a;
  70. code = proj.srsCode;
  71. options = b || {};
  72. this.projection = new L.Proj.Projection(proj);
  73. } else {
  74. code = a;
  75. def = b;
  76. options = c || {};
  77. this.projection = new L.Proj.Projection(code, def);
  78. }
  79. L.Util.setOptions(this, options);
  80. this.code = code;
  81. this.transformation = this.options.transformation;
  82. if (this.options.origin) {
  83. this.transformation =
  84. new L.Transformation(1, -this.options.origin[0],
  85. -1, this.options.origin[1]);
  86. }
  87. if (this.options.scales) {
  88. this._scales = this.options.scales;
  89. } else if (this.options.resolutions) {
  90. this._scales = [];
  91. for (var i = this.options.resolutions.length - 1; i >= 0; i--) {
  92. if (this.options.resolutions[i]) {
  93. this._scales[i] = 1 / this.options.resolutions[i];
  94. }
  95. }
  96. }
  97. this.scale = function(zoom) {
  98. return this._scales[zoom];
  99. };
  100. }
  101. });
  102. L.Proj.CRS.TMS = L.Proj.CRS.extend({
  103. options: {
  104. tileSize: 256
  105. },
  106. initialize: function(a, b, c, d) {
  107. var code,
  108. def,
  109. proj,
  110. projectedBounds,
  111. options;
  112. if (L.Proj._isProj4Obj(a)) {
  113. proj = a;
  114. projectedBounds = b;
  115. options = c || {};
  116. options.origin = [projectedBounds[0], projectedBounds[3]];
  117. L.Proj.CRS.prototype.initialize.call(this, proj, options);
  118. } else {
  119. code = a;
  120. def = b;
  121. projectedBounds = c;
  122. options = d || {};
  123. options.origin = [projectedBounds[0], projectedBounds[3]];
  124. L.Proj.CRS.prototype.initialize.call(this, code, def, options);
  125. }
  126. this.projectedBounds = projectedBounds;
  127. this._sizes = this._calculateSizes();
  128. },
  129. _calculateSizes: function() {
  130. var sizes = [],
  131. crsBounds = this.projectedBounds,
  132. projectedTileSize,
  133. upperY,
  134. i;
  135. for (i = this._scales.length - 1; i >= 0; i--) {
  136. if (this._scales[i]) {
  137. projectedTileSize = this.options.tileSize / this._scales[i];
  138. upperY = crsBounds[1] + Math.ceil((crsBounds[3] - crsBounds[1]) /
  139. projectedTileSize) * projectedTileSize;
  140. sizes[i] = L.point((crsBounds[2] - crsBounds[0]) / this._scales[i],
  141. (upperY - crsBounds[1]) * this._scales[i]);
  142. }
  143. }
  144. return sizes;
  145. },
  146. getSize: function(zoom) {
  147. return this._sizes[zoom];
  148. }
  149. });
  150. L.Proj.TileLayer = {};
  151. // Note: deprecated and not necessary since 0.7, will be removed
  152. L.Proj.TileLayer.TMS = L.TileLayer.extend({
  153. options: {
  154. continuousWorld: true
  155. },
  156. initialize: function(urlTemplate, crs, options) {
  157. var boundsMatchesGrid = true,
  158. scaleTransforms,
  159. upperY,
  160. crsBounds,
  161. i;
  162. if (!(crs instanceof L.Proj.CRS.TMS)) {
  163. throw 'CRS is not L.Proj.CRS.TMS.';
  164. }
  165. L.TileLayer.prototype.initialize.call(this, urlTemplate, options);
  166. this.crs = crs;
  167. crsBounds = this.crs.projectedBounds;
  168. // Verify grid alignment
  169. for (i = this.options.minZoom; i < this.options.maxZoom && boundsMatchesGrid; i++) {
  170. var gridHeight = (crsBounds[3] - crsBounds[1]) /
  171. this._projectedTileSize(i);
  172. boundsMatchesGrid = Math.abs(gridHeight - Math.round(gridHeight)) > 1e-3;
  173. }
  174. if (!boundsMatchesGrid) {
  175. scaleTransforms = {};
  176. for (i = this.options.minZoom; i < this.options.maxZoom; i++) {
  177. upperY = crsBounds[1] + Math.ceil((crsBounds[3] - crsBounds[1]) /
  178. this._projectedTileSize(i)) * this._projectedTileSize(i);
  179. scaleTransforms[this.crs.scale(i)] = new L.Transformation(1, -crsBounds[0], -1, upperY);
  180. }
  181. this.crs = new L.Proj.CRS.TMS(this.crs.projection._proj, crsBounds, this.crs.options);
  182. this.crs.transformation = new L.Proj.ScaleDependantTransformation(scaleTransforms);
  183. }
  184. },
  185. getTileUrl: function(tilePoint) {
  186. var zoom = this._map.getZoom(),
  187. gridHeight = Math.ceil(
  188. (this.crs.projectedBounds[3] - this.crs.projectedBounds[1]) /
  189. this._projectedTileSize(zoom));
  190. return L.Util.template(this._url, L.Util.extend({
  191. s: this._getSubdomain(tilePoint),
  192. z: this._getZoomForUrl(),
  193. x: tilePoint.x,
  194. y: gridHeight - tilePoint.y - 1
  195. }, this.options));
  196. },
  197. _projectedTileSize: function(zoom) {
  198. return (this.options.tileSize / this.crs.scale(zoom));
  199. }
  200. });
  201. L.Proj.GeoJSON = L.GeoJSON.extend({
  202. initialize: function(geojson, options) {
  203. if (geojson.crs && geojson.crs.type === 'name') {
  204. var crs = new L.Proj.CRS(geojson.crs.properties.name);
  205. options = options || {};
  206. options.coordsToLatLng = function(coords) {
  207. var point = L.point(coords[0], coords[1]);
  208. return crs.projection.unproject(point);
  209. };
  210. }
  211. L.GeoJSON.prototype.initialize.call(this, geojson, options);
  212. }
  213. });
  214. L.Proj.geoJson = function(geojson, options) {
  215. return new L.Proj.GeoJSON(geojson, options);
  216. };
  217. if (typeof L.CRS !== 'undefined') {
  218. // This is left here for backwards compatibility
  219. L.CRS.proj4js = (function () {
  220. return function (code, def, transformation, options) {
  221. options = options || {};
  222. if (transformation) {
  223. options.transformation = transformation;
  224. }
  225. return new L.Proj.CRS(code, def, options);
  226. };
  227. }());
  228. }
  229. return L.Proj;
  230. }));