@progress/kendo-charts
Version:
Kendo UI platform-independent Charts library
278 lines (237 loc) • 8.99 kB
JavaScript
import {
geometry as g
} from '@progress/kendo-drawing';
import {
Class,
setDefaultOptions,
limitValue,
rad,
deg,
deepExtend
} from '../common';
import {
Location
} from './location';
import {
datums
} from './datums';
var math = Math,
atan = math.atan,
exp = math.exp,
pow = math.pow,
sin = math.sin,
log = math.log,
tan = math.tan,
Point = g.Point;
var PI = math.PI,
PI_DIV_2 = PI / 2,
PI_DIV_4 = PI / 4,
DEG_TO_RAD = PI / 180;
var WGS84 = datums.WGS84;
// WGS 84 / World Mercator
export var Mercator = (function (Class) {
function Mercator(options) {
Class.call(this);
this.initProperties();
this._initOptions(options);
}
if ( Class ) Mercator.__proto__ = Class;
Mercator.prototype = Object.create( Class && Class.prototype );
Mercator.prototype.constructor = Mercator;
Mercator.prototype._initOptions = function _initOptions (options) {
this.options = deepExtend({}, this.options, options);
};
Mercator.prototype.initProperties = function initProperties () {
// super.initProperties();
deepExtend(this, {
MAX_LNG: 180,
MAX_LAT: 85.0840590501,
INVERSE_ITERATIONS: 15,
INVERSE_CONVERGENCE: 1e-12
});
};
Mercator.prototype.forward = function forward (loc, clamp) {
var proj = this,
options = proj.options,
datum = options.datum,
r = datum.a,
lng0 = options.centralMeridian,
lat = limitValue(loc.lat, -proj.MAX_LAT, proj.MAX_LAT),
lng = clamp ? limitValue(loc.lng, -proj.MAX_LNG, proj.MAX_LNG) : loc.lng,
x = rad(lng - lng0) * r,
y = proj._projectLat(lat);
return new Point(x, y);
};
Mercator.prototype._projectLat = function _projectLat (lat) {
var datum = this.options.datum,
ecc = datum.e,
r = datum.a,
y = rad(lat),
ts = tan(PI_DIV_4 + y / 2),
con = ecc * sin(y),
p = pow((1 - con) / (1 + con), ecc / 2);
// See: http://en.wikipedia.org/wiki/Mercator_projection#Generalization_to_the_ellipsoid
return r * log(ts * p);
};
Mercator.prototype.inverse = function inverse (point, clamp) {
var proj = this,
options = proj.options,
datum = options.datum,
r = datum.a,
lng0 = options.centralMeridian,
lng = point.x / (DEG_TO_RAD * r) + lng0,
lat = limitValue(proj._inverseY(point.y), -proj.MAX_LAT, proj.MAX_LAT);
if (clamp) {
lng = limitValue(lng, -proj.MAX_LNG, proj.MAX_LNG);
}
return new Location(lat, lng);
};
Mercator.prototype._inverseY = function _inverseY (y) {
var proj = this,
datum = proj.options.datum,
r = datum.a,
ecc = datum.e,
ecch = ecc / 2,
ts = exp(-y / r),
phi = PI_DIV_2 - 2 * atan(ts),
i;
for (i = 0; i <= proj.INVERSE_ITERATIONS; i++) {
var con = ecc * sin(phi),
p = pow((1 - con) / (1 + con), ecch),
dphi = PI_DIV_2 - 2 * atan(ts * p) - phi;
phi += dphi;
if (math.abs(dphi) <= proj.INVERSE_CONVERGENCE) {
break;
}
}
return deg(phi);
};
return Mercator;
}(Class));
setDefaultOptions(Mercator, {
centralMeridian: 0,
datum: WGS84
});
// WGS 84 / Pseudo-Mercator
// Used by Google Maps, Bing, OSM, etc.
// Spherical projection of ellipsoidal coordinates.
export var SphericalMercator = (function (Mercator) {
function SphericalMercator () {
Mercator.apply(this, arguments);
}
if ( Mercator ) SphericalMercator.__proto__ = Mercator;
SphericalMercator.prototype = Object.create( Mercator && Mercator.prototype );
SphericalMercator.prototype.constructor = SphericalMercator;
SphericalMercator.prototype.initProperties = function initProperties () {
Mercator.prototype.initProperties.call(this);
deepExtend(this, {
MAX_LAT: 85.0511287798
});
};
SphericalMercator.prototype._projectLat = function _projectLat (lat) {
var r = this.options.datum.a,
y = rad(lat),
ts = tan(PI_DIV_4 + y / 2);
return r * log(ts);
};
SphericalMercator.prototype._inverseY = function _inverseY (y) {
var r = this.options.datum.a,
ts = exp(-y / r);
return deg(PI_DIV_2 - 2 * atan(ts));
};
return SphericalMercator;
}(Mercator));
export var Equirectangular = (function (Class) {
function Equirectangular () {
Class.apply(this, arguments);
}
if ( Class ) Equirectangular.__proto__ = Class;
Equirectangular.prototype = Object.create( Class && Class.prototype );
Equirectangular.prototype.constructor = Equirectangular;
Equirectangular.prototype.forward = function forward (loc) {
return new Point(loc.lng, loc.lat);
};
Equirectangular.prototype.inverse = function inverse (point) {
return new Location(point.y, point.x);
};
return Equirectangular;
}(Class));
// This is the projected coordinate system used for rendering maps in Google Maps, OpenStreetMap, etc
// Unit: metre
// Geodetic CRS: WGS 84
// Scope: Certain Web mapping and visualisation applications. It is not a recognised geodetic system: for that see ellipsoidal Mercator CRS code 3395 (WGS 84 / World Mercator).
// Remarks: Uses spherical development of ellipsoidal coordinates. Relative to WGS 84 / World Mercator (CRS code 3395) errors of 0.7 percent in scale and differences in northing of up to 43km in the map (equivalent to 21km on the ground) may arise.
// Area of use: World between 85.06°S and 85.06°N.
// Coordinate system: Cartesian 2D CS. Axes: easting, northing (X,Y). Orientations: east, north. UoM: m.
// https://epsg.io/3857
export var EPSG3857 = (function (Class) {
function EPSG3857() {
Class.call(this);
var crs = this,
proj = crs._proj = new SphericalMercator();
var c = this.c = 2 * PI * proj.options.datum.a;
// transfrom matrix
// Scale circumference to 1, mirror Y and shift origin to top left
this._tm = g.transform().translate(0.5, 0.5).scale(1 / c, -1 / c);
// Inverse transform matrix
this._itm = g.transform().scale(c, -c).translate(-0.5, -0.5);
}
if ( Class ) EPSG3857.__proto__ = Class;
EPSG3857.prototype = Object.create( Class && Class.prototype );
EPSG3857.prototype.constructor = EPSG3857;
// Location <-> Point (screen coordinates for a given scale)
EPSG3857.prototype.toPoint = function toPoint (loc, scale, clamp) {
var point = this._proj.forward(loc, clamp);
return point.transform(this._tm).scale(scale || 1);
};
EPSG3857.prototype.toLocation = function toLocation (point, scale, clamp) {
var newPoint = point.clone().scale(1 / (scale || 1)).transform(this._itm);
return this._proj.inverse(newPoint, clamp);
};
return EPSG3857;
}(Class));
// Unit: metre
// Geodetic CRS: WGS 84
// Scope: Very small scale mapping.
// Remarks: Euro-centric view of world excluding polar areas.
// Area of use: World between 80°S and 84°N.
// Coordinate system: Cartesian 2D CS. Axes: easting, northing (E,N). Orientations: east, north. UoM: m.
// https://epsg.io/3395
export var EPSG3395 = (function (Class) {
function EPSG3395() {
Class.call(this);
this._proj = new Mercator();
}
if ( Class ) EPSG3395.__proto__ = Class;
EPSG3395.prototype = Object.create( Class && Class.prototype );
EPSG3395.prototype.constructor = EPSG3395;
EPSG3395.prototype.toPoint = function toPoint (loc) {
return this._proj.forward(loc);
};
EPSG3395.prototype.toLocation = function toLocation (point) {
return this._proj.inverse(point);
};
return EPSG3395;
}(Class));
// Unit: degree
// Geodetic CRS: WGS 84
// Scope: Horizontal component of 3D system. Used by the GPS satellite navigation system and for NATO military geodetic surveying.
// Area of use: World.
// Coordinate system: Ellipsoidal 2D CS. Axes: latitude, longitude. Orientations: north, east. UoM: degree
// https://epsg.io/4326
export var EPSG4326 = (function (Class) {
function EPSG4326() {
Class.call(this);
this._proj = new Equirectangular();
}
if ( Class ) EPSG4326.__proto__ = Class;
EPSG4326.prototype = Object.create( Class && Class.prototype );
EPSG4326.prototype.constructor = EPSG4326;
EPSG4326.prototype.toPoint = function toPoint (loc) {
return this._proj.forward(loc);
};
EPSG4326.prototype.toLocation = function toLocation (point) {
return this._proj.inverse(point);
};
return EPSG4326;
}(Class));