@amcharts/amcharts4
Version:
amCharts 4
523 lines • 18.2 kB
JavaScript
/**
* Map line module
*/
import { __extends, __values } from "tslib";
/**
* ============================================================================
* IMPORTS
* ============================================================================
* @hidden
*/
import { MapObject } from "./MapObject";
import { MapLineObject } from "./MapLineObject";
import { MapImage } from "./MapImage";
import { MapImageSeries } from "./MapImageSeries";
import { Triangle } from "../../core/elements/Triangle";
import { ListTemplate, ListDisposer } from "../../core/utils/List";
import { Polyline } from "../../core/elements/Polyline";
import { registry } from "../../core/Registry";
import { color } from "../../core/utils/Color";
import { InterfaceColorSet } from "../../core/utils/InterfaceColorSet";
import { percent, Percent } from "../../core/utils/Percent";
import * as $type from "../../core/utils/Type";
import * as $iter from "../../core/utils/Iterator";
import * as $geo from "./Geo";
import * as $mapUtils from "./MapUtils";
/**
* ============================================================================
* MAIN CLASS
* ============================================================================
* @hidden
*/
/**
* Used to draw a line on the map.
*
* @see {@link IMapLineEvents} for a list of available events
* @see {@link IMapLineAdapters} for a list of available Adapters
*/
var MapLine = /** @class */ (function (_super) {
__extends(MapLine, _super);
/**
* Constructor
*/
function MapLine() {
var _this =
// Init
_super.call(this) || this;
/**
* A list of event disposers for images.
*/
_this._imageListeners = {};
_this.className = "MapLine";
_this.createLine();
_this.line.stroke = color();
_this.line.parent = _this;
_this.strokeOpacity = 1;
_this.setPropertyValue("precision", 0.1);
var interfaceColors = new InterfaceColorSet();
_this.stroke = interfaceColors.getFor("grid");
_this.shortestDistance = true;
// Apply theme
_this.applyTheme();
return _this;
}
/**
* @ignore
*/
MapLine.prototype.createLine = function () {
this.line = new Polyline();
};
/**
* Converts a position within the line (0-1) to a physical point
* coordinates.
*
* 0 indicates start of the line, 0.5 - middle, while 1 indicates the end.
*
* @param position Position (0-1)
* @return Coordinates
*/
MapLine.prototype.positionToPoint = function (position) {
if (this.shortestDistance) {
return this.series.chart.projection.positionToPoint(this.multiGeoLine, position);
}
else {
if (this.line) {
return this.line.positionToPoint(position);
}
}
return { x: 0, y: 0, angle: 0 };
};
Object.defineProperty(MapLine.prototype, "multiGeoLine", {
/**
* @return Coordinates
*/
get: function () {
var multiGeoLine = this.getPropertyValue("multiGeoLine");
if (!multiGeoLine && this.dataItem && this.dataItem.multiGeoLine) {
multiGeoLine = this.dataItem.multiGeoLine;
}
return multiGeoLine;
},
/**
* A collection of X/Y coordinates for a multi-segment line. E.g.:
*
* ```JSON
* [
* // Segment 1
* [
* { longitude: 3.121, latitude: 0.58 },
* { longitude: -5.199, latitude: 21.223 }
* ],
*
* // Segment 2
* [
* { longitude: -5.199, latitude: 21.223 },
* { longitude: -12.9, latitude: 25.85 }
* ]
* ]
* ```
*
* @see {@link https://tools.ietf.org/html/rfc7946#section-3.1.5} GeoJSON MultiLineString reference
* @param multiGeoLine Coordinates
*/
set: function (multiGeoLine) {
if (multiGeoLine && multiGeoLine.length > 0) {
this.setPropertyValue("multiGeoLine", $geo.normalizeMultiline(multiGeoLine), true);
var multiLine = $mapUtils.multiGeoLineToMultiLine(multiGeoLine);
this.setPropertyValue("multiLine", multiLine);
this.updateExtremes();
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(MapLine.prototype, "multiLine", {
/**
* @return Coordinates
*/
get: function () {
var multiLine = this.getPropertyValue("multiLine");
if (!multiLine && this.dataItem && this.dataItem.multiLine) {
multiLine = this.dataItem.multiLine;
}
return multiLine;
},
/**
* A collection of X/Y coordinates for a multi-segment line. E.g.:
*
* ```JSON
* [
* // Segment 1
* [
* [ 100, 150 ],
* [ 120, 200 ]
* ],
*
* // Segment 2
* [
* [ 120, 200 ],
* [ 150, 100 ]
* ]
* ]
* ```
*
* @param multiLine Coordinates
*/
set: function (multiLine) {
this.setPropertyValue("multiLine", multiLine);
this.multiGeoLine = $mapUtils.multiLineToGeo(multiLine);
},
enumerable: true,
configurable: true
});
Object.defineProperty(MapLine.prototype, "imagesToConnect", {
/**
* @return {MapImages[]}
*/
get: function () {
return this.getPropertyValue("imagesToConnect");
},
/**
* Instead of setting longitudes/latitudes you can set an array of images
* which will be connected by the line.
*
* Parameter is an array that can hold string `id`'s to of the images, or
* references to actual [[MapImage]] objects.
*
* @param images Images
*/
set: function (images) {
var _this = this;
this.setPropertyValue("imagesToConnect", images, true);
this.handleImagesToConnect();
if (this.series) {
var chart = this.series.chart;
if (chart) {
chart.series.each(function (series) {
if (series instanceof MapImageSeries) {
if (!series.isReady()) {
_this._disposers.push(series.events.on("ready", _this.handleImagesToConnect, _this, false));
}
}
});
}
}
},
enumerable: true,
configurable: true
});
MapLine.prototype.handleImagesToConnect = function () {
var e_1, _a;
var _this = this;
if (this.imagesToConnect) {
var segment = [];
var multiGeoLine = [segment];
var _loop_1 = function (image) {
if ($type.isString(image)) {
var chart = this_1.series.chart;
if (chart) {
chart.series.each(function (series) {
if (series instanceof MapImageSeries) {
var img = series.getImageById(image);
if (img) {
image = img;
}
}
});
}
}
if (image instanceof MapImage) {
segment.push({ longitude: image.longitude, latitude: image.latitude });
if (!this_1._imageListeners[image.uid]) {
var disposer = image.events.on("propertychanged", function (event) {
if (event.property == "longitude" || event.property == "latitude") {
_this.handleImagesToConnect();
_this.invalidate();
}
}, this_1, false);
this_1._imageListeners[image.uid] = disposer;
this_1._disposers.push(disposer);
}
}
};
var this_1 = this;
try {
for (var _b = __values(this.imagesToConnect), _c = _b.next(); !_c.done; _c = _b.next()) {
var image = _c.value;
_loop_1(image);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_1) throw e_1.error; }
}
this.multiGeoLine = multiGeoLine;
}
};
/**
* (Re)validates the line, effectively forcing it to redraw.
*
* @ignore Exclude from docs
*/
MapLine.prototype.validate = function () {
var chart = this.series.chart;
if (this.multiLine) {
if (!this.shortestDistance) {
var convertedPoints = [];
for (var i = 0, len = this.multiLine.length; i < len; i++) {
var segment = this.multiLine[i];
var convertedSegmentPoints = [];
for (var s = 0, slen = segment.length; s < slen; s++) {
var geoPoint = segment[s];
var point = this.series.chart.projection.convert({ longitude: geoPoint[0], latitude: geoPoint[1] });
convertedSegmentPoints.push(point);
}
convertedPoints.push(convertedSegmentPoints);
}
this.line.segments = convertedPoints;
}
else {
chart.projection.d3Projection.precision(this.precision);
this.line.path = chart.projection.d3Path(this.getFeature());
}
if (this._arrow) {
this._arrow.validatePosition();
}
$iter.each(this.lineObjects.iterator(), function (x) {
x.validatePosition();
});
this.handleGlobalScale();
}
else if (this.imagesToConnect) {
this.handleImagesToConnect();
}
_super.prototype.validate.call(this);
};
/**
* @ignore
*/
MapLine.prototype.getFeature = function () {
if (this.multiLine && this.multiLine.length > 0 && this.multiLine[0] && this.multiLine[0].length > 0) {
return { "type": "Feature", geometry: { type: "MultiLineString", coordinates: this.multiLine } };
}
};
/**
* @ignore Exclude from docs
*/
MapLine.prototype.measureElement = function () {
// Overriding, just to avoid extra measure
};
Object.defineProperty(MapLine.prototype, "shortestDistance", {
/**
* @return Real path?
*/
get: function () {
return this.getPropertyValue("shortestDistance");
},
/**
* The line should take the shortest path over the globe.
*
* Enabling this will make the line look differently in different
* projections. Only `MapLine` supports this setting, `MapArc` and
* `MapSplice` don't.
*
* @default true
* @param value Real path?
*/
set: function (value) {
this.setPropertyValue("shortestDistance", value, true);
},
enumerable: true,
configurable: true
});
Object.defineProperty(MapLine.prototype, "lineObjects", {
/**
* List of separate line objects the line consists of.
*
* @readonly
* @return List of line objects
*/
get: function () {
if (!this._lineObjects) {
this._lineObjects = new ListTemplate(new MapLineObject());
this._lineObjects.events.on("inserted", this.handleLineObjectAdded, this, false);
this._disposers.push(new ListDisposer(this._lineObjects));
this._disposers.push(this._lineObjects.template);
}
return this._lineObjects;
},
enumerable: true,
configurable: true
});
/**
* Decorate a [[LineObject]] when it is added to the line.
*
* @param event Event
*/
MapLine.prototype.handleLineObjectAdded = function (event) {
var mapLineObject = event.newValue;
mapLineObject.mapLine = this;
mapLineObject.shouldClone = false;
mapLineObject.parent = this;
};
Object.defineProperty(MapLine.prototype, "arrow", {
/**
* @return Arrow element
*/
get: function () {
if (!this._arrow) {
var arrow = this.createChild(MapLineObject);
arrow.shouldClone = false;
arrow.width = 8;
arrow.height = 10;
arrow.mapLine = this;
arrow.position = 0.5;
var triangle = arrow.createChild(Triangle);
//triangle.shouldClone = false;
triangle.fillOpacity = 1;
triangle.width = percent(100);
triangle.height = percent(100);
triangle.rotation = 90;
triangle.horizontalCenter = "middle";
triangle.verticalCenter = "middle";
this._arrow = arrow;
}
return this._arrow;
},
/**
* A [[MapLineObject]] to use as an option arrowhead on the line.
*
* Just accessing this property will create a default arrowhead on the line
* automatically.
*
* @param arrow Arrow element
*/
set: function (arrow) {
this._arrow = arrow;
arrow.mapLine = this;
arrow.parent = this;
},
enumerable: true,
configurable: true
});
/**
* Copies line properties and other attributes, like arrow, from another
* instance of [[MapLine]].
*
* @param source Source map line
*/
MapLine.prototype.copyFrom = function (source) {
_super.prototype.copyFrom.call(this, source);
this.line.copyFrom(source.line);
this.lineObjects.copyFrom(source.lineObjects);
if (source._arrow) {
this.arrow = source.arrow.clone();
}
};
Object.defineProperty(MapLine.prototype, "latitude", {
/**
* Latitude of the line center.
*
* @readonly
* @return Latitude
*/
get: function () {
return this.north + (this.south - this.north) / 2;
},
enumerable: true,
configurable: true
});
Object.defineProperty(MapLine.prototype, "longitude", {
/**
* Longitude of the line center.
*
* @readonly
* @return Latitude
*/
get: function () {
return this.east + (this.west - this.east) / 2;
},
enumerable: true,
configurable: true
});
/**
* X coordinate for the slice tooltip.
*
* @ignore
* @return X
*/
MapLine.prototype.getTooltipX = function () {
var x = this.getPropertyValue("tooltipX");
if (!(x instanceof Percent)) {
x = percent(50);
}
if (x instanceof Percent) {
return this.positionToPoint(x.value).x;
}
else {
return 0;
}
};
/**
* Y coordinate for the slice tooltip.
*
* @ignore
* @return Y
*/
MapLine.prototype.getTooltipY = function () {
var y = this.getPropertyValue("tooltipY");
if (!(y instanceof Percent)) {
y = percent(50);
}
if (y instanceof Percent) {
return this.positionToPoint(y.value).y;
}
else {
return 0;
}
};
Object.defineProperty(MapLine.prototype, "precision", {
/**
* @return Precision
*/
get: function () {
return this.getPropertyValue("precision");
},
/**
* When line is plotted, if its `shortestDistance` is set to `true` it is
* bent according to the used projection, to depict the shortest distance how
* it would go on the actual land.
*
* `precision` introduces a setting which can control when such bending
* occurs.
*
* If the distance (in degrees) between line start and end points
* is less than `precision`, no bending will take place and the line will be
* straight.
*
* Set to large number (e.g. 10000) for perfectly straight line.
*
* @since 4.9.1
* @default 0.1
* @param value Precision
*/
set: function (value) {
this.setPropertyValue("precision", value, true);
},
enumerable: true,
configurable: true
});
return MapLine;
}(MapObject));
export { MapLine };
/**
* Register class in system, so that it can be instantiated using its name from
* anywhere.
*
* @ignore
*/
registry.registeredClasses["MapLine"] = MapLine;
//# sourceMappingURL=MapLine.js.map