import { __awaiter } from "tslib"; import { DataItem } from "../../../core/render/Component"; import { Series } from "../../../core/render/Series"; import { List } from "../../../core/util/List"; import { Container } from "../../../core/render/Container"; import { Graphics } from "../../../core/render/Graphics"; import * as $type from "../../../core/util/Type"; import * as $object from "../../../core/util/Object"; import * as $array from "../../../core/util/Array"; import * as $utils from "../../../core/util/Utils"; /** * @ignore */ function min(left, right) { if (left == null) { return right; } else if (right == null) { return left; } else if (right < left) { return right; } else { return left; } } /** * @ignore */ function max(left, right) { if (left == null) { return right; } else if (right == null) { return left; } else if (right > left) { return right; } else { return left; } } /** * A base class for all XY chart series. * * @see {@link https://www.amcharts.com/docs/v5/charts/xy-chart/series/} for more info */ export class XYSeries extends Series { constructor() { super(...arguments); Object.defineProperty(this, "_xField", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "_yField", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "_xOpenField", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "_yOpenField", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "_xLowField", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "_xHighField", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "_yLowField", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "_yHighField", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "_axesDirty", { enumerable: true, configurable: true, writable: true, value: false }); Object.defineProperty(this, "_stackDirty", { enumerable: true, configurable: true, writable: true, value: false }); Object.defineProperty(this, "_selectionProcessed", { enumerable: true, configurable: true, writable: true, value: false }); Object.defineProperty(this, "_dataSets", { enumerable: true, configurable: true, writable: true, value: {} }); Object.defineProperty(this, "_mainContainerMask", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "_x", { enumerable: true, configurable: true, writable: true, value: 0 }); Object.defineProperty(this, "_y", { enumerable: true, configurable: true, writable: true, value: 0 }); Object.defineProperty(this, "_bullets", { enumerable: true, configurable: true, writable: true, value: {} }); /** * A [[Container]] that us used to put series' elements in. * * @default Container.new() */ Object.defineProperty(this, "mainContainer", { enumerable: true, configurable: true, writable: true, value: this.children.push(Container.new(this._root, {})) }); /** * A list of axis ranges that affect the series. * * @see {@link https://www.amcharts.com/docs/v5/charts/xy-chart/axes/axis-ranges/} for more info */ Object.defineProperty(this, "axisRanges", { enumerable: true, configurable: true, writable: true, value: new List() }); Object.defineProperty(this, "_skipped", { enumerable: true, configurable: true, writable: true, value: false }); Object.defineProperty(this, "_couldStackTo", { enumerable: true, configurable: true, writable: true, value: [] }); Object.defineProperty(this, "_reallyStackedTo", { enumerable: true, configurable: true, writable: true, value: {} }); Object.defineProperty(this, "_stackedSeries", { enumerable: true, configurable: true, writable: true, value: {} }); Object.defineProperty(this, "_aLocationX0", { enumerable: true, configurable: true, writable: true, value: 0 }); Object.defineProperty(this, "_aLocationX1", { enumerable: true, configurable: true, writable: true, value: 1 }); Object.defineProperty(this, "_aLocationY0", { enumerable: true, configurable: true, writable: true, value: 0 }); Object.defineProperty(this, "_aLocationY1", { enumerable: true, configurable: true, writable: true, value: 1 }); Object.defineProperty(this, "_showBullets", { enumerable: true, configurable: true, writable: true, value: true }); Object.defineProperty(this, "valueXFields", { enumerable: true, configurable: true, writable: true, value: [ "valueX", "openValueX", "lowValueX", "highValueX" ] }); Object.defineProperty(this, "valueYFields", { enumerable: true, configurable: true, writable: true, value: [ "valueY", "openValueY", "lowValueY", "highValueY" ] }); Object.defineProperty(this, "_valueXFields", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "_valueYFields", { enumerable: true, configurable: true, writable: true, value: void 0 }); // used for full min/max Object.defineProperty(this, "_valueXShowFields", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "_valueYShowFields", { enumerable: true, configurable: true, writable: true, value: void 0 }); // used for selection (uses working) Object.defineProperty(this, "__valueXShowFields", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "__valueYShowFields", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "_emptyDataItem", { enumerable: true, configurable: true, writable: true, value: new DataItem(this, undefined, {}) }); Object.defineProperty(this, "_dataSetId", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "_tooltipFieldX", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "_tooltipFieldY", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "_posXDp", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "_posYDp", { enumerable: true, configurable: true, writable: true, value: void 0 }); } _afterNew() { this.fields.push("categoryX", "categoryY", "openCategoryX", "openCategoryY"); this.valueFields.push("valueX", "valueY", "openValueX", "openValueY", "lowValueX", "lowValueY", "highValueX", "highValueY"); this._setRawDefault("vcx", 1); this._setRawDefault("vcy", 1); // this can't go to themes, as data might be parsed before theme this._setRawDefault("valueXShow", "valueXWorking"); this._setRawDefault("valueYShow", "valueYWorking"); this._setRawDefault("openValueXShow", "openValueXWorking"); this._setRawDefault("openValueYShow", "openValueYWorking"); this._setRawDefault("lowValueXShow", "lowValueXWorking"); this._setRawDefault("lowValueYShow", "lowValueYWorking"); this._setRawDefault("highValueXShow", "highValueXWorking"); this._setRawDefault("highValueYShow", "highValueYWorking"); this._setRawDefault("lowValueXGrouped", "low"); this._setRawDefault("lowValueYGrouped", "low"); this._setRawDefault("highValueXGrouped", "high"); this._setRawDefault("highValueYGrouped", "high"); super._afterNew(); this.set("maskContent", true); this._disposers.push(this.axisRanges.events.onAll((change) => { if (change.type === "clear") { $array.each(change.oldValues, (axisRange) => { this._removeAxisRange(axisRange); }); } else if (change.type === "push") { this._processAxisRange(change.newValue); } else if (change.type === "setIndex") { this._processAxisRange(change.newValue); } else if (change.type === "insertIndex") { this._processAxisRange(change.newValue); } else if (change.type === "removeIndex") { this._removeAxisRange(change.oldValue); } else if (change.type === "moveIndex") { this._processAxisRange(change.value); } else { throw new Error("Unknown IStreamEvent type"); } })); this.states.create("hidden", { opacity: 1, visible: false }); this._makeFieldNames(); } _processAxisRange(axisRange) { const container = Container.new(this._root, {}); axisRange.container = container; this.children.push(container); axisRange.series = this; const axisDataItem = axisRange.axisDataItem; axisDataItem.setRaw("isRange", true); const axis = axisDataItem.component; if (axis) { axis._processAxisRange(axisDataItem, ["range", "series"]); const bullet = axisDataItem.get("bullet"); if (bullet) { const sprite = bullet.get("sprite"); if (sprite) { sprite.setPrivate("visible", false); } } const axisFill = axisDataItem.get("axisFill"); if (axisFill) { container.set("mask", axisFill); } axis._seriesAxisRanges.push(axisDataItem); } } _removeAxisRange(axisRange) { const axisDataItem = axisRange.axisDataItem; const axis = axisDataItem.component; axis.disposeDataItem(axisDataItem); $array.remove(axis._seriesAxisRanges, axisDataItem); const container = axisRange.container; if (container) { container.dispose(); } } _updateFields() { super._updateFields(); this._valueXFields = []; this._valueYFields = []; this._valueXShowFields = []; this._valueYShowFields = []; this.__valueXShowFields = []; this.__valueYShowFields = []; if (this.valueXFields) { $array.each(this.valueXFields, (key) => { const field = this.get((key + "Field")); if (field) { this._valueXFields.push(key); let field = this.get((key + "Show")); this.__valueXShowFields.push(field); if (field.indexOf("Working") != -1) { this._valueXShowFields.push(field.split("Working")[0]); } else { this._valueXShowFields.push(field); } } }); } if (this.valueYFields) { $array.each(this.valueYFields, (key) => { const field = this.get((key + "Field")); if (field) { this._valueYFields.push(key); let field = this.get((key + "Show")); this.__valueYShowFields.push(field); if (field.indexOf("Working") != -1) { this._valueYShowFields.push(field.split("Working")[0]); } else { this._valueYShowFields.push(field); } } }); } } _dispose() { super._dispose(); this._bullets = {}; const chart = this.chart; if (chart) { chart.series.removeValue(this); } $array.removeFirst(this.get("xAxis").series, this); $array.removeFirst(this.get("yAxis").series, this); } // TODO use SelectKeys _min(key, value) { let newValue = min(this.getPrivate(key), value); this.setPrivate(key, newValue); } // TODO use SelectKeys _max(key, value) { let newValue = max(this.getPrivate(key), value); this.setPrivate(key, newValue); } _shouldMakeBullet(dataItem) { const xAxis = this.get("xAxis"); const yAxis = this.get("yAxis"); const baseAxis = this.get("baseAxis"); if (!xAxis.inited || !yAxis.inited) { return false; } const minBulletDistance = this.get("minBulletDistance", 0); if (minBulletDistance > 0) { let startIndex = this.startIndex(); let endIndex = this.endIndex(); let count = endIndex - startIndex; if (xAxis == baseAxis) { if (xAxis.get("renderer").axisLength() / count < minBulletDistance / 5) { return false; } } else if (yAxis == baseAxis) { if (yAxis.get("renderer").axisLength() / count < minBulletDistance / 5) { return false; } } } if (dataItem.get(this._xField) != null && dataItem.get(this._yField) != null) { return true; } return false; } _makeFieldNames() { const xAxis = this.get("xAxis"); const yAxis = this.get("yAxis"); const xName = xAxis.getPrivate("name"); const xCapName = $utils.capitalizeFirst(xName); const yName = yAxis.getPrivate("name"); const yCapName = $utils.capitalizeFirst(yName); const xLetter = xAxis.get("renderer").getPrivate("letter"); const yLetter = yAxis.get("renderer").getPrivate("letter"); const open = "open"; const low = "low"; const high = "high"; const show = "Show"; if (xAxis.className === "ValueAxis") { this._xField = this.get((xName + xLetter + show)); this._xOpenField = this.get((open + xCapName + xLetter + show)); this._xLowField = this.get((low + xCapName + xLetter + show)); this._xHighField = this.get((high + xCapName + xLetter + show)); } else { this._xField = (xName + xLetter); this._xOpenField = (open + xCapName + xLetter); this._xLowField = (low + xCapName + xLetter); this._xHighField = (high + xCapName + xLetter); } if (yAxis.className === "ValueAxis") { this._yField = this.get((yName + yLetter + show)); this._yOpenField = this.get((open + yCapName + yLetter + show)); this._yLowField = this.get((low + yCapName + yLetter + show)); this._yHighField = this.get((high + yCapName + yLetter + show)); } else { this._yField = (yName + yLetter); this._yOpenField = (open + yCapName + yLetter); this._yLowField = (low + yCapName + yLetter); this._yHighField = (high + yCapName + yLetter); } } _fixVC() { const xAxis = this.get("xAxis"); const yAxis = this.get("yAxis"); const baseAxis = this.get("baseAxis"); const hiddenState = this.states.lookup("hidden"); const sequencedInterpolation = this.get("sequencedInterpolation"); if (hiddenState) { let value = 0; if (sequencedInterpolation) { value = 0.999999999999; // makes animate, good for stacked } if (xAxis === baseAxis) { hiddenState.set("vcy", value); } else if (yAxis === baseAxis) { hiddenState.set("vcx", value); } else { hiddenState.set("vcy", value); hiddenState.set("vcx", value); } } } _handleMaskBullets() { if (this.isDirty("maskBullets")) { this.bulletsContainer.set("maskContent", this.get("maskBullets")); } } _fixPosition() { const xAxis = this.get("xAxis"); const yAxis = this.get("yAxis"); this.set("x", xAxis.x() - $utils.relativeToValue(xAxis.get("centerX", 0), xAxis.width()) - xAxis.parent.get("paddingLeft", 0)); this.set("y", yAxis.y() - $utils.relativeToValue(yAxis.get("centerY", 0), yAxis.height()) - yAxis.parent.get("paddingTop", 0)); this.bulletsContainer.set("y", this.y()); this.bulletsContainer.set("x", this.x()); } _prepareChildren() { super._prepareChildren(); this._bullets = {}; if (this.isDirty("valueYShow") || this.isDirty("valueXShow") || this.isDirty("openValueYShow") || this.isDirty("openValueXShow") || this.isDirty("lowValueYShow") || this.isDirty("lowValueXShow") || this.isDirty("highValueYShow") || this.isDirty("highValueXShow")) { this._updateFields(); this._makeFieldNames(); this._valuesDirty = true; } if (this.isDirty("xAxis") || this.isDirty("yAxis")) { this._valuesDirty = true; } this.set("width", this.get("xAxis").width()); this.set("height", this.get("yAxis").height()); this._handleMaskBullets(); const xAxis = this.get("xAxis"); const yAxis = this.get("yAxis"); const baseAxis = this.get("baseAxis"); const tooltipPositionX = this.get("tooltipPositionX"); let tooltipFieldX; switch (tooltipPositionX) { case "open": tooltipFieldX = this._xOpenField; break; case "low": tooltipFieldX = this._xLowField; break; case "high": tooltipFieldX = this._xHighField; break; default: tooltipFieldX = this._xField; } this._tooltipFieldX = tooltipFieldX; const tooltipPositionY = this.get("tooltipPositionY"); let tooltipFieldY; switch (tooltipPositionY) { case "open": tooltipFieldY = this._yOpenField; break; case "low": tooltipFieldY = this._yLowField; break; case "high": tooltipFieldY = this._yHighField; break; default: tooltipFieldY = this._yField; } this._tooltipFieldY = tooltipFieldY; if (this.isDirty("baseAxis")) { this._fixVC(); } this._fixPosition(); const stacked = this.get("stacked"); if (this.isDirty("stacked")) { if (stacked) { if (this._valuesDirty && !this._dataProcessed) { } else { this._stack(); } } else { this._unstack(); } } if (this._valuesDirty && !this._dataProcessed) { this._dataProcessed = true; if (stacked) { this._stack(); } $array.each(this.dataItems, (dataItem) => { $array.each(this._valueXShowFields, (key) => { let value = dataItem.get(key); if (value != null) { if (stacked) { value += this.getStackedXValue(dataItem, key); } this._min("minX", value); this._max("maxX", value); } }); $array.each(this._valueYShowFields, (key) => { let value = dataItem.get(key); if (value != null) { if (stacked) { value += this.getStackedYValue(dataItem, key); } this._min("minY", value); this._max("maxY", value); } }); xAxis.processSeriesDataItem(dataItem, this._valueXFields); yAxis.processSeriesDataItem(dataItem, this._valueYFields); }); xAxis._seriesValuesDirty = true; yAxis._seriesValuesDirty = true; if (!this.get("ignoreMinMax")) { if (this.isPrivateDirty("minX") || this.isPrivateDirty("maxX")) { xAxis.markDirtyExtremes(); } if (this.isPrivateDirty("minY") || this.isPrivateDirty("maxY")) { yAxis.markDirtyExtremes(); } } this._markStakedDirtyStack(); //this.updateLegendMarker(undefined); // causes legend marker to change color instantly when on if (!this.get("tooltipDataItem")) { this.updateLegendValue(undefined); } } if (this.isDirty("vcx") || this.isDirty("vcy")) { this._markStakedDirtyStack(); } if (!this._dataGrouped) { xAxis._groupSeriesData(this); yAxis._groupSeriesData(this); this._dataGrouped = true; } if (this._valuesDirty || this.isPrivateDirty("startIndex") || this.isPrivateDirty("endIndex") || this.isDirty("vcx") || this.isDirty("vcy") || this._stackDirty) { let startIndex = this.startIndex(); let endIndex = this.endIndex(); let minBulletDistance = this.get("minBulletDistance", 0); if (minBulletDistance > 0 && baseAxis) { if (baseAxis.get("renderer").axisLength() / (endIndex - startIndex) > minBulletDistance) { this._showBullets = true; } else { this._showBullets = false; } } if ((this._psi != startIndex || this._pei != endIndex || this.isDirty("vcx") || this.isDirty("vcy") || this._stackDirty || this._valuesDirty) && !this._selectionProcessed) { this._selectionProcessed = true; const vcx = this.get("vcx", 1); const vcy = this.get("vcy", 1); const stacked = this.get("stacked", false); const outOfSelection = this.getPrivate("outOfSelection"); if (baseAxis === xAxis || !baseAxis) { yAxis._calculateTotals(); this.setPrivateRaw("selectionMinY", undefined); this.setPrivateRaw("selectionMaxY", undefined); if (!outOfSelection) { for (let i = startIndex; i < endIndex; i++) { this.processYSelectionDataItem(this.dataItems[i], vcy, stacked); } } else { yAxis.markDirtySelectionExtremes(); } } if (baseAxis === yAxis || !baseAxis) { xAxis._calculateTotals(); this.setPrivateRaw("selectionMinX", undefined); this.setPrivateRaw("selectionMaxX", undefined); if (!outOfSelection) { for (let i = startIndex; i < endIndex; i++) { this.processXSelectionDataItem(this.dataItems[i], vcx, stacked); } } else { yAxis.markDirtySelectionExtremes(); } } if (baseAxis === xAxis || !baseAxis) { if (this.get("valueYShow") !== "valueYWorking") { const selectionMinY = this.getPrivate("selectionMinY"); if (selectionMinY != null) { this.setPrivateRaw("minY", selectionMinY); yAxis.markDirtyExtremes(); } const selectionMaxY = this.getPrivate("selectionMaxY"); if (selectionMaxY != null) { this.setPrivateRaw("maxY", selectionMaxY); yAxis.markDirtyExtremes(); } } } if (baseAxis === yAxis || !baseAxis) { if (this.get("valueXShow") !== "valueXWorking") { const selectionMinX = this.getPrivate("selectionMinX"); if (selectionMinX != null) { this.setPrivateRaw("minX", selectionMinX); yAxis.markDirtyExtremes(); } const selectionMaxX = this.getPrivate("selectionMaxX"); if (selectionMaxX != null) { this.setPrivateRaw("maxX", selectionMaxX); xAxis.markDirtyExtremes(); } } } if (this.isPrivateDirty("selectionMinX") || this.isPrivateDirty("selectionMaxX")) { xAxis.markDirtySelectionExtremes(); } if (this.isPrivateDirty("selectionMinY") || this.isPrivateDirty("selectionMaxY")) { yAxis.markDirtySelectionExtremes(); } // this.updateLegendValue(undefined); flickers while panning } } } _makeRangeMask() { if (this.axisRanges.length > 0) { let mainContainerMask = this._mainContainerMask; if (mainContainerMask == null) { mainContainerMask = this.children.push(Graphics.new(this._root, {})); this._mainContainerMask = mainContainerMask; mainContainerMask.set("draw", (display, target) => { const parent = this.parent; if (parent) { const w = this._root.container.width(); const h = this._root.container.height(); display.moveTo(-w, -h); display.lineTo(-w, h * 2); display.lineTo(w * 2, h * 2); display.lineTo(w * 2, -h); display.lineTo(-w, -h); this.axisRanges.each((axisRange) => { const fill = axisRange.axisDataItem.get("axisFill"); if (parent) { if (fill) { let draw = fill.get("draw"); if (draw) { draw(display, target); } } } }); } this.mainContainer._display.mask = mainContainerMask._display; }); } mainContainerMask.markDirty(); mainContainerMask._markDirtyKey("fill"); } else { this.mainContainer._display.mask = null; } } _updateChildren() { super._updateChildren(); // save for performance this._x = this.x(); this._y = this.y(); this._makeRangeMask(); } _stack() { const chart = this.chart; if (chart) { const seriesIndex = chart.series.indexOf(this); this._couldStackTo = []; if (seriesIndex > 0) { let series; for (let i = seriesIndex - 1; i >= 0; i--) { series = chart.series.getIndex(i); if (series.get("xAxis") === this.get("xAxis") && series.get("yAxis") === this.get("yAxis") && series.className === this.className) { this._couldStackTo.push(series); if (!series.get("stacked")) { break; } } } } this._stackDataItems(); } } _unstack() { $object.each(this._reallyStackedTo, (_key, value) => { delete (value._stackedSeries[this.uid]); }); this._reallyStackedTo = {}; $array.each(this.dataItems, (dataItem) => { dataItem.setRaw("stackToItemY", undefined); dataItem.setRaw("stackToItemX", undefined); }); } _stackDataItems() { // this works only with the same number of data @todo: search by date/category? const baseAxis = this.get("baseAxis"); const xAxis = this.get("xAxis"); const yAxis = this.get("yAxis"); let field; let stackToItemKey; if (baseAxis === xAxis) { field = "valueY"; stackToItemKey = "stackToItemY"; } else if (baseAxis === yAxis) { field = "valueX"; stackToItemKey = "stackToItemX"; } let len = this._couldStackTo.length; let index = 0; const stackToNegative = this.get("stackToNegative"); this._reallyStackedTo = {}; $array.each(this.dataItems, (dataItem) => { for (let s = 0; s < len; s++) { let stackToSeries = this._couldStackTo[s]; let stackToItem = stackToSeries.dataItems[index]; let value = dataItem.get(field); if (stackToItem) { let stackValue = stackToItem.get(field); if (stackToNegative) { if ($type.isNumber(value)) { if ($type.isNumber(stackValue)) { if (value >= 0 && stackValue >= 0) { dataItem.setRaw(stackToItemKey, stackToItem); this._reallyStackedTo[stackToSeries.uid] = stackToSeries; stackToSeries._stackedSeries[this.uid] = this; break; } if (value < 0 && stackValue < 0) { dataItem.setRaw(stackToItemKey, stackToItem); this._reallyStackedTo[stackToSeries.uid] = stackToSeries; stackToSeries._stackedSeries[this.uid] = this; break; } } } else { break; } } else { if ($type.isNumber(value) && $type.isNumber(stackValue)) { dataItem.setRaw(stackToItemKey, stackToItem); this._reallyStackedTo[stackToSeries.uid] = stackToSeries; stackToSeries._stackedSeries[this.uid] = this; break; } } } } index++; }); } processXSelectionDataItem(dataItem, vcx, stacked) { $array.each(this.__valueXShowFields, (key) => { let value = dataItem.get(key); if (value != null) { if (stacked) { value += this.getStackedXValueWorking(dataItem, key); } this._min("selectionMinX", value); this._max("selectionMaxX", value * vcx); } }); } processYSelectionDataItem(dataItem, vcy, stacked) { $array.each(this.__valueYShowFields, (key) => { let value = dataItem.get(key); if (value != null) { if (stacked) { value += this.getStackedYValueWorking(dataItem, key); } this._min("selectionMinY", value); this._max("selectionMaxY", value * vcy); } }); } /** * @ignore */ getStackedYValueWorking(dataItem, key) { const stackToItem = dataItem.get("stackToItemY"); if (stackToItem) { const stackedToSeries = stackToItem.component; return stackToItem.get(key, 0) * stackedToSeries.get("vcy", 1) + this.getStackedYValueWorking(stackToItem, key); } return 0; } /** * @ignore */ getStackedXValueWorking(dataItem, key) { const stackToItem = dataItem.get("stackToItemX"); if (stackToItem) { const stackedToSeries = stackToItem.component; return stackToItem.get(key, 0) * stackedToSeries.get("vcx", 1) + this.getStackedXValueWorking(stackToItem, key); } return 0; } /** * @ignore */ getStackedYValue(dataItem, key) { const stackToItem = dataItem.get("stackToItemY"); if (stackToItem) { return stackToItem.get(key, 0) + this.getStackedYValue(stackToItem, key); } return 0; } /** * @ignore */ getStackedXValue(dataItem, key) { const stackToItem = dataItem.get("stackToItemX"); if (stackToItem) { return stackToItem.get(key, 0) + this.getStackedXValue(stackToItem, key); } return 0; } /** * @ignore */ createLegendMarker(_dataItem) { this.updateLegendMarker(); } _markDirtyAxes() { this._axesDirty = true; this.markDirty(); } _markDataSetDirty() { this._afterDataChange(); this._valuesDirty = true; this._dataProcessed = false; this._aggregatesCalculated = false; this.markDirty(); } _clearDirty() { super._clearDirty(); this._axesDirty = false; this._selectionProcessed = false; this._stackDirty = false; this._dataProcessed = false; } _positionBullet(bullet) { let sprite = bullet.get("sprite"); if (sprite) { let dataItem = sprite.dataItem; let locationX = bullet.get("locationX", dataItem.get("locationX", 0.5)); let locationY = bullet.get("locationY", dataItem.get("locationY", 0.5)); let xAxis = this.get("xAxis"); let yAxis = this.get("yAxis"); let positionX = xAxis.getDataItemPositionX(dataItem, this._xField, locationX, this.get("vcx", 1)); let positionY = yAxis.getDataItemPositionY(dataItem, this._yField, locationY, this.get("vcy", 1)); let point = this.getPoint(positionX, positionY); let left = dataItem.get("left", point.x); let right = dataItem.get("right", point.x); let top = dataItem.get("top", point.y); let bottom = dataItem.get("bottom", point.y); let x = 0; let y = 0; let w = right - left; let h = bottom - top; if (this._shouldShowBullet(positionX, positionY)) { sprite.setPrivate("visible", !bullet.getPrivate("hidden")); let field = bullet.get("field"); const baseAxis = this.get("baseAxis"); const xAxis = this.get("xAxis"); const yAxis = this.get("yAxis"); if (field != undefined) { let realField; if (baseAxis == xAxis) { if (field == "value") { realField = this._yField; } else if (field == "open") { realField = this._yOpenField; } else if (field == "high") { realField = this._yHighField; } else if (field == "low") { realField = this._yLowField; } if (realField) { positionY = yAxis.getDataItemPositionY(dataItem, realField, 0, this.get("vcy", 1)); point = yAxis.get("renderer").positionToPoint(positionY); y = point.y; x = left + w * locationX; } } else { if (field == "value") { realField = this._xField; } else if (field == "open") { realField = this._xOpenField; } else if (field == "high") { realField = this._xHighField; } else if (field == "low") { realField = this._xLowField; } if (realField) { positionX = xAxis.getDataItemPositionX(dataItem, realField, 0, this.get("vcx", 1)); point = xAxis.get("renderer").positionToPoint(positionX); x = point.x; y = bottom - h * locationY; } } } else { x = left + w * locationX; y = bottom - h * locationY; } const stacked = bullet.get("stacked"); if (stacked) { const chart = this.chart; if (baseAxis == xAxis) { let previousBullet = this._bullets[positionX + "_" + positionY]; if (previousBullet) { let previousBounds = previousBullet.bounds(); let bounds = sprite.localBounds(); let yo = y; y = previousBounds.top; if (stacked == "down") { y = previousBounds.bottom - bounds.top; } else if (stacked == "auto") { if (chart) { if (yo < chart.plotContainer.height() / 2) { y = previousBounds.bottom - bounds.top; } else { y += bounds.bottom; } } } else { y += bounds.bottom; } } this._bullets[positionX + "_" + positionY] = sprite; } else { let previousBullet = this._bullets[positionX + "_" + positionY]; if (previousBullet) { let previousBounds = previousBullet.bounds(); let bounds = sprite.localBounds(); let xo = x; x = previousBounds.right; if (stacked == "down") { x = previousBounds.left - bounds.right; } else if (stacked == "auto") { if (chart) { if (xo < chart.plotContainer.width() / 2) { x = previousBounds.left - bounds.right; } else { x -= bounds.left; } } } else { x -= bounds.left; } } this._bullets[positionX + "_" + positionY] = sprite; } } if (sprite.isType("Label")) { sprite.setPrivate("maxWidth", Math.abs(w)); sprite.setPrivate("maxHeight", Math.abs(h)); } sprite.setAll({ x, y }); } else { sprite.setPrivate("visible", false); } } } _shouldShowBullet(_positionX, _positionY) { return this._showBullets; } /** * @ignore */ setDataSet(id) { if (this._dataSets[id]) { this._handleDataSetChange(); this._dataItems = this._dataSets[id]; this._markDataSetDirty(); this._dataSetId = id; const type = "datasetchanged"; if (this.events.isEnabled(type)) { this.events.dispatch(type, { type: type, target: this, id: id }); } } } /** * @ignore */ resetGrouping() { $object.each(this._dataSets, (_key, dataSet) => { if (dataSet != this._mainDataItems) { $array.each(dataSet, (dataItem) => { this.disposeDataItem(dataItem); }); } }); this._dataSets = {}; this._dataItems = this.mainDataItems; } _handleDataSetChange() { $array.each(this._dataItems, (dataItem) => { let bullets = dataItem.bullets; if (bullets) { $array.each(bullets, (bullet) => { if (bullet) { let sprite = bullet.get("sprite"); if (sprite) { sprite.setPrivate("visible", false); } } }); } }); this._selectionProcessed = false; // for totals to be calculated } /** * Shows hidden series. * * @param duration Duration of animation in milliseconds * @return Animation promise */ show(duration) { const _super = Object.create(null, { show: { get: () => super.show } }); return __awaiter(this, void 0, void 0, function* () { this._fixVC(); let promises = []; promises.push(_super.show.call(this, duration).then(() => { this._isShowing = false; let xAxis = this.get("xAxis"); let yAxis = this.get("yAxis"); let baseAxis = this.get("baseAxis"); if (yAxis !== baseAxis) { yAxis.markDirtySelectionExtremes(); } if (xAxis !== baseAxis) { xAxis.markDirtySelectionExtremes(); } })); promises.push(this.bulletsContainer.show(duration)); promises.push(this._sequencedShowHide(true, duration)); yield Promise.all(promises); }); } /** * Hides series. * * @param duration Duration of animation in milliseconds * @return Animation promise */ hide(duration) { const _super = Object.create(null, { hide: { get: () => super.hide } }); return __awaiter(this, void 0, void 0, function* () { this._fixVC(); let promises = []; promises.push(_super.hide.call(this, duration).then(() => { this._isHiding = false; })); promises.push(this.bulletsContainer.hide(duration)); promises.push(this._sequencedShowHide(false, duration)); yield Promise.all(promises); }); } /** * Shows series's data item. * * @param dataItem Data item * @param duration Animation duration in milliseconds * @return Promise */ showDataItem(dataItem, duration) { const _super = Object.create(null, { showDataItem: { get: () => super.showDataItem } }); return __awaiter(this, void 0, void 0, function* () { const promises = [_super.showDataItem.call(this, dataItem, duration)]; if (!$type.isNumber(duration)) { duration = this.get("stateAnimationDuration", 0); } const easing = this.get("stateAnimationEasing"); $array.each(this._valueFields, (key) => { promises.push(dataItem.animate({ key: key + "Working", to: dataItem.get(key), duration: duration, easing: easing }).waitForStop()); }); yield Promise.all(promises); }); } /** * Hides series's data item. * * @param dataItem Data item * @param duration Animation duration in milliseconds * @return Promise */ hideDataItem(dataItem, duration) { const _super = Object.create(null, { hideDataItem: { get: () => super.hideDataItem } }); return __awaiter(this, void 0, void 0, function* () { const promises = [_super.hideDataItem.call(this, dataItem, duration)]; const hiddenState = this.states.create("hidden", {}); if (!$type.isNumber(duration)) { duration = hiddenState.get("stateAnimationDuration", this.get("stateAnimationDuration", 0)); } const easing = hiddenState.get("stateAnimationEasing", this.get("stateAnimationEasing")); const xAxis = this.get("xAxis"); const yAxis = this.get("yAxis"); const baseAxis = this.get("baseAxis"); const stacked = this.get("stacked"); if (baseAxis === xAxis || !baseAxis) { $array.each(this._valueYFields, (key) => { let min = yAxis.getPrivate("min"); let baseValue = yAxis.baseValue(); if ($type.isNumber(min) && min > baseValue) { baseValue = min; } if (stacked) { baseValue = 0; } let value = dataItem.get(key); if (value != null) { promises.push(dataItem.animate({ key: key + "Working", to: baseValue, duration: duration, easing: easing }).waitForStop()); } }); } if (baseAxis === yAxis || !baseAxis) { let min = xAxis.getPrivate("min"); let baseValue = xAxis.baseValue(); if ($type.isNumber(min) && min > baseValue) { baseValue = min; } if (stacked) { baseValue = 0; } $array.each(this._valueXFields, (key) => { let value = dataItem.get(key); if (value != null) { promises.push(dataItem.animate({ key: key + "Working", to: baseValue, duration: duration, easing: easing }).waitForStop()); } }); } yield Promise.all(promises); }); } _markDirtyStack() { this._stackDirty = true; this.markDirty(); this._markStakedDirtyStack(); } _markStakedDirtyStack() { const stackedSeries = this._stackedSeries; if (stackedSeries) { $object.each(stackedSeries, (_key, value) => { if (!value._stackDirty) { value._markDirtyStack(); } }); } } _afterChanged() { super._afterChanged(); if (this._skipped) { this._markDirtyAxes(); this._skipped = false; } } /** * Shows a tooltip for specific data item. * * @param dataItem Data item */ showDataItemTooltip(dataItem) { if (!this.getPrivate("doNotUpdateLegend")) { this.updateLegendMarker(dataItem); this.updateLegendValue(dataItem); } const tooltip = this.get("tooltip"); if (tooltip) { if (!this.isHidden()) { tooltip._setDataItem(dataItem); if (dataItem) { let locationX = this.get("locationX", 0); let locationY = this.get("locationY", 1); let itemLocationX = dataItem.get("locationX", locationX); let itemLocationY = dataItem.get("locationY", locationY); const xAxis = this.get("xAxis"); const yAxis = this.get("yAxis"); const vcx = this.get("vcx", 1); const vcy = this.get("vcy", 1); const xPos = xAxis.getDataItemPositionX(dataItem, this._tooltipFieldX, this._aLocationX0 + (this._aLocationX1 - this._aLocationX0) * itemLocationX, vcx); const yPos = yAxis.getDataItemPositionY(dataItem, this._tooltipFieldY, this._aLocationY0 + (this._aLocationY1 - this._aLocationY0) * itemLocationY, vcy); const point = this.getPoint(xPos, yPos); let show = true; $array.each(this._valueFields, (field) => { if (dataItem.get(field) == null) { show = false; } }); if (show) { const chart = this.chart; if (chart && chart.inPlot(point)) { tooltip.label.text.markDirtyText(); tooltip.set("tooltipTarget", this._getTooltipTarget(dataItem)); tooltip.set("pointTo", this._display.toGlobal({ x: point.x, y: point.y })); } else { tooltip._setDataItem(undefined); } } else { tooltip._setDataItem(undefined); } } } else { this.hideTooltip(); } } } hideTooltip() { const tooltip = this.get("tooltip"); if (tooltip) { tooltip.set("tooltipTarget", this); } return super.hideTooltip(); } _getTooltipTarget(dataItem) { if (this.get("seriesTooltipTarget") == "bullet") { const bullets = dataItem.bullets; if (bullets && bullets.length > 0) { const bullet = bullets[0]; const sprite = bullet.get("sprite"); if (sprite) { return sprite; } } } return this; } /** * @ignore */ updateLegendValue(dataItem) { const legendDataItem = this.get("legendDataItem"); if (legendDataItem) { const label = legendDataItem.get("label"); if (label) { let txt = ""; if (dataItem) { label._setDataItem(dataItem); txt = this.get("legendLabelText", label.get("text", this.get("name", ""))); } else { label._setDataItem(this._emptyDataItem); txt = this.get("legendRangeLabelText", this.get("legendLabelText", label.get("text", this.get("name", "")))); } label.set("text", txt); } const valueLabel = legendDataItem.get("valueLabel"); if (valueLabel) { let txt = ""; if (dataItem) { valueLabel._setDataItem(dataItem); txt = this.get("legendValueText", valueLabel.get("text", "")); } else { valueLabel._setDataItem(this._emptyDataItem); txt = this.get("legendRangeValueText", valueLabel.get("text", "")); } valueLabel.set("text", txt); } } } _getItemReaderLabel() { let text = "X: {" + this._xField; if (this.get("xAxis").isType("DateAxis")) { text += ".formatDate()"; } text += "}; Y: {" + this._yField; if (this.get("yAxis").isType("DateAxis")) { text += ".formatDate()"; } text += "}"; return text; } /** * @ignore */ getPoint(positionX, positionY) { let x = this.get("xAxis").get("renderer").positionToCoordinate(positionX); let y = this.get("yAxis").get("renderer").positionToCoordinate(positionY); // if coordinate is super big, canvas fails to draw line, capping to some big number (won't make any visual difference) let max = 999999999; if (y < -max) { y = -max; } if (y > max) { y = max; } if (x < -max) { x = -max; } if (x > max) { x = max; } return { x: x, y: y }; } _shouldInclude(_position) { return true; } /** * @ignore */ handleCursorHide() { this.hideTooltip(); this.updateLegendValue(undefined); this.updateLegendMarker(undefined); } _afterDataChange() { super._afterDataChange(); this.get("xAxis")._markDirtyKey("start"); this.get("yAxis")._markDirtyKey("start"); this.resetExtremes(); } /** * Resets cached axis scale values. */ resetExtremes() { this.setPrivate("selectionMinX", undefined); this.setPrivate("selectionMaxX", undefined); this.setPrivate("selectionMinY", undefined); this.setPrivate("selectionMaxY", undefined); this.setPrivate("minX", undefined); this.setPrivate("minY", undefined); this.setPrivate("maxX", undefined); this.setPrivate("maxY", undefined); } /** * Creates and returns an axis range object. * * @see {@link https://www.amcharts.com/docs/v5/charts/xy-chart/axes/axis-ranges/} for more info * @param axisDataItem Axis data item * @return Axis range */ createAxisRange(axisDataItem) { return this.axisRanges.push({ axisDataItem: axisDataItem }); } /** * A list of series's main (ungrouped) data items. * * @return Data items */ get mainDataItems() { return this._mainDataItems; } } Object.defineProperty(XYSeries, "className", { enumerable: true, configurable: true, writable: true, value: "XYSeries" }); Object.defineProperty(XYSeries, "classNames", { enumerable: true, configurable: true, writable: true, value: Series.classNames.concat([XYSeries.className]) }); //# sourceMappingURL=XYSeries.js.map