import { BaseChart as e } from "../base.js";
import { ChartTooltip as t } from "../tooltip.js";
import { defaultColors as n, formatNumber as r, hexToRgba as i } from "../utils.js";
//#region src/charts/sankey/index.ts
var a = 20, o = 10, s = .4, c = "11px system-ui, sans-serif", l = "#334155", u = class extends e {
	nodes;
	links;
	nodeWidth;
	nodePadding;
	linkOpacity;
	tooltipEnabled;
	tooltipFormat;
	tooltip;
	computedNodes;
	computedLinks;
	colors;
	handleMouseMove;
	handleMouseLeave;
	hoveredNodeId;
	hoveredLinkIndex;
	constructor(e) {
		super(e), this.nodes = e.nodes, this.links = e.links, this.nodeWidth = e.nodeWidth ?? a, this.nodePadding = e.nodePadding ?? o, this.linkOpacity = e.linkOpacity ?? s, this.tooltipEnabled = e.tooltip?.enabled !== !1, this.tooltipFormat = e.tooltip?.format ?? null, this.tooltip = null, this.computedNodes = [], this.computedLinks = [], this.colors = n(), this.handleMouseMove = null, this.handleMouseLeave = null, this.hoveredNodeId = null, this.hoveredLinkIndex = -1, this.tooltipEnabled && this.setupTooltip(), this.render();
	}
	computeLayout() {
		let e = this.plotArea, t = /* @__PURE__ */ new Map();
		for (let e = 0; e < this.nodes.length; e++) {
			let n = this.nodes[e];
			n !== void 0 && t.set(n.id, {
				id: n.id,
				label: n.label,
				color: n.color ?? this.colors[e % this.colors.length] ?? "#3b82f6",
				x: 0,
				y: 0,
				width: this.nodeWidth,
				height: 0,
				column: 0,
				value: 0,
				sourceLinks: [],
				targetLinks: []
			});
		}
		let n = /* @__PURE__ */ new Map();
		for (let e of this.nodes) n.set(e.id, 0);
		for (let e of this.links) {
			let t = n.get(e.target);
			t !== void 0 && n.set(e.target, t + 1);
		}
		let r = /* @__PURE__ */ new Set(), i = [];
		for (let [e, t] of n) t === 0 && i.push({
			id: e,
			col: 0
		});
		if (i.length === 0 && this.nodes.length > 0) {
			let e = this.nodes[0];
			e !== void 0 && i.push({
				id: e.id,
				col: 0
			});
		}
		let a = 0;
		for (; i.length > 0;) {
			let e = i.shift();
			if (e === void 0 || r.has(e.id)) continue;
			r.add(e.id);
			let n = t.get(e.id);
			n !== void 0 && (n.column = Math.max(n.column, e.col), n.column > a && (a = n.column));
			for (let n of this.links) if (n.source === e.id && !r.has(n.target)) {
				let r = t.get(n.target);
				r !== void 0 && (r.column = Math.max(r.column, e.col + 1)), i.push({
					id: n.target,
					col: e.col + 1
				});
			}
		}
		for (let e of t.values()) e.column > a && (a = e.column);
		for (let e of this.links) {
			let n = t.get(e.source), r = t.get(e.target);
			n !== void 0 && (n.value += e.value), r !== void 0 && (r.value += e.value);
		}
		for (let e of t.values()) {
			let t = 0, n = 0;
			for (let r of this.links) r.source === e.id && (t += r.value), r.target === e.id && (n += r.value);
			e.value = Math.max(t, n);
		}
		let o = a > 0 ? (e.width - this.nodeWidth) / a : 0, s = /* @__PURE__ */ new Map();
		for (let n of t.values()) {
			n.x = e.x + n.column * o;
			let t = s.get(n.column);
			t === void 0 ? s.set(n.column, [n]) : t.push(n);
		}
		for (let t of s.values()) {
			let n = t.reduce((e, t) => e + t.value, 0), r = this.nodePadding * Math.max(0, t.length - 1), i = e.height - r, a = e.y;
			for (let e of t) {
				let r = n > 0 ? e.value / n * i : i / t.length;
				e.height = Math.max(1, r), e.y = a, a += e.height + this.nodePadding;
			}
		}
		this.computedLinks = [];
		let c = /* @__PURE__ */ new Map(), l = /* @__PURE__ */ new Map();
		for (let e of this.links) {
			let n = t.get(e.source), r = t.get(e.target);
			if (n === void 0 || r === void 0) continue;
			let i = n.value > 0 ? e.value / n.value * n.height : 0, a = c.get(n.id) ?? 0, o = l.get(r.id) ?? 0, s = {
				source: n,
				target: r,
				value: e.value,
				color: e.color ?? n.color,
				sourceY: n.y + a + i / 2,
				targetY: r.y + o + i / 2,
				width: i
			};
			c.set(n.id, a + i), l.set(r.id, o + i), s.source.sourceLinks.push(s), s.target.targetLinks.push(s), this.computedLinks.push(s);
		}
		this.computedNodes = [...t.values()];
	}
	setupTooltip() {
		this.tooltip = new t(this.container), this.handleMouseMove = (e) => {
			let t = this.canvas.getBoundingClientRect(), n = e.clientX - t.left, i = e.clientY - t.top, a = null;
			for (let e of this.computedNodes) if (n >= e.x && n <= e.x + e.width && i >= e.y && i <= e.y + e.height) {
				a = e.id;
				break;
			}
			let o = -1;
			if (a === null) for (let e = 0; e < this.computedLinks.length; e++) {
				let t = this.computedLinks[e];
				if (t !== void 0 && this.isPointOnLink(n, i, t)) {
					o = e;
					break;
				}
			}
			let s = a !== this.hoveredNodeId || o !== this.hoveredLinkIndex;
			if (this.hoveredNodeId = a, this.hoveredLinkIndex = o, s && this.render(), a !== null) {
				let e = this.computedNodes.find((e) => e.id === a);
				if (e !== void 0) {
					let t;
					t = this.tooltipFormat === null ? `<strong>${e.label}</strong><br/>Total: ${r(e.value)}` : this.tooltipFormat(e.value, e.label, ""), this.tooltip?.show(n, i, t);
				}
			} else if (o >= 0) {
				let e = this.computedLinks[o];
				if (e !== void 0) {
					let t;
					t = this.tooltipFormat === null ? `<strong>${e.source.label} &rarr; ${e.target.label}</strong><br/>Value: ${r(e.value)}` : this.tooltipFormat(e.value, e.source.label, e.target.label), this.tooltip?.show(n, i, t);
				}
			} else this.tooltip?.hide();
		}, this.handleMouseLeave = () => {
			(this.hoveredNodeId !== null || this.hoveredLinkIndex !== -1) && (this.hoveredNodeId = null, this.hoveredLinkIndex = -1, this.render()), this.tooltip?.hide();
		}, this.canvas.addEventListener("mousemove", this.handleMouseMove), this.canvas.addEventListener("mouseleave", this.handleMouseLeave);
	}
	isPointOnLink(e, t, n) {
		let r = n.source.x + n.source.width, i = n.target.x, a = n.width / 2;
		if (e < r || e > i) return !1;
		let o = r + (i - r) / 3, s = i - (i - r) / 3, c = this.solveBezierT(r, o, s, i, e), l = this.cubicBezier(n.sourceY, n.sourceY, n.targetY, n.targetY, c);
		return Math.abs(t - l) <= a + 4;
	}
	solveBezierT(e, t, n, r, i) {
		let a = e, o = r;
		return o === a ? 0 : (i - a) / (o - a);
	}
	cubicBezier(e, t, n, r, i) {
		let a = 1 - i;
		return a * a * a * e + 3 * a * a * i * t + 3 * a * i * i * n + i * i * i * r;
	}
	render() {
		this.clear(), this.computeLayout();
		let { ctx: e } = this;
		e.save();
		for (let t = 0; t < this.computedLinks.length; t++) {
			let n = this.computedLinks[t];
			if (n === void 0) continue;
			let r = this.hoveredNodeId !== null && (n.source.id === this.hoveredNodeId || n.target.id === this.hoveredNodeId), a = t === this.hoveredLinkIndex, o = r || a ? Math.min(this.linkOpacity * 2, .9) : this.linkOpacity, s = n.source.x + n.source.width, c = n.sourceY, l = n.target.x, u = n.targetY, d = s + (l - s) * .4, f = l - (l - s) * .4;
			e.beginPath(), e.moveTo(s, c - n.width / 2), e.bezierCurveTo(d, c - n.width / 2, f, u - n.width / 2, l, u - n.width / 2), e.lineTo(l, u + n.width / 2), e.bezierCurveTo(f, u + n.width / 2, d, c + n.width / 2, s, c + n.width / 2), e.closePath(), e.fillStyle = i(n.color, o), e.fill();
		}
		e.restore(), e.save();
		for (let t of this.computedNodes) {
			let n = t.id === this.hoveredNodeId;
			e.fillStyle = n ? i(t.color, .85) : t.color, e.fillRect(t.x, t.y, t.width, t.height), n && (e.strokeStyle = "#1e293b", e.lineWidth = 2, e.strokeRect(t.x, t.y, t.width, t.height)), e.fillStyle = l, e.font = c, e.textBaseline = "middle";
			let r = t.y + t.height / 2;
			t.column === 0 ? (e.textAlign = "right", e.fillText(t.label, t.x - 6, r)) : (e.textAlign = "left", e.fillText(t.label, t.x + t.width + 6, r));
		}
		e.restore();
	}
	update(e, t) {
		this.nodes = e, this.links = t, this.hoveredNodeId = null, this.hoveredLinkIndex = -1, this.render();
	}
	destroy() {
		this.handleMouseMove !== null && this.canvas.removeEventListener("mousemove", this.handleMouseMove), this.handleMouseLeave !== null && this.canvas.removeEventListener("mouseleave", this.handleMouseLeave), this.tooltip?.destroy(), super.destroy();
	}
};
//#endregion
export { u as SankeyChart };

//# sourceMappingURL=index.js.map