function _assert_this_initialized(self) {
    if (self === void 0) {
        throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
    }
    return self;
}
function _call_super(_this, derived, args) {
    derived = _get_prototype_of(derived);
    return _possible_constructor_return(_this, _is_native_reflect_construct() ? Reflect.construct(derived, args || [], _get_prototype_of(_this).constructor) : derived.apply(_this, args));
}
function _class_call_check(instance, Constructor) {
    if (!(instance instanceof Constructor)) {
        throw new TypeError("Cannot call a class as a function");
    }
}
function _defineProperties(target, props) {
    for(var i = 0; i < props.length; i++){
        var descriptor = props[i];
        descriptor.enumerable = descriptor.enumerable || false;
        descriptor.configurable = true;
        if ("value" in descriptor) descriptor.writable = true;
        Object.defineProperty(target, descriptor.key, descriptor);
    }
}
function _create_class(Constructor, protoProps, staticProps) {
    if (protoProps) _defineProperties(Constructor.prototype, protoProps);
    if (staticProps) _defineProperties(Constructor, staticProps);
    return Constructor;
}
function _define_property(obj, key, value) {
    if (key in obj) {
        Object.defineProperty(obj, key, {
            value: value,
            enumerable: true,
            configurable: true,
            writable: true
        });
    } else {
        obj[key] = value;
    }
    return obj;
}
function _get(target, property, receiver) {
    if (typeof Reflect !== "undefined" && Reflect.get) {
        _get = Reflect.get;
    } else {
        _get = function get(target, property, receiver) {
            var base = _super_prop_base(target, property);
            if (!base) return;
            var desc = Object.getOwnPropertyDescriptor(base, property);
            if (desc.get) {
                return desc.get.call(receiver || target);
            }
            return desc.value;
        };
    }
    return _get(target, property, receiver || target);
}
function _get_prototype_of(o) {
    _get_prototype_of = Object.setPrototypeOf ? Object.getPrototypeOf : function getPrototypeOf(o) {
        return o.__proto__ || Object.getPrototypeOf(o);
    };
    return _get_prototype_of(o);
}
function _inherits(subClass, superClass) {
    if (typeof superClass !== "function" && superClass !== null) {
        throw new TypeError("Super expression must either be null or a function");
    }
    subClass.prototype = Object.create(superClass && superClass.prototype, {
        constructor: {
            value: subClass,
            writable: true,
            configurable: true
        }
    });
    if (superClass) _set_prototype_of(subClass, superClass);
}
function _possible_constructor_return(self, call) {
    if (call && (_type_of(call) === "object" || typeof call === "function")) {
        return call;
    }
    return _assert_this_initialized(self);
}
function _set_prototype_of(o, p) {
    _set_prototype_of = Object.setPrototypeOf || function setPrototypeOf(o, p) {
        o.__proto__ = p;
        return o;
    };
    return _set_prototype_of(o, p);
}
function _super_prop_base(object, property) {
    while(!Object.prototype.hasOwnProperty.call(object, property)){
        object = _get_prototype_of(object);
        if (object === null) break;
    }
    return object;
}
function _type_of(obj) {
    "@swc/helpers - typeof";
    return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
}
function _is_native_reflect_construct() {
    try {
        var result = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() {}));
    } catch (_) {}
    return (_is_native_reflect_construct = function() {
        return !!result;
    })();
}
import { extent, min, max } from "d3-array";
import { hierarchy, tree } from "d3-hierarchy";
import { scaleLinear } from "d3-scale";
import { colorContrast, colorDefaults } from "@d3plus/color";
import { assign, backgroundColor, elem } from "@d3plus/dom";
import { merge, nest } from "@d3plus/data";
import { configPrep, constant } from "../utils/index.js";
import * as shapes from "../shapes/index.js";
import { legendLabel } from "./drawSteps/drawLegend.js";
import Viz from "./Viz.js";
var Tree = /*#__PURE__*/ function(Viz) {
    "use strict";
    _inherits(Tree, Viz);
    function Tree() {
        _class_call_check(this, Tree);
        var _this;
        _this = _call_super(this, Tree);
        _this._orient = "vertical";
        _this._separation = function(a, b) {
            return a.parent === b.parent ? 1 : 2;
        };
        _this._legendTooltip = assign(_this._legendTooltip, {
            title: legendLabel.bind(_this)
        });
        _this._previousShapes = [];
        _this._shape = constant("Circle");
        _this._shapeConfig = assign(_this._shapeConfig, {
            ariaLabel: function ariaLabel(d, i) {
                return _this._treeData ? "".concat(_this._treeData[i].depth, ". ").concat(_this._drawLabel(d, i), ".") : "";
            },
            labelConfig: {
                fontColor: function fontColor() {
                    var bg = _this._select ? backgroundColor(_this._select.node()) : "rgb(255, 255, 255)";
                    return colorContrast(bg);
                }
            },
            Path: {
                fill: "none",
                stroke: colorDefaults.missing,
                strokeWidth: 2
            },
            r: constant(7),
            width: constant(12),
            height: constant(12)
        });
        _this._tooltipConfig = assign(_this._tooltipConfig, {
            title: function title(d, i, x) {
                return _this._drawLabel(d, i, x.depth - 1);
            }
        });
        _this._tree = tree();
        return _this;
    }
    _create_class(Tree, [
        {
            /**
      Extends the draw behavior of the abstract Viz class.
      @private
*/ key: "_draw",
            value: function _draw(callback) {
                var _this = this;
                _get(_get_prototype_of(Tree.prototype), "_draw", this).call(this, callback);
                var isVertical = this._orient === "vertical";
                var isHorizontal = this._orient === "horizontal";
                var height = isVertical ? this._height - this._margin.top - this._margin.bottom : this._width - this._margin.left - this._margin.right, left = isVertical ? "left" : "top", that = this, transform = "translate(".concat(this._margin.left, ", ").concat(this._margin.top, ")"), width = isHorizontal ? this._height - this._margin.top - this._margin.bottom : this._width - this._margin.left - this._margin.right;
                var treeData = this._treeData = this._tree.separation(this._separation).size([
                    width,
                    height
                ])(hierarchy({
                    key: "root",
                    values: nest(this._filteredData, this._groupBy.slice(0, this._drawDepth + 1))
                }, function(d) {
                    return d.key && d.values ? d.values : null;
                }).sort(this._sort)).descendants().filter(function(d) {
                    return d.depth <= _this._groupBy.length && d.parent;
                });
                /**
        Merges the values of a given nest branch.
        @private
*/ function flattenBranchData(branch) {
                    return merge(branch.values.map(function(l) {
                        return l.key && l.values ? flattenBranchData(l) : l;
                    }), that._aggs);
                }
                treeData.forEach(function(d, i) {
                    if (d.data.key && d.data.values) d.data = flattenBranchData(d.data);
                    d.__d3plus__ = true;
                    d.i = i;
                });
                var r = this._shapeConfig.r;
                if (typeof r !== "function") r = constant(r);
                var rBufferRoot = max(treeData, function(d) {
                    return d.depth === 1 ? r(d.data, d.i) : 0;
                });
                var rBufferEnd = max(treeData, function(d) {
                    return d.children ? 0 : r(d.data, d.i);
                });
                var yExtent = extent(treeData, function(d) {
                    return d.y;
                });
                this._labelHeight = min([
                    isVertical ? 50 : 100,
                    (yExtent[1] - rBufferRoot - rBufferEnd) / (this._groupBy.length + 1)
                ]);
                this._labelWidths = nest(treeData, function(d) {
                    return d.depth;
                }).map(function(d) {
                    return d.values.reduce(function(num, v, i) {
                        var vals = d.values;
                        var next = i < vals.length - 1 ? vals[i + 1].x : width + _this._margin[left], prev = i ? vals[i - 1].x : _this._margin[left];
                        return min([
                            num,
                            next - v.x,
                            v.x - prev
                        ]);
                    }, width);
                });
                var yScale = scaleLinear().domain(yExtent).range([
                    rBufferRoot + this._labelHeight,
                    height - rBufferEnd - this._labelHeight
                ]);
                treeData.forEach(function(d) {
                    var val = yScale(d.y);
                    if (isHorizontal) {
                        d.y = d.x;
                        d.x = val;
                    } else d.y = val;
                });
                var elemObject = {
                    parent: this._select,
                    enter: {
                        transform: transform
                    },
                    update: {
                        transform: transform
                    }
                };
                this._shapes.push(new shapes.Path().data(treeData.filter(function(d) {
                    return d.depth > 1;
                }).map(function(d) {
                    return assign({}, d);
                })).select(elem("g.d3plus-Tree-Links", elemObject).node()).config(configPrep.bind(this)(this._shapeConfig, "shape", "Path")).config({
                    d: function d(d) {
                        var r = _this._shapeConfig.r;
                        if (typeof r === "function") r = r(d.data, d.i);
                        var px = d.parent.x - d.x + (isVertical ? 0 : r), py = d.parent.y - d.y + (isVertical ? r : 0), x = isVertical ? 0 : -r, y = isVertical ? -r : 0;
                        return isVertical ? "M".concat(x, ",").concat(y, "C").concat(x, ",").concat((y + py) / 2, " ").concat(px, ",").concat((y + py) / 2, " ").concat(px, ",").concat(py) : "M".concat(x, ",").concat(y, "C").concat((x + px) / 2, ",").concat(y, " ").concat((x + px) / 2, ",").concat(py, " ").concat(px, ",").concat(py);
                    },
                    id: function id(d, i) {
                        return _this._ids(d, i)[d.depth - 1];
                    }
                }).render());
                var shapeConfig = {
                    id: function id(d, i) {
                        return _this._ids(d, i)[d.depth - 1];
                    },
                    label: function label(d, i) {
                        if (_this._label) return _this._label(d.data, i);
                        var ids = _this._ids(d, i).slice(0, d.depth);
                        return ids[ids.length - 1];
                    },
                    labelConfig: {
                        textAnchor: function textAnchor(d, i, x) {
                            return isVertical ? "middle" : x.children && x.depth !== _this._drawDepth + 1 ? "end" : "start";
                        },
                        verticalAlign: function verticalAlign(d, i, x) {
                            return isVertical ? x.depth === 1 ? "bottom" : "top" : "middle";
                        }
                    },
                    hitArea: function hitArea(d, i, s) {
                        var h = _this._labelHeight, offset = s.r ? s.r : isVertical ? s.height / 2 : s.width / 2, w = _this._labelWidths[d.depth - 1];
                        return {
                            width: isVertical ? w : offset * 2 + w,
                            height: isHorizontal ? h : offset * 2 + h,
                            x: isVertical ? -w / 2 : d.children && d.depth !== _this._groupBy.length ? -(offset + w) : -offset,
                            y: isHorizontal ? -h / 2 : d.children && d.depth !== _this._groupBy.length ? -(offset + _this._labelHeight) : -offset
                        };
                    },
                    labelBounds: function labelBounds(d, i, s) {
                        var h = _this._labelHeight, height = isVertical ? "height" : "width", offset = s.r ? s.r : isVertical ? s.height / 2 : s.width / 2, w = _this._labelWidths[d.depth - 1], width = isVertical ? "width" : "height", x = isVertical ? "x" : "y", y = isVertical ? "y" : "x";
                        var _obj;
                        return _obj = {}, _define_property(_obj, width, w), _define_property(_obj, height, h), _define_property(_obj, x, -w / 2), _define_property(_obj, y, d.children && d.depth !== _this._groupBy.length ? -(offset + h) : offset), _obj;
                    }
                };
                var shapeData = nest(treeData, function(d) {
                    return _this._shape(d.data);
                });
                var dataShapes = shapeData.map(function(d) {
                    return d.key;
                });
                var exitShapes = this._previousShapes.filter(function(d) {
                    return !dataShapes.includes(d);
                });
                shapeData.concat(exitShapes.map(function(key) {
                    return {
                        key: key,
                        values: []
                    };
                })).forEach(function(param) {
                    var key = param.key, values = param.values;
                    _this._shapes.push(new shapes[key]().data(values).select(elem("g.d3plus-Tree-".concat(key), elemObject).node()).config(configPrep.bind(_this)(_this._shapeConfig, "shape", key)).config(shapeConfig).render());
                });
                this._previousShapes = dataShapes;
                return this;
            }
        },
        {
            /**
      Changes the orientation of the entire Tree, either "vertical" (top to bottom) or "horizontal" (left to right).
*/ key: "orient",
            value: function orient(_) {
                return arguments.length ? (this._orient = _, this) : this._orient;
            }
        },
        {
            /**
      The separation function between neighboring nodes.

From the [d3-hierarchy documentation](https://github.com/d3/d3-hierarchy#tree_separation):
> The separation accessor is used to separate neighboring nodes. The separation function is passed two nodes a and b, and must return the desired separation. The nodes are typically siblings, though the nodes may be more distantly related if the layout decides to place such nodes adjacent.

@example
function separation(a, b) {
  return a.parent === b.parent ? 1 : 2;
}
*/ key: "separation",
            value: function separation(_) {
                return arguments.length ? (this._separation = _, this) : this._separation;
            }
        }
    ]);
    return Tree;
}(Viz);
/**
    Uses d3's [tree layout](https://github.com/d3/d3-hierarchy#tree) to create a tidy tree chart based on an array of data.
*/ export { Tree as default };
