import * as d3 from "d3";
import HorizontalStackedbarOptions from './HorizontalStackedbarOptions';
import { getDigit, getLetter } from '../../../support/Strings';
var HorizontalStackedbar = /** @class */ (function () {
    function HorizontalStackedbar(options) {
        if (options === void 0) { options = new HorizontalStackedbarOptions(); }
        this.idMap = new Map();
        this.margin = { top: 0, right: 0, bottom: 0, left: 0 };
        this.options = options;
    }
    HorizontalStackedbar.prototype.render = function () {
        var div = document.createElement("div");
        div.classList.add("lto-vis-stackedbar");
        div.innerHTML = "<svg viewBox=\"0 0 " + this.options.width + " " + this.options.height + "\"></svg>";
        if (this.options.showAxis) {
            this.margin.right = 20;
            this.margin.left = 40;
            this.margin.bottom = 40;
        }
        if (this.options.showLegend) {
            this.margin.top = this.options.height * 0.35;
        }
        return div;
    };
    HorizontalStackedbar.prototype.init = function (element) {
        var _this = this;
        this.options.data.then(function (data) {
            var svg = d3.select(element.querySelector("svg"));
            var width = _this.options.width - _this.margin.left - _this.margin.right;
            var height = _this.options.height - _this.margin.top - _this.margin.bottom;
            var g = svg.append("g");
            _this.xAxis = d3.scaleLinear().rangeRound([_this.margin.left, width + _this.margin.left]);
            _this.yAxis = d3.scaleBand().rangeRound([height + _this.margin.top, 0]).padding(0.0).align(0.1);
            var layers;
            var rect;
            if (_this.options.sort) {
                data.sort(function (a, b) { return b.total - a.total; });
            }
            var columns = _this.getLabels(data);
            var numStates = data.length;
            var stack = d3.stack().keys(columns);
            layers = stack(data).map(function (layer) { return layer.map(function (e, i) {
                return {
                    type: e.data.type,
                    x: _this.getValues(columns, e.data, "values")[columns.indexOf(layer.key)],
                    y: i,
                    column: layer.key,
                    barLabels: _this.getValues(columns, e.data, "barLabels")[columns.indexOf(layer.key)],
                };
            }); });
            for (var s = 0; s < numStates; ++s) {
                var x0 = 0;
                for (var ag = 0; ag < columns.length; ++ag) {
                    var e = layers[ag][s];
                    e.x0 = x0;
                    x0 += e.x;
                }
            }
            /*
             * Calculate the maximum of the total populations,
             * and the maximum of the age groups.
             */
            // const yGroupMax = d3.max(layers, (layer: any) => d3.max(layer, (d: any) => d.y));
            var xStackMax = parseFloat(d3.max(layers, function (layer) { return d3.max(layer, function (d) { return d.x0 + d.x; }); }));
            /*
             * Set the domains for the x-, y-axis and categorical color scales.
             */
            _this.yAxis.domain(data.map(function (d) { return d.type; }));
            // @ts-ignore
            _this.xAxis.domain([0, d3.max(data, function (d) { return _this.sumup(d); })]).nice();
            /*
             * Render intial state of bars
             */
            g.selectAll(".serie")
                .data(layers)
                .enter().append("g")
                .attr("class", function (d) { return "serie lto-vis-" + getDigit(_this.idMap, d[0].column) + " lto-vis-" + getLetter(_this.idMap, d[0].column); })
                .selectAll("rect")
                .data(function (d) { return d; })
                .enter().append("rect")
                .attr("x", 0)
                .attr("y", function (d) { return _this.yAxis(d.type); })
                .attr("width", 0)
                .attr("height", _this.yAxis.bandwidth());
            rect = g.selectAll("rect");
            // Animation to gradually "grow" the bars from the y-axis.
            rect.transition()
                .delay(function (d, i) { return i; })
                .attr("x", function (d) { return _this.xAxis(d.x0); })
                .attr("width", function (d) { return _this.getBarWidth(d); })
                .attr("class", function (d) { return d.column; });
            // bar tooltips
            rect.append("svg:title")
                .text(function (d) { return d.column + ": " + d.x; });
            // render bar labels
            g.selectAll(".serie")
                .append("text")
                .attr("class", "axis axis--x")
                .attr("text-anchor", "middle")
                .attr("x", function (d) { return _this.xAxis(d[0].x0) + (_this.getBarWidth(d[0]) / 2); })
                .attr("y", _this.yAxis.bandwidth() / 2)
                .attr("alignment-baseline", "middle")
                .text(function (d) { return d[0].barLabels; })
                .style('fill', 'white');
            if (_this.options.showAxis) {
                _this.renderAxis(g, svg, width, height);
            }
            if (_this.options.showLegend) {
                var transition = _this.transitionStacked(g, xStackMax);
                transition.on("end", function () { return _this.renderLegend(g, columns); });
            }
        });
    };
    HorizontalStackedbar.prototype.renderAxis = function (g, svg, width, height) {
        g.append("g")
            .attr("class", "axis axis--x")
            .attr("transform", "translate(0," + (height + this.margin.top) + ")")
            .call(d3.axisBottom(this.xAxis));
        // Labels
        svg.append("text")
            .attr("class", "axis axis--x")
            .attr("text-anchor", "middle")
            .attr("transform", "translate(" + ((width / 2) + this.margin.left) + "," + (height + this.margin.top + 35) + ")")
            .text(this.options.textY);
        svg.append("text")
            .attr("class", "axis axis--y")
            .attr("text-anchor", "middle")
            .attr("transform", "translate(0," + ((height / 2) + this.margin.top) + ")rotate(-90)")
            .attr("dy", "20.0")
            .text(this.options.textX);
    };
    HorizontalStackedbar.prototype.getBarWidth = function (d) {
        return Math.abs(this.xAxis(d.x + d.x0) - this.xAxis(d.x0));
    };
    HorizontalStackedbar.prototype.getBarHeight = function () {
        return this.yAxis.bandwidth() - this.margin.top;
    };
    HorizontalStackedbar.prototype.renderLegend = function (g, columns) {
        var _this = this;
        var elementsPerRow = 3;
        var elementWidth = (this.options.width - this.margin.left) / elementsPerRow;
        var legend = g.selectAll(".legend")
            .data(columns)
            .enter().append("g")
            .attr("class", "legend")
            .attr("transform", function (d, i) { return "translate(" + (((i % elementsPerRow) * elementWidth) + _this.margin.left) + ", " + (Math.floor(i / elementsPerRow) * 20) + ")"; });
        var rectSize = 0.036 * this.options.width;
        legend.append("rect")
            .attr("x", 0)
            .attr("width", rectSize)
            .attr("height", rectSize)
            .attr("class", function (d) { return "serie lto-vis-" + getDigit(_this.idMap, d) + " lto-vis-" + getLetter(_this.idMap, d); });
        legend.append("circle")
            .attr("cx", rectSize / 2)
            .attr("cy", rectSize / 2)
            .attr("r", rectSize / 2)
            .attr("class", function (d) { return "serie lto-vis-" + getDigit(_this.idMap, d) + " lto-vis-" + getLetter(_this.idMap, d); });
        legend.append("text")
            .attr("x", rectSize * 1.12)
            .attr("y", rectSize / 2)
            .attr("dy", ".35em")
            .attr("text-anchor", "start")
            .text(function (d) { return d; });
    };
    HorizontalStackedbar.prototype.renderBarLabels = function (g, xStackMax) {
        var _this = this;
        g.selectAll(".serie").selectAll("text")
            .transition()
            .duration(500)
            .attr("y", function (d) { return _this.margin.top + _this.yAxis(d[0].type) + (_this.getBarHeight() / 2); })
            .attr("x", function (d) { return _this.xAxis(d[0].x0) + (_this.getBarWidth(d[0]) / 2); })
            .attr("class", function (d) { return d[0].x / xStackMax < 0.1 ? "lower-10-pct" : "higher-10-pct"; });
    };
    /*
     * Reset the domain for the x-axis scaling to maximum of the x axis totals,
     * transition the y-axis changes to the bar heights, and then transition the
     * x-axis changes to the bar widths.
     */
    HorizontalStackedbar.prototype.transitionStacked = function (g, xStackMax) {
        var _this = this;
        this.xAxis.domain([0, xStackMax]);
        return g.selectAll("rect").transition()
            .duration(500)
            .delay(function (d, i) { return i; })
            .attr("x", function (d) { return _this.xAxis(d.x0); })
            .attr("width", function (d) { return _this.xAxis(d.x + d.x0) - _this.xAxis(d.x0); })
            .transition()
            .call(function () { return _this.renderBarLabels(g, xStackMax); })
            .attr("y", function (d) {
            return _this.margin.top + _this.yAxis(d.type);
        })
            .attr("height", this.getBarHeight());
    };
    HorizontalStackedbar.prototype.sumup = function (data) {
        return data.values.reduce(function (sum, val) { return sum + val; }, 0);
    };
    HorizontalStackedbar.prototype.getLabels = function (data) {
        var labels = [];
        data.forEach(function (e) {
            e.labels.forEach(function (key) {
                if (key !== "type") {
                    if (labels.indexOf(key) < 0) {
                        labels.push(key);
                    }
                }
            });
        });
        return labels;
    };
    HorizontalStackedbar.prototype.getValues = function (labels, data, fieldName) {
        var values = Array.from({ length: labels.length }, function () { return 0; });
        data.labels.forEach(function (key) {
            var index = labels.indexOf(key);
            values[labels.indexOf(key)] = data[fieldName].length > index ? data[fieldName][index] : 0;
        });
        return values;
    };
    return HorizontalStackedbar;
}());
export default HorizontalStackedbar;
//# sourceMappingURL=HorizontalStackedbar.js.map