| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418 |
- /**
- * DevExtreme (viz/vector_map/projection.main.js)
- * Version: 19.1.16
- * Build date: Tue Oct 18 2022
- *
- * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED
- * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
- */
- "use strict";
- var extend = require("../../core/utils/extend").extend;
- var eventEmitterModule = require("./event_emitter");
- var _Number = Number;
- var _min = Math.min;
- var _max = Math.max;
- var _abs = Math.abs;
- var _round = Math.round;
- var _ln = Math.log;
- var _pow = Math.pow;
- var TWO_TO_LN2 = 2 / Math.LN2;
- var MIN_BOUNDS_RANGE = 1 / 3600 / 180 / 10;
- var DEFAULT_MIN_ZOOM = 1;
- var DEFAULT_MAX_ZOOM = 256;
- var DEFAULT_CENTER = [NaN, NaN];
- var DEFAULT_ENGINE_NAME = "mercator";
- function floatsEqual(f1, f2) {
- return _abs(f1 - f2) < 1e-8
- }
- function arraysEqual(a1, a2) {
- return floatsEqual(a1[0], a2[0]) && floatsEqual(a1[1], a2[1])
- }
- function parseAndClamp(value, minValue, maxValue, defaultValue) {
- var val = _Number(value);
- return isFinite(val) ? _min(_max(val, minValue), maxValue) : defaultValue
- }
- function parseAndClampArray(value, minValue, maxValue, defaultValue) {
- return [parseAndClamp(value[0], minValue[0], maxValue[0], defaultValue[0]), parseAndClamp(value[1], minValue[1], maxValue[1], defaultValue[1])]
- }
- function getEngine(engine) {
- return engine instanceof Engine && engine || projection.get(engine) || projection.get(DEFAULT_ENGINE_NAME)
- }
- function Projection(parameters) {
- var that = this;
- that._initEvents();
- that._params = parameters;
- that._engine = getEngine();
- that._center = that._engine.center();
- that._adjustCenter()
- }
- Projection.prototype = {
- constructor: Projection,
- _minZoom: DEFAULT_MIN_ZOOM,
- _maxZoom: DEFAULT_MAX_ZOOM,
- _zoom: DEFAULT_MIN_ZOOM,
- _center: DEFAULT_CENTER,
- _canvas: {},
- _scale: [],
- dispose: function() {
- this._disposeEvents()
- },
- setEngine: function(value) {
- var that = this;
- var engine = getEngine(value);
- if (that._engine !== engine) {
- that._engine = engine;
- that._fire("engine");
- if (that._changeCenter(engine.center())) {
- that._triggerCenterChanged()
- }
- if (that._changeZoom(that._minZoom)) {
- that._triggerZoomChanged()
- }
- that._adjustCenter();
- that._setupScreen()
- }
- },
- setBounds: function(bounds) {
- if (void 0 !== bounds) {
- this.setEngine(this._engine.original().bounds(bounds))
- }
- },
- _setupScreen: function() {
- var that = this;
- var canvas = that._canvas;
- var width = canvas.width;
- var height = canvas.height;
- var aspectRatio = that._engine.ar();
- that._x0 = canvas.left + width / 2;
- that._y0 = canvas.top + height / 2;
- if (width / height <= aspectRatio) {
- that._xRadius = width / 2;
- that._yRadius = width / 2 / aspectRatio
- } else {
- that._xRadius = height / 2 * aspectRatio;
- that._yRadius = height / 2
- }
- that._fire("screen")
- },
- setSize: function(canvas) {
- var that = this;
- that._canvas = canvas;
- that._setupScreen()
- },
- _toScreen: function(coordinates) {
- return [this._x0 + this._xRadius * coordinates[0], this._y0 + this._yRadius * coordinates[1]]
- },
- _fromScreen: function(coordinates) {
- return [(coordinates[0] - this._x0) / this._xRadius, (coordinates[1] - this._y0) / this._yRadius]
- },
- _toTransformed: function(coordinates) {
- return [coordinates[0] * this._zoom + this._xCenter, coordinates[1] * this._zoom + this._yCenter]
- },
- _toTransformedFast: function(coordinates) {
- return [coordinates[0] * this._zoom, coordinates[1] * this._zoom]
- },
- _fromTransformed: function(coordinates) {
- return [(coordinates[0] - this._xCenter) / this._zoom, (coordinates[1] - this._yCenter) / this._zoom]
- },
- _adjustCenter: function() {
- var that = this;
- var center = that._engine.project(that._center);
- that._xCenter = -center[0] * that._zoom || 0;
- that._yCenter = -center[1] * that._zoom || 0
- },
- project: function(coordinates) {
- return this._engine.project(coordinates)
- },
- transform: function(coordinates) {
- return this._toScreen(this._toTransformedFast(coordinates))
- },
- isInvertible: function() {
- return this._engine.isInvertible()
- },
- getSquareSize: function(size) {
- return [size[0] * this._zoom * this._xRadius, size[1] * this._zoom * this._yRadius]
- },
- getZoom: function() {
- return this._zoom
- },
- _changeZoom: function(value) {
- var that = this;
- var oldZoom = that._zoom;
- var newZoom = that._zoom = parseAndClamp(value, that._minZoom, that._maxZoom, that._minZoom);
- var isChanged = !floatsEqual(oldZoom, newZoom);
- if (isChanged) {
- that._adjustCenter();
- that._fire("zoom")
- }
- return isChanged
- },
- setZoom: function(value) {
- if (this._engine.isInvertible() && this._changeZoom(value)) {
- this._triggerZoomChanged()
- }
- },
- getScaledZoom: function() {
- return _round((this._scale.length - 1) * _ln(this._zoom) / _ln(this._maxZoom))
- },
- setScaledZoom: function(scaledZoom) {
- this.setZoom(this._scale[_round(scaledZoom)])
- },
- changeScaledZoom: function(deltaZoom) {
- this.setZoom(this._scale[_max(_min(_round(this.getScaledZoom() + deltaZoom), this._scale.length - 1), 0)])
- },
- getZoomScalePartition: function() {
- return this._scale.length - 1
- },
- _setupScaling: function() {
- var that = this;
- var k = _round(TWO_TO_LN2 * _ln(that._maxZoom));
- var i = 1;
- k = k > 4 ? k : 4;
- var step = _pow(that._maxZoom, 1 / k);
- var zoom = that._minZoom;
- that._scale = [zoom];
- for (; i <= k; ++i) {
- that._scale.push(zoom *= step)
- }
- },
- setMaxZoom: function(maxZoom) {
- var that = this;
- that._minZoom = DEFAULT_MIN_ZOOM;
- that._maxZoom = parseAndClamp(maxZoom, that._minZoom, _Number.MAX_VALUE, DEFAULT_MAX_ZOOM);
- that._setupScaling();
- if (that._zoom > that._maxZoom) {
- that.setZoom(that._maxZoom)
- }
- that._fire("max-zoom")
- },
- getCenter: function() {
- return this._center.slice()
- },
- setCenter: function(value) {
- if (this._engine.isInvertible() && this._changeCenter(value || [])) {
- this._triggerCenterChanged()
- }
- },
- _changeCenter: function(value) {
- var that = this;
- var engine = that._engine;
- var oldCenter = that._center;
- var newCenter = that._center = parseAndClampArray(value, engine.min(), engine.max(), engine.center());
- var isChanged = !arraysEqual(oldCenter, newCenter);
- if (isChanged) {
- that._adjustCenter();
- that._fire("center")
- }
- return isChanged
- },
- _triggerCenterChanged: function() {
- this._params.centerChanged(this.getCenter())
- },
- _triggerZoomChanged: function() {
- this._params.zoomChanged(this.getZoom())
- },
- setCenterByPoint: function(coordinates, screenPosition) {
- var that = this;
- var p = that._engine.project(coordinates);
- var q = that._fromScreen(screenPosition);
- that.setCenter(that._engine.unproject([-q[0] / that._zoom + p[0], -q[1] / that._zoom + p[1]]))
- },
- beginMoveCenter: function() {
- if (this._engine.isInvertible()) {
- this._moveCenter = this._center
- }
- },
- endMoveCenter: function() {
- var that = this;
- if (that._moveCenter) {
- if (!arraysEqual(that._moveCenter, that._center)) {
- that._triggerCenterChanged()
- }
- that._moveCenter = null
- }
- },
- moveCenter: function(shift) {
- var that = this;
- if (that._moveCenter) {
- var current = that._toScreen(that._toTransformed(that._engine.project(that._center)));
- var center = that._engine.unproject(that._fromTransformed(that._fromScreen([current[0] + shift[0], current[1] + shift[1]])));
- that._changeCenter(center)
- }
- },
- getViewport: function() {
- var that = this;
- var unproject = that._engine.unproject;
- var lt = unproject(that._fromTransformed([-1, -1]));
- var lb = unproject(that._fromTransformed([-1, 1]));
- var rt = unproject(that._fromTransformed([1, -1]));
- var rb = unproject(that._fromTransformed([1, 1]));
- var minMax = findMinMax([selectFarthestPoint(lt[0], lb[0], rt[0], rb[0]), selectFarthestPoint(lt[1], rt[1], lb[1], rb[1])], [selectFarthestPoint(rt[0], rb[0], lt[0], lb[0]), selectFarthestPoint(lb[1], rb[1], lt[1], rt[1])]);
- return [].concat(minMax.min, minMax.max)
- },
- setViewport: function(viewport) {
- var engine = this._engine;
- var data = viewport ? getZoomAndCenterFromViewport(engine.project, engine.unproject, viewport) : [this._minZoom, engine.center()];
- this.setZoom(data[0]);
- this.setCenter(data[1])
- },
- getTransform: function() {
- return {
- translateX: this._xCenter * this._xRadius,
- translateY: this._yCenter * this._yRadius
- }
- },
- fromScreenPoint: function(coordinates) {
- return this._engine.unproject(this._fromTransformed(this._fromScreen(coordinates)))
- },
- _eventNames: ["engine", "screen", "center", "zoom", "max-zoom"]
- };
- eventEmitterModule.makeEventEmitter(Projection);
- function selectFarthestPoint(point1, point2, basePoint1, basePoint2) {
- var basePoint = (basePoint1 + basePoint2) / 2;
- return _abs(point1 - basePoint) > _abs(point2 - basePoint) ? point1 : point2
- }
- function selectClosestPoint(point1, point2, basePoint1, basePoint2) {
- var basePoint = (basePoint1 + basePoint2) / 2;
- return _abs(point1 - basePoint) < _abs(point2 - basePoint) ? point1 : point2
- }
- function getZoomAndCenterFromViewport(project, unproject, viewport) {
- var lt = project([viewport[0], viewport[3]]);
- var lb = project([viewport[0], viewport[1]]);
- var rt = project([viewport[2], viewport[3]]);
- var rb = project([viewport[2], viewport[1]]);
- var l = selectClosestPoint(lt[0], lb[0], rt[0], rb[0]);
- var r = selectClosestPoint(rt[0], rb[0], lt[0], lb[0]);
- var t = selectClosestPoint(lt[1], rt[1], lb[1], rb[1]);
- var b = selectClosestPoint(lb[1], rb[1], lt[1], rt[1]);
- return [2 / _max(_abs(l - r), _abs(t - b)), unproject([(l + r) / 2, (t + b) / 2])]
- }
- function setMinMax(engine, p1, p2) {
- var minMax = findMinMax(p1, p2);
- engine.min = returnArray(minMax.min);
- engine.max = returnArray(minMax.max)
- }
- function Engine(parameters) {
- var that = this;
- var project = createProjectMethod(parameters.to);
- var unproject = parameters.from ? createUnprojectMethod(parameters.from) : returnValue(DEFAULT_CENTER);
- that.project = project;
- that.unproject = unproject;
- that.original = returnValue(that);
- that.source = function() {
- return extend({}, parameters)
- };
- that.isInvertible = returnValue(!!parameters.from);
- that.ar = returnValue(parameters.aspectRatio > 0 ? _Number(parameters.aspectRatio) : 1);
- that.center = returnArray(unproject([0, 0]));
- setMinMax(that, [unproject([-1, 0])[0], unproject([0, 1])[1]], [unproject([1, 0])[0], unproject([0, -1])[1]])
- }
- Engine.prototype.aspectRatio = function(aspectRatio) {
- var engine = new Engine(extend(this.source(), {
- aspectRatio: aspectRatio
- }));
- engine.original = this.original;
- engine.min = this.min;
- engine.max = this.max;
- return engine
- };
- Engine.prototype.bounds = function(bounds) {
- bounds = bounds || [];
- var parameters = this.source();
- var min = this.min();
- var max = this.max();
- var b1 = parseAndClampArray([bounds[0], bounds[1]], min, max, min);
- var b2 = parseAndClampArray([bounds[2], bounds[3]], min, max, max);
- var p1 = parameters.to(b1);
- var p2 = parameters.to(b2);
- var delta = _min(_abs(p2[0] - p1[0]) > MIN_BOUNDS_RANGE ? _abs(p2[0] - p1[0]) : 2, _abs(p2[1] - p1[1]) > MIN_BOUNDS_RANGE ? _abs(p2[1] - p1[1]) : 2);
- if (delta < 2) {
- extend(parameters, createProjectUnprojectMethods(parameters.to, parameters.from, p1, p2, delta))
- }
- var engine = new Engine(parameters);
- engine.original = this.original;
- setMinMax(engine, b1, b2);
- return engine
- };
- function isEngine(engine) {
- return engine instanceof Engine
- }
- function invertVerticalAxis(pair) {
- return [pair[0], -pair[1]]
- }
- function createProjectMethod(method) {
- return function(arg) {
- return invertVerticalAxis(method(arg))
- }
- }
- function createUnprojectMethod(method) {
- return function(arg) {
- return method(invertVerticalAxis(arg))
- }
- }
- function returnValue(value) {
- return function() {
- return value
- }
- }
- function returnArray(value) {
- return function() {
- return value.slice()
- }
- }
- function projection(parameters) {
- return parameters && parameters.to ? new Engine(parameters) : null
- }
- function findMinMax(p1, p2) {
- return {
- min: [_min(p1[0], p2[0]), _min(p1[1], p2[1])],
- max: [_max(p1[0], p2[0]), _max(p1[1], p2[1])]
- }
- }
- var projectionsCache = {};
- projection.get = function(name) {
- return projectionsCache[name] || null
- };
- projection.add = function(name, engine) {
- if (!projectionsCache[name] && isEngine(engine)) {
- projectionsCache[name] = engine
- }
- return projection
- };
- function createProjectUnprojectMethods(project, unproject, p1, p2, delta) {
- var x0 = (p1[0] + p2[0]) / 2 - delta / 2;
- var y0 = (p1[1] + p2[1]) / 2 - delta / 2;
- var k = 2 / delta;
- return {
- to: function(coordinates) {
- var p = project(coordinates);
- return [-1 + (p[0] - x0) * k, -1 + (p[1] - y0) * k]
- },
- from: function(coordinates) {
- var p = [x0 + (coordinates[0] + 1) / k, y0 + (coordinates[1] + 1) / k];
- return unproject(p)
- }
- }
- }
- exports.Projection = Projection;
- exports.projection = projection;
|