import { n as e, t } from "../../utils-C_mWfcFX.js";
//#region src/visualization/network-graph/index.ts
var n = "http://www.w3.org/2000/svg", r = 20, i = 300, a = 5e3, o = .005, s = .01, c = .9, l = 8, u = [
	"#3b82f6",
	"#ef4444",
	"#10b981",
	"#f59e0b",
	"#8b5cf6",
	"#ec4899",
	"#06b6d4",
	"#f97316",
	"#14b8a6",
	"#6366f1"
], d = class {
	el;
	graphId;
	defaultRadius;
	showLabels;
	onNodeClick;
	onEdgeClick;
	svg;
	mainGroup;
	defsEl;
	nodes;
	edges;
	simNodes = [];
	simEdges = [];
	layout;
	zoomable;
	pannable;
	hoveredNodeId = null;
	viewBox;
	isPanning = !1;
	panStart = {
		x: 0,
		y: 0
	};
	panOrigin = {
		x: 0,
		y: 0
	};
	dragNode = null;
	dragOffset = {
		x: 0,
		y: 0
	};
	boundWheel;
	boundMouseDown;
	boundMouseMove;
	boundMouseUp;
	constructor(i) {
		this.graphId = e("cmm-network-graph"), this.layout = i.layout ?? "force", this.zoomable = i.zoomable !== !1, this.pannable = i.pannable !== !1, this.defaultRadius = i.nodeRadius ?? r, this.showLabels = i.showLabels !== !1, this.onNodeClick = i.onNodeClick, this.onEdgeClick = i.onEdgeClick, this.nodes = [...i.nodes], this.edges = [...i.edges], this.viewBox = {
			x: 0,
			y: 0,
			w: 800,
			h: 600
		}, this.el = document.createElement("div"), this.el.id = this.graphId, this.el.className = this.buildClassName(i.className), this.svg = document.createElementNS(n, "svg"), this.svg.classList.add("cmm-network-graph__svg"), this.defsEl = document.createElementNS(n, "defs"), this.svg.appendChild(this.defsEl), this.mainGroup = document.createElementNS(n, "g"), this.svg.appendChild(this.mainGroup), this.el.appendChild(this.svg), this.createArrowMarker(), t(i.container).appendChild(this.el);
		let a = this.el.getBoundingClientRect();
		a.width > 0 && a.height > 0 && (this.viewBox.w = a.width, this.viewBox.h = a.height), this.boundWheel = (e) => {
			this.handleWheel(e);
		}, this.boundMouseDown = (e) => {
			this.handleMouseDown(e);
		}, this.boundMouseMove = (e) => {
			this.handleMouseMove(e);
		}, this.boundMouseUp = () => {
			this.handleMouseUp();
		}, this.zoomable && this.el.addEventListener("wheel", this.boundWheel, { passive: !1 }), this.el.addEventListener("mousedown", this.boundMouseDown), document.addEventListener("mousemove", this.boundMouseMove), document.addEventListener("mouseup", this.boundMouseUp), this.buildSimulation(), this.applyLayout(), this.renderGraph(), this.zoomToFit();
	}
	update(e, t) {
		this.nodes = [...e], this.edges = [...t], this.hoveredNodeId = null, this.dragNode = null, this.buildSimulation(), this.applyLayout(), this.renderGraph(), this.zoomToFit();
	}
	setLayout(e) {
		this.layout = e, this.applyLayout(), this.renderGraph(), this.zoomToFit();
	}
	zoomToFit() {
		if (this.simNodes.length === 0) return;
		let e = Infinity, t = Infinity, n = -Infinity, r = -Infinity;
		for (let i of this.simNodes) {
			let a = i.radius;
			i.x - a < e && (e = i.x - a), i.y - a < t && (t = i.y - a), i.x + a > n && (n = i.x + a), i.y + a > r && (r = i.y + a);
		}
		this.viewBox = {
			x: e - 60,
			y: t - 60,
			w: n - e + 120,
			h: r - t + 120
		}, this.applyViewBox();
	}
	destroy() {
		this.zoomable && this.el.removeEventListener("wheel", this.boundWheel), this.el.removeEventListener("mousedown", this.boundMouseDown), document.removeEventListener("mousemove", this.boundMouseMove), document.removeEventListener("mouseup", this.boundMouseUp), this.el.remove();
	}
	buildSimulation() {
		let e = /* @__PURE__ */ new Map(), t = 0;
		this.simNodes = this.nodes.map((n) => {
			let r = n.color;
			if (r === void 0 && n.group !== void 0) {
				let i = e.get(n.group);
				i === void 0 ? (r = u[t % u.length] ?? "#3b82f6", e.set(n.group, r), t++) : r = i;
			}
			return r === void 0 && (r = u[t % u.length] ?? "#3b82f6", t++), {
				id: n.id,
				label: n.label,
				x: n.x ?? 0,
				y: n.y ?? 0,
				vx: 0,
				vy: 0,
				radius: n.radius ?? this.defaultRadius,
				color: r,
				icon: n.icon,
				group: n.group,
				data: n.data,
				original: n
			};
		});
		let n = /* @__PURE__ */ new Map();
		for (let e of this.simNodes) n.set(e.id, e);
		this.simEdges = [];
		for (let e of this.edges) {
			let t = n.get(e.source), r = n.get(e.target);
			t === void 0 || r === void 0 || this.simEdges.push({
				source: t,
				target: r,
				label: e.label,
				weight: e.weight ?? 1,
				color: e.color,
				directed: e.directed === !0,
				original: e
			});
		}
	}
	applyLayout() {
		switch (this.layout) {
			case "force":
				this.forceLayout();
				break;
			case "circular":
				this.circularLayout();
				break;
			case "grid":
				this.gridLayout();
				break;
		}
	}
	forceLayout() {
		let e = this.viewBox.w / 2, t = this.viewBox.h / 2;
		for (let n of this.simNodes) (n.original.x === void 0 || n.original.y === void 0) && (n.x = e + (Math.random() - .5) * 200, n.y = t + (Math.random() - .5) * 200), n.vx = 0, n.vy = 0;
		for (let n = 0; n < i; n++) {
			for (let e = 0; e < this.simNodes.length; e++) {
				let t = this.simNodes[e];
				if (t !== void 0) for (let n = e + 1; n < this.simNodes.length; n++) {
					let e = this.simNodes[n];
					if (e === void 0) continue;
					let r = e.x - t.x, i = e.y - t.y, o = Math.sqrt(r * r + i * i);
					o < 1 && (o = 1, r = (Math.random() - .5) * 2, i = (Math.random() - .5) * 2);
					let s = a / (o * o), c = r / o * s, l = i / o * s;
					t.vx -= c, t.vy -= l, e.vx += c, e.vy += l;
				}
			}
			for (let e of this.simEdges) {
				let t = e.target.x - e.source.x, n = e.target.y - e.source.y, r = Math.sqrt(t * t + n * n), i = r * o * e.weight, a = t / Math.max(r, 1) * i, s = n / Math.max(r, 1) * i;
				e.source.vx += a, e.source.vy += s, e.target.vx -= a, e.target.vy -= s;
			}
			for (let n of this.simNodes) n.vx += (e - n.x) * s, n.vy += (t - n.y) * s;
			for (let e of this.simNodes) e.vx *= c, e.vy *= c, e.x += e.vx, e.y += e.vy;
		}
	}
	circularLayout() {
		let e = this.viewBox.w / 2, t = this.viewBox.h / 2, n = this.simNodes.length;
		if (n === 0) return;
		let r = n * (Math.max(...this.simNodes.map((e) => e.radius)) * 2 + 20), i = Math.max(r / (2 * Math.PI), 100);
		for (let r = 0; r < n; r++) {
			let a = this.simNodes[r];
			if (a === void 0) continue;
			let o = 2 * Math.PI * r / n - Math.PI / 2;
			a.x = e + i * Math.cos(o), a.y = t + i * Math.sin(o);
		}
	}
	gridLayout() {
		let e = this.simNodes.length;
		if (e === 0) return;
		let t = Math.ceil(Math.sqrt(e)), n = Math.max(...this.simNodes.map((e) => e.radius)) * 3 + 20;
		for (let r = 0; r < e; r++) {
			let e = this.simNodes[r];
			if (e === void 0) continue;
			let i = r % t, a = Math.floor(r / t);
			e.x = i * n + n / 2, e.y = a * n + n / 2;
		}
	}
	renderGraph() {
		for (; this.mainGroup.firstChild !== null;) this.mainGroup.removeChild(this.mainGroup.firstChild);
		for (let e of this.simEdges) this.renderEdge(e);
		for (let e of this.simNodes) this.renderNode(e);
		this.applyViewBox();
	}
	renderNode(e) {
		let t = document.createElementNS(n, "g");
		t.classList.add("cmm-network-graph__node"), t.setAttribute("data-node-id", e.id), this.hoveredNodeId !== null && this.hoveredNodeId !== e.id && (this.simEdges.some((t) => t.source.id === this.hoveredNodeId && t.target.id === e.id || t.target.id === this.hoveredNodeId && t.source.id === e.id) ? t.classList.add("cmm-network-graph__node--highlighted") : t.classList.add("cmm-network-graph__node--dimmed"));
		let r = document.createElementNS(n, "circle");
		if (r.classList.add("cmm-network-graph__node-circle"), r.setAttribute("cx", String(e.x)), r.setAttribute("cy", String(e.y)), r.setAttribute("r", String(e.radius)), r.setAttribute("fill", e.color), t.appendChild(r), e.icon !== void 0) {
			let r = document.createElementNS(n, "text");
			r.classList.add("cmm-network-graph__node-icon"), r.setAttribute("x", String(e.x)), r.setAttribute("y", String(e.y)), r.textContent = e.icon, t.appendChild(r);
		}
		if (this.showLabels) {
			let r = document.createElementNS(n, "text");
			r.classList.add("cmm-network-graph__label"), r.setAttribute("x", String(e.x)), r.setAttribute("y", String(e.y + e.radius + 14)), r.textContent = e.label, t.appendChild(r);
		}
		t.addEventListener("mouseenter", () => {
			this.hoveredNodeId = e.id, this.renderGraph();
		}), t.addEventListener("mouseleave", () => {
			this.hoveredNodeId = null, this.renderGraph();
		}), t.addEventListener("click", (t) => {
			t.stopPropagation(), this.onNodeClick?.(e.original);
		}), this.mainGroup.appendChild(t);
	}
	renderEdge(e) {
		let t = document.createElementNS(n, "g");
		t.classList.add("cmm-network-graph__edge"), this.hoveredNodeId !== null && (e.source.id === this.hoveredNodeId || e.target.id === this.hoveredNodeId ? t.classList.add("cmm-network-graph__edge--highlighted") : t.classList.add("cmm-network-graph__edge--dimmed"));
		let r = document.createElementNS(n, "line");
		if (r.classList.add("cmm-network-graph__edge-line"), r.setAttribute("x1", String(e.source.x)), r.setAttribute("y1", String(e.source.y)), r.setAttribute("x2", String(e.target.x)), r.setAttribute("y2", String(e.target.y)), e.color !== void 0 && r.setAttribute("stroke", e.color), e.weight > 1 && r.setAttribute("stroke-width", String(Math.min(e.weight * 1.5, 6))), e.directed && r.setAttribute("marker-end", `url(#${this.graphId}-arrow)`), t.appendChild(r), e.label !== void 0) {
			let r = (e.source.x + e.target.x) / 2, i = (e.source.y + e.target.y) / 2, a = document.createElementNS(n, "text");
			a.classList.add("cmm-network-graph__edge-label"), a.setAttribute("x", String(r)), a.setAttribute("y", String(i - 6)), a.textContent = e.label, t.appendChild(a);
		}
		t.addEventListener("click", (t) => {
			t.stopPropagation(), this.onEdgeClick?.(e.original);
		}), this.mainGroup.appendChild(t);
	}
	createArrowMarker() {
		let e = document.createElementNS(n, "marker");
		e.setAttribute("id", `${this.graphId}-arrow`), e.setAttribute("markerWidth", String(l)), e.setAttribute("markerHeight", String(l)), e.setAttribute("refX", String(l)), e.setAttribute("refY", String(l / 2)), e.setAttribute("orient", "auto-start-reverse"), e.setAttribute("markerUnits", "userSpaceOnUse");
		let t = document.createElementNS(n, "polygon");
		t.classList.add("cmm-network-graph__arrowhead"), t.setAttribute("points", `0 0, ${String(l)} ${String(l / 2)}, 0 ${String(l)}`), e.appendChild(t), this.defsEl.appendChild(e);
	}
	applyViewBox() {
		this.svg.setAttribute("viewBox", `${String(this.viewBox.x)} ${String(this.viewBox.y)} ${String(this.viewBox.w)} ${String(this.viewBox.h)}`);
	}
	handleWheel(e) {
		e.preventDefault();
		let t = e.deltaY > 0 ? 1.1 : .9, n = this.el.getBoundingClientRect(), r = (e.clientX - n.left) / n.width * this.viewBox.w + this.viewBox.x, i = (e.clientY - n.top) / n.height * this.viewBox.h + this.viewBox.y, a = this.viewBox.w * t, o = this.viewBox.h * t;
		this.viewBox.x = r - (r - this.viewBox.x) * (a / this.viewBox.w), this.viewBox.y = i - (i - this.viewBox.y) * (o / this.viewBox.h), this.viewBox.w = a, this.viewBox.h = o, this.applyViewBox();
	}
	handleMouseDown(e) {
		if (e.button !== 0) return;
		let t = e.target, n = t === null ? null : t.closest(".cmm-network-graph__node");
		if (n !== null) {
			let t = n.getAttribute("data-node-id");
			if (t !== null) {
				let n = this.simNodes.find((e) => e.id === t);
				if (n !== void 0) {
					this.dragNode = n;
					let t = this.clientToSvg(e.clientX, e.clientY);
					this.dragOffset = {
						x: n.x - t.x,
						y: n.y - t.y
					};
					return;
				}
			}
		}
		this.pannable && (this.isPanning = !0, this.panStart = {
			x: e.clientX,
			y: e.clientY
		}, this.panOrigin = {
			x: this.viewBox.x,
			y: this.viewBox.y
		});
	}
	handleMouseMove(e) {
		if (this.dragNode !== null) {
			let t = this.clientToSvg(e.clientX, e.clientY);
			this.dragNode.x = t.x + this.dragOffset.x, this.dragNode.y = t.y + this.dragOffset.y, this.renderGraph();
			return;
		}
		if (this.isPanning) {
			let t = this.el.getBoundingClientRect(), n = this.viewBox.w / t.width, r = this.viewBox.h / t.height;
			this.viewBox.x = this.panOrigin.x - (e.clientX - this.panStart.x) * n, this.viewBox.y = this.panOrigin.y - (e.clientY - this.panStart.y) * r, this.applyViewBox();
		}
	}
	handleMouseUp() {
		this.dragNode = null, this.isPanning = !1;
	}
	clientToSvg(e, t) {
		let n = this.el.getBoundingClientRect();
		return {
			x: (e - n.left) / n.width * this.viewBox.w + this.viewBox.x,
			y: (t - n.top) / n.height * this.viewBox.h + this.viewBox.y
		};
	}
	buildClassName(e) {
		let t = ["cmm-network-graph"];
		return e !== void 0 && t.push(e), t.join(" ");
	}
};
//#endregion
export { d as NetworkGraph };

//# sourceMappingURL=index.js.map