@almadar/ui 5.119.0 → 5.120.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.
@@ -36789,8 +36789,11 @@ var init_GraphCanvas = __esm({
36789
36789
  React73.useEffect(() => {
36790
36790
  const canvas = canvasRef.current;
36791
36791
  if (!canvas || propNodes.length === 0) return;
36792
- const w = logicalW;
36793
- const h = height;
36792
+ const viewW = logicalW;
36793
+ const viewH = height;
36794
+ const layoutScale = Math.max(1, Math.min(3, Math.sqrt(propNodes.length / 12)));
36795
+ const w = viewW * layoutScale;
36796
+ const h = viewH * layoutScale;
36794
36797
  const labelFont = resolveColor3("var(--font-family)", canvas) || "system-ui";
36795
36798
  const prevPos = /* @__PURE__ */ new Map();
36796
36799
  for (const pn of nodesRef.current) if (pn.x != null && pn.y != null) prevPos.set(pn.id, { x: pn.x, y: pn.y });
@@ -36830,93 +36833,122 @@ var init_GraphCanvas = __esm({
36830
36833
  const COLLIDE_PASSES = 6;
36831
36834
  const LABEL_GAP = 12;
36832
36835
  const LABEL_H = 16;
36833
- const tick = (iter) => {
36836
+ const SIMILARITY_NEIGHBORS = 5;
36837
+ const SIMILARITY_MIN_WEIGHT = 0.25;
36838
+ const drawnPairs = /* @__PURE__ */ new Set();
36839
+ for (const edge of propEdges) drawnPairs.add(edgeKeyOf(edge.source, edge.target));
36840
+ const similarityNeighbors = /* @__PURE__ */ new Map();
36841
+ {
36842
+ const bySource = /* @__PURE__ */ new Map();
36843
+ for (const pair of propSimilarity) {
36844
+ if (pair.weight < SIMILARITY_MIN_WEIGHT) continue;
36845
+ if (drawnPairs.has(edgeKeyOf(pair.source, pair.target))) continue;
36846
+ const arr = bySource.get(pair.source) ?? [];
36847
+ arr.push(pair);
36848
+ bySource.set(pair.source, arr);
36849
+ }
36850
+ for (const [id, arr] of bySource) {
36851
+ arr.sort((a, b) => b.weight - a.weight);
36852
+ const keep = new Set(arr.slice(0, SIMILARITY_NEIGHBORS).map((p) => p.target));
36853
+ similarityNeighbors.set(id, keep);
36854
+ }
36855
+ }
36856
+ const activeSimilarity = propSimilarity.filter((pair) => {
36857
+ if (drawnPairs.has(edgeKeyOf(pair.source, pair.target))) return false;
36858
+ const a = similarityNeighbors.get(pair.source);
36859
+ const b = similarityNeighbors.get(pair.target);
36860
+ return (a?.has(pair.target) ?? false) || (b?.has(pair.source) ?? false);
36861
+ });
36862
+ const tick = (iter, options) => {
36863
+ const skipForces = options?.skipForces ?? false;
36834
36864
  const nodes = nodesRef.current;
36835
36865
  const centerX = w / 2;
36836
36866
  const centerY = h / 2;
36837
- const temp = Math.max(COOL, 1 - iter / maxIterations);
36867
+ const temp = skipForces ? 0 : Math.max(COOL, 1 - iter / maxIterations);
36838
36868
  for (const node of nodes) {
36839
36869
  node.fx = 0;
36840
36870
  node.fy = 0;
36841
36871
  }
36842
- for (let i = 0; i < nodes.length; i++) {
36843
- for (let j = i + 1; j < nodes.length; j++) {
36844
- const dx = nodes[j].x - nodes[i].x;
36845
- const dy = nodes[j].y - nodes[i].y;
36872
+ if (!skipForces) {
36873
+ for (let i = 0; i < nodes.length; i++) {
36874
+ for (let j = i + 1; j < nodes.length; j++) {
36875
+ const dx = nodes[j].x - nodes[i].x;
36876
+ const dy = nodes[j].y - nodes[i].y;
36877
+ const dist = Math.sqrt(dx * dx + dy * dy) || 1;
36878
+ const force = repulsion / (dist * dist) * temp;
36879
+ const fx = dx / dist * force;
36880
+ const fy = dy / dist * force;
36881
+ nodes[i].fx -= fx;
36882
+ nodes[i].fy -= fy;
36883
+ nodes[j].fx += fx;
36884
+ nodes[j].fy += fy;
36885
+ }
36886
+ }
36887
+ const nodeById = new Map(nodes.map((n) => [n.id, n]));
36888
+ const spring = (a, b, rest, k) => {
36889
+ const dx = b.x - a.x;
36890
+ const dy = b.y - a.y;
36846
36891
  const dist = Math.sqrt(dx * dx + dy * dy) || 1;
36847
- const force = repulsion / (dist * dist) * temp;
36892
+ const force = (dist - rest) * k * temp;
36848
36893
  const fx = dx / dist * force;
36849
36894
  const fy = dy / dist * force;
36850
- nodes[i].fx -= fx;
36851
- nodes[i].fy -= fy;
36852
- nodes[j].fx += fx;
36853
- nodes[j].fy += fy;
36895
+ a.fx += fx;
36896
+ a.fy += fy;
36897
+ b.fx -= fx;
36898
+ b.fy -= fy;
36899
+ };
36900
+ for (const edge of propEdges) {
36901
+ const source = nodeById.get(edge.source);
36902
+ const target = nodeById.get(edge.target);
36903
+ if (!source || !target) continue;
36904
+ drawnPairs.add(edgeKeyOf(edge.source, edge.target));
36905
+ const w2 = Math.min(1, Math.max(0, edge.weight ?? 1));
36906
+ spring(source, target, linkDistance * (0.35 + (1 - w2) * 0.3), 0.14);
36854
36907
  }
36855
- }
36856
- const nodeById = new Map(nodes.map((n) => [n.id, n]));
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);
36885
- }
36886
- const centroids = /* @__PURE__ */ new Map();
36887
- for (const node of nodes) {
36888
- const g = node.group ?? "__none__";
36889
- let c = centroids.get(g);
36890
- if (!c) {
36891
- c = { x: 0, y: 0, n: 0 };
36892
- centroids.set(g, c);
36908
+ for (const pair of activeSimilarity) {
36909
+ const source = nodeById.get(pair.source);
36910
+ const target = nodeById.get(pair.target);
36911
+ if (!source || !target) continue;
36912
+ const w2 = Math.min(1, Math.max(0, pair.weight));
36913
+ spring(source, target, linkDistance * (1.35 - 0.55 * w2), 0.015);
36893
36914
  }
36894
- c.x += node.x;
36895
- c.y += node.y;
36896
- c.n += 1;
36897
- }
36898
- const multiCluster = centroids.size > 1;
36899
- for (const node of nodes) {
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;
36915
+ const centroids = /* @__PURE__ */ new Map();
36916
+ for (const node of nodes) {
36917
+ const g = node.group ?? "__none__";
36918
+ let c = centroids.get(g);
36919
+ if (!c) {
36920
+ c = { x: 0, y: 0, n: 0 };
36921
+ centroids.set(g, c);
36922
+ }
36923
+ c.x += node.x;
36924
+ c.y += node.y;
36925
+ c.n += 1;
36926
+ }
36927
+ const multiCluster = centroids.size > 1;
36928
+ for (const node of nodes) {
36929
+ if (multiCluster) {
36930
+ const c = centroids.get(node.group ?? "__none__");
36931
+ if (c && c.n > 1) {
36932
+ node.fx += (c.x / c.n - node.x) * 0.06 * temp;
36933
+ node.fy += (c.y / c.n - node.y) * 0.06 * temp;
36934
+ } else {
36935
+ node.fx += (centerX - node.x) * 0.01 * temp;
36936
+ node.fy += (centerY - node.y) * 0.01 * temp;
36937
+ }
36905
36938
  } else {
36906
- node.fx += (centerX - node.x) * 0.01 * temp;
36907
- node.fy += (centerY - node.y) * 0.01 * temp;
36939
+ node.fx += (centerX - node.x) * 8e-3 * temp;
36940
+ node.fy += (centerY - node.y) * 8e-3 * temp;
36908
36941
  }
36909
- } else {
36910
- node.fx += (centerX - node.x) * 8e-3 * temp;
36911
- node.fy += (centerY - node.y) * 8e-3 * temp;
36942
+ }
36943
+ const damping = 0.9;
36944
+ for (const node of nodes) {
36945
+ node.vx = (node.vx + node.fx) * damping;
36946
+ node.vy = (node.vy + node.fy) * damping;
36947
+ node.x += node.vx;
36948
+ node.y += node.vy;
36912
36949
  }
36913
36950
  }
36914
- const damping = 0.9;
36915
36951
  for (const node of nodes) {
36916
- node.vx = (node.vx + node.fx) * damping;
36917
- node.vy = (node.vy + node.fy) * damping;
36918
- node.x += node.vx;
36919
- node.y += node.vy;
36920
36952
  node.x = Math.max(30, Math.min(w - 30, node.x));
36921
36953
  node.y = Math.max(30, Math.min(h - 30, node.y));
36922
36954
  }
@@ -36967,6 +36999,22 @@ var init_GraphCanvas = __esm({
36967
36999
  };
36968
37000
  if (fullRelayout) {
36969
37001
  for (let i = 0; i < maxIterations; i++) tick(i);
37002
+ for (let i = 0; i < 4; i++) tick(maxIterations, { skipForces: true });
37003
+ const fitPad = 40;
37004
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
37005
+ for (const node of nodesRef.current) {
37006
+ const r = node.size || 8;
37007
+ const lw = showLabels ? node.labelW ?? (node.labelW = node.label ? measureLabelWidth(node.label, labelFont) : 0) : 0;
37008
+ minX = Math.min(minX, node.x - r, node.x - lw / 2);
37009
+ minY = Math.min(minY, node.y - r);
37010
+ maxX = Math.max(maxX, node.x + r, node.x + lw / 2);
37011
+ maxY = Math.max(maxY, node.y + r + LABEL_GAP + LABEL_H);
37012
+ }
37013
+ const bboxW = Math.max(1, maxX - minX + fitPad * 2);
37014
+ const bboxH = Math.max(1, maxY - minY + fitPad * 2);
37015
+ const nextZoom = Math.min(1, viewW / bboxW, viewH / bboxH);
37016
+ setZoom(nextZoom);
37017
+ setOffset({ x: fitPad - minX * nextZoom, y: fitPad - minY * nextZoom });
36970
37018
  laidOutRef.current = true;
36971
37019
  } else {
36972
37020
  const centroids = /* @__PURE__ */ new Map();
@@ -36744,8 +36744,11 @@ var init_GraphCanvas = __esm({
36744
36744
  useEffect(() => {
36745
36745
  const canvas = canvasRef.current;
36746
36746
  if (!canvas || propNodes.length === 0) return;
36747
- const w = logicalW;
36748
- const h = height;
36747
+ const viewW = logicalW;
36748
+ const viewH = height;
36749
+ const layoutScale = Math.max(1, Math.min(3, Math.sqrt(propNodes.length / 12)));
36750
+ const w = viewW * layoutScale;
36751
+ const h = viewH * layoutScale;
36749
36752
  const labelFont = resolveColor3("var(--font-family)", canvas) || "system-ui";
36750
36753
  const prevPos = /* @__PURE__ */ new Map();
36751
36754
  for (const pn of nodesRef.current) if (pn.x != null && pn.y != null) prevPos.set(pn.id, { x: pn.x, y: pn.y });
@@ -36785,93 +36788,122 @@ var init_GraphCanvas = __esm({
36785
36788
  const COLLIDE_PASSES = 6;
36786
36789
  const LABEL_GAP = 12;
36787
36790
  const LABEL_H = 16;
36788
- const tick = (iter) => {
36791
+ const SIMILARITY_NEIGHBORS = 5;
36792
+ const SIMILARITY_MIN_WEIGHT = 0.25;
36793
+ const drawnPairs = /* @__PURE__ */ new Set();
36794
+ for (const edge of propEdges) drawnPairs.add(edgeKeyOf(edge.source, edge.target));
36795
+ const similarityNeighbors = /* @__PURE__ */ new Map();
36796
+ {
36797
+ const bySource = /* @__PURE__ */ new Map();
36798
+ for (const pair of propSimilarity) {
36799
+ if (pair.weight < SIMILARITY_MIN_WEIGHT) continue;
36800
+ if (drawnPairs.has(edgeKeyOf(pair.source, pair.target))) continue;
36801
+ const arr = bySource.get(pair.source) ?? [];
36802
+ arr.push(pair);
36803
+ bySource.set(pair.source, arr);
36804
+ }
36805
+ for (const [id, arr] of bySource) {
36806
+ arr.sort((a, b) => b.weight - a.weight);
36807
+ const keep = new Set(arr.slice(0, SIMILARITY_NEIGHBORS).map((p) => p.target));
36808
+ similarityNeighbors.set(id, keep);
36809
+ }
36810
+ }
36811
+ const activeSimilarity = propSimilarity.filter((pair) => {
36812
+ if (drawnPairs.has(edgeKeyOf(pair.source, pair.target))) return false;
36813
+ const a = similarityNeighbors.get(pair.source);
36814
+ const b = similarityNeighbors.get(pair.target);
36815
+ return (a?.has(pair.target) ?? false) || (b?.has(pair.source) ?? false);
36816
+ });
36817
+ const tick = (iter, options) => {
36818
+ const skipForces = options?.skipForces ?? false;
36789
36819
  const nodes = nodesRef.current;
36790
36820
  const centerX = w / 2;
36791
36821
  const centerY = h / 2;
36792
- const temp = Math.max(COOL, 1 - iter / maxIterations);
36822
+ const temp = skipForces ? 0 : Math.max(COOL, 1 - iter / maxIterations);
36793
36823
  for (const node of nodes) {
36794
36824
  node.fx = 0;
36795
36825
  node.fy = 0;
36796
36826
  }
36797
- for (let i = 0; i < nodes.length; i++) {
36798
- for (let j = i + 1; j < nodes.length; j++) {
36799
- const dx = nodes[j].x - nodes[i].x;
36800
- const dy = nodes[j].y - nodes[i].y;
36827
+ if (!skipForces) {
36828
+ for (let i = 0; i < nodes.length; i++) {
36829
+ for (let j = i + 1; j < nodes.length; j++) {
36830
+ const dx = nodes[j].x - nodes[i].x;
36831
+ const dy = nodes[j].y - nodes[i].y;
36832
+ const dist = Math.sqrt(dx * dx + dy * dy) || 1;
36833
+ const force = repulsion / (dist * dist) * temp;
36834
+ const fx = dx / dist * force;
36835
+ const fy = dy / dist * force;
36836
+ nodes[i].fx -= fx;
36837
+ nodes[i].fy -= fy;
36838
+ nodes[j].fx += fx;
36839
+ nodes[j].fy += fy;
36840
+ }
36841
+ }
36842
+ const nodeById = new Map(nodes.map((n) => [n.id, n]));
36843
+ const spring = (a, b, rest, k) => {
36844
+ const dx = b.x - a.x;
36845
+ const dy = b.y - a.y;
36801
36846
  const dist = Math.sqrt(dx * dx + dy * dy) || 1;
36802
- const force = repulsion / (dist * dist) * temp;
36847
+ const force = (dist - rest) * k * temp;
36803
36848
  const fx = dx / dist * force;
36804
36849
  const fy = dy / dist * force;
36805
- nodes[i].fx -= fx;
36806
- nodes[i].fy -= fy;
36807
- nodes[j].fx += fx;
36808
- nodes[j].fy += fy;
36850
+ a.fx += fx;
36851
+ a.fy += fy;
36852
+ b.fx -= fx;
36853
+ b.fy -= fy;
36854
+ };
36855
+ for (const edge of propEdges) {
36856
+ const source = nodeById.get(edge.source);
36857
+ const target = nodeById.get(edge.target);
36858
+ if (!source || !target) continue;
36859
+ drawnPairs.add(edgeKeyOf(edge.source, edge.target));
36860
+ const w2 = Math.min(1, Math.max(0, edge.weight ?? 1));
36861
+ spring(source, target, linkDistance * (0.35 + (1 - w2) * 0.3), 0.14);
36809
36862
  }
36810
- }
36811
- const nodeById = new Map(nodes.map((n) => [n.id, n]));
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);
36840
- }
36841
- const centroids = /* @__PURE__ */ new Map();
36842
- for (const node of nodes) {
36843
- const g = node.group ?? "__none__";
36844
- let c = centroids.get(g);
36845
- if (!c) {
36846
- c = { x: 0, y: 0, n: 0 };
36847
- centroids.set(g, c);
36863
+ for (const pair of activeSimilarity) {
36864
+ const source = nodeById.get(pair.source);
36865
+ const target = nodeById.get(pair.target);
36866
+ if (!source || !target) continue;
36867
+ const w2 = Math.min(1, Math.max(0, pair.weight));
36868
+ spring(source, target, linkDistance * (1.35 - 0.55 * w2), 0.015);
36848
36869
  }
36849
- c.x += node.x;
36850
- c.y += node.y;
36851
- c.n += 1;
36852
- }
36853
- const multiCluster = centroids.size > 1;
36854
- for (const node of nodes) {
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;
36870
+ const centroids = /* @__PURE__ */ new Map();
36871
+ for (const node of nodes) {
36872
+ const g = node.group ?? "__none__";
36873
+ let c = centroids.get(g);
36874
+ if (!c) {
36875
+ c = { x: 0, y: 0, n: 0 };
36876
+ centroids.set(g, c);
36877
+ }
36878
+ c.x += node.x;
36879
+ c.y += node.y;
36880
+ c.n += 1;
36881
+ }
36882
+ const multiCluster = centroids.size > 1;
36883
+ for (const node of nodes) {
36884
+ if (multiCluster) {
36885
+ const c = centroids.get(node.group ?? "__none__");
36886
+ if (c && c.n > 1) {
36887
+ node.fx += (c.x / c.n - node.x) * 0.06 * temp;
36888
+ node.fy += (c.y / c.n - node.y) * 0.06 * temp;
36889
+ } else {
36890
+ node.fx += (centerX - node.x) * 0.01 * temp;
36891
+ node.fy += (centerY - node.y) * 0.01 * temp;
36892
+ }
36860
36893
  } else {
36861
- node.fx += (centerX - node.x) * 0.01 * temp;
36862
- node.fy += (centerY - node.y) * 0.01 * temp;
36894
+ node.fx += (centerX - node.x) * 8e-3 * temp;
36895
+ node.fy += (centerY - node.y) * 8e-3 * temp;
36863
36896
  }
36864
- } else {
36865
- node.fx += (centerX - node.x) * 8e-3 * temp;
36866
- node.fy += (centerY - node.y) * 8e-3 * temp;
36897
+ }
36898
+ const damping = 0.9;
36899
+ for (const node of nodes) {
36900
+ node.vx = (node.vx + node.fx) * damping;
36901
+ node.vy = (node.vy + node.fy) * damping;
36902
+ node.x += node.vx;
36903
+ node.y += node.vy;
36867
36904
  }
36868
36905
  }
36869
- const damping = 0.9;
36870
36906
  for (const node of nodes) {
36871
- node.vx = (node.vx + node.fx) * damping;
36872
- node.vy = (node.vy + node.fy) * damping;
36873
- node.x += node.vx;
36874
- node.y += node.vy;
36875
36907
  node.x = Math.max(30, Math.min(w - 30, node.x));
36876
36908
  node.y = Math.max(30, Math.min(h - 30, node.y));
36877
36909
  }
@@ -36922,6 +36954,22 @@ var init_GraphCanvas = __esm({
36922
36954
  };
36923
36955
  if (fullRelayout) {
36924
36956
  for (let i = 0; i < maxIterations; i++) tick(i);
36957
+ for (let i = 0; i < 4; i++) tick(maxIterations, { skipForces: true });
36958
+ const fitPad = 40;
36959
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
36960
+ for (const node of nodesRef.current) {
36961
+ const r = node.size || 8;
36962
+ const lw = showLabels ? node.labelW ?? (node.labelW = node.label ? measureLabelWidth(node.label, labelFont) : 0) : 0;
36963
+ minX = Math.min(minX, node.x - r, node.x - lw / 2);
36964
+ minY = Math.min(minY, node.y - r);
36965
+ maxX = Math.max(maxX, node.x + r, node.x + lw / 2);
36966
+ maxY = Math.max(maxY, node.y + r + LABEL_GAP + LABEL_H);
36967
+ }
36968
+ const bboxW = Math.max(1, maxX - minX + fitPad * 2);
36969
+ const bboxH = Math.max(1, maxY - minY + fitPad * 2);
36970
+ const nextZoom = Math.min(1, viewW / bboxW, viewH / bboxH);
36971
+ setZoom(nextZoom);
36972
+ setOffset({ x: fitPad - minX * nextZoom, y: fitPad - minY * nextZoom });
36925
36973
  laidOutRef.current = true;
36926
36974
  } else {
36927
36975
  const centroids = /* @__PURE__ */ new Map();