UNPKG

@amcharts/amcharts5

Version:
1,537 lines 59.7 kB
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<this["_privateSettings"], number | undefined>
    _min(key, value) {
        let newValue = min(this.getPrivate(key), value);
        this.setPrivate(key, newValue);
    }
    // TODO use  SelectKeys<this["_privateSettings"], number | undefined>
    _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