123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- (function (factory) {
- var L, proj4;
- if (typeof define === 'function' && define.amd) {
- // AMD
- define(['leaflet', 'proj4'], factory);
- } else if (typeof module === 'object' && typeof module.exports === "object") {
- // Node/CommonJS
- L = require('leaflet');
- proj4 = require('proj4');
- module.exports = factory(L, proj4);
- } else {
- // Browser globals
- if (typeof window.L === 'undefined' || typeof window.proj4 === 'undefined')
- throw 'Leaflet and proj4 must be loaded first';
- factory(window.L, window.proj4);
- }
- }(function (L, proj4) {
- L.Proj = {};
- L.Proj._isProj4Obj = function(a) {
- return (typeof a.inverse !== 'undefined' &&
- typeof a.forward !== 'undefined');
- };
- L.Proj.Projection = L.Class.extend({
- initialize: function(code, def, bounds) {
- var isP4 = L.Proj._isProj4Obj(code);
- this._proj = isP4 ? code : this._projFromCodeDef(code, def);
- this.bounds = isP4 ? def : bounds;
- },
- project: function (latlng) {
- var point = this._proj.forward([latlng.lng, latlng.lat]);
- return new L.Point(point[0], point[1]);
- },
- unproject: function (point, unbounded) {
- var point2 = this._proj.inverse([point.x, point.y]);
- return new L.LatLng(point2[1], point2[0], unbounded);
- },
- _projFromCodeDef: function(code, def) {
- if (def) {
- proj4.defs(code, def);
- } else if (proj4.defs[code] === undefined) {
- var urn = code.split(':');
- if (urn.length > 3) {
- code = urn[urn.length - 3] + ':' + urn[urn.length - 1];
- }
- if (proj4.defs[code] === undefined) {
- throw 'No projection definition for code ' + code;
- }
- }
- return proj4(code);
- }
- });
- L.Proj.CRS = L.Class.extend({
- includes: L.CRS,
- options: {
- transformation: new L.Transformation(1, 0, -1, 0)
- },
- initialize: function(a, b, c) {
- var code,
- proj,
- def,
- options;
- if (L.Proj._isProj4Obj(a)) {
- proj = a;
- code = proj.srsCode;
- options = b || {};
- this.projection = new L.Proj.Projection(proj, options.bounds);
- } else {
- code = a;
- def = b;
- options = c || {};
- this.projection = new L.Proj.Projection(code, def, options.bounds);
- }
- L.Util.setOptions(this, options);
- this.code = code;
- this.transformation = this.options.transformation;
- if (this.options.origin) {
- this.transformation =
- new L.Transformation(1, -this.options.origin[0],
- -1, this.options.origin[1]);
- }
- if (this.options.scales) {
- this._scales = this.options.scales;
- } else if (this.options.resolutions) {
- this._scales = [];
- for (var i = this.options.resolutions.length - 1; i >= 0; i--) {
- if (this.options.resolutions[i]) {
- this._scales[i] = 1 / this.options.resolutions[i];
- }
- }
- }
- this.infinite = !this.options.bounds;
- },
- scale: function(zoom) {
- var iZoom = Math.floor(zoom),
- baseScale,
- nextScale,
- scaleDiff,
- zDiff;
- if (zoom === iZoom) {
- return this._scales[zoom];
- } else {
- // Non-integer zoom, interpolate
- baseScale = this._scales[iZoom];
- nextScale = this._scales[iZoom + 1];
- scaleDiff = nextScale - baseScale;
- zDiff = (zoom - iZoom);
- return baseScale + scaleDiff * zDiff;
- }
- },
- zoom: function(scale) {
- // Find closest number in this._scales, down
- var downScale = this._closestElement(this._scales, scale),
- downZoom = this._scales.indexOf(downScale),
- nextScale,
- nextZoom,
- scaleDiff;
- // Check if scale is downScale => return array index
- if (scale === downScale) {
- return downZoom;
- }
- // Interpolate
- nextZoom = downZoom + 1;
- nextScale = this._scales[nextZoom];
- if (nextScale === undefined) {
- return Infinity;
- }
- scaleDiff = nextScale - downScale;
- return (scale - downScale) / scaleDiff + downZoom;
- },
- /* Get the closest lowest element in an array */
- _closestElement: function(array, element) {
- var low;
- for (var i = array.length; i--;) {
- if (array[i] <= element && (low === undefined || low < array[i])) {
- low = array[i];
- }
- }
- return low;
- }
- });
- L.Proj.GeoJSON = L.GeoJSON.extend({
- initialize: function(geojson, options) {
- this._callLevel = 0;
- L.GeoJSON.prototype.initialize.call(this, geojson, options);
- },
- addData: function(geojson) {
- var crs;
- if (geojson) {
- if (geojson.crs && geojson.crs.type === 'name') {
- crs = new L.Proj.CRS(geojson.crs.properties.name);
- } else if (geojson.crs && geojson.crs.type) {
- crs = new L.Proj.CRS(geojson.crs.type + ':' + geojson.crs.properties.code);
- }
- if (crs !== undefined) {
- this.options.coordsToLatLng = function(coords) {
- var point = L.point(coords[0], coords[1]);
- return crs.projection.unproject(point);
- };
- }
- }
- // Base class' addData might call us recursively, but
- // CRS shouldn't be cleared in that case, since CRS applies
- // to the whole GeoJSON, inluding sub-features.
- this._callLevel++;
- try {
- L.GeoJSON.prototype.addData.call(this, geojson);
- } finally {
- this._callLevel--;
- if (this._callLevel === 0) {
- delete this.options.coordsToLatLng;
- }
- }
- }
- });
- L.Proj.geoJson = function(geojson, options) {
- return new L.Proj.GeoJSON(geojson, options);
- };
- L.Proj.ImageOverlay = L.ImageOverlay.extend({
- initialize: function (url, bounds, options) {
- L.ImageOverlay.prototype.initialize.call(this, url, null, options);
- this._projectedBounds = bounds;
- },
- // Danger ahead: Overriding internal methods in Leaflet.
- // Decided to do this rather than making a copy of L.ImageOverlay
- // and doing very tiny modifications to it.
- // Future will tell if this was wise or not.
- _animateZoom: function (event) {
- var scale = this._map.getZoomScale(event.zoom);
- var northWest = L.point(this._projectedBounds.min.x, this._projectedBounds.max.y);
- var offset = this._projectedToNewLayerPoint(northWest, event.zoom, event.center);
- L.DomUtil.setTransform(this._image, offset, scale);
- },
- _reset: function () {
- var zoom = this._map.getZoom();
- var pixelOrigin = this._map.getPixelOrigin();
- var bounds = L.bounds(
- this._transform(this._projectedBounds.min, zoom)._subtract(pixelOrigin),
- this._transform(this._projectedBounds.max, zoom)._subtract(pixelOrigin)
- );
- var size = bounds.getSize();
- L.DomUtil.setPosition(this._image, bounds.min);
- this._image.style.width = size.x + 'px';
- this._image.style.height = size.y + 'px';
- },
- _projectedToNewLayerPoint: function (point, zoom, center) {
- var viewHalf = this._map.getSize()._divideBy(2);
- var newTopLeft = this._map.project(center, zoom)._subtract(viewHalf)._round();
- var topLeft = newTopLeft.add(this._map._getMapPanePos());
- return this._transform(point, zoom)._subtract(topLeft);
- },
- _transform: function (point, zoom) {
- var crs = this._map.options.crs;
- var transformation = crs.transformation;
- var scale = crs.scale(zoom);
- return transformation.transform(point, scale);
- }
- });
- L.Proj.imageOverlay = function (url, bounds, options) {
- return new L.Proj.ImageOverlay(url, bounds, options);
- };
- return L.Proj;
- }));
|