define(["require", "exports", "tslib", "react", "d3-array", "d3-selection", "d3-scale", "@fluentui/react/lib/Utilities", "@fluentui/react/lib/Callout", "../Legends/index", "../../index", "@fluentui/react-focus", "../../utilities/index", "../../utilities/image-export-utils"], function (require, exports, tslib_1, React, d3_array_1, d3_selection_1, d3_scale_1, Utilities_1, Callout_1, index_1, index_2, react_focus_1, index_3, image_export_utils_1) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.VerticalStackedBarChartBase = void 0;
    var getClassNames = (0, Utilities_1.classNamesFunction)();
    var COMPONENT_NAME = 'VERTICAL STACKED BAR CHART';
    // When displaying gaps between bars, the max height of the gap is given in the
    // props. The actual gap is calculated with this multiplier, with a minimum gap
    // of 1 pixel. (If these values are changed, update the comment for barGapMax.)
    var barGapMultiplier = 0.2;
    var barGapMin = 1;
    var MIN_DOMAIN_MARGIN = 8;
    var CircleVisbility;
    (function (CircleVisbility) {
        CircleVisbility["show"] = "visibility";
        CircleVisbility["hide"] = "hidden";
    })(CircleVisbility || (CircleVisbility = {}));
    var VerticalStackedBarChartBase = /** @class */ (function (_super) {
        tslib_1.__extends(VerticalStackedBarChartBase, _super);
        function VerticalStackedBarChartBase(props) {
            var _a;
            var _this = _super.call(this, props) || this;
            _this._isRtl = (0, Utilities_1.getRTL)();
            _this.toImage = function (opts) {
                var _a, _b;
                return (0, image_export_utils_1.toImage)((_a = _this._cartesianChartRef.current) === null || _a === void 0 ? void 0 : _a.chartContainer, (_b = _this._legendsRef.current) === null || _b === void 0 ? void 0 : _b.toSVG, _this._isRtl, opts);
            };
            /**
             * This function tells us what to focus either the whole stack as focusable item.
             * or each individual item in the stack as focusable item. basically it depends
             * on the prop `isCalloutForStack` if it's false user can focus each individual bar
             * within the bar if it's true then user can focus whole bar as item.
             * but if we have lines in the chart then we force the user to focus only the whole
             * bar, even if isCalloutForStack is false
             */
            _this._toFocusWholeStack = function (_isHavingLines) {
                var _a = _this.props.isCalloutForStack, isCalloutForStack = _a === void 0 ? false : _a;
                var shouldFocusStackOnly = false;
                if (_isHavingLines) {
                    if (_this._getHighlightedLegend().length === 1) {
                        shouldFocusStackOnly = false;
                    }
                    else {
                        shouldFocusStackOnly = true;
                    }
                }
                else {
                    shouldFocusStackOnly = isCalloutForStack;
                }
                return shouldFocusStackOnly;
            };
            _this._getDomainNRangeValues = function (points, margins, width, chartType, isRTL, xAxisType, barWidth, tickValues, shiftX) {
                var domainNRangeValue;
                if (xAxisType === index_3.XAxisTypes.NumericAxis) {
                    domainNRangeValue = (0, index_3.domainRangeOfVSBCNumeric)(points, margins, width, isRTL, barWidth);
                }
                else if (xAxisType === index_3.XAxisTypes.DateAxis) {
                    domainNRangeValue = (0, index_3.domainRangeOfDateForAreaLineVerticalBarChart)(points, margins, width, isRTL, tickValues, chartType, barWidth);
                }
                else {
                    domainNRangeValue = (0, index_3.domainRangeOfXStringAxis)(margins, width, isRTL);
                }
                return domainNRangeValue;
            };
            _this._getFormattedLineData = function (data) {
                var linesData = [];
                var formattedLineData = {};
                data.forEach(function (item, index) {
                    if (item.lineData) {
                        // injecting corresponding x data point in each of the line data
                        // we inject index also , it will be helpful to draw lines when x axis is
                        // of string type
                        item.lineData.forEach(function (line) {
                            linesData.push(tslib_1.__assign(tslib_1.__assign({}, line), { index: index, xItem: item }));
                        });
                    }
                });
                linesData.forEach(function (item) {
                    if (formattedLineData[item.legend]) {
                        formattedLineData[item.legend].push(item);
                    }
                    else {
                        formattedLineData[item.legend] = [item];
                    }
                });
                return formattedLineData;
            };
            _this._getLineLegends = function (data) {
                var lineObject = _this._lineObject;
                var lineLegends = [];
                Object.keys(lineObject).forEach(function (item) {
                    lineLegends.push({
                        title: item,
                        color: lineObject[item][0].color,
                    });
                });
                return lineLegends;
            };
            _this._createLines = function (
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            xScale, yScale, containerHeight, containerWidth, secondaryYScale) {
                var _a;
                var lineObject = _this._getFormattedLineData(_this.props.data);
                var lines = [];
                var borderForLines = [];
                var dots = [];
                var theme = _this.props.theme;
                var lineBorderWidth = ((_a = _this.props.lineOptions) === null || _a === void 0 ? void 0 : _a.lineBorderWidth)
                    ? Number.parseFloat(_this.props.lineOptions.lineBorderWidth.toString())
                    : 0;
                var xScaleBandwidthTranslate = _this._xAxisType !== index_3.XAxisTypes.StringAxis ? 0 : xScale.bandwidth() / 2;
                Object.keys(lineObject).forEach(function (item, index) {
                    var _a, _b, _c, _d, _e;
                    var shouldHighlight = _this._isLegendHighlighted(item) || _this._noLegendHighlighted(); // item is legend name
                    for (var i = 1; i < lineObject[item].length; i++) {
                        var x1 = xScale(lineObject[item][i - 1].xItem.xAxisPoint);
                        var useSecondaryYScale = lineObject[item][i - 1].useSecondaryYScale && lineObject[item][i].useSecondaryYScale && secondaryYScale;
                        var y1 = useSecondaryYScale ? secondaryYScale(lineObject[item][i - 1].y) : yScale(lineObject[item][i - 1].y);
                        var x2 = xScale(lineObject[item][i].xItem.xAxisPoint);
                        var y2 = useSecondaryYScale ? secondaryYScale(lineObject[item][i].y) : yScale(lineObject[item][i].y);
                        if (lineBorderWidth > 0) {
                            borderForLines.push(React.createElement("line", { key: "".concat(index, "-").concat(i, "-BorderLine"), x1: x1, y1: y1, x2: x2, y2: y2, opacity: shouldHighlight ? 1 : 0.1, strokeWidth: 3 + lineBorderWidth * 2, fill: "transparent", strokeLinecap: "round", stroke: theme.semanticColors.bodyBackground, transform: "translate(".concat(xScaleBandwidthTranslate, ", 0)") }));
                        }
                        lines.push(React.createElement("line", tslib_1.__assign({ key: "".concat(index, "-").concat(i, "-line"), x1: x1, y1: y1, x2: x2, y2: y2, opacity: shouldHighlight ? 1 : 0.1, strokeWidth: (_b = (_a = lineObject[item][0].lineOptions) === null || _a === void 0 ? void 0 : _a.strokeWidth) !== null && _b !== void 0 ? _b : 3, strokeLinecap: (_d = (_c = lineObject[item][0].lineOptions) === null || _c === void 0 ? void 0 : _c.strokeLinecap) !== null && _d !== void 0 ? _d : 'round', strokeDasharray: (_e = lineObject[item][0].lineOptions) === null || _e === void 0 ? void 0 : _e.strokeDasharray, stroke: lineObject[item][i].color, transform: "translate(".concat(xScaleBandwidthTranslate, ", 0)") }, (_this._isLegendHighlighted(item) && {
                            onMouseOver: _this._lineHover.bind(_this, lineObject[item][i - 1]),
                            onMouseLeave: _this._lineHoverOut,
                        }))));
                    }
                });
                Object.keys(lineObject).forEach(function (item, index) {
                    lineObject[item].forEach(function (circlePoint, subIndex) {
                        // Create an object to store line point ref so that the object can be passed by reference to the focus handler
                        var circleRef = { refElement: null };
                        dots.push(React.createElement("circle", tslib_1.__assign({ key: "".concat(index, "-").concat(subIndex, "-dot"), cx: xScale(circlePoint.xItem.xAxisPoint), cy: circlePoint.useSecondaryYScale && secondaryYScale ? secondaryYScale(circlePoint.y) : yScale(circlePoint.y), onMouseOver: _this._isLegendHighlighted(item)
                                ? _this._lineHover.bind(_this, circlePoint)
                                : _this._onStackHover.bind(_this, circlePoint.xItem) }, (_this._isLegendHighlighted(item) && {
                            onMouseLeave: _this._lineHoverOut,
                        }), { r: _this._getCircleVisibilityAndRadius(circlePoint.xItem.xAxisPoint, circlePoint.legend).radius, stroke: circlePoint.color, fill: _this.props.theme.semanticColors.bodyBackground, strokeWidth: 3, visibility: _this._getCircleVisibilityAndRadius(circlePoint.xItem.xAxisPoint, circlePoint.legend).visibility, transform: "translate(".concat(xScaleBandwidthTranslate, ", 0)"), "data-is-focusable": _this._isLegendHighlighted(item), ref: function (e) { return (circleRef.refElement = e); }, onFocus: _this._lineFocus.bind(_this, circlePoint, circleRef), onBlur: _this._lineHoverOut })));
                    });
                });
                return (React.createElement(React.Fragment, null,
                    borderForLines,
                    lines,
                    dots));
            };
            _this._getCircleVisibilityAndRadius = function (xAxisPoint, legend) {
                var activeXAxisDataPoint = _this.state.activeXAxisDataPoint;
                if (!_this._noLegendHighlighted()) {
                    if (xAxisPoint === activeXAxisDataPoint && _this._isLegendHighlighted(legend)) {
                        return { visibility: CircleVisbility.show, radius: 8 };
                    }
                    else if (_this._isLegendHighlighted(legend)) {
                        return { visibility: CircleVisbility.show, radius: 0.3 };
                    }
                    else {
                        return { visibility: CircleVisbility.hide, radius: 0 };
                    }
                }
                else {
                    return {
                        visibility: activeXAxisDataPoint === xAxisPoint ? CircleVisbility.show : CircleVisbility.hide,
                        radius: 8,
                    };
                }
            };
            _this._getMargins = function (margins) {
                _this.margins = margins;
            };
            _this._getCustomizedCallout = function () {
                var _isHavingLines = _this.props.data.some(function (item) { return item.lineData && item.lineData.length > 0; });
                return _this.props.onRenderCalloutPerStack
                    ? _this.props.onRenderCalloutPerStack(_this.state.stackCalloutProps)
                    : _this.props.onRenderCalloutPerDataPoint && !_isHavingLines
                        ? _this.props.onRenderCalloutPerDataPoint(_this.state.dataPointCalloutProps, _this._renderCallout)
                        : null;
            };
            _this._lineHover = function (lineData, mouseEvent) {
                mouseEvent.persist();
                _this._lineHoverFocus(lineData, mouseEvent);
            };
            _this._lineHoverOut = function () {
                _this.setState({
                    refSelected: null,
                    isCalloutVisible: false,
                    xCalloutValue: '',
                    yCalloutValue: '',
                    activeXAxisDataPoint: '',
                    color: '',
                });
            };
            _this._lineFocus = function (lineData, ref) {
                if (ref.refElement) {
                    _this._lineHoverFocus(lineData, ref.refElement);
                }
            };
            _this._lineHoverFocus = function (lineData, refSelected) {
                _this.setState({
                    refSelected: refSelected,
                    isCalloutVisible: true,
                    xCalloutValue: "".concat(lineData.xItem.xAxisPoint),
                    yCalloutValue: "".concat(lineData.yAxisCalloutData || lineData.data || lineData.y),
                    activeXAxisDataPoint: lineData.xItem.xAxisPoint,
                    color: lineData.color,
                });
            };
            _this._handleMouseOut = function () {
                /**/
            };
            _this._handleChartMouseLeave = function () {
                _this._calloutAnchorPoint = null;
                _this.setState({
                    isCalloutVisible: false,
                    activeXAxisDataPoint: '',
                });
            };
            _this._createBar = function (
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            xBarScale, yBarScale, containerHeight, xElement) {
                var _a = _this.props, _b = _a.barCornerRadius, barCornerRadius = _b === void 0 ? 0 : _b, _c = _a.barMinimumHeight, barMinimumHeight = _c === void 0 ? 0 : _c;
                var _isHavingLines = _this.props.data.some(function (item) { return item.lineData && item.lineData.length > 0; });
                var shouldFocusWholeStack = _this._toFocusWholeStack(_isHavingLines);
                if (_this._xAxisType === index_3.XAxisTypes.StringAxis) {
                    // Setting the bar width here is safe because there are no dependencies earlier in the code
                    // that rely on the width of bars in vertical bar charts with string x-axis.
                    _this._barWidth = (0, index_3.getBarWidth)(_this.props.barWidth, _this.props.maxBarWidth, xBarScale.bandwidth());
                }
                var bars = _this._points.map(function (singleChartData, indexNumber) {
                    var yPoint = containerHeight - _this.margins.bottom;
                    var xPoint = xBarScale(_this._xAxisType === index_3.XAxisTypes.NumericAxis
                        ? singleChartData.xAxisPoint
                        : _this._xAxisType === index_3.XAxisTypes.DateAxis
                            ? singleChartData.xAxisPoint
                            : singleChartData.xAxisPoint);
                    var xScaleBandwidthTranslate = _this._xAxisType !== index_3.XAxisTypes.StringAxis ? -_this._barWidth / 2 : (xBarScale.bandwidth() - _this._barWidth) / 2;
                    var barTotalValue = 0;
                    // Removing datapoints with zero data
                    var barsToDisplay = singleChartData.chartData.filter(function (point) { return point.data > 0; });
                    if (!barsToDisplay.length) {
                        return undefined;
                    }
                    var _a = _this._getBarGapAndScale(barsToDisplay, yBarScale), gapHeight = _a.gapHeight, heightValueScale = _a.heightValueScale;
                    if (heightValueScale < 0) {
                        return undefined;
                    }
                    var singleBar = barsToDisplay.map(function (point, index) {
                        var _a, _b, _c, _d;
                        var startColor = point.color ? point.color : _this._colors[index];
                        var endColor = startColor;
                        if (_this.props.enableGradient) {
                            startColor = ((_a = point.gradient) === null || _a === void 0 ? void 0 : _a[0]) || (0, index_3.getNextGradient)(index, 0, (_b = _this.props.theme) === null || _b === void 0 ? void 0 : _b.isInverted)[0];
                            endColor = ((_c = point.gradient) === null || _c === void 0 ? void 0 : _c[1]) || (0, index_3.getNextGradient)(index, 0, (_d = _this.props.theme) === null || _d === void 0 ? void 0 : _d.isInverted)[1];
                            singleChartData.chartData[index].color = startColor;
                        }
                        var ref = {};
                        var shouldHighlight = _this._isLegendHighlighted(point.legend) || _this._noLegendHighlighted() ? true : false;
                        _this._classNames = getClassNames(_this.props.styles, {
                            theme: _this.props.theme,
                            shouldHighlight: shouldHighlight,
                            href: _this.props.href,
                        });
                        var rectFocusProps = !shouldFocusWholeStack && {
                            'data-is-focusable': !_this.props.hideTooltip && shouldHighlight,
                            'aria-label': _this._getAriaLabel(singleChartData, point),
                            onMouseOver: _this._onRectHover.bind(_this, singleChartData.xAxisPoint, point, startColor),
                            onMouseMove: _this._onRectHover.bind(_this, singleChartData.xAxisPoint, point, startColor),
                            onMouseLeave: _this._handleMouseOut,
                            onFocus: _this._onRectFocus.bind(_this, point, singleChartData.xAxisPoint, startColor, ref),
                            onBlur: _this._handleMouseOut,
                            onClick: _this._onClick.bind(_this, point),
                            role: 'img',
                        };
                        var barHeight = heightValueScale * point.data;
                        if (barHeight < Math.max(Math.ceil((heightValueScale * _this._yMax) / 100.0), barMinimumHeight)) {
                            barHeight = Math.max(Math.ceil((heightValueScale * _this._yMax) / 100.0), barMinimumHeight);
                        }
                        yPoint = yPoint - barHeight - (index ? gapHeight : 0);
                        barTotalValue += point.data;
                        var gradientId = (0, Utilities_1.getId)('VSBC_Gradient') + "_".concat(indexNumber, "_").concat(index);
                        // If set, apply the corner radius to the top of the final bar
                        if (barCornerRadius && barHeight > barCornerRadius && index === barsToDisplay.length - 1) {
                            return (React.createElement(React.Fragment, { key: index + indexNumber + "".concat(shouldFocusWholeStack) },
                                _this.props.enableGradient && (React.createElement("defs", null,
                                    React.createElement("linearGradient", { id: gradientId, x1: "0%", y1: "100%", x2: "0%", y2: "0%" },
                                        React.createElement("stop", { offset: "0", stopColor: startColor }),
                                        React.createElement("stop", { offset: "100%", stopColor: endColor })))),
                                React.createElement("path", tslib_1.__assign({ className: _this._classNames.opacityChangeOnHover, d: "\n                  M ".concat(xPoint, " ").concat(yPoint + barCornerRadius, "\n                  a ").concat(barCornerRadius, " ").concat(barCornerRadius, " 0 0 1 ").concat(barCornerRadius, " ").concat(-barCornerRadius, "\n                  h ").concat(_this._barWidth - 2 * barCornerRadius, "\n                  a ").concat(barCornerRadius, " ").concat(barCornerRadius, " 0 0 1 ").concat(barCornerRadius, " ").concat(barCornerRadius, "\n                  v ").concat(barHeight - barCornerRadius, "\n                  h ").concat(-_this._barWidth, "\n                  z\n                "), fill: _this.props.enableGradient ? "url(#".concat(gradientId, ")") : startColor, rx: _this.props.roundCorners ? 3 : 0, ref: function (e) { return (ref.refElement = e); }, transform: "translate(".concat(xScaleBandwidthTranslate, ", 0)") }, rectFocusProps))));
                        }
                        if (barHeight < 0) {
                            return React.createElement(React.Fragment, { key: index + indexNumber }, " ");
                        }
                        return (React.createElement(React.Fragment, { key: index + indexNumber },
                            _this.props.enableGradient && (React.createElement("defs", null,
                                React.createElement("linearGradient", { id: gradientId, x1: "0%", y1: "100%", x2: "0%", y2: "0%" },
                                    React.createElement("stop", { offset: "0", stopColor: startColor }),
                                    React.createElement("stop", { offset: "100%", stopColor: endColor })))),
                            React.createElement("rect", tslib_1.__assign({ className: _this._classNames.opacityChangeOnHover, x: xPoint, y: yPoint, width: _this._barWidth, height: barHeight, fill: _this.props.enableGradient ? "url(#".concat(gradientId, ")") : startColor, rx: _this.props.roundCorners ? 3 : 0, ref: function (e) { return (ref.refElement = e); } }, rectFocusProps, { transform: "translate(".concat(xScaleBandwidthTranslate, ", 0)") }))));
                    });
                    var groupRef = {};
                    var stackFocusProps = shouldFocusWholeStack && {
                        'data-is-focusable': !_this.props.hideTooltip,
                        'aria-label': _this._getAriaLabel(singleChartData),
                        onMouseOver: _this._onStackHover.bind(_this, singleChartData),
                        onMouseMove: _this._onStackHover.bind(_this, singleChartData),
                        onMouseLeave: _this._handleMouseOut,
                        onFocus: _this._onStackFocus.bind(_this, singleChartData, groupRef),
                        onBlur: _this._handleMouseOut,
                        onClick: _this._onClick.bind(_this, singleChartData),
                        role: 'img',
                    };
                    var showLabel = false;
                    var barLabel = 0;
                    if (!_this.props.hideLabels) {
                        if (_this._noLegendHighlighted()) {
                            showLabel = true;
                            barLabel = barTotalValue;
                        }
                        else {
                            barsToDisplay.forEach(function (point) {
                                if (_this._isLegendHighlighted(point.legend)) {
                                    showLabel = true;
                                    barLabel += point.data;
                                }
                            });
                        }
                    }
                    return (React.createElement("g", { key: indexNumber + "".concat(shouldFocusWholeStack) },
                        React.createElement("g", tslib_1.__assign({ id: "".concat(indexNumber, "-singleBar"), ref: function (e) { return (groupRef.refElement = e); } }, stackFocusProps), singleBar),
                        !_this.props.hideLabels && _this._barWidth >= 16 && showLabel && (React.createElement("text", { x: xPoint + _this._barWidth / 2, y: yPoint - 6, textAnchor: "middle", className: _this._classNames.barLabel, "aria-label": "Total: ".concat(barLabel), role: "img", transform: "translate(".concat(xScaleBandwidthTranslate, ", 0)") }, (0, index_3.formatValueWithSIPrefix)(barLabel)))));
                });
                // Removing un wanted tooltip div from DOM, when prop not provided.
                if (!_this.props.showXAxisLablesTooltip) {
                    try {
                        document.getElementById(_this._tooltipId) && document.getElementById(_this._tooltipId).remove();
                        // eslint-disable-next-line no-empty
                    }
                    catch (e) { }
                }
                // Used to display tooltip at x axis labels.
                if (!_this.props.wrapXAxisLables && _this.props.showXAxisLablesTooltip) {
                    var xAxisElement = (0, d3_selection_1.select)(xElement).call(xBarScale);
                    try {
                        document.getElementById(_this._tooltipId) && document.getElementById(_this._tooltipId).remove();
                        // eslint-disable-next-line no-empty
                    }
                    catch (e) { }
                    var tooltipProps = {
                        tooltipCls: _this._classNames.tooltip,
                        id: _this._tooltipId,
                        xAxis: xAxisElement,
                    };
                    xAxisElement && (0, index_3.tooltipOfXAxislabels)(tooltipProps);
                }
                return bars.filter(function (bar) { return !!bar; });
            };
            _this._getScales = function (containerHeight, containerWidth) {
                var yMax = _this._yMax;
                var yBarScale = (0, d3_scale_1.scaleLinear)()
                    .domain([0, yMax])
                    .range([0, containerHeight - _this.margins.bottom - _this.margins.top]);
                if (_this._xAxisType === index_3.XAxisTypes.NumericAxis) {
                    var xMax = (0, d3_array_1.max)(_this._dataset, function (point) { return point.x; });
                    var xMin = (0, d3_array_1.min)(_this._dataset, function (point) { return point.x; });
                    var xBarScale_1 = (0, d3_scale_1.scaleLinear)()
                        .domain(_this._isRtl ? [xMax, xMin] : [xMin, xMax])
                        .nice()
                        .range([_this.margins.left + _this._domainMargin, containerWidth - _this.margins.right - _this._domainMargin]);
                    return { xBarScale: xBarScale_1, yBarScale: yBarScale };
                }
                if (_this._xAxisType === index_3.XAxisTypes.DateAxis) {
                    var sDate = (0, d3_array_1.min)(_this._dataset, function (point) {
                        return point.x;
                    });
                    var lDate = (0, d3_array_1.max)(_this._dataset, function (point) {
                        return point.x;
                    });
                    var xBarScale_2 = _this.props.useUTC ? (0, d3_scale_1.scaleUtc)() : (0, d3_scale_1.scaleTime)();
                    xBarScale_2
                        .domain(_this._isRtl ? [lDate, sDate] : [sDate, lDate])
                        .range([_this.margins.left + _this._domainMargin, containerWidth - _this.margins.right - _this._domainMargin]);
                    return { xBarScale: xBarScale_2, yBarScale: yBarScale };
                }
                var xBarScale = (0, d3_scale_1.scaleBand)()
                    .domain(_this._xAxisLabels)
                    .range(_this._isRtl
                    ? [containerWidth - _this.margins.right - _this._domainMargin, _this.margins.left + _this._domainMargin]
                    : [_this.margins.left + _this._domainMargin, containerWidth - _this.margins.right - _this._domainMargin])
                    .paddingInner(_this._xAxisInnerPadding)
                    .paddingOuter(_this._xAxisOuterPadding);
                return { xBarScale: xBarScale, yBarScale: yBarScale };
            };
            _this._getGraphData = function (
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            xScale, yScale, containerHeight, containerWidth, xElement) {
                var _a = _this._getScales(containerHeight, containerWidth), xBarScale = _a.xBarScale, yBarScale = _a.yBarScale;
                return (_this._bars = _this._createBar(xBarScale, yBarScale, containerHeight, xElement));
            };
            _this._closeCallout = function () {
                _this.setState({
                    isCalloutVisible: false,
                });
            };
            _this._getAxisData = function (yAxisData) {
                if (yAxisData && yAxisData.yAxisDomainValues.length) {
                    var domainValue = yAxisData.yAxisDomainValues;
                    _this._yMax = Math.max(domainValue[domainValue.length - 1], _this.props.yMaxValue || 0);
                }
            };
            /**
             * This function checks if the given legend is highlighted or not.
             * A legend can be highlighted in 2 ways:
             * 1. selection: if the user clicks on it
             * 2. hovering: if there is no selected legend and the user hovers over it
             */
            _this._isLegendHighlighted = function (legendTitle) {
                return _this._getHighlightedLegend().includes(legendTitle);
            };
            /**
             * This function checks if none of the legends is selected or hovered.
             */
            _this._noLegendHighlighted = function () {
                return _this._getHighlightedLegend().length === 0;
            };
            _this._getAriaLabel = function (singleChartData, point) {
                var _a, _b, _c;
                if (!point) {
                    /** if shouldFocusWholeStack is true */
                    var xValue_1 = singleChartData.xAxisCalloutData ||
                        (singleChartData.xAxisPoint instanceof Date
                            ? (0, index_3.formatDate)(singleChartData.xAxisPoint)
                            : singleChartData.xAxisPoint);
                    var pointValues = singleChartData.chartData
                        .map(function (pt) {
                        var legend = pt.legend;
                        var yValue = pt.yAxisCalloutData || pt.data;
                        return "".concat(legend, ", ").concat(yValue, ".");
                    })
                        .join(' ');
                    var lineValues = (_a = singleChartData.lineData) === null || _a === void 0 ? void 0 : _a.map(function (ln) {
                        var legend = ln.legend;
                        var yValue = ln.yAxisCalloutData || ln.data || ln.y;
                        return "".concat(legend, ", ").concat(yValue, ".");
                    }).join(' ');
                    return (((_b = singleChartData.stackCallOutAccessibilityData) === null || _b === void 0 ? void 0 : _b.ariaLabel) ||
                        "".concat(xValue_1, ". ").concat(pointValues) + (lineValues ? " ".concat(lineValues) : ''));
                }
                /** if shouldFocusWholeStack is false */
                var xValue = singleChartData.xAxisCalloutData ||
                    point.xAxisCalloutData ||
                    (singleChartData.xAxisPoint instanceof Date
                        ? (0, index_3.formatDate)(singleChartData.xAxisPoint)
                        : singleChartData.xAxisPoint);
                var legend = point.legend;
                var yValue = point.yAxisCalloutData || point.data;
                return ((_c = point.callOutAccessibilityData) === null || _c === void 0 ? void 0 : _c.ariaLabel) || "".concat(xValue, ". ").concat(legend, ", ").concat(yValue, ".");
            };
            _this._getDomainMargins = function (containerWidth) {
                var _a;
                _this._domainMargin = MIN_DOMAIN_MARGIN;
                /** Total width available to render the bars */
                var totalWidth = containerWidth - (_this.margins.left + MIN_DOMAIN_MARGIN) - (_this.margins.right + MIN_DOMAIN_MARGIN);
                /** Rate at which the space between the bars changes wrt the bar width */
                var barGapRate = _this._xAxisInnerPadding / (1 - _this._xAxisInnerPadding);
                if (_this._xAxisType === index_3.XAxisTypes.StringAxis) {
                    if ((0, index_3.isScalePaddingDefined)(_this.props.xAxisOuterPadding, _this.props.xAxisPadding)) {
                        // Setting the domain margin for string x-axis to 0 because the xAxisOuterPadding prop is now available
                        // to adjust the space before the first bar and after the last bar.
                        _this._domainMargin = 0;
                    }
                    else if (_this.props.barWidth !== 'auto') {
                        // Update the bar width so that when CartesianChart rerenders,
                        // the following calculations don't use the previous bar width.
                        _this._barWidth = (0, index_3.getBarWidth)(_this.props.barWidth, _this.props.maxBarWidth);
                        /** Total width required to render the bars. Directly proportional to bar width */
                        var reqWidth = (_this._xAxisLabels.length + (_this._xAxisLabels.length - 1) * barGapRate) * _this._barWidth;
                        if (totalWidth >= reqWidth) {
                            // Center align the chart by setting equal left and right margins for domain
                            _this._domainMargin = MIN_DOMAIN_MARGIN + (totalWidth - reqWidth) / 2;
                        }
                    }
                    else if (_this.props.mode === 'plotly' && _this._xAxisLabels.length > 1) {
                        // Calculate the remaining width after rendering bars at their maximum allowable width
                        var bandwidth = totalWidth / (_this._xAxisLabels.length + (_this._xAxisLabels.length - 1) * barGapRate);
                        var barWidth = (0, index_3.getBarWidth)(_this.props.barWidth, _this.props.maxBarWidth, bandwidth);
                        var reqWidth = (_this._xAxisLabels.length + (_this._xAxisLabels.length - 1) * barGapRate) * barWidth;
                        var margin1 = (totalWidth - reqWidth) / 2;
                        // Calculate the remaining width after accounting for the space required to render x-axis labels
                        var step = (0, index_3.calculateLongestLabelWidth)(_this._xAxisLabels) + 20;
                        reqWidth = (_this._xAxisLabels.length - _this._xAxisInnerPadding) * step;
                        var margin2 = (totalWidth - reqWidth) / 2;
                        _this._domainMargin = MIN_DOMAIN_MARGIN + Math.max(0, Math.min(margin1, margin2));
                    }
                }
                else {
                    var data = ((_a = _this.props.data) === null || _a === void 0 ? void 0 : _a.map(function (point) { return point.xAxisPoint; })) || [];
                    _this._barWidth = (0, index_3.getBarWidth)(_this.props.barWidth, _this.props.maxBarWidth, (0, index_3.calculateAppropriateBarWidth)(data, totalWidth));
                    _this._domainMargin = MIN_DOMAIN_MARGIN + _this._barWidth / 2;
                }
                return tslib_1.__assign(tslib_1.__assign({}, _this.margins), { left: _this.margins.left + _this._domainMargin, right: _this.margins.right + _this._domainMargin });
            };
            _this._getChartTitle = function () {
                var _a = _this.props, chartTitle = _a.chartTitle, data = _a.data;
                var numLines = Object.keys(_this._lineObject).length;
                return ((chartTitle ? "".concat(chartTitle, ". ") : '') +
                    "Vertical bar chart with ".concat((data === null || data === void 0 ? void 0 : data.length) || 0, " stacked bars") +
                    (numLines > 0 ? " and ".concat(numLines, " lines") : '') +
                    '. ');
            };
            (0, Utilities_1.initializeComponentRef)(_this);
            _this.state = {
                isCalloutVisible: false,
                selectedLegends: ((_a = props.legendProps) === null || _a === void 0 ? void 0 : _a.selectedLegends) || [],
                activeLegend: undefined,
                refSelected: null,
                dataForHoverCard: 0,
                color: '',
                hoverXValue: '',
                YValueHover: [],
                xCalloutValue: '',
                yCalloutValue: '',
                activeXAxisDataPoint: '',
                calloutLegend: '',
            };
            (0, Utilities_1.warnDeprecations)(COMPONENT_NAME, props, {
                colors: 'IVSChartDataPoint.color',
                chartLabel: 'use your own title for chart',
            });
            _this._handleMouseOut = _this._handleMouseOut.bind(_this);
            _this._calloutId = (0, Utilities_1.getId)('callout');
            _this._tooltipId = (0, Utilities_1.getId)('VSBCTooltipId_');
            if (!_this._isChartEmpty()) {
                _this._adjustProps();
                _this._dataset = _this._createDataSetLayer();
            }
            _this._createLegendsForLine = (0, Utilities_1.memoizeFunction)(function (data) { return _this._getLineLegends(data); });
            _this._emptyChartId = (0, Utilities_1.getId)('_VSBC_empty');
            _this._domainMargin = MIN_DOMAIN_MARGIN;
            _this._cartesianChartRef = React.createRef();
            _this._legendsRef = React.createRef();
            return _this;
        }
        VerticalStackedBarChartBase.prototype.componentDidUpdate = function (prevProps) {
            var _a, _b, _c;
            if (!(0, index_3.areArraysEqual)((_a = prevProps.legendProps) === null || _a === void 0 ? void 0 : _a.selectedLegends, (_b = this.props.legendProps) === null || _b === void 0 ? void 0 : _b.selectedLegends)) {
                this.setState({
                    selectedLegends: ((_c = this.props.legendProps) === null || _c === void 0 ? void 0 : _c.selectedLegends) || [],
                });
            }
            if (prevProps.height !== this.props.height ||
                prevProps.width !== this.props.width ||
                prevProps.data !== this.props.data) {
                this._adjustProps();
                this._dataset = this._createDataSetLayer();
            }
        };
        VerticalStackedBarChartBase.prototype.render = function () {
            var _this = this;
            if (!this._isChartEmpty()) {
                this._adjustProps();
                var _isHavingLines_1 = this.props.data.some(function (item) { return item.lineData && item.lineData.length > 0; });
                var shouldFocusWholeStack = this._toFocusWholeStack(_isHavingLines_1);
                var _a = this.props.isCalloutForStack, isCalloutForStack = _a === void 0 ? false : _a;
                this._dataset = this._createDataSetLayer();
                var legendBars = this._getLegendData(this._points, this.props.theme.palette, this._createLegendsForLine(this.props.data));
                this._classNames = getClassNames(this.props.styles, {
                    theme: this.props.theme,
                    href: this.props.href,
                });
                var calloutProps = tslib_1.__assign(tslib_1.__assign({ isCalloutVisible: this.state.isCalloutVisible, directionalHint: Callout_1.DirectionalHint.topAutoEdge, id: "toolTip".concat(this._calloutId), target: this.state.refSelected, isBeakVisible: false, gapSpace: 15, color: this.state.color, legend: this.state.calloutLegend, XValue: this.state.xCalloutValue, YValue: this.state.yCalloutValue ? this.state.yCalloutValue : this.state.dataForHoverCard, YValueHover: this.state.YValueHover, hoverXValue: this.state.hoverXValue, onDismiss: this._closeCallout, preventDismissOnLostFocus: true }, this.props.calloutProps), (0, index_3.getAccessibleDataObject)(this.state.callOutAccessibilityData));
                var tickParams = {
                    tickValues: this.props.tickValues,
                    tickFormat: this.props.tickFormat,
                };
                return (React.createElement(index_2.CartesianChart, tslib_1.__assign({}, this.props, { chartTitle: this._getChartTitle(), points: this._dataset, chartType: index_3.ChartTypes.VerticalStackedBarChart, xAxisType: this._xAxisType, calloutProps: calloutProps, createYAxis: index_3.createNumericYAxis, tickParams: tickParams, legendBars: legendBars, getMinMaxOfYAxis: index_3.findVSBCNumericMinMaxOfY, datasetForXAxisDomain: this._xAxisLabels, isCalloutForStack: shouldFocusWholeStack, getDomainNRangeValues: this._getDomainNRangeValues, createStringYAxis: index_3.createStringYAxis, barwidth: this._barWidth, focusZoneDirection: isCalloutForStack || _isHavingLines_1 ? react_focus_1.FocusZoneDirection.horizontal : react_focus_1.FocusZoneDirection.vertical, getmargins: this._getMargins, getGraphData: this._getGraphData, getAxisData: this._getAxisData, customizedCallout: this._getCustomizedCallout(), onChartMouseLeave: this._handleChartMouseLeave, getDomainMargins: this._getDomainMargins }, (this._xAxisType === index_3.XAxisTypes.StringAxis && {
                    xAxisInnerPadding: this._xAxisInnerPadding,
                    xAxisOuterPadding: this._xAxisOuterPadding,
                }), { ref: this._cartesianChartRef, 
                    /* eslint-disable react/jsx-no-bind */
                    children: function (props) {
                        return (React.createElement(React.Fragment, null,
                            React.createElement("g", null, _this._bars),
                            React.createElement("g", null, _isHavingLines_1 &&
                                _this._createLines(props.xScale, props.yScale, props.containerHeight, props.containerWidth, props.yScaleSecondary))));
                    } })));
            }
            return (React.createElement("div", { id: this._emptyChartId, role: 'alert', style: { opacity: '0' }, "aria-label": 'Graph has no data to display' }));
        };
        Object.defineProperty(VerticalStackedBarChartBase.prototype, "chartContainer", {
            get: function () {
                var _a;
                return ((_a = this._cartesianChartRef.current) === null || _a === void 0 ? void 0 : _a.chartContainer) || null;
            },
            enumerable: false,
            configurable: true
        });
        VerticalStackedBarChartBase.prototype._adjustProps = function () {
            this._points = this.props.data || [];
            this._barWidth = (0, index_3.getBarWidth)(this.props.barWidth, this.props.maxBarWidth);
            var theme = this.props.theme;
            var palette = theme.palette;
            // eslint-disable-next-line @typescript-eslint/no-deprecated
            this._colors = this.props.colors || [palette.blueLight, palette.blue, palette.blueMid, palette.red, palette.black];
            this._xAxisType = (0, index_3.getTypeOfAxis)(this.props.data[0].xAxisPoint, true);
            this._lineObject = this._getFormattedLineData(this.props.data);
            this._xAxisInnerPadding = (0, index_3.getScalePadding)(this.props.xAxisInnerPadding, this.props.xAxisPadding, 2 / 3);
            this._xAxisOuterPadding = (0, index_3.getScalePadding)(this.props.xAxisOuterPadding, this.props.xAxisPadding, 0);
        };
        VerticalStackedBarChartBase.prototype._createDataSetLayer = function () {
            var tempArr = [];
            var dataset = this._points.map(function (singlePointData) {
                var total = 0;
                singlePointData.chartData.forEach(function (point) {
                    total = total + point.data;
                });
                tempArr.push(singlePointData.xAxisPoint);
                return {
                    x: singlePointData.xAxisPoint,
                    y: total,
                };
            });
            this._xAxisLabels = tempArr;
            return dataset;
        };
        VerticalStackedBarChartBase.prototype._renderCallout = function (props) {
            return props ? (React.createElement(index_2.ChartHoverCard, { XValue: props.xAxisCalloutData, Legend: props.legend, YValue: props.yAxisCalloutData, color: props.color, culture: this.props.culture })) : null;
        };
        VerticalStackedBarChartBase.prototype._onLegendHover = function (legendTitle) {
            this.setState({
                activeLegend: legendTitle,
            });
        };
        VerticalStackedBarChartBase.prototype._onLegendLeave = function () {
            this.setState({
                activeLegend: undefined,
            });
        };
        VerticalStackedBarChartBase.prototype._getLegendData = function (data, palette, lineLegends) {
            var _this = this;
            if (this.props.hideLegend) {
                return React.createElement(React.Fragment, null);
            }
            var defaultPalette = [palette.blueLight, palette.blue, palette.blueMid, palette.red, palette.black];
            var actions = [];
            var _a = this.props, _b = _a.allowHoverOnLegend, allowHoverOnLegend = _b === void 0 ? true : _b, theme = _a.theme;
            data.forEach(function (singleChartData) {
                singleChartData.chartData.forEach(function (point) {
                    var _a, _b;
                    var color = point.color ? point.color : defaultPalette[Math.floor(Math.random() * 4 + 1)];
                    if (_this.props.enableGradient) {
                        var pointIndex = Math.max(((_a = singleChartData.chartData) === null || _a === void 0 ? void 0 : _a.findIndex(function (item) { return item.legend === point.legend; })) || 0, 0);
                        color = ((_b = point.gradient) === null || _b === void 0 ? void 0 : _b[0]) || (0, index_3.getNextGradient)(pointIndex, 0, theme === null || theme === void 0 ? void 0 : theme.isInverted)[0];
                    }
                    var checkSimilarLegends = actions.filter(function (leg) { return leg.title === point.legend && leg.color === color; });
                    if (checkSimilarLegends.length > 0) {
                        return;
                    }
                    var legend = {
                        title: point.legend,
                        color: color,
                        hoverAction: allowHoverOnLegend
                            ? function () {
                                _this._handleChartMouseLeave();
                                _this._onLegendHover(point.legend);
                            }
                            : undefined,
                        onMouseOutAction: allowHoverOnLegend ? function () { return _this._onLegendLeave(); } : undefined,
                    };
                    actions.push(legend);
                });
            });
            var legendsOfLine = [];
            if (lineLegends && lineLegends.length > 0) {
                lineLegends.forEach(function (point) {
                    var legend = {
                        title: point.title,
                        color: point.color,
                        isLineLegendInBarChart: true,
                        hoverAction: allowHoverOnLegend
                            ? function () {
                                _this._handleChartMouseLeave();
                                _this._onLegendHover(point.title);
                            }
                            : undefined,
                        onMouseOutAction: allowHoverOnLegend ? function () { return _this._onLegendLeave(); } : undefined,
                    };
                    legendsOfLine.push(legend);
                });
            }
            var totalLegends = legendsOfLine.concat(actions);
            return (React.createElement(index_1.Legends, tslib_1.__assign({ legends: totalLegends, overflowProps: this.props.legendsOverflowProps, enabledWrapLines: this.props.enabledLegendsWrapLines, focusZonePropsInHoverCard: this.props.focusZonePropsForLegendsInHoverCard, overflowText: this.props.legendsOverflowText }, this.props.legendProps, { onChange: this._onLegendSelectionChange.bind(this), ref: this._legendsRef })));
        };
        VerticalStackedBarChartBase.prototype._onLegendSelectionChange = function (selectedLegends, event, currentLegend) {
            var _a, _b;
            if ((_a = this.props.legendProps) === null || _a === void 0 ? void 0 : _a.canSelectMultipleLegends) {
                this.setState({ selectedLegends: selectedLegends });
            }
            else {
                this.setState({ selectedLegends: selectedLegends.slice(-1) });
            }
            if ((_b = this.props.legendProps) === null || _b === void 0 ? void 0 : _b.onChange) {
                this.props.legendProps.onChange(selectedLegends, event, currentLegend);
            }
        };
        VerticalStackedBarChartBase.prototype._getHighlightedLegend = function () {
            return this.state.selectedLegends.length > 0
                ? this.state.selectedLegends
                : this.state.activeLegend
                    ? [this.state.activeLegend]
                    : [];
        };
        VerticalStackedBarChartBase.prototype._onRectHover = function (xAxisPoint, point, color, mouseEvent) {
            mouseEvent.persist();
            this._onRectFocusHover(xAxisPoint, point, color, mouseEvent);
        };
        VerticalStackedBarChartBase.prototype._onRectFocusHover = function (xAxisPoint, point, color, refSelected) {
            var _a, _b;
            if (((_a = this._calloutAnchorPoint) === null || _a === void 0 ? void 0 : _a.chartDataPoint) !== point || ((_b = this._calloutAnchorPoint) === null || _b === void 0 ? void 0 : _b.xAxisDataPoint) !== xAxisPoint) {
                this._calloutAnchorPoint = {
                    chartDataPoint: point,
                    xAxisDataPoint: xAxisPoint,
                };
                this.setState({
                    refSelected: refSelected,
                    /**
                     * Show the callout if highlighted bar is focused/hovered
                     * and Hide it if unhighlighted bar is focused/hovered
                     */
                    isCalloutVisible: this._noLegendHighlighted() || this._isLegendHighlighted(point.legend),
                    calloutLegend: point.legend,
                    dataForHoverCard: point.data,
                    color: color,
                    xCalloutValue: point.xAxisCalloutData ? point.xAxisCalloutData : xAxisPoint,
                    yCalloutValue: point.yAxisCalloutData,
                    dataPointCalloutProps: point,
                    callOutAccessibilityData: point.callOutAccessibilityData,
                });
            }
        };
        VerticalStackedBarChartBase.prototype._onStackHover = function (stack, mouseEvent) {
            mouseEvent.persist();
            this._onStackHoverFocus(stack, mouseEvent);
        };
        VerticalStackedBarChartBase.prototype._onStackHoverFocus = function (stack, refSelected) {
            var _this = this;
            var _a, _b, _c;
            if (!this._noLegendHighlighted()) {
                stack = tslib_1.__assign(tslib_1.__assign({}, stack), { chartData: stack.chartData.filter(function (dataPoint) { return _this._isLegendHighlighted(dataPoint.legend); }), lineData: (_a = stack.lineData) === null || _a === void 0 ? void 0 : _a.filter(function (dataPoint) { return _this._isLegendHighlighted(dataPoint.legend); }) });
            }
            var lineData = stack.lineData;
            var isLinesPresent = lineData !== undefined && lineData.length > 0;
            if (isLinesPresent) {
                lineData.forEach(function (item) {
                    item.data = item.data || item.y;
                    item.shouldDrawBorderBottom = true;
                });
            }
            this.setState({
                refSelected: refSelected,
                isCalloutVisible: stack.chartData.length > 0 || ((_c = (_b = stack.lineData) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0) > 0,
                YValueHover: isLinesPresent
                    ? tslib_1.__spreadArray(tslib_1.__spreadArray([], lineData.sort(function (a, b) { return (a.data < b.data ? 1 : -1); }), true), stack.chartData.slice().reverse(), true) : stack.chartData.slice().reverse(),
                hoverXValue: stack.xAxisPoint instanceof Date ? (0, index_3.formatDate)(stack.xAxisPoint, this.props.useUTC) : stack.xAxisPoint,
                stackCalloutProps: stack,
                activeXAxisDataPoint: stack.xAxisPoint,
                callOutAccessibilityData: stack.stackCallOutAccessibilityData,
            });
        };
        VerticalStackedBarChartBase.prototype._onRectFocus = function (point, xAxisPoint, color, ref) {
            if (ref.refElement) {
                this._onRectFocusHover(xAxisPoint, point, color, ref.refElement);
            }
        };
        VerticalStackedBarChartBase.prototype._onStackFocus = function (stack, groupRef) {
            if (groupRef.refElement) {
                this._onStackHoverFocus(stack, groupRef.refElement);
            }
        };
        VerticalStackedBarChartBase.prototype._onClick = function (data, mouseEvent) {
            var _a, _b;
            (_b = (_a = this.props).onBarClick) === null || _b === void 0 ? void 0 : _b.call(_a, mouseEvent, data);
            this.props.href ? (window.location.href = this.props.href) : '';
        };
        VerticalStackedBarChartBase.prototype._getBarGapAndScale = function (bars, yBarScale, defaultTotalHeight) {
            var _a = this.props.barGapMax, barGapMax = _a === void 0 ? 0 : _a;
            // When displaying gaps between the bars, the height of each bar is
            // adjusted so that the total of all bars is not changed by the gaps
            var totalData = bars.reduce(function (iter, value) { return iter + value.data; }, 0);
            var totalHeight = defaultTotalHeight !== null && defaultTotalHeight !== void 0 ? defaultTotalHeight : yBarScale(totalData);
            var gaps = barGapMax && bars.length - 1;
            var gapHeight = gaps && Math.max(barGapMin, Math.min(barGapMax, (totalHeight * barGapMultiplier) / gaps));
            var heightValueScale = (totalHeight - gapHeight * gaps) / totalData;
            return {
                gapHeight: gapHeight,
                heightValueScale: heightValueScale,
            };
        };
        VerticalStackedBarChartBase.prototype._isChartEmpty = function () {
            return !(this.props.data &&
                this.props.data.length > 0 &&
                this.props.data.some(function (item) { return item.chartData.length > 0 || (item.lineData && item.lineData.length > 0); }));
        };
        VerticalStackedBarChartBase.defaultProps = {
            maxBarWidth: 24,
            useUTC: true,
        };
        return VerticalStackedBarChartBase;
    }(React.Component));
    exports.VerticalStackedBarChartBase = VerticalStackedBarChartBase;
});
//# sourceMappingURL=VerticalStackedBarChart.base.js.map