
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
import { MapChartDefaultTheme } from "./MapChartDefaultTheme";
import { SerialChart } from "../../core/render/SerialChart";
import { Rectangle } from "../../core/render/Rectangle";
import { geoPath } from "d3-geo";
import { Color } from "../../core/util/Color";
import { registry } from "../../core/Registry";
import * as $math from "../../core/util/Math";
import * as $array from "../../core/util/Array";
import * as $type from "../../core/util/Type";
import * as $mapUtils from "./MapUtils";
import * as $object from "../../core/util/Object";
import * as $utils from "../../core/util/Utils";
export class MapChart extends SerialChart {
constructor() {
super(...arguments);
Object.defineProperty(this, "_downTranslateX", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_downTranslateY", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_downRotationX", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_downRotationY", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_downRotationZ", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_pLat", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "_pLon", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "_movePoints", {
enumerable: true,
configurable: true,
writable: true,
value: {}
});
Object.defineProperty(this, "_downZoomLevel", {
enumerable: true,
configurable: true,
writable: true,
value: 1
});
Object.defineProperty(this, "_doubleDownDistance", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "_dirtyGeometries", {
enumerable: true,
configurable: true,
writable: true,
value: false
});
Object.defineProperty(this, "_geometryColection", {
enumerable: true,
configurable: true,
writable: true,
value: { type: "GeometryCollection", geometries: [] }
});
Object.defineProperty(this, "_centerLocation", {
enumerable: true,
configurable: true,
writable: true,
value: null
});
Object.defineProperty(this, "_za", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_rxa", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_rya", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_txa", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_tya", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_mapBounds", {
enumerable: true,
configurable: true,
writable: true,
value: [[0, 0], [0, 0]]
});
Object.defineProperty(this, "_geoCentroid", {
enumerable: true,
configurable: true,
writable: true,
value: { longitude: 0, latitude: 0 }
});
Object.defineProperty(this, "_geoBounds", {
enumerable: true,
configurable: true,
writable: true,
value: { left: 0, right: 0, top: 0, bottom: 0 }
});
Object.defineProperty(this, "_prevGeoBounds", {
enumerable: true,
configurable: true,
writable: true,
value: { left: 0, right: 0, top: 0, bottom: 0 }
});
Object.defineProperty(this, "_dispatchBounds", {
enumerable: true,
configurable: true,
writable: true,
value: false
});
Object.defineProperty(this, "_wheelDp", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_pw", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_ph", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_mapFitted", {
enumerable: true,
configurable: true,
writable: true,
value: false
});
Object.defineProperty(this, "_centerX", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
Object.defineProperty(this, "_centerY", {
enumerable: true,
configurable: true,
writable: true,
value: 0
});
}
_makeGeoPath() {
const projection = this.get("projection");
const path = geoPath();
path.projection(projection);
this.setPrivateRaw("geoPath", path);
}
/**
* Returns a geoPoint of the current zoom position.
*
* You can later use it to restore zoom position, e.g.: `chart.zoomToGeoPoint(geoPoint, zoomLevel, true)`.
*
* @since 5.2.19
*/
geoPoint() {
return this.invert(this.seriesContainer.toGlobal({ x: this.width() / 2, y: this.height() / 2 }));
}
/**
* Returns coordinates to geographical center of the map.
*/
geoCentroid() {
return this._geoCentroid;
}
/**
* Returns geographical bounds of the map.
*/
geoBounds() {
return this._geoBounds;
}
_handleSetWheel() {
const wheelX = this.get("wheelX");
const wheelY = this.get("wheelY");
const chartContainer = this.chartContainer;
if (wheelX != "none" || wheelY != "none") {
if (this._wheelDp) {
this._wheelDp.dispose();
}
this._wheelDp = chartContainer.events.on("wheel", (event) => {
const wheelEasing = this.get("wheelEasing");
const wheelSensitivity = this.get("wheelSensitivity", 1);
const wheelDuration = this.get("wheelDuration", 0);
const wheelEvent = event.originalEvent;
// Ignore wheel event if it is happening on a non-chart element, e.g. if
// some page element is over the chart.
if ($utils.isLocalEvent(wheelEvent, this)) {
wheelEvent.preventDefault();
}
else {
return;
}
const point = chartContainer._display.toLocal(event.point);
if ((wheelY == "zoom")) {
this._handleWheelZoom(wheelEvent.deltaY, point);
}
else if (wheelY == "rotateY") {
this._handleWheelRotateY(wheelEvent.deltaY / 5 * wheelSensitivity, wheelDuration, wheelEasing);
}
else if (wheelY == "rotateX") {
this._handleWheelRotateX(wheelEvent.deltaY / 5 * wheelSensitivity, wheelDuration, wheelEasing);
}
if ((wheelX == "zoom")) {
this._handleWheelZoom(wheelEvent.deltaX, point);
}
else if (wheelX == "rotateY") {
this._handleWheelRotateY(wheelEvent.deltaX / 5 * wheelSensitivity, wheelDuration, wheelEasing);
}
else if (wheelX == "rotateX") {
this._handleWheelRotateX(wheelEvent.deltaX / 5 * wheelSensitivity, wheelDuration, wheelEasing);
}
});
this._disposers.push(this._wheelDp);
}
else {
if (this._wheelDp) {
this._wheelDp.dispose();
}
}
}
_prepareChildren() {
super._prepareChildren();
const projection = this.get("projection");
const w = this.innerWidth();
const h = this.innerHeight();
const previousGeometries = this._geometryColection.geometries;
if (this.isDirty("projection")) {
this._makeGeoPath();
this.markDirtyProjection();
this._fitMap();
projection.scale(this.getPrivate("mapScale") * this.get("zoomLevel", 1));
if (projection.rotate) {
projection.rotate([this.get("rotationX", 0), this.get("rotationY", 0), this.get("rotationZ", 0)]);
}
let prev = this._prevSettings.projection;
if (prev && prev != projection) {
let hw = w / 2;
let hh = h / 2;
if (prev.invert) {
let centerLocation = prev.invert([hw, hh]);
if (centerLocation) {
let xy = projection(centerLocation);
if (xy) {
let translate = projection.translate();
let xx = hw - ((xy[0] - translate[0]));
let yy = hh - ((xy[1] - translate[1]));
projection.translate([xx, yy]);
this.setRaw("translateX", xx);
this.setRaw("translateY", yy);
}
}
}
}
}
if (this.isDirty("wheelX") || this.isDirty("wheelY")) {
this._handleSetWheel();
}
if (this._dirtyGeometries) {
this._geometryColection.geometries = [];
this.series.each((series) => {
$array.pushAll(this._geometryColection.geometries, series._geometries);
});
this._fitMap();
}
if (previousGeometries.length != 0 && (w != this._pw || h != this._ph || this._dirtyGeometries)) {
if (w > 0 && h > 0) {
let hw = w / 2;
let hh = h / 2;
projection.fitSize([w, h], this._geometryColection);
const newScale = projection.scale();
this.setPrivateRaw("mapScale", newScale);
projection.scale(newScale * this.get("zoomLevel", 1));
if (this._centerLocation) {
let xy = projection(this._centerLocation);
if (xy) {
let translate = projection.translate();
let xx = hw - ((xy[0] - translate[0]));
let yy = hh - ((xy[1] - translate[1]));
projection.translate([xx, yy]);
this.setRaw("translateX", xx);
this.setRaw("translateY", yy);
this._centerX = translate[0];
this._centerY = translate[1];
}
}
this.markDirtyProjection();
const geoPath = this.getPrivate("geoPath");
this._mapBounds = geoPath.bounds(this._geometryColection);
}
}
this._pw = w;
this._ph = h;
if (this.isDirty("zoomControl")) {
const previous = this._prevSettings.zoomControl;
const zoomControl = this.get("zoomControl");
if (zoomControl !== previous) {
this._disposeProperty("zoomControl");
if (previous) {
previous.dispose();
}
if (zoomControl) {
zoomControl.setPrivate("chart", this);
this.children.push(zoomControl);
}
this.setRaw("zoomControl", zoomControl);
}
}
if (this.isDirty("zoomLevel")) {
projection.scale(this.getPrivate("mapScale") * this.get("zoomLevel", 1));
this.markDirtyProjection();
this.series.each((series) => {
if (series.isType("MapPointSeries")) {
if (series.get("autoScale")) {
$array.each(series.dataItems, (dataItem) => {
const bullets = dataItem.bullets;
if (bullets) {
$array.each(bullets, (bullet) => {
const sprite = bullet.get("sprite");
if (sprite) {
sprite.set("scale", this.get("zoomLevel"));
}
});
}
});
}
}
});
}
if (this.isDirty("translateX") || this.isDirty("translateY")) {
projection.translate([this.get("translateX", this.width() / 2), this.get("translateY", this.height() / 2)]);
this.markDirtyProjection();
}
if (projection.rotate) {
if (this.isDirty("rotationX") || this.isDirty("rotationY") || this.isDirty("rotationZ")) {
projection.rotate([this.get("rotationX", 0), this.get("rotationY", 0), this.get("rotationZ", 0)]);
this.markDirtyProjection();
}
}
if (this.isDirty("pinchZoom") || this.get("panX") || this.get("panY")) {
this._setUpTouch();
}
}
_fitMap() {
const projection = this.get("projection");
let w = this.innerWidth();
let h = this.innerHeight();
if (w > 0 && h > 0) {
projection.fitSize([w, h], this._geometryColection);
this.setPrivateRaw("mapScale", projection.scale());
const translate = projection.translate();
this.setRaw("translateX", translate[0]);
this.setRaw("translateY", translate[1]);
this._centerX = translate[0];
this._centerY = translate[1];
const geoPath = this.getPrivate("geoPath");
this._mapBounds = geoPath.bounds(this._geometryColection);
this._geoCentroid = $mapUtils.getGeoCentroid(this._geometryColection);
const bounds = $mapUtils.getGeoBounds(this._geometryColection);
this._geoBounds = bounds;
if (this._geometryColection.geometries.length > 0) {
bounds.left = $math.round(this._geoBounds.left, 3);
bounds.right = $math.round(this._geoBounds.right, 3);
bounds.top = $math.round(this._geoBounds.top, 3);
bounds.bottom = $math.round(this._geoBounds.bottom, 3);
const prevGeoBounds = this._prevGeoBounds;
if (prevGeoBounds && !$utils.sameBounds(bounds, prevGeoBounds)) {
this._dispatchBounds = true;
this._prevGeoBounds = bounds;
}
}
this._mapFitted = true;
}
}
/**
* Returns geographical coordinates for calculated or manual center of the
* map.
*/
homeGeoPoint() {
let homeGeoPoint = this.get("homeGeoPoint");
if (!homeGeoPoint) {
const geoPath = this.getPrivate("geoPath");
const bounds = geoPath.bounds(this._geometryColection);
const left = bounds[0][0];
const top = bounds[0][1];
const right = bounds[1][0];
const bottom = bounds[1][1];
homeGeoPoint = this.invert({ x: left + (right - left) / 2, y: top + (bottom - top) / 2 });
}
return homeGeoPoint;
}
/**
* Repositions the map to the "home" zoom level and center coordinates.
*
* @see {@link https://www.amcharts.com/docs/v5/charts/map-chart/map-pan-zoom/#Resetting_position_level} for more info
* @param duration Animation duration in milliseconds
*/
goHome(duration) {
this.zoomToGeoPoint(this.homeGeoPoint(), this.get("homeZoomLevel", 1), true, duration, this.get("homeRotationX"), this.get("homeRotationY"));
}
_updateChildren() {
const projection = this.get("projection");
if (projection.invert) {
let w = this.innerWidth();
let h = this.innerHeight();
if (w > 0 && h > 0) {
this._centerLocation = projection.invert([this.innerWidth() / 2, this.innerHeight() / 2]);
}
}
super._updateChildren();
}
_afterChanged() {
super._afterChanged();
if (this._dispatchBounds) {
this._dispatchBounds = false;
const type = "geoboundschanged";
if (this.events.isEnabled(type)) {
this.events.dispatch(type, { type: type, target: this });
}
}
}
_setUpTouch() {
if (!this.chartContainer._display.cancelTouch) {
this.chartContainer._display.cancelTouch = (this.get("pinchZoom") || this.get("panX") || this.get("panY")) ? true : false;
}
}
/**
* @ignore
*/
markDirtyGeometries() {
this._dirtyGeometries = true;
this.markDirty();
}
/**
* @ignore
*/
markDirtyProjection() {
this.series.each((series) => {
series.markDirtyProjection();
});
}
_afterNew() {
this._defaultThemes.push(MapChartDefaultTheme.new(this._root));
this._settings.themeTags = $utils.mergeTags(this._settings.themeTags, ["map"]);
this.children.push(this.bulletsContainer);
super._afterNew();
this._makeGeoPath();
this.chartContainer.children.push(this.seriesContainer);
if (this.get("translateX") == null) {
this.set("translateX", this.width() / 2);
}
if (this.get("translateY") == null) {
this.set("translateY", this.height() / 2);
}
// Setting trasnparent background so that full body of the plot container
// is interactive
this.chartContainer.set("interactive", true);
this.chartContainer.set("interactiveChildren", false);
this.chartContainer.set("background", Rectangle.new(this._root, {
themeTags: ["map", "background"],
fill: Color.fromHex(0x000000),
fillOpacity: 0
}));
this._disposers.push(this.chartContainer.events.on("pointerdown", (event) => {
this._handleChartDown(event);
}));
this._disposers.push(this.chartContainer.events.on("globalpointerup", (event) => {
this._handleChartUp(event);
}));
this._disposers.push(this.chartContainer.events.on("globalpointermove", (event) => {
this._handleChartMove(event);
}));
let license = false;
for (let i = 0; i < registry.licenses.length; i++) {
if (registry.licenses[i].match(/^AM5M.{5,}/i)) {
license = true;
}
}
if (!license) {
this._root._showBranding();
}
this._setUpTouch();
}
_handleChartDown(event) {
this._downZoomLevel = this.get("zoomLevel", 1);
const downPoints = this.chartContainer._downPoints;
let count = $object.keys(downPoints).length;
if (count == 1) {
// workaround to solve a problem when events are added to some children of chart container (rotation stops working)
let downPoint = downPoints[1];
if (!downPoint) {
downPoint = downPoints[0];
}
if (downPoint && (downPoint.x == event.point.x && downPoint.y == event.point.y)) {
count = 0;
}
}
if (count > 0) {
this._downTranslateX = this.get("translateX");
this._downTranslateY = this.get("translateY");
this._downRotationX = this.get("rotationX");
this._downRotationY = this.get("rotationY");
this._downRotationZ = this.get("rotationZ");
const downId = this.chartContainer._getDownPointId();
if (downId) {
let movePoint = this._movePoints[downId];
if (movePoint) {
this.chartContainer._downPoints[downId] = movePoint;
}
}
}
else if (count == 0) {
let bg = this.chartContainer.get("background");
if (bg) {
bg.events.enableType("click");
}
if (this.get("panX") || this.get("panY")) {
if (this._za) {
this._za.stop();
}
if (this._txa) {
this._txa.stop();
}
if (this._tya) {
this._tya.stop();
}
if (this._rxa) {
this._rxa.stop();
}
if (this._rya) {
this._rya.stop();
}
const downPoint = this.chartContainer._display.toLocal(event.point);
this._downTranslateX = this.get("translateX");
this._downTranslateY = this.get("translateY");
this._downRotationX = this.get("rotationX");
this._downRotationY = this.get("rotationY");
this._downRotationZ = this.get("rotationZ");
let projection = this.get("projection");
if (projection.invert) {
let l0 = projection.invert([downPoint.x, downPoint.y]);
let l1 = projection.invert([downPoint.x + 1, downPoint.y + 1]);
if (l0 && l1) {
this._pLon = Math.abs(l1[0] - l0[0]);
this._pLat = Math.abs(l1[1] - l0[1]);
}
}
}
}
}
/**
* Converts screen coordinates (X and Y) within chart to latitude and
* longitude.
*
* @param point Screen coordinates
* @return Geographical coordinates
*/
invert(point) {
let projection = this.get("projection");
if (projection.invert) {
const ll = projection.invert([point.x, point.y]);
if (ll) {
return { longitude: ll[0], latitude: ll[1] };
}
}
return { longitude: 0, latitude: 0 };
}
/**
* Converts latitude/longitude to screen coordinates (X and Y).
*
* @param point Geographical coordinates
* @param rotationX X rotation of a map if different from current
* @param rotationY Y rotation of a map if different from current
*
* @return Screen coordinates
*/
convert(point, rotationX, rotationY) {
let projection = this.get("projection");
let xy;
if (!projection.rotate) {
rotationX = undefined;
rotationY = undefined;
}
if (rotationX != null || rotationY != null) {
if (rotationX == null) {
rotationX = 0;
}
if (rotationY == null) {
rotationY = 0;
}
let rotation = projection.rotate();
projection.rotate([rotationX, rotationY, 0]);
xy = projection([point.longitude, point.latitude]);
projection.rotate(rotation);
}
else {
xy = projection([point.longitude, point.latitude]);
}
if (xy) {
return { x: xy[0], y: xy[1] };
}
return { x: 0, y: 0 };
}
_handleChartUp(_event) {
this.chartContainer._downPoints = {};
}
_handlePinch() {
const chartContainer = this.chartContainer;
let i = 0;
let downPoints = [];
let movePoints = [];
$object.each(chartContainer._downPoints, (k, point) => {
downPoints[i] = point;
let movePoint = this._movePoints[k];
if (movePoint) {
movePoints[i] = movePoint;
}
i++;
});
if (downPoints.length > 1 && movePoints.length > 1) {
const display = chartContainer._display;
let downPoint0 = downPoints[0];
let downPoint1 = downPoints[1];
let movePoint0 = movePoints[0];
let movePoint1 = movePoints[1];
if (downPoint0 && downPoint1 && movePoint0 && movePoint1) {
downPoint0 = display.toLocal(downPoint0);
downPoint1 = display.toLocal(downPoint1);
movePoint0 = display.toLocal(movePoint0);
movePoint1 = display.toLocal(movePoint1);
let initialDistance = Math.hypot(downPoint1.x - downPoint0.x, downPoint1.y - downPoint0.y);
let currentDistance = Math.hypot(movePoint1.x - movePoint0.x, movePoint1.y - movePoint0.y);
let level = currentDistance / initialDistance * this._downZoomLevel;
level = $math.fitToRange(level, this.get("minZoomLevel", 1), this.get("maxZoomLevel", 32));
let moveCenter = { x: movePoint0.x + (movePoint1.x - movePoint0.x) / 2, y: movePoint0.y + (movePoint1.y - movePoint0.y) / 2 };
let downCenter = { x: downPoint0.x + (downPoint1.x - downPoint0.x) / 2, y: downPoint0.y + (downPoint1.y - downPoint0.y) / 2 };
let tx = this._downTranslateX || 0;
let ty = this._downTranslateY || 0;
let zoomLevel = this._downZoomLevel;
let xx = moveCenter.x - (-tx + downCenter.x) / zoomLevel * level;
let yy = moveCenter.y - (-ty + downCenter.y) / zoomLevel * level;
this.set("zoomLevel", level);
this.set("translateX", xx);
this.set("translateY", yy);
}
}
}
_handleChartMove(event) {
const chartContainer = this.chartContainer;
let downPoint = chartContainer._getDownPoint();
const downPointId = chartContainer._getDownPointId();
const originalEvent = event.originalEvent;
const pointerId = originalEvent.pointerId;
if (this.get("pinchZoom")) {
if (pointerId) {
this._movePoints[pointerId] = event.point;
if ($object.keys(chartContainer._downPoints).length > 1) {
this._handlePinch();
return;
}
}
}
if (downPointId && pointerId && pointerId != downPointId) {
return;
}
else {
if (downPoint) {
const panX = this.get("panX");
const panY = this.get("panY");
if (panX != "none" || panY != "none") {
const display = chartContainer._display;
let local = display.toLocal(event.point);
downPoint = display.toLocal(downPoint);
let x = this._downTranslateX;
let y = this._downTranslateY;
if (Math.hypot(downPoint.x - local.x, downPoint.y - local.y) > 5) {
let bg = chartContainer.get("background");
if (bg) {
bg.events.disableType("click");
}
if ($type.isNumber(x) && $type.isNumber(y)) {
let projection = this.get("projection");
const zoomLevel = this.get("zoomLevel", 1);
const maxPanOut = this.get("maxPanOut", 0.4);
const bounds = this._mapBounds;
const w = this.width();
const h = this.height();
const ww = bounds[1][0] - bounds[0][0];
const hh = bounds[1][1] - bounds[0][1];
if (panX == "translateX") {
x += local.x - downPoint.x;
const cx = w / 2 - (w / 2 - this._centerX) * zoomLevel;
x = Math.min(x, cx + ww * maxPanOut * zoomLevel);
x = Math.max(x, cx - ww * maxPanOut * zoomLevel);
}
if (panY == "translateY") {
y += local.y - downPoint.y;
const cy = h / 2 - (h / 2 - this._centerY) * zoomLevel;
y = Math.min(y, cy + hh * maxPanOut * zoomLevel);
y = Math.max(y, cy - hh * maxPanOut * zoomLevel);
}
this.set("translateX", x);
this.set("translateY", y);
if (projection.invert) {
let downLocation = projection.invert([downPoint.x, downPoint.y]);
if (location && downLocation) {
if (panX == "rotateX") {
this.set("rotationX", this._downRotationX - (downPoint.x - local.x) * this._pLon);
}
if (panY == "rotateY") {
this.set("rotationY", this._downRotationY + (downPoint.y - local.y) * this._pLat);
}
}
}
}
}
}
}
}
}
_handleWheelRotateY(delta, duration, easing) {
this._rya = this.animate({ key: "rotationY", to: this.get("rotationY", 0) - delta, duration: duration, easing: easing });
}
_handleWheelRotateX(delta, duration, easing) {
this._rxa = this.animate({ key: "rotationX", to: this.get("rotationX", 0) - delta, duration: duration, easing: easing });
}
_handleWheelZoom(delta, point) {
let step = this.get("zoomStep", 2);
let zoomLevel = this.get("zoomLevel", 1);
let newZoomLevel = zoomLevel;
if (delta > 0) {
newZoomLevel = zoomLevel / step;
}
else if (delta < 0) {
newZoomLevel = zoomLevel * step;
}
if (newZoomLevel != zoomLevel) {
this.zoomToPoint(point, newZoomLevel);
}
}
/**
* Zoom the map to geographical bounds.
*
* @param geoBounds Bounds
* @param duration Animation duration in milliseconds
* @param rotationX X rotation of a map at the end of zoom
* @param rotationY Y rotation of a map at the end of zoom
*/
zoomToGeoBounds(geoBounds, duration, rotationX, rotationY) {
if (geoBounds.right < geoBounds.left) {
geoBounds.right = 180;
geoBounds.left = -180;
}
const geoPath = this.getPrivate("geoPath");
const mapBounds = geoPath.bounds(this._geometryColection);
let p0 = this.convert({ longitude: geoBounds.left, latitude: geoBounds.top }, rotationX, rotationY);
let p1 = this.convert({ longitude: geoBounds.right, latitude: geoBounds.bottom }, rotationX, rotationY);
if (p0.y < mapBounds[0][1]) {
p0.y = mapBounds[0][1];
}
if (p1.y > mapBounds[1][1]) {
p1.y = mapBounds[1][1];
}
let zl = this.get("zoomLevel", 1);
let bounds = { left: p0.x, right: p1.x, top: p0.y, bottom: p1.y };
let seriesContainer = this.seriesContainer;
let zoomLevel = .9 * Math.min(seriesContainer.innerWidth() / (bounds.right - bounds.left) * zl, seriesContainer.innerHeight() / (bounds.bottom - bounds.top) * zl);
let x = bounds.left + (bounds.right - bounds.left) / 2;
let y = bounds.top + (bounds.bottom - bounds.top) / 2;
let geoPoint = this.invert({ x, y });
if (rotationX != null || rotationY != null) {
this.rotate(rotationX, rotationY);
}
return this.zoomToGeoPoint(geoPoint, zoomLevel, true, duration);
}
/**
* Zooms the map to specific screen point.
*
* @param point Point
* @param level Zoom level
* @param center Center the map
* @param duration Duration of the animation in milliseconds
*/
zoomToPoint(point, level, center, duration) {
if (level) {
level = $math.fitToRange(level, this.get("minZoomLevel", 1), this.get("maxZoomLevel", 32));
}
if (!$type.isNumber(duration)) {
duration = this.get("animationDuration", 0);
}
const easing = this.get("animationEasing");
const zoomLevel = this.get("zoomLevel", 1);
if (this.get("centerMapOnZoomOut") && level == this.get("homeZoomLevel", 1)) {
point = this.convert(this.homeGeoPoint());
center = true;
}
let x = point.x;
let y = point.y;
let tx = this.get("translateX", 0);
let ty = this.get("translateY", 0);
let cx = x;
let cy = y;
if (center) {
cx = this.width() / 2;
cy = this.height() / 2;
}
let xx = cx - ((x - tx) / zoomLevel * level);
let yy = cy - ((y - ty) / zoomLevel * level);
this._txa = this.animate({ key: "translateX", to: xx, duration: duration, easing: easing });
this._tya = this.animate({ key: "translateY", to: yy, duration: duration, easing: easing });
this._za = this.animate({ key: "zoomLevel", to: level, duration: duration, easing: easing });
if (zoomLevel != level) {
this._root.readerAlert(this._t("Zoom level changed to %1", this._root.locale, $type.numberToString(level)));
}
return this._za;
}
/**
* Zooms the map to specific geographical point.
*
* @param geoPoint Point
* @param level Zoom level
* @param center Center the map
* @param duration Duration of the animation in milliseconds
* @param rotationX X rotation of a map at the end of zoom
* @param rotationY Y rotation of a map at the end of zoom
*
*/
zoomToGeoPoint(geoPoint, level, center, duration, rotationX, rotationY) {
let xy = this.convert(geoPoint, rotationX, rotationY);
if (rotationX != null || rotationY != null) {
this.rotate(rotationX, rotationY, duration);
}
if (xy) {
return this.zoomToPoint(xy, level, center, duration);
}
}
rotate(rotationX, rotationY, duration) {
const projection = this.get("projection");
if (!projection.rotate) {
}
else {
if (!$type.isNumber(duration)) {
duration = this.get("animationDuration", 0);
}
const easing = this.get("animationEasing");
if (rotationX != null) {
this.animate({ key: "rotationX", to: rotationX, duration: duration, easing: easing });
}
if (rotationY != null) {
this.animate({ key: "rotationY", to: rotationY, duration: duration, easing: easing });
}
}
}
/**
* Zooms the map in.
*/
zoomIn() {
return this.zoomToPoint({ x: this.width() / 2, y: this.height() / 2 }, this.get("zoomLevel", 1) * this.get("zoomStep", 2));
}
/**
* Zooms the map out.
*/
zoomOut() {
return this.zoomToPoint({ x: this.width() / 2, y: this.height() / 2 }, this.get("zoomLevel", 1) / this.get("zoomStep", 2));
}
_clearDirty() {
super._clearDirty();
this._dirtyGeometries = false;
this._mapFitted = false;
}
/**
* Returns area of a mapPolygon in square pixels.
*/
getArea(dataItem) {
const geoPath = this.getPrivate("geoPath");
const geometry = dataItem.get("geometry");
if (geometry) {
return geoPath.area(geometry);
}
return 0;
}
}
Object.defineProperty(MapChart, "className", {
enumerable: true,
configurable: true,
writable: true,
value: "MapChart"
});
Object.defineProperty(MapChart, "classNames", {
enumerable: true,
configurable: true,
writable: true,
value: SerialChart.classNames.concat([MapChart.className])
});
//# sourceMappingURL=MapChart.js.map