/* eslint-disable @typescript-eslint/no-explicit-any */
import { h, Host } from "@stencil/core";
import * as d3 from "d3";
import { _t } from "../../../text";
import { randomIdGenerator } from "../../../global/utils/randomIdGenerator";
import { BarChartVariation } from "./bar-chart-variation.enum";
/**
 *
 * @enums Orientation - BarChartVariation.enum.ts
 * @noTokens - Komponentens färger sätts direkt som i graferna. Behöver skrivas om för att kunna hantera olika brands och teman.
 * @swedishName Stapeldiagram
 */
export class barChart {
    constructor() {
        // States
        this.loading = false;
        this.placeholderTicks = ['0', '1', '2', '3', '4', '5', '6', '7'];
        // Width of data at each tick, if we have two data series that have values att same tick, this will be 2 for example. defaults to 1;
        this.dataWidth = 1;
        // Bar gap when using multiple bars for each point, this will be doubled, since it is applied on both bars
        this.barGap = 0;
        this.dims = {};
        this.margin = {
            bottom: 0,
            top: 6,
            left: 5,
            right: 15,
            ellipsis: false
        };
        this.tickPadding = 8;
        this.yTickSize = 0;
        this.xTickSize = 5;
        // Width of the largets X-tick-value
        this.tickWidth = 1;
        // Transition
        this.defaultDuration = 400;
        // Text and formats
        this.fontSize = '0.875rem';
        this.colorPalettes = ['--digi--color--background--brand-primary', '--digi--color--infographic--brand--primary', '--digi--color--background--sentiment--beta--primary', '--digi--color--text--interactive--visited', '--digi--color--icon--validation--error'];
        // Observer for watching size changes when in line chart mode
        this.barChartObserver = new ResizeObserver((entries) => {
            entries.forEach(() => {
                if (this.loading)
                    return this.loadingResize();
                this.resize();
            });
        });
        this.highlightBars = (serie) => {
            this.barChartContainer.selectAll('.bar')
                .attr('fill', (barData) => this.colorFunction(barData.serie))
                .transition('color')
                .duration(150)
                .attr('fill', (barData) => {
                var _a;
                if (barData.serie === serie)
                    return this.colorFunction(barData.serie);
                else {
                    if (((_a = this.chartData.meta) === null || _a === void 0 ? void 0 : _a.prognosisPattern) && this.series.indexOf(barData.serie) > 0) {
                        return 'url(#prognosisInactive)';
                    }
                    return this.evalColorVar('--digi--color--background--secondary-accent');
                }
            });
            d3.select(this.legendDiv).selectAll('.legendChip').transition('colorLegend').duration(150).style('opacity', (title) => title === serie ? 1 : 0.25);
        };
        this.resetBarColor = () => {
            this.barChartContainer.selectAll('.bar').transition('color').duration(150).attr('fill', (barData) => this.colorFunction(barData.serie));
            d3.select(this.legendDiv).selectAll('.legendChip').transition('colorLegend').duration(150).style('opacity', 1);
            if (this.chartData.data.averageLine) {
                this.barChartContainer.selectAll('.averageLine').transition('avgLine').style('mix-blend-mode', 'plus-lighter')
                    .style('filter', 'contrast(0.5)');
                /*       this.barChartContainer.selectAll('.averageLineText').transition('avgLine').style('mix-blend-mode', 'plus-lighter')
                        .style('filter', 'contrast(0.5)'); */
            }
        };
        this.highlightAverageLine = (serie) => {
            this.barChartContainer.selectAll('.bar')
                .transition('color')
                .duration(150)
                .attr('fill', (barData) => {
                var _a;
                if (((_a = this.chartData.meta) === null || _a === void 0 ? void 0 : _a.prognosisPattern) && this.series.indexOf(barData.serie) > 0) {
                    return 'url(#prognosisInactive)';
                }
                else
                    return this.evalColorVar('--digi--color--background--secondary-accent');
            });
            this.barChartContainer.selectAll('.averageLine').transition('avgLine')
                .duration(150).style('mix-blend-mode', null).style('filter', null);
            /*     this.barChartContainer.selectAll('.averageLineText').transition('avgLineText')
                  .duration(150).style('mix-blend-mode', null).style('filter', null) */
            d3.select(this.legendDiv).selectAll('.legendChip').transition('colorLegend').duration(150).style('opacity', (title) => title === serie ? 1 : 0.25);
        };
        // Sets and resizespositions the average line
        this.averageLine = () => {
            if (!this.chartData.data.averageLine)
                return;
            const avLineGroup = this.barChartContainer.select('.interactiveElements').selectAll('.averageLineGroup').data([this.chartData.data.averageLine]).join('g').attr('class', 'averageLineGroup');
            /*     avLineGroup.selectAll('.averageLineText')
                  .data(d => [d])
                  .join('text')
                  .attr('class', 'averageLineText')
                  .text(d => d.text)
                  .attr('x', this.xScale.range()[0])
                  .attr('y', (d) => this.yScale(d.value))
                  .attr('dy', -2)
                  .attr('font-size', this.fontSize)
                  .attr('fill', 'var(--digi--color--infographic--lineart)')
                  .style('mix-blend-mode', 'plus-lighter')
                  .style('filter', 'contrast(0.5)'); */
            avLineGroup.selectAll('.averageLine')
                .data(d => [d.value])
                .join('line')
                .attr('class', 'averageLine')
                .attr('x1', this.xScale.range()[0])
                .attr('y1', (d) => this.yScale(d))
                .attr('x2', this.xScale.range()[1])
                .attr('y2', (d) => this.yScale(d))
                .attr('stroke', 'var(--digi--color--infographic--lineart)')
                .attr('stroke-width', 2)
                .attr('stroke-dasharray', '12, 7')
                .attr('stroke-linecap', 'round')
                .style('mix-blend-mode', 'plus-lighter')
                .style('filter', 'contrast(0.5)')
                .style('pointer-events', 'none');
        };
        // Resizing chart while loading
        this.loadingResize = () => {
            const newHeight = this.setDims();
            this.barChartContainer.attr('transform', `translate(${this.margin.left + this.tickPadding + this.yTickSize},0)`);
            this.margin.right =
                this.getTextSize(this.xScale.domain()[1].toLocaleString()) / 2 +
                    this.yTickSize +
                    this.tickPadding;
            // If there is a new height
            if (newHeight) {
                // Update y-axis with potentially new height (might want to do a check here)
                this.afVariation === BarChartVariation.Horizontal
                    ? this.yScale.range([
                        this.margin.top,
                        this.dims.height - this.margin.bottom
                    ])
                    : this.yScale.range([
                        this.dims.height - this.margin.bottom,
                        this.margin.top
                    ]);
                this.xAxisHandle.attr('transform', `translate(0,${this.dims.height - this.margin.bottom})`);
            }
            // Update x-axis with new width
            this.xScale.range([
                0,
                this.dims.width - this.margin.right - this.margin.left
            ]);
            this.setValueTicks();
            this.adjustBarSize();
        };
        this.highlightBarGroup = (_event, datum) => {
            if (typeof datum === 'string') {
                const barGroupID = '#' + this.barGroupID(datum);
                this.barChartContainer.select(barGroupID).selectAll('.bar').transition('color')
                    .duration(20)
                    .attr('fill', (d) => {
                    var _a;
                    if (((_a = this.chartData.meta) === null || _a === void 0 ? void 0 : _a.prognosisPattern) && this.series.indexOf(d.serie) > 0) {
                        return 'url(#prognosisHighlight)';
                    }
                    else
                        return this.adjustColor(this.colorFunction(d.serie), 50);
                });
            }
        };
        this.unHighlightBarGroup = () => {
            this.barSelection.selectAll('.bar').transition('color')
                .duration(100)
                .attr('fill', (d) => {
                return this.colorFunction(d.serie);
            });
        };
        // Adding click listener for tool tip text
        this.setTickInteraction = () => {
            if (this.afVariation === BarChartVariation.Horizontal) {
                this.yAxisHandle
                    .selectAll('text')
                    .style('cursor', 'pointer')
                    .on('click', this.openTooltip)
                    .on('mouseenter', this.highlightBarGroup)
                    .on('mouseleave', this.unHighlightBarGroup);
            }
            else {
                this.xAxisHandle
                    .selectAll('text')
                    .style('cursor', 'pointer')
                    .on('click', this.openTooltip)
                    .on('mouseenter', this.highlightBarGroup)
                    .on('mouseleave', this.unHighlightBarGroup);
            }
        };
        // Setting Y-scale
        this.setYScale = (empty) => {
            var _a, _b, _c;
            if (this.afVariation == BarChartVariation.Horizontal) {
                this.yScale = d3
                    .scaleBand(empty
                    ? ['0', '1', '2', '3', '4', '5', '6', '7']
                    : this.chartData.data.xValueNames, [this.margin.top, this.dims.height - this.margin.bottom])
                    .paddingOuter(0.1)
                    .paddingInner(0.1);
                this.yAxis = d3.axisLeft(this.yScale);
            }
            else {
                this.yScale = d3
                    .scaleLinear()
                    .domain(empty ? [0, 10] : [this.minVal, this.maxVal])
                    .nice(((_b = (_a = this.chartData) === null || _a === void 0 ? void 0 : _a.meta) === null || _b === void 0 ? void 0 : _b.numberOfReferenceLines)
                    ? (_c = this.chartData) === null || _c === void 0 ? void 0 : _c.meta.numberOfReferenceLines
                    : 3);
                this.yScale.range([
                    this.dims.height - this.margin.bottom,
                    this.margin.top
                ]);
                this.yAxis = d3.axisLeft(this.yScale);
            }
        };
        // Setting X-Scale
        this.setXScale = (empty) => {
            // Horizontal
            if (this.afVariation == BarChartVariation.Horizontal) {
                this.xScale = d3
                    .scaleLinear()
                    .domain(empty ? [0, 10] : [this.minVal, this.maxVal])
                    .nice(3);
                this.margin.right =
                    this.getTextSize(this.xScale.domain()[1].toLocaleString()) / 2 +
                        this.yTickSize +
                        this.tickPadding;
                this.xScale.range([
                    0,
                    this.dims.width - this.margin.right - this.margin.left
                ]);
                // Initializing actual axis
                this.xAxis = d3.axisBottom(this.xScale);
                this.tickWidth = this.getLargestText(this.xScale.ticks().map((tick) => tick.toLocaleString()));
            }
            else {
                // Vertical
                this.xScale = d3
                    .scaleBand()
                    .domain(empty ? this.placeholderTicks : this.chartData.data.xValueNames)
                    .range([0, this.dims.width - this.margin.right - this.margin.left])
                    .paddingOuter(0.1)
                    .paddingInner(0.1);
                this.xAxis = d3.axisBottom(this.xScale);
            }
        };
        // Stores all tick text sizes in an indexable array
        this.tickSizes = () => {
            // Initializing tick size array
            this.namedTickSizes = [];
            this.ellipsisSize = this.getTextSize('...');
            if (this.chartData && this.chartData.data) {
                for (let i = 0; i < this.chartData.data.xValueNames.length; i++) {
                    this.namedTickSizes.push(Math.ceil(this.getTextSize(this.chartData.data.xValueNames[i])));
                }
            }
        };
        this.barGroupID = (key) => {
            return 'barGroup' + key.replace(/[^A-Z0-9]+/gi, '');
        };
        this.updateBars = () => {
            this.barSelection = this.barChartContainer.select('.interactiveElements')
                .selectAll('.barGroup')
                .data(this.mappedData)
                .join('g')
                .attr('class', 'barGroup')
                .attr('id', (d) => this.barGroupID(d.key));
            this.barSelection.selectAll('.bar')
                .data((d) => {
                return d.series;
            })
                .join('rect')
                .attr('class', 'bar')
                .style('cursor', 'pointer')
                .attr('x', this.xFunction)
                .attr('y', this.yFunction)
                .attr('ry', 4)
                .attr('rx', 4)
                .attr('width', this.widthFunction)
                .attr('height', this.heightFunction)
                .attr('fill', (d) => this.colorFunction(d.serie))
                .on('mouseenter', this.hover)
                .on('mouseleave', this.hoverOut)
                .on('click', this.openTooltip);
            this.barSelection = this.barChartContainer.selectAll('.barGroup');
            this.textSelection = this.barChartContainer.selectAll('.barText');
        };
        // Setting position of text according to bar size
        this.adjustBarText = () => {
            var _a, _b;
            if (!((_b = (_a = this.chartData) === null || _a === void 0 ? void 0 : _a.meta) === null || _b === void 0 ? void 0 : _b.valueLabels))
                return;
            this.textSelection
                .attr('y', (d) => this.afVariation === BarChartVariation.Horizontal
                ? this.yScale(d.key) + this.yScale.bandwidth() / 2
                : this.yScale(d.value))
                .attr('x', (d) => this.afVariation === BarChartVariation.Horizontal
                ? this.xScale(d.value)
                : this.xScale(d.key) + this.xScale.bandwidth() / 2)
                .attr('dx', (d) => {
                if (this.afVariation === BarChartVariation.Horizontal)
                    return this.xScale(d.value) < d.len + this.tickPadding * 2
                        ? this.tickPadding
                        : -this.tickPadding;
                return 0;
            })
                .attr('fill', (d) => {
                if (this.afVariation === BarChartVariation.Vertical)
                    return 'black';
                return this.xScale(d.value) < d.len + this.tickPadding * 2
                    ? 'black'
                    : 'white';
            })
                .attr('text-anchor', (d) => {
                if (this.afVariation === BarChartVariation.Vertical)
                    return 'middle';
                return this.xScale(d.value) < d.len + this.tickPadding * 2
                    ? 'start'
                    : 'end';
            });
        };
        this.reshapeData = () => {
            const toReturn = [];
            if (!this.chartData) {
                this.placeholderTicks.forEach((key) => {
                    const tick = { key: key, series: [] };
                    tick.series.push({
                        key: key,
                        serie: 'loading',
                        value: Math.floor(Math.random() * (9 - 2 + 1) + 2),
                        len: 0
                    });
                    toReturn.push(tick);
                });
                return toReturn;
            }
            else {
                if (this.chartData.data.xValueNames) {
                    this.chartData.data.xValueNames.forEach((key, index) => {
                        const tick = { key: key, series: [] };
                        this.chartData.data.series.forEach((serie) => {
                            if (serie.yValues[index]) {
                                tick.series.push({
                                    key: key,
                                    serie: serie.title,
                                    value: serie.yValues[index],
                                    len: serie.yValues[index] ? this.getTextSize(serie.yValues[index].toLocaleString()) : 0
                                });
                            }
                        });
                        toReturn.push(tick);
                    });
                }
                else {
                    this.chartData.data.xValues.forEach((key, index) => {
                        const tick = { key: key.toString(), series: [] };
                        this.chartData.data.series.forEach((serie) => {
                            if (serie.yValues[index]) {
                                tick.series.push({
                                    key: key.toString(),
                                    serie: serie.title,
                                    value: serie.yValues[index],
                                    len: serie.yValues[index] ? this.getTextSize(serie.yValues[index].toLocaleString()) : 0
                                });
                            }
                        });
                        toReturn.push(tick);
                    });
                }
            }
            return toReturn;
        };
        this.adjustBarSize = () => {
            this.barSelection.selectAll('.bar')
                .attr('x', this.xFunction)
                .attr('y', this.yFunction)
                .attr('width', this.widthFunction)
                .attr('height', this.heightFunction);
        };
        this.evalColorVar = (colorVar) => {
            return getComputedStyle(document.documentElement)
                .getPropertyValue(colorVar)
                .trim()
                .toLocaleLowerCase();
        };
        // Handling x positioning of bars
        this.xFunction = (d, i) => {
            return this.afVariation === BarChartVariation.Horizontal
                ? (d.value > 0 ? this.xScale(0) : this.xScale(d.value))
                : this.xScale(d.key) + ((this.xScale.bandwidth() / this.dataWidth) * i + (this.barGap * i));
        };
        // Handling y positioning of bars
        this.yFunction = (d, i) => {
            if (!d.value)
                return 0;
            return this.afVariation === BarChartVariation.Horizontal
                ? this.yScale(d.key) + ((this.yScale.bandwidth() / this.dataWidth) * i + (this.barGap * i))
                : (d.value < 0 ? this.yScale(0) : this.yScale(d.value));
        };
        // Handling height for bars
        this.heightFunction = (d) => {
            if (!d.value)
                return 0;
            return this.afVariation === BarChartVariation.Horizontal
                ? this.yScale.bandwidth() / this.dataWidth - (this.barGap)
                : (d.value < 0 ? this.yScale(d.value) - this.yScale(0) : this.yScale(0) - this.yScale(d.value));
        };
        // Handling width for bars
        this.widthFunction = (d) => {
            return this.afVariation === BarChartVariation.Horizontal
                ? Math.abs(this.xScale(0) - this.xScale(d.value))
                : this.xScale.bandwidth() / this.dataWidth - (this.barGap);
        };
        // Setting dimension variable
        this.setDims = (onlyHeight = false) => {
            // Get title dimensions
            const tempTitle = d3.select(this.titleDiv).node().getBoundingClientRect(), tempLegend = d3.select(this.legendDiv).node().getBoundingClientRect();
            const prevHeight = this.dims.height;
            if (!onlyHeight)
                this.dims = d3.select(this.chartDiv).node().getBoundingClientRect();
            this.dims.height =
                this.maxHeight - tempLegend.height - tempTitle.height - 1.75 * this.rem;
            // Making sure height and width are defined
            this.dims.height = Number.isNaN(this.dims.height) ? 10 : this.dims.height;
            this.dims.width = Number.isNaN(this.dims.width) ? 10 : this.dims.width;
            return prevHeight !== this.dims.height;
        };
        // Setting margins given text size
        this.setMargins = (fromLoading) => {
            var _a;
            this.pixelSize =
                Number(window
                    .getComputedStyle(document.body)
                    .getPropertyValue('font-size')
                    .match(/\d+/)[0]) * Number(this.fontSize.replace(/[^\d.]|\.(?=.*\.)/g, ''));
            // Getting the longest word, assuming it will also be the widest in terms of pixels
            if (this.afVariation === BarChartVariation.Horizontal) {
                const left = ((_a = this.chartData) === null || _a === void 0 ? void 0 : _a.data) &&
                    this.getLargestText(this.chartData.data.xValueNames)
                    ? this.getLargestText(this.chartData.data.xValueNames)
                    : 0;
                this.margin.left = left;
                this.margin.bottom = this.pixelSize + this.tickPadding + this.xTickSize;
            }
            else {
                this.margin.left = this.getLargestText(fromLoading
                    ? ['0', '10']
                    : [
                        this.minVal ? this.tempScale[0].toLocaleString() : '0',
                        this.maxVal ? this.tempScale[1].toLocaleString() : '10'
                    ]);
                this.margin.bottom = this.pixelSize;
            }
            if (this.margin.left > this.dims.width / 4) {
                this.margin.left = Math.floor(this.dims.width / 4);
                this.margin.ellipsis = true;
            }
            else
                this.margin.ellipsis = false;
        };
        // Adjusting y-ticks
        this.setNamedTicks = (transition = false) => {
            if (this.afVariation == BarChartVariation.Horizontal) {
                if (!transition) {
                    this.yAxisHandle
                        .style('font-size', this.fontSize)
                        .style('font-family', 'Open Sans')
                        .call(this.yAxis
                        .tickPadding(this.tickPadding)
                        .tickSize(this.yTickSize)
                        .tickSizeOuter(0)
                        .tickFormat((d, i) => {
                        if (!this.margin.ellipsis)
                            return d.toLocaleString();
                        // Adding ellipsis to text
                        const size = this.namedTickSizes[i] + this.tickPadding + this.yTickSize;
                        const mSize = this.margin.left;
                        if (size < mSize)
                            return d.toLocaleString();
                        const newSize = this.getTextSize(d.slice(0, Math.max(Math.floor((mSize / (size + this.ellipsisSize)) * d.length), 3)) + '...');
                        let adjustment = 0;
                        if (newSize > mSize) {
                            adjustment = Math.ceil((newSize - mSize) / (size / d.length));
                        }
                        // Slicing the text up, saving atleast 3 characters
                        return (d
                            .slice(0, Math.max(Math.floor((mSize / (size + this.ellipsisSize)) * d.length) - adjustment, 3))
                            .trim() + '...');
                    }));
                }
                else {
                    this.yAxisHandle
                        .style('font-size', this.fontSize)
                        .style('font-family', 'Open Sans')
                        .transition()
                        .duration(this.defaultDuration)
                        .call(this.yAxis
                        .tickPadding(this.tickPadding)
                        .tickSize(this.yTickSize)
                        .tickSizeOuter(0)
                        .tickFormat((d, i) => {
                        if (!this.margin.ellipsis)
                            return d;
                        // Adding ellipsis to text
                        const size = this.namedTickSizes[i] + this.tickPadding + this.yTickSize;
                        const mSize = this.margin.left;
                        if (size < mSize)
                            return d;
                        const newSize = this.getTextSize(d
                            .slice(0, Math.max(Math.floor((mSize / (size + this.ellipsisSize)) * d.length), 3))
                            .trim() + '...');
                        let adjustment = 0;
                        if (newSize > mSize) {
                            adjustment = Math.ceil((newSize - mSize) / (size / d.length));
                        }
                        // Slicing the text up, saving atleast 3 characters
                        return (d
                            .slice(0, Math.max(Math.floor((mSize / (size + this.ellipsisSize)) * d.length) - adjustment, 3))
                            .trim() + '...');
                    }));
                }
            }
            else {
                //Calculating every n:th text to show
                let nTh = Math.max(Math.round(this.chartData.data.xValues.length /
                    ((this.dims.width - this.margin.left - this.margin.right) / 90 - 1)), 1);
                if (Math.floor(this.chartData.data.xValues.length / nTh) < 4) {
                    nTh = Math.round(this.chartData.data.xValues.length / 4);
                }
                const allowedWidth = (this.dims.width - this.margin.left - this.margin.right) /
                    Math.floor(this.chartData.data.xValues.length / nTh + 1);
                if (!transition) {
                    this.xAxisHandle
                        .style('font-size', this.fontSize)
                        .style('font-family', 'Open Sans')
                        .call(this.xAxis
                        .tickValues(this.xScale.domain().filter((...[, i]) => {
                        if (i == 0)
                            return true;
                        else {
                            return i % nTh == 0;
                        }
                    }))
                        .tickPadding(this.tickPadding)
                        .tickSize(this.xTickSize)
                        .tickSizeOuter(0)
                        .tickFormat((d, i) => {
                        const index = i * nTh;
                        if (this.namedTickSizes[index] < allowedWidth)
                            return d;
                        return (d.slice(0, Math.max(Math.floor((allowedWidth /
                            (this.namedTickSizes[index] +
                                this.ellipsisSize +
                                5)) *
                            d.length), 3)) + '...');
                    }));
                }
                else {
                    this.xAxisHandle
                        .style('font-size', this.fontSize)
                        .style('font-family', 'Open Sans')
                        .transition()
                        .duration(this.defaultDuration)
                        .call(this.xAxis
                        .tickValues(this.xScale.domain().filter((...[, i]) => {
                        if (i == 0)
                            return true;
                        else {
                            return i % nTh == 0;
                        }
                    }))
                        .tickPadding(this.tickPadding)
                        .tickSize(this.xTickSize)
                        .tickSizeOuter(0)
                        .tickFormat((d, i) => {
                        const index = i * nTh;
                        if (this.namedTickSizes[index] < allowedWidth)
                            return d;
                        return (d.slice(0, Math.max(Math.floor((allowedWidth /
                            (this.namedTickSizes[index] +
                                this.ellipsisSize +
                                5)) *
                            d.length), 3)) + '...');
                    }));
                }
            }
        };
        // Positioning the ticks of the value bearing axis
        this.setValueTicks = (transition = false) => {
            var _a, _b;
            if (((_a = this.chartData) === null || _a === void 0 ? void 0 : _a.meta) && ((_b = this.chartData) === null || _b === void 0 ? void 0 : _b.meta.hideXAxis)) {
                this.afVariation === BarChartVariation.Horizontal
                    ? this.xAxisHandle.attr('display', 'none')
                    : this.yAxisHandle.attr('display', 'none');
                return;
            }
            let toCall, tickSize, handle;
            if (this.afVariation === BarChartVariation.Horizontal) {
                this.xAxisHandle.attr('display', null);
                toCall = this.xAxis;
                tickSize = -(this.dims.height - this.margin.top - this.margin.bottom);
                handle = this.xAxisHandle;
            }
            else {
                this.yAxisHandle.attr('display', null);
                toCall = this.yAxis;
                tickSize = -(this.dims.width - this.margin.left - this.margin.right);
                handle = this.yAxisHandle;
            }
            // Computing the amount of ticks to show
            const ticks = Math.min(Math.floor((this.dims.width - this.margin.left - this.margin.right) /
                (this.tickWidth + this.xTickSize)) - 2, this.afVariation == BarChartVariation.Horizontal
                ? this.xScale.ticks().length
                : this.yScale.ticks().length);
            if (!transition) {
                handle
                    .style('font-size', this.fontSize)
                    .style('font-family', 'Open Sans')
                    .call(toCall
                    .ticks(this.afVariation === BarChartVariation.Horizontal
                    ? Math.max(2, Math.min(ticks, 9))
                    : 5) // Clamping value between 2 and 10
                    .tickPadding(this.tickPadding)
                    .tickSize(tickSize)
                    .tickSizeOuter(0)
                    .tickFormat((d) => d.toLocaleString()));
            }
            else {
                handle
                    .style('font-size', this.fontSize)
                    .style('font-family', 'Open Sans')
                    .transition('newScale')
                    .duration(this.defaultDuration)
                    .call(toCall
                    .ticks(this.afVariation === BarChartVariation.Horizontal
                    ? Math.max(2, Math.min(ticks, 9))
                    : 5) // Clamping value between 2 and 10
                    .tickPadding(this.tickPadding)
                    .tickSize(tickSize)
                    .tickSizeOuter(0)
                    .tickFormat((d) => d.toLocaleString()));
            }
            handle.selectAll('line').attr('stroke', 'lightgray');
            if (this.afVariation === BarChartVariation.Vertical)
                this.yAxisHandle.select('.domain').attr('display', 'none');
        };
        // Highlight bar
        this.hover = (event) => {
            d3.select(event.target)
                .transition('color')
                .duration(20)
                .attr('fill', (d) => {
                var _a;
                if (event.target.tagName === 'rect') {
                    if (((_a = this.chartData.meta) === null || _a === void 0 ? void 0 : _a.prognosisPattern) && this.series.indexOf(d.serie) > 0) {
                        return 'url(#prognosisHighlight)';
                    }
                    else
                        return this.adjustColor(this.colorFunction(d.serie), 50);
                }
                else {
                    return this.evalColorVar('--digi--color--background--interactive--hover--tertiary');
                }
            });
        };
        // Removing highlight from bar
        this.hoverOut = (event) => {
            d3.select(event.target)
                .transition('color')
                .duration(this.defaultDuration)
                .attr('fill', (d) => event.target.tagName === 'rect' ? this.colorFunction(d.serie) : '#333333');
        };
        this.openTooltip = (...[, d]) => {
            // If type is string, the user has clicked on a y-axis tick
            if (typeof d === 'string') {
                this.tooltipData = this.barChartContainer
                    .select(`#${this.barGroupID(d)}`)
                    .datum();
            }
            else
                this.tooltipData = d;
            const tooltipBody = this.tooltip.select('.tooltipBody');
            this.tooltip
                .select('.tooltipHeading')
                .html(this.tooltipData.key);
            tooltipBody
                .selectAll('div')
                .data(this.tooltipData.series ? this.tooltipData.series : [this.tooltipData])
                .join('div')
                .style('display', 'flex')
                .style('flex-direction', 'row')
                .style('flex-wrap', 'nowrap')
                .style('white-space', 'nowrap')
                .style('justify-content', 'space-between')
                .style('margin', '0.25rem 0')
                .html((d) => {
                return `<span>${d.serie}: <b style="font-weight:600;">${d.value.toLocaleString(undefined, this.numberFormat)}</b></span>`;
            });
            this.tooltip.style('display', null);
            this.positionTooltip(this.tooltipData);
        };
        this.closeTooltip = () => {
            this.tooltip.style('display', 'none');
        };
        // Positions tooltip in horizontal mode
        this.positionTooltip = (data) => {
            var _a;
            const width = this.tooltip.node().getBoundingClientRect().width;
            // Single bar
            if ('serie' in data) {
                if (this.afVariation === BarChartVariation.Horizontal) {
                    const diff = this.xScale(data.value) / 2 - width / 2;
                    this.tooltip
                        .style('transform', `translate(${this.margin.left + this.tickPadding + Math.max(diff, -4)}px, ${this.yScale(data.key) + this.yScale.bandwidth() + this.yScale.paddingInner() * this.yScale.bandwidth()}px )`)
                        .style('max-width', this.xScale.range()[1] + 'px');
                    this.tooltip
                        .select('digi-icon-caret-up')
                        .style('position', 'absolute')
                        .style('top', '-11px')
                        .style('left', '0')
                        .style('transform', `translate(${diff > 0 ? width / 2 - 10 : this.xScale(data.value) / 2}px,0)`);
                }
                else {
                    const index = (_a = this.mappedData.find(xPoint => xPoint.key === data.key)) === null || _a === void 0 ? void 0 : _a.series.findIndex(serie => serie.serie === data.serie);
                    const barIndex = ((this.xScale.bandwidth() / this.dataWidth) * (index ? index + 1 : 1)) - (this.xScale.bandwidth() / this.dataWidth) / 2;
                    // This should be where the x-axis starts
                    const xStart = this.margin.left + this.tickPadding + this.yTickSize;
                    // Creating adjustment for tooltip to not appear outside of chart
                    const spaceToSVGEdge = 5;
                    const inlineAdjustment = (this.dims.width - spaceToSVGEdge) < (this.xScale(data.key) + xStart + barIndex + width / 2) ? (((this.xScale(data.key) + xStart + barIndex + width / 2) - (this.dims.width - spaceToSVGEdge)) / width) * 100 : 0;
                    this.tooltip
                        .style('transform', `translate( calc(${this.xScale(data.key) + xStart + barIndex}px - ${50 + inlineAdjustment}%), calc(-100% + ${(data.value > 0 ? this.yScale(data.value) : this.yScale(0)) - 2}px) )`);
                    this.tooltip
                        .select('digi-icon-caret-down')
                        .style('position', 'absolute')
                        .style('left', `calc(${50 + inlineAdjustment}% - 6px)`)
                        .style('bottom', '-12px');
                }
            }
            else {
                if (this.afVariation === BarChartVariation.Horizontal) {
                    this.tooltip
                        .style('transform', `translate(${this.tickPadding}px, ${this.yScale(data.key) + this.series.length * this.yScale.bandwidth() + 5}px )` // 5 is for half caret size
                    );
                    this.tooltip
                        .select('digi-icon-caret-up')
                        .style('position', 'absolute')
                        .style('top', '-11px')
                        .style('left', '0')
                        .style('transform', `translate(50%,0)`);
                    //this.yScale(data.key) + ((this.yScale.bandwidth() / this.dataWidth) * i + (this.barGap * i))
                }
                else {
                    const xStart = this.margin.left + this.tickPadding + this.yTickSize;
                    const translatePoint = this.xScale(data.key) + xStart + this.xScale.bandwidth() / 2;
                    const yMax = d3.max(data.series.map(elem => elem.value));
                    // Creating adjustment for tooltip to not appear outside of chart
                    const spaceToSVGEdge = 5;
                    const inlineAdjustment = (this.dims.width - spaceToSVGEdge) < (translatePoint + width / 2) ? (((translatePoint + width / 2) - (this.dims.width - spaceToSVGEdge)) / width) * 100 : 0;
                    this.tooltip
                        .style('transform', `translate( calc(${this.xScale(data.key) + xStart + this.xScale.bandwidth() / 2}px - ${50 + inlineAdjustment}%), calc(-100% + ${this.yScale(yMax && yMax > 0 ? yMax : 0) - 1}px) )`);
                    this.tooltip
                        .select('digi-icon-caret-down')
                        .style('position', 'absolute')
                        .style('left', `calc(${50 + inlineAdjustment}% - 6px)`)
                        .style('bottom', '-12px');
                }
            }
        };
        // Once texts has fully loaded, we can recompute some sizes
        this.recomputeTextSize = () => {
            var _a, _b;
            if (this.afVariation == BarChartVariation.Horizontal)
                this.tickWidth = this.getLargestText(this.xScale.ticks().map((tick) => tick.toLocaleString()));
            this.tickSizes();
            this.barChartContainer.selectAll('.barGroup').data(this.mappedData);
            if ((_b = (_a = this.chartData) === null || _a === void 0 ? void 0 : _a.meta) === null || _b === void 0 ? void 0 : _b.valueLabels)
                this.textSelection.remove();
            this.initBarText();
        };
        // Removes resize observer for chart and inits table
        this.activateTable = (event) => {
            this.closeTooltip();
            this.barChartObserver.disconnect();
            this.status.innerHTML = '<p>Visas som tabell</p>';
            d3.select(this.host).select('.tableButton').style('display', 'none');
            d3.select(this.host).select('.chartButton').style('display', null);
            event.target.nextSibling.lastChild.focus();
            const duration = 150;
            this.svg
                .attr('opacity', 1)
                .transition('fadeout')
                .duration(duration)
                .attr('opacity', 0)
                .on('end', () => {
                this.svg.remove();
                d3.select(this.legendDiv).select('.legend').selectAll('.legendChip').remove();
                this.legendDiv.style['display'] = 'none';
                this.tableDiv.style['display'] = 'block';
                this.setTableContent();
                this.setTableDimensions();
                d3.select(this.tableDiv)
                    .style('opacity', 0)
                    .transition('fadein')
                    .duration(duration)
                    .style('opacity', 1);
                this.chartDiv.style['display'] = 'none';
            });
            d3.select(this.legendDiv)
                .style('opacity', 1)
                .transition('fadeout')
                .duration(duration)
                .style('opacity', 0);
        };
        // Removes observer and calls init functions for line chart
        this.reInitChart = (event) => {
            this.status.innerHTML = '<p>Visas som diagram</p>';
            d3.select(this.host).select('.tableButton').style('display', null);
            d3.select(this.host).select('.chartButton').style('display', 'none');
            event.target.previousSibling.lastChild.focus();
            const table = d3.select(this.tableDiv);
            const duration = 150;
            table
                .style('opacity', 1)
                .transition()
                .duration(150)
                .style('opacity', 0)
                .on('end', () => {
                table.style('display', 'none');
                this.chartDiv.style['display'] = 'flex';
                this.legendDiv.style['display'] = 'grid';
                this.initChain();
                this.svg
                    .attr('opacity', 0)
                    .transition()
                    .duration(duration)
                    .attr('opacity', 1);
                d3.select(this.legendDiv)
                    .style('opacity', 0)
                    .transition('fadeout')
                    .duration(duration)
                    .style('opacity', 1);
            });
        };
        this.afVariation = BarChartVariation.Vertical;
        this.afHeadingLevel = 'h3';
        this.afId = randomIdGenerator('tooltip');
        this.afChartData = undefined;
    }
    afChartDataUpdate(data) {
        if (typeof data === 'string' && Object.keys(JSON.parse(data)).length > 0 || typeof data !== 'string' && Object.keys(data).length > 0) {
            if (typeof data != 'string')
                this.chartData = data;
            else
                this.chartData = JSON.parse(data);
            this.series = this.chartData.data.series.map(serie => serie.title);
        }
        this.mappedData = this.reshapeData();
        // checking for width of each tick
        this.mappedData.forEach((elem) => {
            if (elem.series.length > this.dataWidth)
                this.dataWidth = elem.series.length;
        });
        if (this.dataWidth > 1)
            this.barGap = 1;
    }
    initSvg() {
        var _a, _b, _c, _d, _e, _f, _g;
        // Fetch number formatting
        this.numberFormat = {
            maximumSignificantDigits: (_c = (_b = (_a = this.chartData) === null || _a === void 0 ? void 0 : _a.meta) === null || _b === void 0 ? void 0 : _b.labelProperties) === null || _c === void 0 ? void 0 : _c.significantDigits,
            notation: ((_f = (_e = (_d = this.chartData) === null || _d === void 0 ? void 0 : _d.meta) === null || _e === void 0 ? void 0 : _e.labelProperties) === null || _f === void 0 ? void 0 : _f.shortHand)
                ? 'compact'
                : 'standard'
        };
        d3.select(this.chartDiv).select('.chartSVG').remove();
        this.maxHeight = (_g = d3
            .select(this.host)
            .node()
            .parentNode) === null || _g === void 0 ? void 0 : _g.getBoundingClientRect().height;
        this.barChartObserver.observe(this.chartDiv);
        // Getting rem-size
        this.rem = parseFloat(getComputedStyle(document.documentElement).fontSize);
        this.setDims();
        this.setMinMax();
        this.setMargins();
        // Appending svg
        this.svg = d3
            .select(this.chartDiv)
            .append('svg')
            .attr('class', 'chartSVG')
            .attr('aria-hidden', true)
            .attr('role', 'img')
            .attr('aria-label', this.chartData && this.chartData.title
            ? 'Stapeldiagram om ' + this.chartData.title.toLowerCase()
            : 'Stapeldiagram')
            .attr('style', 'display: flex;min-width: 0;width: 100%;height: auto;');
    }
    initLegend() {
        const rectSize = 18;
        const legendData = this.chartData.data.series.map(serie => serie.title);
        if (this.chartData.data.averageLine)
            legendData.push(this.chartData.data.averageLine.text);
        const legendChips = d3.select(this.legendDiv).select('.legend')
            .style('margin-left', `${this.margin.left + this.tickPadding + this.yTickSize}px`)
            .selectAll('.legendChip')
            .data(legendData)
            .join('div')
            .attr('class', 'legendChip')
            .style('display', 'flex')
            .style('flex-direction', 'row')
            .style('align-items', 'center')
            .style('gap', '0.25rem')
            .style('cursor', 'default')
            .on('mouseenter', (_event, serie) => this.highlightBars(serie))
            .on('mouseleave', this.resetBarColor);
        legendChips.append('svg')
            .attr('width', rectSize)
            .attr('height', rectSize)
            .append('rect')
            .attr('x', 0)
            .attr('y', 0)
            .attr('width', rectSize)
            .attr('height', rectSize)
            .attr('rx', 4)
            .attr('ry', 4)
            .attr('fill', (title) => this.colorFunction(title));
        legendChips.append('span').style('text-wrap', 'nowrap').text((d) => d);
        if (this.chartData.data.averageLine) {
            const averageLine = legendChips.filter(':last-child')
                .on('mouseenter', (_event, serie) => this.highlightAverageLine(serie));
            const miniSVG = averageLine
                .select('svg')
                .attr('width', rectSize * 2);
            miniSVG.select('rect').remove();
            miniSVG.append('line')
                .attr('x1', 1)
                .attr('x2', rectSize * 2 - 1)
                .attr('y1', rectSize / 2 + 1)
                .attr('y2', rectSize / 2 + 1)
                .attr('stroke', 'var(--digi--color--infographic--lineart)')
                .attr('stroke-linecap', 'round')
                .attr('stroke-dasharray', '12, 7');
        }
    }
    initToolTip() {
        // Getting handle for tooltip
        this.tooltip = d3.select('#' + this.afId);
        this.tooltip.select('.tooltipClose').on('click', this.closeTooltip);
        this.tooltip.selectAll('.tooltipHeading').remove();
        this.tooltip
            .select('.tooltipHead')
            .insert('h' + (parseInt(this.afHeadingLevel.replace(/\D/g, '')) + 1), ':first-child') // increment heading level by one
            .attr('class', 'tooltipHeading') // Adding class to try to dodge global css classes
            .style('text-wrap', 'wrap')
            .style('font-size', '1rem')
            .style('margin', '0 0.75rem 0.25rem 0 ')
            .style('font-weight', '500');
        this.tooltip.style('display', 'none');
    }
    initEmpty() {
        d3.select(this.chartDiv).select('.chartSVG').remove();
        this.maxHeight = d3
            .select(this.host)
            .node()
            .parentNode.getBoundingClientRect().height;
        this.barChartObserver.observe(this.chartDiv);
        this.setDims();
        // Getting rem-size
        this.rem = parseFloat(getComputedStyle(document.documentElement).fontSize);
        this.setMargins();
        // Appending svg
        this.svg = d3
            .select(this.chartDiv)
            .append('svg')
            .attr('class', 'chartSVG')
            .attr('aria-hidden', true)
            .attr('role', 'img')
            .attr('aria-label', this.chartData && this.chartData.title
            ? 'Stapeldiagram om ' + this.chartData.title.toLowerCase()
            : 'Stapeldiagram').attr('style', 'display: flex;min-width: 0;width: 100%;height: auto;');
        // Hide unusable components
        d3.select(this.titleDiv)
            .select(this.afHeadingLevel)
            .html(`${_t.loading}...`);
        this.initYAxis(true);
        this.initXAxis(true);
        this.tooltip = d3.select('#' + this.afId);
        this.tooltip.style('display', 'none');
        this.loadingState(true);
    }
    loadingState(empty) {
        this.loading = true;
        // close potentially open tooltip
        if (this.tooltip)
            this.closeTooltip();
        d3.select(this.host).select('.tableButton').style('display', 'none');
        const newHeight = this.setDims();
        this.transitionTitle();
        this.xAxisHandle.selectAll('.tick').remove();
        this.xAxisHandle.select('path').remove();
        this.svg
            .transition()
            .duration(400)
            .attr('aria-label', this.chartData && this.chartData.title
            ? 'Stapeldiagram om ' + this.chartData.title.toLowerCase()
            : 'Stapeldiagram');
        this.setMargins(true);
        d3.select(this.titleDiv)
            .select(this.afHeadingLevel)
            .html(`${_t.loading}...`);
        // Waiting with observing for changes until transition to regular bars is complete
        this.barChartContainer
            .transition('position')
            .duration(this.defaultDuration)
            .ease(d3.easePolyInOut)
            .attr('transform', `translate(${this.margin.left + this.tickPadding + this.yTickSize},0)`);
        // If there is a new height
        if (newHeight) {
            // Update y-axis with potentially new height (might want to do a check here)
            this.afVariation === BarChartVariation.Horizontal
                ? this.yScale.range([
                    this.margin.top,
                    this.dims.height - this.margin.bottom
                ])
                : this.yScale.range([
                    this.dims.height - this.margin.bottom,
                    this.margin.top
                ]);
            this.xAxisHandle.attr('transform', `translate(0,${this.dims.height - this.margin.bottom})`);
        }
        const animateBars = () => {
            this.barChartContainer.selectAll('.interactiveElements').remove();
            this.barSelection = this.barChartContainer
                .append('g')
                .attr('class', 'interactiveElements')
                .style('isolation', 'isolate')
                .selectAll('barGroup')
                .data(this.mappedData)
                .join('g')
                .attr('class', 'barGroup')
                .attr('id', (d) => this.barGroupID(d.key));
            this.barSelection.selectAll('bar')
                .data((d) => {
                return d.series;
            })
                .join('rect')
                .attr('class', 'bar')
                .attr('y', (d) => this.afVariation === BarChartVariation.Horizontal
                ? this.yScale(d.key)
                : this.dims.height - this.margin.bottom)
                .attr('x', this.xFunction)
                .attr('ry', 4)
                .attr('rx', 4)
                .attr('width', this.widthFunction)
                .attr('height', () => 0)
                .attr('fill', 'gray');
            this.barChartContainer.selectAll('.bar')
                .transition('animateBar')
                .duration(400)
                .delay((...[, i]) => i * 150)
                .attr('y', this.yFunction)
                .attr('height', this.heightFunction);
            this.barChartContainer.selectAll('.bar')
                .transition('animateBar')
                .duration(400)
                .ease(d3.easeLinear)
                .delay((...[, i]) => i * 150 + 400)
                .attr('y', (d) => this.afVariation === BarChartVariation.Horizontal
                ? this.yScale(d.key)
                : this.dims.height - this.margin.bottom)
                .attr('height', () => 0)
                .on('end', (...[, i]) => {
                if (i === this.placeholderTicks.length - 1)
                    animateBars();
            });
        };
        const flattenBars = () => {
            this.barChartContainer
                .selectAll('.bar')
                .transition('animateBar')
                .duration(200)
                .ease(d3.easeLinear)
                .attr('y', (d) => this.afVariation === BarChartVariation.Horizontal
                ? this.yScale(d.key)
                : this.dims.height - this.margin.bottom)
                .attr('height', () => 0)
                .on('end', (...[, i]) => {
                if (i != 0)
                    return;
                this.setYScale(true);
                this.setValueTicks();
                this.setXScale(true);
                this.barChartObserver.observe(this.chartDiv);
                animateBars();
            });
        };
        if (empty)
            animateBars();
        else
            flattenBars();
    }
    transitionTitle() {
        const height = d3.select(this.titleDiv).style('height');
        d3.select(this.titleDiv)
            .style('height', this.prevHeight)
            .transition('adjust')
            .duration(400)
            .style('height', height)
            .on('end', () => d3.select(this.titleDiv).style('height', null));
    }
    initYAxis(empty) {
        this.setYScale(empty);
        this.barChartContainer = this.svg
            .append('g')
            .attr('transform', `translate(${this.margin.left + this.tickPadding + this.yTickSize},0)`);
        this.yAxisHandle = this.barChartContainer.append('g');
        if (this.afVariation === BarChartVariation.Horizontal) {
            this.tickSizes();
            this.setNamedTicks();
            this.setTickInteraction();
        }
        else
            this.setValueTicks();
    }
    // Sets the largest and smallest value from series 0, Should only be used when not loading
    setMinMax() {
        var _a, _b, _c, _d, _e, _f, _g;
        const max = d3.max((_a = this.chartData) === null || _a === void 0 ? void 0 : _a.data.series[0].yValues)
            ? d3.max((_b = this.chartData) === null || _b === void 0 ? void 0 : _b.data.series[0].yValues)
            : 0;
        const min = d3.min([0, d3.min((_c = this.chartData) === null || _c === void 0 ? void 0 : _c.data.series[0].yValues)])
            ? d3.min([0, d3.min((_d = this.chartData) === null || _d === void 0 ? void 0 : _d.data.series[0].yValues)])
            : 0;
        this.maxVal = max;
        this.minVal = min;
        this.tempScale = d3
            .scaleLinear()
            .domain([this.minVal, this.maxVal])
            .nice(((_f = (_e = this.chartData) === null || _e === void 0 ? void 0 : _e.meta) === null || _f === void 0 ? void 0 : _f.numberOfReferenceLines)
            ? (_g = this.chartData) === null || _g === void 0 ? void 0 : _g.meta.numberOfReferenceLines
            : 3)
            .domain();
    }
    // Setting up x-axis, getting margin.right in this function
    initXAxis(empty) {
        this.setXScale(empty);
        this.xAxisHandle = this.barChartContainer
            .append('g')
            .attr('transform', `translate(0,${this.dims.height - this.margin.bottom})`);
        if (this.afVariation === BarChartVariation.Horizontal) {
            this.setValueTicks();
            // Removing first tick, because it aligns with y-axis domain
            //this.xAxisHandle.select('.tick').select('line').remove();
        }
        else {
            if (!empty) {
                this.tickSizes();
                this.setNamedTicks();
                this.setTickInteraction();
            }
        }
    }
    // Initializing bars, can only handle one series of bars for now
    initBars() {
        this.barSelection = this.barChartContainer
            .append('g')
            .attr('class', 'interactiveElements')
            .style('isolation', 'isolate')
            .selectAll('barGroup')
            .data(this.mappedData)
            .join('g')
            .attr('class', 'barGroup')
            .attr('id', (d) => this.barGroupID(d.key));
        this.barSelection.selectAll('.barGroup')
            .data((d) => {
            return d.series;
        })
            .join('rect')
            .attr('class', 'bar')
            .style('cursor', 'pointer')
            .attr('x', this.xFunction)
            .attr('y', this.yFunction)
            .attr('ry', 4)
            .attr('rx', 4)
            .attr('width', this.widthFunction)
            .attr('height', this.heightFunction)
            .attr('fill', (d) => this.colorFunction(d.serie))
            .on('mouseenter', this.hover)
            .on('mouseleave', this.hoverOut)
            .on('click', this.openTooltip);
    }
    initBarText() {
        var _a, _b;
        if (!((_b = (_a = this.chartData) === null || _a === void 0 ? void 0 : _a.meta) === null || _b === void 0 ? void 0 : _b.valueLabels))
            return;
        this.textSelection = this.barChartContainer
            .selectAll('.barGroup')
            .append('text');
        this.textSelection
            .text((d) => {
            return d.value ? d.value.toLocaleString(undefined, this.numberFormat) : undefined;
        })
            .attr('class', 'barText')
            .attr('font-size', this.fontSize)
            .attr('font-weight', '600')
            .attr('text-anchor', 'end')
            .attr('y', (d) => this.afVariation === BarChartVariation.Horizontal
            ? this.yScale(d.key) + this.yScale.bandwidth() / 2
            : this.yScale(d.value))
            .attr('x', (d) => this.afVariation === BarChartVariation.Horizontal
            ? this.xScale(d)
            : this.xScale(d.key) + this.xScale.bandwidth())
            .attr('dy', () => this.afVariation == BarChartVariation.Horizontal ? '0.35em' : '-0.25em')
            .style('pointer-events', 'none')
            .style('display', () => { var _a, _b; return ((_b = (_a = this.chartData) === null || _a === void 0 ? void 0 : _a.meta) === null || _b === void 0 ? void 0 : _b.valueLabels) ? null : 'none'; });
        this.adjustBarText();
    }
    initChain() {
        this.initSvg();
        this.initLegend();
        this.initToolTip();
        this.initYAxis();
        this.initXAxis();
        this.initBars();
        this.averageLine();
        this.initBarText();
    }
    async updateChain() {
        var _a, _b, _c, _d, _e, _f;
        // Fetch number formatting
        this.numberFormat = {
            maximumSignificantDigits: (_c = (_b = (_a = this.chartData) === null || _a === void 0 ? void 0 : _a.meta) === null || _b === void 0 ? void 0 : _b.labelProperties) === null || _c === void 0 ? void 0 : _c.significantDigits,
            notation: ((_f = (_e = (_d = this.chartData) === null || _d === void 0 ? void 0 : _d.meta) === null || _e === void 0 ? void 0 : _e.labelProperties) === null || _f === void 0 ? void 0 : _f.shortHand)
                ? 'compact'
                : 'standard'
        };
        if (this.tooltip)
            this.closeTooltip();
        // Check whether we are in table mode or not
        if (this.tableDiv.style['display'] == 'block') {
            if (!this.chartData.title) {
                d3.select(this.titleDiv)
                    .select(this.afHeadingLevel)
                    .html(`${_t.loading}...`);
            }
            else {
                this.setTableContent();
                this.setTableDimensions();
            }
            this.transitionTitle();
        }
        else {
            // displaying legend again
            if (this.loading) {
                d3.select(this.host).select('.tableButton').style('display', null);
                d3.select(this.legendDiv).style('display', null);
                this.initToolTip();
                this.initLegend();
            }
            // Disconnect resize observer while adjusting things
            this.barChartObserver.disconnect();
            this.setMinMax();
            const newHeight = this.setDims();
            this.transitionTitle();
            this.svg
                .attr('aria-label', this.chartData && this.chartData.title
                ? 'Stapeldiagram om ' + this.chartData.title.toLowerCase()
                : 'Stapeldiagram');
            this.setMargins();
            // Waiting with observing for changes until transition to regular bars is complete
            this.barChartContainer
                .transition('position')
                .duration(this.defaultDuration)
                .ease(d3.easePolyInOut)
                .attr('transform', `translate(${this.margin.left + this.tickPadding + this.yTickSize},0)`);
            if (!this.loading)
                this.barChartContainer.on('end', () => this.barChartObserver.observe(this.chartDiv));
            // If there is a new height
            if (newHeight) {
                // Update y-axis with potentially new height (might want to do a check here)
                this.afVariation === BarChartVariation.Horizontal
                    ? this.yScale.range([
                        this.margin.top,
                        this.dims.height - this.margin.bottom
                    ])
                    : this.yScale.range([
                        this.dims.height - this.margin.bottom,
                        this.margin.top
                    ]);
                this.xAxisHandle.attr('transform', `translate(0,${this.dims.height - this.margin.bottom})`);
            }
            this.tickSizes();
            this.setYScale();
            this.setXScale();
            this.setTickInteraction();
            this.tickWidth = this.getLargestText(this.afVariation == BarChartVariation.Horizontal
                ? this.xScale.ticks().map((tick) => tick.toLocaleString())
                : this.yScale.ticks().map((tick) => tick.toLocaleString()));
            this.setValueTicks(true);
            if (this.loading) {
                d3.select(this.legendDiv)
                    .style('opacity', 0)
                    .transition()
                    .duration(400)
                    .ease(d3.easePolyInOut)
                    .style('opacity', 1);
                this.margin.right =
                    this.getTextSize(this.xScale.domain()[1].toLocaleString()) / 2 +
                        this.yTickSize +
                        this.tickPadding;
                // Update x-axis with new width
                this.xScale.range([
                    0,
                    this.dims.width - this.margin.right - this.margin.left
                ]);
                this.setNamedTicks(true);
                // Stop animation
                this.barChartContainer.selectAll('.barGroup').on('end', null);
                d3.select(this.titleDiv).select('.loadingHeader').remove();
                this.loading = false;
                this.barChartContainer.selectAll('.bar').interrupt('animateBar');
                this.barChartContainer.selectAll('.bar').transition()
                    .duration(this.defaultDuration)
                    .attr('y', (d) => this.afVariation === BarChartVariation.Horizontal
                    ? this.yScale(d.key)
                    : this.dims.height - this.margin.bottom)
                    .attr('height', () => 0)
                    .on('end', (...[, i]) => {
                    if (i === this.placeholderTicks.length - 1) {
                        this.updateBars();
                        this.barChartObserver.observe(this.chartDiv);
                    }
                });
                this.setTickInteraction();
            }
            else {
                this.setNamedTicks(true);
                // Removing first tick, because it aligns with y-axis domain
                this.updateBars();
            }
        }
    }
    // Getting correct color given index or name of data serie
    colorFunction(input) {
        var _a;
        if (typeof input === 'number') {
            return this.evalColorVar(this.colorPalettes[input]);
        }
        else {
            const index = this.chartData.data.series.findIndex((serie) => serie.title === input);
            if (index > 0) {
                if ((_a = this.chartData.meta) === null || _a === void 0 ? void 0 : _a.prognosisPattern)
                    return 'url(#prognosis)';
                else
                    return this.evalColorVar(this.colorPalettes[index]);
            }
            else
                return this.evalColorVar(this.colorPalettes[0]);
        }
    }
    // Resizing bar chart
    resize() {
        const newHeight = this.setDims();
        //this.setMargins();
        this.barChartContainer.attr('transform', `translate(${this.margin.left + this.tickPadding + this.yTickSize},0)`);
        this.margin.right =
            this.getTextSize(this.xScale.domain()[1].toLocaleString()) / 2 +
                this.yTickSize +
                this.tickPadding;
        // If there is a new height
        if (newHeight) {
            // Update y-axis with potentially new height (might want to do a check here)
            this.afVariation === BarChartVariation.Horizontal
                ? this.yScale.range([
                    this.margin.top,
                    this.dims.height - this.margin.bottom
                ])
                : this.yScale.range([
                    this.dims.height - this.margin.bottom,
                    this.margin.top
                ]);
            this.xAxisHandle.attr('transform', `translate(0,${this.dims.height - this.margin.bottom})`);
        }
        // Update x-axis with new width
        this.xScale.range([
            0,
            this.dims.width - this.margin.right - this.margin.left
        ]);
        this.setNamedTicks();
        this.setValueTicks();
        this.setTickInteraction();
        this.averageLine();
        this.adjustBarSize();
        this.adjustBarText();
        if (this.tooltip.style('display') !== 'none')
            this.positionTooltip(this.tooltipData);
    }
    // Returns the longest text from an array of strings
    getLargestText(array) {
        let width = 0;
        array.forEach((elem) => {
            const temp = this.getTextSize(elem);
            if (temp > width) {
                width = temp;
            }
        });
        return width;
    }
    adjustColor(color, amount) {
        return '#' + color.replace(/^#/, '').replace(/../g, color => ('0' + Math.min(255, Math.max(0, parseInt(color, 16) + amount)).toString(16)).substr(-2));
    }
    componentWillLoad() {
        this.afChartDataUpdate(this.afChartData);
    }
    componentDidLoad() {
        if (!this.chartData || Object.keys(this.chartData).length === 0) {
            this.loading = true;
            return this.initEmpty();
        }
        this.initChain();
        document.fonts.ready.then(() => {
            this.recomputeTextSize();
            this.setNamedTicks();
            this.barChartContainer.attr('transform', `translate(${this.margin.left + this.tickPadding + this.yTickSize},0)`);
        });
    }
    disconnectedCallback() {
        this.barChartObserver.disconnect();
    }
    componentWillUpdate() {
        this.prevHeight = d3.select(this.titleDiv).style('height');
    }
    componentDidUpdate() {
        if (this.tableDiv.style['display'] != 'block' &&
            Object.keys(this.chartData).length === 0) {
            // Disconnect old barchartobserver while doing resizing
            this.barChartObserver.disconnect();
            return this.loadingState();
        }
        this.updateChain();
    }
    // Not currently used
    /*get cssModifiers() {
      return {
        'digi-bar-chart--vertical': this.afVariation == 'vertical',
        'digi-bar-chart--horizontal': this.afVariation == 'horizontal'
      };
    }*/
    // Returns pixelwidth of text given the current fontSize (costly function using .each)
    getTextSize(text) {
        const textWidth = [];
        const svg = d3.select(this.chartDiv).append('svg');
        svg
            .selectAll('dummyText')
            .data([text])
            .join('text')
            .attr('font-size', this.fontSize) // <- using 1rem here whereas default is 0.875rem
            .text((d) => d)
            .each((...[, i, nodelist]) => {
            const thisWidth = nodelist[i].getComputedTextLength();
            textWidth.push(thisWidth);
            nodelist[i].remove();
        });
        svg.remove().exit();
        return textWidth[0];
    }
    // Setting table content from this.chartData
    setTableContent() {
        this.tableDiv.innerHTML = `<digi-table af-size="small" style="width:100%" af-variation="primary"> <table><caption>${this.chartData.title}</caption><thead><tr>${this.headings()}</tr></thead><tbody>${this.tableBody()}</tbody></table></digi-table>`;
    }
    setTableDimensions() {
        const table = d3.select(this.tableDiv);
        table.style('display', 'flex').style('height', '100%').style('width', '100%');
    }
    // Extracting all headings from data and returning a string with <th>-elements with headings
    headings() {
        let headingsString = `<th scope="col">${this.chartData.x}</th>`;
        this.chartData.data.series.forEach((elem) => {
            headingsString = headingsString.concat(`<th scope="col">${elem.title}</th>`);
        });
        return headingsString;
    }
    // Building the table body
    tableBody() {
        let body = '';
        if (this.chartData && this.chartData.data) {
            const loopable = this.chartData.data.xValueNames
                ? this.chartData.data.xValueNames
                : this.chartData.data.xValues;
            loopable.forEach((elem, index) => {
                let cells = '';
                this.chartData.data.series.forEach((serie) => {
                    cells = cells.concat(`<td>${serie.yValues[index] != null ? serie.yValues[index].toLocaleString() : '-'}</td>`);
                });
                body = body.concat(`<tr><th scope='row'>${elem}${cells}</th></tr>`);
            });
        }
        return body;
    }
    render() {
        var _a, _b, _c, _d, _e;
        // Setting header
        let heading = '';
        if (this.chartData) {
            if (!this.chartData.subTitle)
                heading = `<${this.afHeadingLevel}>${this.chartData.title}</${this.afHeadingLevel}>`;
            else {
                if (!this.chartData.infoText)
                    heading = `<${this.afHeadingLevel}>${this.chartData.title}</${this.afHeadingLevel}><p>${this.chartData.subTitle}</p>`;
                else
                    heading = `<${this.afHeadingLevel}>${this.chartData.title}</${this.afHeadingLevel}><p>${(_a = this.chartData) === null || _a === void 0 ? void 0 : _a.subTitle}
				<span style="display:block;margin-top:0.25rem;font-size:0.875rem;color:var(--digi--global--color--neutral--grayscale--darkest-3)">${this.chartData.infoText}</span></p>`;
            }
        }
        return (h(Host, { key: '9831c62ff3d90f45a07e70af75dd84be96db33b9', ref: (el) => (this.host = el) }, h("svg", { key: 'b8f79471bead222318336cc7054b33641a238d60', xmlns: "http://www.w3.org/2000/svg", width: "0", height: "0" }, h("defs", { key: 'f7ff28fcdaa190138722f269eb003e88951b3069' }, h("pattern", { key: 'db8b09311be9ad0311d61e334a225adbf60e7875', id: "prognosis", patternUnits: "userSpaceOnUse", width: "8", height: "8", patternTransform: "rotate(45)" }, h("line", { key: '1ba55d47f9ce13b688d941c5aad17fb977899f74', x1: "0", y: "0", x2: "0", y2: "12", stroke: this.evalColorVar(this.colorPalettes[0]), "stroke-width": "8" })), h("pattern", { key: '0822d197957d12f7b10641c3091b2767418798b6', id: "prognosisInactive", patternUnits: "userSpaceOnUse", width: "8", height: "8", patternTransform: "rotate(45)" }, h("line", { key: '588e4e2eef4e47883f3bd0921f06af0431542fbd', x1: "0", y: "0", x2: "0", y2: "12", stroke: this.evalColorVar('--digi--color--background--secondary-accent'), "stroke-width": "8" })), h("pattern", { key: '874c0a3bf86d50fde9f1391b3e6aff9505fae0a4', id: "prognosisHighlight", patternUnits: "userSpaceOnUse", width: "8", height: "8", patternTransform: "rotate(45)" }, h("line", { key: '3a2caa855d1f9b1e46b0e6261a0ec44e0ccd0eb4', x1: "0", y: "0", x2: "0", y2: "12", stroke: this.adjustColor(this.colorFunction(0), 50), "stroke-width": "8" })))), h("div", { key: '421f2daa00a316cb8d58efc3ab1e87fd1eb9adc6', class: "topWrapper", ref: (el) => (this.titleDiv = el) }, h("digi-typography", { key: 'df08ae5f563fa186570a0807e7fe394b88739d3f', class: "chartTitle", innerHTML: heading }), h("digi-button", { key: '910f5e7e9ea22daaa024867b24aabd76309ae3f8', class: "buttonWrapper tableButton", "af-size": "medium", "af-variation": "function", "af-full-width": "false", onAfOnClick: this.activateTable, afAriaLabel: `Visa tabell ${((_b = this.chartData) === null || _b === void 0 ? void 0 : _b.title) ? (_c = this.chartData) === null || _c === void 0 ? void 0 : _c.title.toLowerCase() : ''}` }, h("digi-icon-table", { key: '5d455b0801afb981a70a6edea9e7b70d08fdfc2d', slot: "icon" }), "Visa tabell"), h("digi-button", { key: '02dd552bd8d5e642c937b5a28b6f19d18be9e463', style: { display: 'none' }, class: "buttonWrapper chartButton", "af-size": "medium", "af-variation": "function", "af-full-width": "false", onAfOnClick: this.reInitChart, afAriaLabel: `Visa diagram ${((_d = this.chartData) === null || _d === void 0 ? void 0 : _d.title) ? (_e = this.chartData) === null || _e === void 0 ? void 0 : _e.title.toLowerCase() : ''}` }, h("digi-icon-chart", { key: 'c5f23473e37dfced6db806472e6a1bb78eab42ed', slot: "icon" }), "Visa diagram"), h("div", { key: 'a00b4c14917d63a1ec821cd83c4357fcd3ea7237', class: "scChartStatus", role: "status", ref: (el) => (this.status = el) })), h("div", { key: 'c5df03e7f9a4f206e30e7688f45de825f006ca48', class: "svgWrap", ref: (el) => (this.chartDiv = el) }, h("div", { key: '2fc9d94d36120cf26dbb0a4ecbe9e1d3b9312761', class: "chartTooltip", id: this.afId }, h("div", { key: '975934290e072ccc342325866d7b5412306734a6', class: "tooltipHead" }, h("digi-icon-x", { key: '9360ecc6854dc77302e39be05d3d87c9b12fc5dc', class: "tooltipClose" })), h("div", { key: '2f116ec7969d7828ef4123681ad839b3bd531fc9', class: "tooltipBody" }), this.afVariation === BarChartVariation.Horizontal ? (h("digi-icon-caret-up", { class: "caret" })) : (h("digi-icon-caret-down", { class: "caret" })))), h("div", { key: '7679e9f3f2c1054d170990b6b451591b7ea43543', class: "legendWrap", ref: (el) => (this.legendDiv = el) }, h("div", { key: 'e9098a071e54162ac4f923ee4578eee21944e114', class: "legend" })), h("div", { key: '9da8f97848ece4ef3190388e9f939e2c7187f4a1', class: "table", ref: (el) => (this.tableDiv = el) }, ' ')));
    }
    static get is() { return "digi-bar-chart"; }
    static get encapsulation() { return "scoped"; }
    static get originalStyleUrls() {
        return {
            "$": ["bar-chart.scss"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["bar-chart.css"]
        };
    }
    static get properties() {
        return {
            "afVariation": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "BarChartVariation",
                    "resolved": "BarChartVariation.Horizontal | BarChartVariation.Vertical",
                    "references": {
                        "BarChartVariation": {
                            "location": "import",
                            "path": "./bar-chart-variation.enum",
                            "id": "src/components/_chart/bar-chart/bar-chart-variation.enum.ts::BarChartVariation"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "S\u00E4tter orienteringen p\u00E5 diagrammet, kan vara vertikalt eller horisontellt, vertikalt \u00E4r f\u00F6rvalt."
                },
                "getter": false,
                "setter": false,
                "attribute": "af-variation",
                "reflect": false,
                "defaultValue": "BarChartVariation.Vertical"
            },
            "afHeadingLevel": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "En str\u00E4ng med rubrikniv\u00E5n du vill ha i diagrammet, default \u00E4r 'h3'"
                },
                "getter": false,
                "setter": false,
                "attribute": "af-heading-level",
                "reflect": false,
                "defaultValue": "'h3'"
            },
            "afId": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "(Frivillig) Om du vill att komponenten ska ha ett unikt ID, kan du skicka in detta h\u00E4r, annars genereras ett automatiskt"
                },
                "getter": false,
                "setter": false,
                "attribute": "af-id",
                "reflect": false,
                "defaultValue": "randomIdGenerator('tooltip')"
            },
            "afChartData": {
                "type": "string",
                "mutable": true,
                "complexType": {
                    "original": "BarChartData | string",
                    "resolved": "BarChartData | string",
                    "references": {
                        "BarChartData": {
                            "location": "import",
                            "path": "../interfaces/bar-chart-data.interface",
                            "id": "src/components/_chart/interfaces/bar-chart-data.interface.ts::BarChartData"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Datan som ska visas upp i stapeldiagrammet, kan vara av antingen typen BarChartData, eller str\u00E4ngifierad BarChartData"
                },
                "getter": false,
                "setter": false,
                "attribute": "af-chart-data",
                "reflect": false
            }
        };
    }
    static get elementRef() { return "hostElement"; }
    static get watchers() {
        return [{
                "propName": "afChartData",
                "methodName": "afChartDataUpdate"
            }];
    }
}
