@almadar/ui 5.118.0 → 5.119.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -36626,11 +36626,11 @@ var init_DocumentViewer = __esm({
36626
36626
  exports.DocumentViewer.displayName = "DocumentViewer";
36627
36627
  }
36628
36628
  });
36629
- function measureLabelWidth(text) {
36629
+ function measureLabelWidth(text, fontFamily = "system-ui") {
36630
36630
  if (typeof document === "undefined") return text.length * 6;
36631
36631
  if (!labelMeasureCtx) labelMeasureCtx = document.createElement("canvas").getContext("2d");
36632
36632
  if (!labelMeasureCtx) return text.length * 6;
36633
- labelMeasureCtx.font = "12px system-ui";
36633
+ labelMeasureCtx.font = `12px ${fontFamily}`;
36634
36634
  return labelMeasureCtx.measureText(text).width + 4;
36635
36635
  }
36636
36636
  function getGroupColor(group, groups) {
@@ -36655,6 +36655,9 @@ function mulberry32(a) {
36655
36655
  return ((t ^ t >>> 14) >>> 0) / 4294967296;
36656
36656
  };
36657
36657
  }
36658
+ function edgeKeyOf(a, b) {
36659
+ return a < b ? `${a}\0${b}` : `${b}\0${a}`;
36660
+ }
36658
36661
  function resolveColor3(color, el) {
36659
36662
  const m = /^var\((--[^,)]+)(?:,\s*([^)]+))?\)$/.exec(color.trim());
36660
36663
  if (!m) return color;
@@ -36788,6 +36791,7 @@ var init_GraphCanvas = __esm({
36788
36791
  if (!canvas || propNodes.length === 0) return;
36789
36792
  const w = logicalW;
36790
36793
  const h = height;
36794
+ const labelFont = resolveColor3("var(--font-family)", canvas) || "system-ui";
36791
36795
  const prevPos = /* @__PURE__ */ new Map();
36792
36796
  for (const pn of nodesRef.current) if (pn.x != null && pn.y != null) prevPos.set(pn.id, { x: pn.x, y: pn.y });
36793
36797
  const simNodes = propNodes.map((n, idx) => {
@@ -36822,10 +36826,15 @@ var init_GraphCanvas = __esm({
36822
36826
  const fullRelayout = !laidOutRef.current || overlap < 0.5;
36823
36827
  if (layout === "force") {
36824
36828
  const maxIterations = 300;
36825
- const tick = () => {
36829
+ const COOL = 0.12;
36830
+ const COLLIDE_PASSES = 6;
36831
+ const LABEL_GAP = 12;
36832
+ const LABEL_H = 16;
36833
+ const tick = (iter) => {
36826
36834
  const nodes = nodesRef.current;
36827
36835
  const centerX = w / 2;
36828
36836
  const centerY = h / 2;
36837
+ const temp = Math.max(COOL, 1 - iter / maxIterations);
36829
36838
  for (const node of nodes) {
36830
36839
  node.fx = 0;
36831
36840
  node.fy = 0;
@@ -36835,7 +36844,7 @@ var init_GraphCanvas = __esm({
36835
36844
  const dx = nodes[j].x - nodes[i].x;
36836
36845
  const dy = nodes[j].y - nodes[i].y;
36837
36846
  const dist = Math.sqrt(dx * dx + dy * dy) || 1;
36838
- const force = repulsion / (dist * dist);
36847
+ const force = repulsion / (dist * dist) * temp;
36839
36848
  const fx = dx / dist * force;
36840
36849
  const fy = dy / dist * force;
36841
36850
  nodes[i].fx -= fx;
@@ -36845,42 +36854,34 @@ var init_GraphCanvas = __esm({
36845
36854
  }
36846
36855
  }
36847
36856
  const nodeById = new Map(nodes.map((n) => [n.id, n]));
36848
- if (propSimilarity.length > 0) {
36849
- for (const pair of propSimilarity) {
36850
- const source = nodeById.get(pair.source);
36851
- const target = nodeById.get(pair.target);
36852
- if (!source || !target) continue;
36853
- const dx = target.x - source.x;
36854
- const dy = target.y - source.y;
36855
- const dist = Math.sqrt(dx * dx + dy * dy) || 1;
36856
- const w2 = Math.min(1, Math.max(0, pair.weight));
36857
- const linkTarget = linkDistance * (1 - w2);
36858
- const force = (dist - linkTarget) * (0.04 + 0.1 * w2);
36859
- const fx = dx / dist * force;
36860
- const fy = dy / dist * force;
36861
- source.fx += fx;
36862
- source.fy += fy;
36863
- target.fx -= fx;
36864
- target.fy -= fy;
36865
- }
36866
- } else {
36867
- for (const edge of propEdges) {
36868
- const source = nodeById.get(edge.source);
36869
- const target = nodeById.get(edge.target);
36870
- if (!source || !target) continue;
36871
- const dx = target.x - source.x;
36872
- const dy = target.y - source.y;
36873
- const dist = Math.sqrt(dx * dx + dy * dy) || 1;
36874
- const w2 = Math.min(1, Math.max(0, edge.weight ?? 1));
36875
- const linkTarget = linkDistance * (0.5 + (1 - w2) * 1.5);
36876
- const force = (dist - linkTarget) * (0.04 + 0.1 * w2);
36877
- const fx = dx / dist * force;
36878
- const fy = dy / dist * force;
36879
- source.fx += fx;
36880
- source.fy += fy;
36881
- target.fx -= fx;
36882
- target.fy -= fy;
36883
- }
36857
+ const spring = (a, b, rest, k) => {
36858
+ const dx = b.x - a.x;
36859
+ const dy = b.y - a.y;
36860
+ const dist = Math.sqrt(dx * dx + dy * dy) || 1;
36861
+ const force = (dist - rest) * k * temp;
36862
+ const fx = dx / dist * force;
36863
+ const fy = dy / dist * force;
36864
+ a.fx += fx;
36865
+ a.fy += fy;
36866
+ b.fx -= fx;
36867
+ b.fy -= fy;
36868
+ };
36869
+ const drawnPairs = /* @__PURE__ */ new Set();
36870
+ for (const edge of propEdges) {
36871
+ const source = nodeById.get(edge.source);
36872
+ const target = nodeById.get(edge.target);
36873
+ if (!source || !target) continue;
36874
+ drawnPairs.add(edgeKeyOf(edge.source, edge.target));
36875
+ const w2 = Math.min(1, Math.max(0, edge.weight ?? 1));
36876
+ spring(source, target, linkDistance * (0.35 + (1 - w2) * 0.3), 0.14);
36877
+ }
36878
+ for (const pair of propSimilarity) {
36879
+ if (drawnPairs.has(edgeKeyOf(pair.source, pair.target))) continue;
36880
+ const source = nodeById.get(pair.source);
36881
+ const target = nodeById.get(pair.target);
36882
+ if (!source || !target) continue;
36883
+ const w2 = Math.min(1, Math.max(0, pair.weight));
36884
+ spring(source, target, linkDistance * (1.35 - 0.55 * w2), 0.015);
36884
36885
  }
36885
36886
  const centroids = /* @__PURE__ */ new Map();
36886
36887
  for (const node of nodes) {
@@ -36894,14 +36895,20 @@ var init_GraphCanvas = __esm({
36894
36895
  c.y += node.y;
36895
36896
  c.n += 1;
36896
36897
  }
36898
+ const multiCluster = centroids.size > 1;
36897
36899
  for (const node of nodes) {
36898
- const c = centroids.get(node.group ?? "__none__");
36899
- if (c && c.n > 1) {
36900
- node.fx += (c.x / c.n - node.x) * 0.04;
36901
- node.fy += (c.y / c.n - node.y) * 0.04;
36900
+ if (multiCluster) {
36901
+ const c = centroids.get(node.group ?? "__none__");
36902
+ if (c && c.n > 1) {
36903
+ node.fx += (c.x / c.n - node.x) * 0.04 * temp;
36904
+ node.fy += (c.y / c.n - node.y) * 0.04 * temp;
36905
+ } else {
36906
+ node.fx += (centerX - node.x) * 0.01 * temp;
36907
+ node.fy += (centerY - node.y) * 0.01 * temp;
36908
+ }
36902
36909
  } else {
36903
- node.fx += (centerX - node.x) * 0.01;
36904
- node.fy += (centerY - node.y) * 0.01;
36910
+ node.fx += (centerX - node.x) * 8e-3 * temp;
36911
+ node.fy += (centerY - node.y) * 8e-3 * temp;
36905
36912
  }
36906
36913
  }
36907
36914
  const damping = 0.9;
@@ -36913,42 +36920,53 @@ var init_GraphCanvas = __esm({
36913
36920
  node.x = Math.max(30, Math.min(w - 30, node.x));
36914
36921
  node.y = Math.max(30, Math.min(h - 30, node.y));
36915
36922
  }
36916
- const LABEL_GAP = 12;
36917
- const LABEL_H = 16;
36918
36923
  const pad = nodeSpacing / 2;
36919
- for (let i = 0; i < nodes.length; i++) {
36920
- for (let j = i + 1; j < nodes.length; j++) {
36921
- const a = nodes[i];
36922
- const b = nodes[j];
36923
- const ar = a.size || 8;
36924
- const br = b.size || 8;
36925
- if (showLabels) {
36926
- if (a.labelW === void 0) a.labelW = a.label ? measureLabelWidth(a.label) : 0;
36927
- if (b.labelW === void 0) b.labelW = b.label ? measureLabelWidth(b.label) : 0;
36928
- }
36929
- const labelBelow = showLabels ? LABEL_GAP + LABEL_H : 0;
36930
- const aHalfW = Math.max(ar, (a.labelW ?? 0) / 2) + pad;
36931
- const bHalfW = Math.max(br, (b.labelW ?? 0) / 2) + pad;
36932
- const aTop = a.y - ar - pad, aBot = a.y + ar + labelBelow + pad;
36933
- const bTop = b.y - br - pad, bBot = b.y + br + labelBelow + pad;
36934
- const overlapX = Math.min(a.x + aHalfW, b.x + bHalfW) - Math.max(a.x - aHalfW, b.x - bHalfW);
36935
- const overlapY = Math.min(aBot, bBot) - Math.max(aTop, bTop);
36936
- if (overlapX > 0 && overlapY > 0) {
36937
- if (overlapX <= overlapY) {
36938
- const push = overlapX / 2 * (b.x >= a.x ? 1 : -1);
36939
- a.x = Math.max(30, Math.min(w - 30, a.x - push));
36940
- b.x = Math.max(30, Math.min(w - 30, b.x + push));
36941
- } else {
36942
- const push = overlapY / 2 * (bTop + bBot >= aTop + aBot ? 1 : -1);
36943
- a.y = Math.max(30, Math.min(h - 30, a.y - push));
36944
- b.y = Math.max(30, Math.min(h - 30, b.y + push));
36924
+ const rectsOf = (n) => {
36925
+ const r = n.size || 8;
36926
+ const lw = showLabels ? n.labelW ?? (n.labelW = n.label ? measureLabelWidth(n.label, labelFont) : 0) : 0;
36927
+ return {
36928
+ circle: [n.x - r - pad, n.y - r - pad, n.x + r + pad, n.y + r + pad],
36929
+ label: [n.x - lw / 2 - pad, n.y + r + LABEL_GAP - 8, n.x + lw / 2 + pad, n.y + r + LABEL_GAP + LABEL_H]
36930
+ };
36931
+ };
36932
+ const sep = (r1, r2) => {
36933
+ const ox = Math.min(r1[2], r2[2]) - Math.max(r1[0], r2[0]);
36934
+ const oy = Math.min(r1[3], r2[3]) - Math.max(r1[1], r2[1]);
36935
+ if (ox <= 0 || oy <= 0) return null;
36936
+ return ox <= oy ? { axis: "x", depth: ox, sign: r1[0] + r1[2] < r2[0] + r2[2] ? 1 : -1 } : { axis: "y", depth: oy, sign: r1[1] + r1[3] < r2[1] + r2[3] ? 1 : -1 };
36937
+ };
36938
+ for (let pass = 0; pass < COLLIDE_PASSES; pass++) {
36939
+ for (let i = 0; i < nodes.length; i++) {
36940
+ for (let j = i + 1; j < nodes.length; j++) {
36941
+ const a = nodes[i];
36942
+ const b = nodes[j];
36943
+ const ra = rectsOf(a);
36944
+ const rb = rectsOf(b);
36945
+ let best = null;
36946
+ for (const [r1, r2] of [[ra.circle, rb.circle], [ra.circle, rb.label], [ra.label, rb.circle], [ra.label, rb.label]]) {
36947
+ const s = sep(r1, r2);
36948
+ if (s && (!best || s.depth < best.depth)) best = s;
36949
+ }
36950
+ if (best) {
36951
+ const push = best.depth / 2;
36952
+ if (best.axis === "x") {
36953
+ a.x = Math.max(30, Math.min(w - 30, a.x - push * best.sign));
36954
+ b.x = Math.max(30, Math.min(w - 30, b.x + push * best.sign));
36955
+ a.vx = 0;
36956
+ b.vx = 0;
36957
+ } else {
36958
+ a.y = Math.max(30, Math.min(h - 30, a.y - push * best.sign));
36959
+ b.y = Math.max(30, Math.min(h - 30, b.y + push * best.sign));
36960
+ a.vy = 0;
36961
+ b.vy = 0;
36962
+ }
36945
36963
  }
36946
36964
  }
36947
36965
  }
36948
36966
  }
36949
36967
  };
36950
36968
  if (fullRelayout) {
36951
- for (let i = 0; i < maxIterations; i++) tick();
36969
+ for (let i = 0; i < maxIterations; i++) tick(i);
36952
36970
  laidOutRef.current = true;
36953
36971
  } else {
36954
36972
  const centroids = /* @__PURE__ */ new Map();
@@ -8832,10 +8832,11 @@ interface GraphEdge {
8832
8832
  color?: string;
8833
8833
  }
8834
8834
  /**
8835
- * All-pairs similarity (cosine 0–1) used ONLY for layout: ideal pair distance
8836
- * is derived from similarity (higher closer). Never drawn `edges` remain
8837
- * the only rendered links. When provided it supersedes edge-weight attraction;
8838
- * when omitted, edges drive layout as before.
8835
+ * All-pairs similarity (cosine 0–1) used ONLY for layout, never drawn — `edges`
8836
+ * remain the only rendered links. It is the SECONDARY macro-layout: pairs that are
8837
+ * NOT directly connected get a weak spring (higher cosine ⇒ closer) so clusters
8838
+ * arrange relative to each other, while drawn `edges` stay the primary tight
8839
+ * structure. When omitted, edges alone drive the layout.
8839
8840
  */
8840
8841
  interface GraphSimilarity {
8841
8842
  source: string;
@@ -8857,9 +8858,10 @@ interface GraphCanvasProps {
8857
8858
  /** Graph edges (the only rendered links) */
8858
8859
  edges?: readonly GraphEdge[];
8859
8860
  /**
8860
- * All-pairs similarity (cosine 0–1) used ONLY for layout: ideal pair
8861
- * distance = linkDistance × (1 cosine). Never drawn. When provided it
8862
- * supersedes edge-weight attraction; when omitted, edges drive layout.
8861
+ * All-pairs similarity (cosine 0–1) used ONLY for layout, never drawn. It is the
8862
+ * secondary macro-layout: non-connected pairs get a weak spring (higher cosine
8863
+ * closer) so clusters arrange relative to each other; drawn `edges` stay the
8864
+ * primary tight structure. When omitted, edges alone drive the layout.
8863
8865
  */
8864
8866
  similarity?: readonly GraphSimilarity[];
8865
8867
  /** Canvas height */
@@ -8832,10 +8832,11 @@ interface GraphEdge {
8832
8832
  color?: string;
8833
8833
  }
8834
8834
  /**
8835
- * All-pairs similarity (cosine 0–1) used ONLY for layout: ideal pair distance
8836
- * is derived from similarity (higher closer). Never drawn `edges` remain
8837
- * the only rendered links. When provided it supersedes edge-weight attraction;
8838
- * when omitted, edges drive layout as before.
8835
+ * All-pairs similarity (cosine 0–1) used ONLY for layout, never drawn — `edges`
8836
+ * remain the only rendered links. It is the SECONDARY macro-layout: pairs that are
8837
+ * NOT directly connected get a weak spring (higher cosine ⇒ closer) so clusters
8838
+ * arrange relative to each other, while drawn `edges` stay the primary tight
8839
+ * structure. When omitted, edges alone drive the layout.
8839
8840
  */
8840
8841
  interface GraphSimilarity {
8841
8842
  source: string;
@@ -8857,9 +8858,10 @@ interface GraphCanvasProps {
8857
8858
  /** Graph edges (the only rendered links) */
8858
8859
  edges?: readonly GraphEdge[];
8859
8860
  /**
8860
- * All-pairs similarity (cosine 0–1) used ONLY for layout: ideal pair
8861
- * distance = linkDistance × (1 cosine). Never drawn. When provided it
8862
- * supersedes edge-weight attraction; when omitted, edges drive layout.
8861
+ * All-pairs similarity (cosine 0–1) used ONLY for layout, never drawn. It is the
8862
+ * secondary macro-layout: non-connected pairs get a weak spring (higher cosine
8863
+ * closer) so clusters arrange relative to each other; drawn `edges` stay the
8864
+ * primary tight structure. When omitted, edges alone drive the layout.
8863
8865
  */
8864
8866
  similarity?: readonly GraphSimilarity[];
8865
8867
  /** Canvas height */
@@ -36581,11 +36581,11 @@ var init_DocumentViewer = __esm({
36581
36581
  DocumentViewer.displayName = "DocumentViewer";
36582
36582
  }
36583
36583
  });
36584
- function measureLabelWidth(text) {
36584
+ function measureLabelWidth(text, fontFamily = "system-ui") {
36585
36585
  if (typeof document === "undefined") return text.length * 6;
36586
36586
  if (!labelMeasureCtx) labelMeasureCtx = document.createElement("canvas").getContext("2d");
36587
36587
  if (!labelMeasureCtx) return text.length * 6;
36588
- labelMeasureCtx.font = "12px system-ui";
36588
+ labelMeasureCtx.font = `12px ${fontFamily}`;
36589
36589
  return labelMeasureCtx.measureText(text).width + 4;
36590
36590
  }
36591
36591
  function getGroupColor(group, groups) {
@@ -36610,6 +36610,9 @@ function mulberry32(a) {
36610
36610
  return ((t ^ t >>> 14) >>> 0) / 4294967296;
36611
36611
  };
36612
36612
  }
36613
+ function edgeKeyOf(a, b) {
36614
+ return a < b ? `${a}\0${b}` : `${b}\0${a}`;
36615
+ }
36613
36616
  function resolveColor3(color, el) {
36614
36617
  const m = /^var\((--[^,)]+)(?:,\s*([^)]+))?\)$/.exec(color.trim());
36615
36618
  if (!m) return color;
@@ -36743,6 +36746,7 @@ var init_GraphCanvas = __esm({
36743
36746
  if (!canvas || propNodes.length === 0) return;
36744
36747
  const w = logicalW;
36745
36748
  const h = height;
36749
+ const labelFont = resolveColor3("var(--font-family)", canvas) || "system-ui";
36746
36750
  const prevPos = /* @__PURE__ */ new Map();
36747
36751
  for (const pn of nodesRef.current) if (pn.x != null && pn.y != null) prevPos.set(pn.id, { x: pn.x, y: pn.y });
36748
36752
  const simNodes = propNodes.map((n, idx) => {
@@ -36777,10 +36781,15 @@ var init_GraphCanvas = __esm({
36777
36781
  const fullRelayout = !laidOutRef.current || overlap < 0.5;
36778
36782
  if (layout === "force") {
36779
36783
  const maxIterations = 300;
36780
- const tick = () => {
36784
+ const COOL = 0.12;
36785
+ const COLLIDE_PASSES = 6;
36786
+ const LABEL_GAP = 12;
36787
+ const LABEL_H = 16;
36788
+ const tick = (iter) => {
36781
36789
  const nodes = nodesRef.current;
36782
36790
  const centerX = w / 2;
36783
36791
  const centerY = h / 2;
36792
+ const temp = Math.max(COOL, 1 - iter / maxIterations);
36784
36793
  for (const node of nodes) {
36785
36794
  node.fx = 0;
36786
36795
  node.fy = 0;
@@ -36790,7 +36799,7 @@ var init_GraphCanvas = __esm({
36790
36799
  const dx = nodes[j].x - nodes[i].x;
36791
36800
  const dy = nodes[j].y - nodes[i].y;
36792
36801
  const dist = Math.sqrt(dx * dx + dy * dy) || 1;
36793
- const force = repulsion / (dist * dist);
36802
+ const force = repulsion / (dist * dist) * temp;
36794
36803
  const fx = dx / dist * force;
36795
36804
  const fy = dy / dist * force;
36796
36805
  nodes[i].fx -= fx;
@@ -36800,42 +36809,34 @@ var init_GraphCanvas = __esm({
36800
36809
  }
36801
36810
  }
36802
36811
  const nodeById = new Map(nodes.map((n) => [n.id, n]));
36803
- if (propSimilarity.length > 0) {
36804
- for (const pair of propSimilarity) {
36805
- const source = nodeById.get(pair.source);
36806
- const target = nodeById.get(pair.target);
36807
- if (!source || !target) continue;
36808
- const dx = target.x - source.x;
36809
- const dy = target.y - source.y;
36810
- const dist = Math.sqrt(dx * dx + dy * dy) || 1;
36811
- const w2 = Math.min(1, Math.max(0, pair.weight));
36812
- const linkTarget = linkDistance * (1 - w2);
36813
- const force = (dist - linkTarget) * (0.04 + 0.1 * w2);
36814
- const fx = dx / dist * force;
36815
- const fy = dy / dist * force;
36816
- source.fx += fx;
36817
- source.fy += fy;
36818
- target.fx -= fx;
36819
- target.fy -= fy;
36820
- }
36821
- } else {
36822
- for (const edge of propEdges) {
36823
- const source = nodeById.get(edge.source);
36824
- const target = nodeById.get(edge.target);
36825
- if (!source || !target) continue;
36826
- const dx = target.x - source.x;
36827
- const dy = target.y - source.y;
36828
- const dist = Math.sqrt(dx * dx + dy * dy) || 1;
36829
- const w2 = Math.min(1, Math.max(0, edge.weight ?? 1));
36830
- const linkTarget = linkDistance * (0.5 + (1 - w2) * 1.5);
36831
- const force = (dist - linkTarget) * (0.04 + 0.1 * w2);
36832
- const fx = dx / dist * force;
36833
- const fy = dy / dist * force;
36834
- source.fx += fx;
36835
- source.fy += fy;
36836
- target.fx -= fx;
36837
- target.fy -= fy;
36838
- }
36812
+ const spring = (a, b, rest, k) => {
36813
+ const dx = b.x - a.x;
36814
+ const dy = b.y - a.y;
36815
+ const dist = Math.sqrt(dx * dx + dy * dy) || 1;
36816
+ const force = (dist - rest) * k * temp;
36817
+ const fx = dx / dist * force;
36818
+ const fy = dy / dist * force;
36819
+ a.fx += fx;
36820
+ a.fy += fy;
36821
+ b.fx -= fx;
36822
+ b.fy -= fy;
36823
+ };
36824
+ const drawnPairs = /* @__PURE__ */ new Set();
36825
+ for (const edge of propEdges) {
36826
+ const source = nodeById.get(edge.source);
36827
+ const target = nodeById.get(edge.target);
36828
+ if (!source || !target) continue;
36829
+ drawnPairs.add(edgeKeyOf(edge.source, edge.target));
36830
+ const w2 = Math.min(1, Math.max(0, edge.weight ?? 1));
36831
+ spring(source, target, linkDistance * (0.35 + (1 - w2) * 0.3), 0.14);
36832
+ }
36833
+ for (const pair of propSimilarity) {
36834
+ if (drawnPairs.has(edgeKeyOf(pair.source, pair.target))) continue;
36835
+ const source = nodeById.get(pair.source);
36836
+ const target = nodeById.get(pair.target);
36837
+ if (!source || !target) continue;
36838
+ const w2 = Math.min(1, Math.max(0, pair.weight));
36839
+ spring(source, target, linkDistance * (1.35 - 0.55 * w2), 0.015);
36839
36840
  }
36840
36841
  const centroids = /* @__PURE__ */ new Map();
36841
36842
  for (const node of nodes) {
@@ -36849,14 +36850,20 @@ var init_GraphCanvas = __esm({
36849
36850
  c.y += node.y;
36850
36851
  c.n += 1;
36851
36852
  }
36853
+ const multiCluster = centroids.size > 1;
36852
36854
  for (const node of nodes) {
36853
- const c = centroids.get(node.group ?? "__none__");
36854
- if (c && c.n > 1) {
36855
- node.fx += (c.x / c.n - node.x) * 0.04;
36856
- node.fy += (c.y / c.n - node.y) * 0.04;
36855
+ if (multiCluster) {
36856
+ const c = centroids.get(node.group ?? "__none__");
36857
+ if (c && c.n > 1) {
36858
+ node.fx += (c.x / c.n - node.x) * 0.04 * temp;
36859
+ node.fy += (c.y / c.n - node.y) * 0.04 * temp;
36860
+ } else {
36861
+ node.fx += (centerX - node.x) * 0.01 * temp;
36862
+ node.fy += (centerY - node.y) * 0.01 * temp;
36863
+ }
36857
36864
  } else {
36858
- node.fx += (centerX - node.x) * 0.01;
36859
- node.fy += (centerY - node.y) * 0.01;
36865
+ node.fx += (centerX - node.x) * 8e-3 * temp;
36866
+ node.fy += (centerY - node.y) * 8e-3 * temp;
36860
36867
  }
36861
36868
  }
36862
36869
  const damping = 0.9;
@@ -36868,42 +36875,53 @@ var init_GraphCanvas = __esm({
36868
36875
  node.x = Math.max(30, Math.min(w - 30, node.x));
36869
36876
  node.y = Math.max(30, Math.min(h - 30, node.y));
36870
36877
  }
36871
- const LABEL_GAP = 12;
36872
- const LABEL_H = 16;
36873
36878
  const pad = nodeSpacing / 2;
36874
- for (let i = 0; i < nodes.length; i++) {
36875
- for (let j = i + 1; j < nodes.length; j++) {
36876
- const a = nodes[i];
36877
- const b = nodes[j];
36878
- const ar = a.size || 8;
36879
- const br = b.size || 8;
36880
- if (showLabels) {
36881
- if (a.labelW === void 0) a.labelW = a.label ? measureLabelWidth(a.label) : 0;
36882
- if (b.labelW === void 0) b.labelW = b.label ? measureLabelWidth(b.label) : 0;
36883
- }
36884
- const labelBelow = showLabels ? LABEL_GAP + LABEL_H : 0;
36885
- const aHalfW = Math.max(ar, (a.labelW ?? 0) / 2) + pad;
36886
- const bHalfW = Math.max(br, (b.labelW ?? 0) / 2) + pad;
36887
- const aTop = a.y - ar - pad, aBot = a.y + ar + labelBelow + pad;
36888
- const bTop = b.y - br - pad, bBot = b.y + br + labelBelow + pad;
36889
- const overlapX = Math.min(a.x + aHalfW, b.x + bHalfW) - Math.max(a.x - aHalfW, b.x - bHalfW);
36890
- const overlapY = Math.min(aBot, bBot) - Math.max(aTop, bTop);
36891
- if (overlapX > 0 && overlapY > 0) {
36892
- if (overlapX <= overlapY) {
36893
- const push = overlapX / 2 * (b.x >= a.x ? 1 : -1);
36894
- a.x = Math.max(30, Math.min(w - 30, a.x - push));
36895
- b.x = Math.max(30, Math.min(w - 30, b.x + push));
36896
- } else {
36897
- const push = overlapY / 2 * (bTop + bBot >= aTop + aBot ? 1 : -1);
36898
- a.y = Math.max(30, Math.min(h - 30, a.y - push));
36899
- b.y = Math.max(30, Math.min(h - 30, b.y + push));
36879
+ const rectsOf = (n) => {
36880
+ const r = n.size || 8;
36881
+ const lw = showLabels ? n.labelW ?? (n.labelW = n.label ? measureLabelWidth(n.label, labelFont) : 0) : 0;
36882
+ return {
36883
+ circle: [n.x - r - pad, n.y - r - pad, n.x + r + pad, n.y + r + pad],
36884
+ label: [n.x - lw / 2 - pad, n.y + r + LABEL_GAP - 8, n.x + lw / 2 + pad, n.y + r + LABEL_GAP + LABEL_H]
36885
+ };
36886
+ };
36887
+ const sep = (r1, r2) => {
36888
+ const ox = Math.min(r1[2], r2[2]) - Math.max(r1[0], r2[0]);
36889
+ const oy = Math.min(r1[3], r2[3]) - Math.max(r1[1], r2[1]);
36890
+ if (ox <= 0 || oy <= 0) return null;
36891
+ return ox <= oy ? { axis: "x", depth: ox, sign: r1[0] + r1[2] < r2[0] + r2[2] ? 1 : -1 } : { axis: "y", depth: oy, sign: r1[1] + r1[3] < r2[1] + r2[3] ? 1 : -1 };
36892
+ };
36893
+ for (let pass = 0; pass < COLLIDE_PASSES; pass++) {
36894
+ for (let i = 0; i < nodes.length; i++) {
36895
+ for (let j = i + 1; j < nodes.length; j++) {
36896
+ const a = nodes[i];
36897
+ const b = nodes[j];
36898
+ const ra = rectsOf(a);
36899
+ const rb = rectsOf(b);
36900
+ let best = null;
36901
+ for (const [r1, r2] of [[ra.circle, rb.circle], [ra.circle, rb.label], [ra.label, rb.circle], [ra.label, rb.label]]) {
36902
+ const s = sep(r1, r2);
36903
+ if (s && (!best || s.depth < best.depth)) best = s;
36904
+ }
36905
+ if (best) {
36906
+ const push = best.depth / 2;
36907
+ if (best.axis === "x") {
36908
+ a.x = Math.max(30, Math.min(w - 30, a.x - push * best.sign));
36909
+ b.x = Math.max(30, Math.min(w - 30, b.x + push * best.sign));
36910
+ a.vx = 0;
36911
+ b.vx = 0;
36912
+ } else {
36913
+ a.y = Math.max(30, Math.min(h - 30, a.y - push * best.sign));
36914
+ b.y = Math.max(30, Math.min(h - 30, b.y + push * best.sign));
36915
+ a.vy = 0;
36916
+ b.vy = 0;
36917
+ }
36900
36918
  }
36901
36919
  }
36902
36920
  }
36903
36921
  }
36904
36922
  };
36905
36923
  if (fullRelayout) {
36906
- for (let i = 0; i < maxIterations; i++) tick();
36924
+ for (let i = 0; i < maxIterations; i++) tick(i);
36907
36925
  laidOutRef.current = true;
36908
36926
  } else {
36909
36927
  const centroids = /* @__PURE__ */ new Map();