Non puoi selezionare più di 25 argomenti
Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
391 righe
11 KiB
391 righe
11 KiB
2 anni fa
|
(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.ScaleDependantTransformation = function(scaleTransforms) {
|
||
|
this.scaleTransforms = scaleTransforms;
|
||
|
};
|
||
|
|
||
|
L.Proj.ScaleDependantTransformation.prototype.transform = function(point, scale) {
|
||
|
return this.scaleTransforms[scale].transform(point, scale);
|
||
|
};
|
||
|
|
||
|
L.Proj.ScaleDependantTransformation.prototype.untransform = function(point, scale) {
|
||
|
return this.scaleTransforms[scale].untransform(point, scale);
|
||
|
};
|
||
|
|
||
|
L.Proj.Projection = L.Class.extend({
|
||
|
initialize: function(a, def) {
|
||
|
if (L.Proj._isProj4Obj(a)) {
|
||
|
this._proj = a;
|
||
|
} else {
|
||
|
var code = a;
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
this._proj = proj4(code);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
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);
|
||
|
} else {
|
||
|
code = a;
|
||
|
def = b;
|
||
|
options = c || {};
|
||
|
this.projection = new L.Proj.Projection(code, def);
|
||
|
}
|
||
|
|
||
|
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];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
getSize: function(zoom) {
|
||
|
var b = this.options.bounds,
|
||
|
s,
|
||
|
min,
|
||
|
max;
|
||
|
|
||
|
if (b) {
|
||
|
s = this.scale(zoom);
|
||
|
min = this.transformation.transform(b.min, s);
|
||
|
max = this.transformation.transform(b.max, s);
|
||
|
return L.point(Math.abs(max.x - min.x), Math.abs(max.y - min.y));
|
||
|
} else {
|
||
|
// Backwards compatibility with Leaflet < 0.7
|
||
|
s = 256 * Math.pow(2, zoom);
|
||
|
return L.point(s, s);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
L.Proj.CRS.TMS = L.Proj.CRS.extend({
|
||
|
options: {
|
||
|
tileSize: 256
|
||
|
},
|
||
|
|
||
|
initialize: function(a, b, c, d) {
|
||
|
var code,
|
||
|
def,
|
||
|
proj,
|
||
|
projectedBounds,
|
||
|
options;
|
||
|
|
||
|
if (L.Proj._isProj4Obj(a)) {
|
||
|
proj = a;
|
||
|
projectedBounds = b;
|
||
|
options = c || {};
|
||
|
options.origin = [projectedBounds[0], projectedBounds[3]];
|
||
|
L.Proj.CRS.prototype.initialize.call(this, proj, options);
|
||
|
} else {
|
||
|
code = a;
|
||
|
def = b;
|
||
|
projectedBounds = c;
|
||
|
options = d || {};
|
||
|
options.origin = [projectedBounds[0], projectedBounds[3]];
|
||
|
L.Proj.CRS.prototype.initialize.call(this, code, def, options);
|
||
|
}
|
||
|
|
||
|
this.projectedBounds = projectedBounds;
|
||
|
|
||
|
this._sizes = this._calculateSizes();
|
||
|
},
|
||
|
|
||
|
_calculateSizes: function() {
|
||
|
var sizes = [],
|
||
|
crsBounds = this.projectedBounds,
|
||
|
projectedTileSize,
|
||
|
i,
|
||
|
x,
|
||
|
y;
|
||
|
for (i = this._scales.length - 1; i >= 0; i--) {
|
||
|
if (this._scales[i]) {
|
||
|
projectedTileSize = this.options.tileSize / this._scales[i];
|
||
|
// to prevent very small rounding errors from causing us to round up,
|
||
|
// cut any decimals after 3rd before rounding up.
|
||
|
x = Math.ceil(parseFloat((crsBounds[2] - crsBounds[0]) / projectedTileSize).toPrecision(3)) *
|
||
|
projectedTileSize * this._scales[i];
|
||
|
y = Math.ceil(parseFloat((crsBounds[3] - crsBounds[1]) / projectedTileSize).toPrecision(3)) *
|
||
|
projectedTileSize * this._scales[i];
|
||
|
sizes[i] = L.point(x, y);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return sizes;
|
||
|
},
|
||
|
|
||
|
getSize: function(zoom) {
|
||
|
return this._sizes[zoom];
|
||
|
}
|
||
|
});
|
||
|
|
||
|
L.Proj.TileLayer = {};
|
||
|
|
||
|
// Note: deprecated and not necessary since 0.7, will be removed
|
||
|
L.Proj.TileLayer.TMS = L.TileLayer.extend({
|
||
|
options: {
|
||
|
continuousWorld: true
|
||
|
},
|
||
|
|
||
|
initialize: function(urlTemplate, crs, options) {
|
||
|
var boundsMatchesGrid = true,
|
||
|
scaleTransforms,
|
||
|
upperY,
|
||
|
crsBounds,
|
||
|
i;
|
||
|
|
||
|
if (!(crs instanceof L.Proj.CRS.TMS)) {
|
||
|
throw 'CRS is not L.Proj.CRS.TMS.';
|
||
|
}
|
||
|
|
||
|
L.TileLayer.prototype.initialize.call(this, urlTemplate, options);
|
||
|
// Enabling tms will cause Leaflet to also try to do TMS, which will
|
||
|
// break (at least prior to 0.7.0). Actively disable it, to prevent
|
||
|
// well-meaning users from shooting themselves in the foot.
|
||
|
this.options.tms = false;
|
||
|
this.crs = crs;
|
||
|
crsBounds = this.crs.projectedBounds;
|
||
|
|
||
|
// Verify grid alignment
|
||
|
for (i = this.options.minZoom; i < this.options.maxZoom && boundsMatchesGrid; i++) {
|
||
|
var gridHeight = (crsBounds[3] - crsBounds[1]) /
|
||
|
this._projectedTileSize(i);
|
||
|
boundsMatchesGrid = Math.abs(gridHeight - Math.round(gridHeight)) > 1e-3;
|
||
|
}
|
||
|
|
||
|
if (!boundsMatchesGrid) {
|
||
|
scaleTransforms = {};
|
||
|
for (i = this.options.minZoom; i < this.options.maxZoom; i++) {
|
||
|
upperY = crsBounds[1] + Math.ceil((crsBounds[3] - crsBounds[1]) /
|
||
|
this._projectedTileSize(i)) * this._projectedTileSize(i);
|
||
|
scaleTransforms[this.crs.scale(i)] = new L.Transformation(1, -crsBounds[0], -1, upperY);
|
||
|
}
|
||
|
|
||
|
this.crs = new L.Proj.CRS.TMS(this.crs.projection._proj, crsBounds, this.crs.options);
|
||
|
this.crs.transformation = new L.Proj.ScaleDependantTransformation(scaleTransforms);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
getTileUrl: function(tilePoint) {
|
||
|
var zoom = this._map.getZoom(),
|
||
|
gridHeight = Math.ceil(
|
||
|
(this.crs.projectedBounds[3] - this.crs.projectedBounds[1]) /
|
||
|
this._projectedTileSize(zoom));
|
||
|
|
||
|
return L.Util.template(this._url, L.Util.extend({
|
||
|
s: this._getSubdomain(tilePoint),
|
||
|
z: this._getZoomForUrl(),
|
||
|
x: tilePoint.x,
|
||
|
y: gridHeight - tilePoint.y - 1
|
||
|
}, this.options));
|
||
|
},
|
||
|
|
||
|
_projectedTileSize: function(zoom) {
|
||
|
return (this.options.tileSize / this.crs.scale(zoom));
|
||
|
}
|
||
|
});
|
||
|
|
||
|
L.Proj.GeoJSON = L.GeoJSON.extend({
|
||
|
initialize: function(geojson, options) {
|
||
|
this._callLevel = 0;
|
||
|
L.GeoJSON.prototype.initialize.call(this, null, options);
|
||
|
if (geojson) {
|
||
|
this.addData(geojson);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
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._projBounds = bounds;
|
||
|
},
|
||
|
|
||
|
/* Danger ahead: overriding internal methods in Leaflet.
|
||
|
I've decided to do this rather than making a copy of L.ImageOverlay
|
||
|
and making very tiny modifications to it. Future will tell if this
|
||
|
was wise or not. */
|
||
|
_animateZoom: function (e) {
|
||
|
var northwest = L.point(this._projBounds.min.x, this._projBounds.max.y),
|
||
|
southeast = L.point(this._projBounds.max.x, this._projBounds.min.y),
|
||
|
topLeft = this._projectedToNewLayerPoint(northwest, e.zoom, e.center),
|
||
|
size = this._projectedToNewLayerPoint(southeast, e.zoom, e.center).subtract(topLeft),
|
||
|
origin = topLeft.add(size._multiplyBy((1 - 1 / e.scale) / 2));
|
||
|
|
||
|
this._image.style[L.DomUtil.TRANSFORM] =
|
||
|
L.DomUtil.getTranslateString(origin) + ' scale(' + this._map.getZoomScale(e.zoom) + ') ';
|
||
|
},
|
||
|
|
||
|
_reset: function() {
|
||
|
var zoom = this._map.getZoom(),
|
||
|
pixelOrigin = this._map.getPixelOrigin(),
|
||
|
bounds = L.bounds(this._transform(this._projBounds.min, zoom)._subtract(pixelOrigin),
|
||
|
this._transform(this._projBounds.max, zoom)._subtract(pixelOrigin)),
|
||
|
size = bounds.getSize(),
|
||
|
image = this._image;
|
||
|
|
||
|
L.DomUtil.setPosition(image, bounds.min);
|
||
|
image.style.width = size.x + 'px';
|
||
|
image.style.height = size.y + 'px';
|
||
|
},
|
||
|
|
||
|
_projectedToNewLayerPoint: function (point, newZoom, newCenter) {
|
||
|
var topLeft = this._map._getNewTopLeftPoint(newCenter, newZoom).add(this._map._getMapPanePos());
|
||
|
return this._transform(point, newZoom)._subtract(topLeft);
|
||
|
},
|
||
|
|
||
|
_transform: function(p, zoom) {
|
||
|
var crs = this._map.options.crs,
|
||
|
transformation = crs.transformation,
|
||
|
scale = crs.scale(zoom);
|
||
|
return transformation.transform(p, scale);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
L.Proj.imageOverlay = function(url, bounds, options) {
|
||
|
return new L.Proj.ImageOverlay(url, bounds, options);
|
||
|
};
|
||
|
|
||
|
if (typeof L.CRS !== 'undefined') {
|
||
|
// This is left here for backwards compatibility
|
||
|
L.CRS.proj4js = (function () {
|
||
|
return function (code, def, transformation, options) {
|
||
|
options = options || {};
|
||
|
if (transformation) {
|
||
|
options.transformation = transformation;
|
||
|
}
|
||
|
|
||
|
return new L.Proj.CRS(code, def, options);
|
||
|
};
|
||
|
}());
|
||
|
}
|
||
|
|
||
|
return L.Proj;
|
||
|
}));
|