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 _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 _instanceof(left, right) {
    "@swc/helpers - instanceof";
    if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
        return !!right[Symbol.hasInstance](left);
    } else {
        return left instanceof right;
    }
}
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 { min } from "d3-array";
import { arc } from "d3-shape";
import { colorContrast } from "@d3plus/color";
import { assign, backgroundColor, elem } from "@d3plus/dom";
import { Path } from "../shapes/index.js";
import { TextBox } from "../components/index.js";
import { accessor, configPrep, constant, getProp } from "../utils/index.js";
import Viz from "./Viz.js";
import prepData from "./helpers/matrixData.js";
var tau = Math.PI * 2;
var RadialMatrix = /*#__PURE__*/ function(Viz) {
    "use strict";
    _inherits(RadialMatrix, Viz);
    function RadialMatrix() {
        _class_call_check(this, RadialMatrix);
        var _this;
        _this = _call_super(this, RadialMatrix);
        _this._cellPadding = 2;
        _this._column = accessor("column");
        _this._columnConfig = {
            shapeConfig: {
                labelConfig: {
                    fontColor: function fontColor() {
                        var bg = _this._select ? backgroundColor(_this._select.node()) : "rgb(255, 255, 255)";
                        return colorContrast(bg);
                    },
                    padding: 5,
                    textAnchor: function textAnchor(d) {
                        return [
                            0,
                            180
                        ].includes(d.angle) ? "middle" : [
                            2,
                            3
                        ].includes(d.quadrant) ? "end" : "start";
                    },
                    verticalAlign: function verticalAlign(d) {
                        return [
                            90,
                            270
                        ].includes(d.angle) ? "middle" : [
                            2,
                            1
                        ].includes(d.quadrant) ? "bottom" : "top";
                    }
                }
            }
        };
        _this._columnSort = function(a, b) {
            return "".concat(a).localeCompare("".concat(b));
        };
        _this._innerRadius = function(radius) {
            return radius / 5;
        };
        _this._label = function(d, i) {
            return "".concat(getProp.bind(_this)("row", d, i), " / ").concat(getProp.bind(_this)("column", d, i));
        };
        var defaultMouseMoveShape = _this._on["mousemove.shape"];
        _this._on["mousemove.shape"] = function(d, i, x, event) {
            defaultMouseMoveShape(d, i, x, event);
            var row = getProp.bind(_this)("row", d, i);
            var column = getProp.bind(_this)("column", d, i);
            _this.hover(function(h, ii) {
                return getProp.bind(_this)("row", h, ii) === row || getProp.bind(_this)("column", h, ii) === column;
            });
        };
        _this._row = accessor("row");
        _this._rowSort = function(a, b) {
            return "".concat(a).localeCompare("".concat(b));
        };
        _this._columnLabels = new TextBox();
        return _this;
    }
    _create_class(RadialMatrix, [
        {
            /**
      Extends the draw behavior of the abstract Viz class.
      @private
  */ key: "_draw",
            value: function _draw(callback) {
                var _this = this;
                var _prepData_bind = prepData.bind(this)(this._filteredData), rowValues = _prepData_bind.rowValues, columnValues = _prepData_bind.columnValues, shapeData = _prepData_bind.shapeData;
                if (!rowValues.length || !columnValues.length) return this;
                _get(_get_prototype_of(RadialMatrix.prototype), "_draw", this).call(this, callback);
                var height = this._height - this._margin.top - this._margin.bottom, parent = this._select, transition = this._transition, width = this._width - this._margin.left - this._margin.right;
                var labelHeight = 50, labelWidth = 100;
                var radius = min([
                    height - labelHeight * 2,
                    width - labelWidth * 2
                ]) / 2, transform = "translate(".concat(width / 2 + this._margin.left, ", ").concat(height / 2 + this._margin.top, ")");
                var flippedColumns = columnValues.slice().reverse();
                flippedColumns.unshift(flippedColumns.pop());
                var total = flippedColumns.length;
                var labelData = flippedColumns.map(function(key, i) {
                    var radians = i / total * tau;
                    var angle = Math.round(radians * 180 / Math.PI);
                    var quadrant = Math.floor((angle + 90) / 90 % 4 + 1);
                    var xMod = [
                        0,
                        180
                    ].includes(angle) ? -labelWidth / 2 : [
                        2,
                        3
                    ].includes(quadrant) ? -labelWidth : 0;
                    var yMod = [
                        90,
                        270
                    ].includes(angle) ? -labelHeight / 2 : [
                        2,
                        1
                    ].includes(quadrant) ? -labelHeight : 0;
                    return {
                        key: key,
                        angle: angle,
                        quadrant: quadrant,
                        radians: radians,
                        x: radius * Math.sin(radians + Math.PI) + xMod,
                        y: radius * Math.cos(radians + Math.PI) + yMod
                    };
                });
                /**
     * Extracts the axis config "labels" Array, if it exists, it filters
     * the column labels by the values included in the Array.
     */ var displayLabels = _instanceof(this._columnConfig.labels, Array) ? labelData.filter(function(d) {
                    return _this._columnConfig.labels.includes(d.key);
                }) : labelData;
                this._columnLabels.data(displayLabels).x(function(d) {
                    return d.x;
                }).y(function(d) {
                    return d.y;
                }).text(function(d) {
                    return d.key;
                }).width(labelWidth).height(labelHeight).config(this._columnConfig.shapeConfig.labelConfig).select(elem("g.d3plus-RadialMatrix-columns", {
                    parent: parent,
                    transition: transition,
                    enter: {
                        transform: transform
                    },
                    update: {
                        transform: transform
                    }
                }).node()).render();
                var innerRadius = this._innerRadius(radius);
                var rowHeight = (radius - innerRadius) / rowValues.length;
                var columnWidth = labelData.length > 1 ? labelData[1].radians - labelData[0].radians : tau;
                var flippedRows = rowValues.slice().reverse();
                var arcData = arc().padAngle(this._cellPadding / radius).innerRadius(function(d) {
                    return innerRadius + flippedRows.indexOf(d.row) * rowHeight + _this._cellPadding / 2;
                }).outerRadius(function(d) {
                    return innerRadius + (flippedRows.indexOf(d.row) + 1) * rowHeight - _this._cellPadding / 2;
                }).startAngle(function(d) {
                    return labelData[columnValues.indexOf(d.column)].radians - columnWidth / 2;
                }).endAngle(function(d) {
                    return labelData[columnValues.indexOf(d.column)].radians + columnWidth / 2;
                });
                this._shapes.push(new Path().data(shapeData).d(arcData).select(elem("g.d3plus-RadialMatrix-arcs", {
                    parent: parent,
                    transition: transition,
                    enter: {
                        transform: transform
                    },
                    update: {
                        transform: transform
                    }
                }).node()).config({
                    id: function id(d) {
                        return _this._ids(d).join("-");
                    },
                    x: 0,
                    y: 0
                }).config(configPrep.bind(this)(this._shapeConfig, "shape", "Path")).render());
                return this;
            }
        },
        {
            /**
      The pixel padding in between each cell.
*/ key: "cellPadding",
            value: function cellPadding(_) {
                return arguments.length ? (this._cellPadding = _, this) : this._cellPadding;
            }
        },
        {
            /**
      Determines which key in your data should be used for each column in the matrix. Can be either a String that matches a key used in every data point, or an accessor function that receives a data point and it's index in the data array, and is expected to return it's column value.

@example
function column(d) {
  return d.name;
}
  */ key: "column",
            value: function column(_) {
                return arguments.length ? (this._column = typeof _ === "function" ? _ : accessor(_), this) : this._column;
            }
        },
        {
            /**
      A pass-through to the underlying [Axis](http://d3plus.org/docs/#Axis) config used for the column labels.
*/ key: "columnConfig",
            value: function columnConfig(_) {
                return arguments.length ? (this._columnConfig = assign(this._columnConfig, _), this) : this._columnConfig;
            }
        },
        {
            /**
      A manual list of IDs to be used for rows.
*/ key: "columnList",
            value: function columnList(_) {
                return arguments.length ? (this._columnList = _, this) : this._columnList;
            }
        },
        {
            /**
      A sort comparator function that is run on the unique set of column values.

@example
function column(a, b) {
  return a.localeCompare(b);
}
  */ key: "columnSort",
            value: function columnSort(_) {
                return arguments.length ? (this._columnSort = _, this) : this._columnSort;
            }
        },
        {
            /**
      The radius (in pixels) for the inner donut hole of the diagram. Can either be a static Number, or an accessor function that receives the outer radius as it's only argument.

@example
function(outerRadius) {
  return outerRadius / 5;
}
  */ key: "innerRadius",
            value: function innerRadius(_) {
                return arguments.length ? (this._innerRadius = typeof _ === "function" ? _ : constant(_), this) : this._innerRadius;
            }
        },
        {
            /**
      Determines which key in your data should be used for each row in the matrix. Can be either a String that matches a key used in every data point, or an accessor function that receives a data point and it's index in the data array, and is expected to return it's row value.

@example
function row(d) {
  return d.name;
}
  */ key: "row",
            value: function row(_) {
                return arguments.length ? (this._row = typeof _ === "function" ? _ : accessor(_), this) : this._row;
            }
        },
        {
            /**
      A manual list of IDs to be used for rows.
*/ key: "rowList",
            value: function rowList(_) {
                return arguments.length ? (this._rowList = _, this) : this._rowList;
            }
        },
        {
            /**
      A sort comparator function that is run on the unique set of row values.

@example
function row(a, b) {
  return a.localeCompare(b);
}
  */ key: "rowSort",
            value: function rowSort(_) {
                return arguments.length ? (this._rowSort = _, this) : this._rowSort;
            }
        }
    ]);
    return RadialMatrix;
}(Viz);
/**
    Creates a radial layout of a rows/columns Matrix of any dataset. See [this example](https://d3plus.org/examples/d3plus-matrix/radial-matrix/) for help getting started using the Matrix class.
*/ export { RadialMatrix as default };
