@opentrace/components 0.1.1-rc.11 → 0.1.1-rc.30

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.
Files changed (39) hide show
  1. package/dist/opentrace-components.cjs +159 -47
  2. package/dist/opentrace-components.cjs.map +1 -1
  3. package/dist/opentrace-components.js +160 -48
  4. package/dist/opentrace-components.js.map +1 -1
  5. package/dist/src/GraphCanvas.d.ts +22 -1
  6. package/dist/src/GraphCanvas.d.ts.map +1 -1
  7. package/dist/src/colors/linkColors.d.ts.map +1 -1
  8. package/dist/src/colors/nodeColors.d.ts.map +1 -1
  9. package/dist/src/config/graphLayout.d.ts +3 -2
  10. package/dist/src/config/graphLayout.d.ts.map +1 -1
  11. package/dist/src/graph/LayoutPipeline.d.ts.map +1 -1
  12. package/dist/src/graph/__tests__/optimizeWorker.test.d.ts +2 -0
  13. package/dist/src/graph/__tests__/optimizeWorker.test.d.ts.map +1 -0
  14. package/dist/src/graph/__tests__/spacingWorker.test.d.ts +2 -0
  15. package/dist/src/graph/__tests__/spacingWorker.test.d.ts.map +1 -0
  16. package/dist/src/graph/__tests__/useCommunities.test.d.ts +2 -0
  17. package/dist/src/graph/__tests__/useCommunities.test.d.ts.map +1 -0
  18. package/dist/src/graph/__tests__/useGraphFilters.test.d.ts +2 -0
  19. package/dist/src/graph/__tests__/useGraphFilters.test.d.ts.map +1 -0
  20. package/dist/src/graph/__tests__/useHighlights.test.d.ts +2 -0
  21. package/dist/src/graph/__tests__/useHighlights.test.d.ts.map +1 -0
  22. package/dist/src/graph/types.d.ts +2 -0
  23. package/dist/src/graph/types.d.ts.map +1 -1
  24. package/dist/src/graph/useGraphFilters.d.ts.map +1 -1
  25. package/dist/src/graph/useGraphInstance.d.ts.map +1 -1
  26. package/dist/src/graph/useGraphVisuals.d.ts.map +1 -1
  27. package/dist/src/index.d.ts +2 -1
  28. package/dist/src/index.d.ts.map +1 -1
  29. package/dist/src/sigma/zoomToNodes.d.ts +7 -2
  30. package/dist/src/sigma/zoomToNodes.d.ts.map +1 -1
  31. package/dist/{useHighlights-BHlafcBH.js → useHighlights-DbMfb0-p.js} +122 -74
  32. package/dist/useHighlights-DbMfb0-p.js.map +1 -0
  33. package/dist/{useHighlights-D6Jl6Woe.cjs → useHighlights-fRWg-A_c.cjs} +122 -74
  34. package/dist/useHighlights-fRWg-A_c.cjs.map +1 -0
  35. package/dist/utils.cjs +1 -1
  36. package/dist/utils.js +1 -1
  37. package/package.json +1 -1
  38. package/dist/useHighlights-BHlafcBH.js.map +0 -1
  39. package/dist/useHighlights-D6Jl6Woe.cjs.map +0 -1
@@ -1,7 +1,7 @@
1
1
  import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
2
  import t, { forwardRef, useRef, useState, useEffect, useImperativeHandle, useMemo, useContext, createContext, useCallback, memo, createElement as createElement$1, useLayoutEffect } from "react";
3
- import { f as eventsExports, h as getDefaultExportFromCjs, r as requireIsGraph, G as Graph, g as getCommunityColor, a as buildCommunityNames, b as buildCommunityColorMap, c as getLinkColor, d as getNodeColor, i as requireGetters, u as useCommunities, j as useGraphFilters, e as useHighlights } from "./useHighlights-BHlafcBH.js";
4
- import { s } from "./useHighlights-BHlafcBH.js";
3
+ import { f as eventsExports, h as getDefaultExportFromCjs, r as requireIsGraph, G as Graph, g as getCommunityColor, a as buildCommunityNames, b as buildCommunityColorMap, c as getLinkColor, d as getNodeColor, i as requireGetters, u as useCommunities, j as useGraphFilters, e as useHighlights } from "./useHighlights-DbMfb0-p.js";
4
+ import { s } from "./useHighlights-DbMfb0-p.js";
5
5
  function _toPrimitive$1(t2, r) {
6
6
  if ("object" != typeof t2 || !t2) return t2;
7
7
  var e2 = t2[Symbol.toPrimitive];
@@ -5251,7 +5251,7 @@ createEdgeCurveProgram({
5251
5251
  });
5252
5252
  const NODE_SIZE_MIN = 2;
5253
5253
  const NODE_SIZE_MAX = 8;
5254
- const NODE_SIZE_DEGREE_SCALE = 1.1;
5254
+ const NODE_SIZE_DEGREE_SCALE = 1;
5255
5255
  const NODE_SIZE_MULTIPLIERS = {
5256
5256
  Repository: 1,
5257
5257
  // All other STRUCTURAL_TYPES default to this:
@@ -5286,8 +5286,9 @@ const FA2_ADJUST_SIZES = true;
5286
5286
  const FA2_DURATION = 3e3;
5287
5287
  const NOVERLAP_MAX_ITERATIONS = 50;
5288
5288
  const NOVERLAP_RATIO = 1.5;
5289
- const NOVERLAP_MARGIN = 10;
5289
+ const NOVERLAP_MARGIN = 25;
5290
5290
  const NOVERLAP_EXPANSION = 1.5;
5291
+ const NOVERLAP_COMMUNITY_ITERATIONS = 20;
5291
5292
  const EDGE_PROGRAM_THRESHOLD = 5e4;
5292
5293
  const LABEL_RENDERED_SIZE_THRESHOLD = 8;
5293
5294
  const LABEL_SIZE = 12;
@@ -5317,6 +5318,7 @@ const DEFAULT_LAYOUT_CONFIG = {
5317
5318
  noverlapRatio: NOVERLAP_RATIO,
5318
5319
  noverlapMargin: NOVERLAP_MARGIN,
5319
5320
  noverlapExpansion: NOVERLAP_EXPANSION,
5321
+ noverlapCommunityIterations: NOVERLAP_COMMUNITY_ITERATIONS,
5320
5322
  louvainResolution: LOUVAIN_RESOLUTION,
5321
5323
  edgeProgramThreshold: 5e4,
5322
5324
  // Graph structure
@@ -5367,6 +5369,13 @@ function useGraphInstance({
5367
5369
  if (allNodes.length === 0) return;
5368
5370
  const { assignments, colorMap, names } = communityData;
5369
5371
  const { getNodeColor: getNodeColor2, getLinkColor: getLinkColor2, getCommunityColor: getCommunityColor2 } = layoutConfig;
5372
+ const degreeMap = /* @__PURE__ */ new Map();
5373
+ for (const link of allLinks) {
5374
+ const s2 = endpointId(link.source);
5375
+ const t2 = endpointId(link.target);
5376
+ degreeMap.set(s2, (degreeMap.get(s2) || 0) + 1);
5377
+ degreeMap.set(t2, (degreeMap.get(t2) || 0) + 1);
5378
+ }
5370
5379
  const nodeIdSet = /* @__PURE__ */ new Set();
5371
5380
  const serializedNodes = allNodes.map((node) => {
5372
5381
  nodeIdSet.add(node.id);
@@ -5374,13 +5383,17 @@ function useGraphInstance({
5374
5383
  const commColor = getCommunityColor2(assignments, colorMap, node.id);
5375
5384
  const cid = assignments[node.id];
5376
5385
  const commName = cid !== void 0 ? names.get(cid) : void 0;
5386
+ const degree = degreeMap.get(node.id) || 0;
5387
+ const size = nodeSize(degree, node.type, structuralTypes);
5377
5388
  return {
5378
5389
  key: node.id,
5379
5390
  attributes: {
5380
5391
  label: node.name || node.id,
5392
+ _originalLabel: node.name || node.id,
5381
5393
  x: 0,
5382
5394
  y: 0,
5383
- size: nodeSize(0, node.type, structuralTypes),
5395
+ size,
5396
+ _baseSize: size,
5384
5397
  nodeType: node.type,
5385
5398
  _graphNode: node,
5386
5399
  _typeColor: typeColor,
@@ -5545,21 +5558,24 @@ function useGraphVisuals(graph, layoutReady, visualState, layoutConfig, _degreeM
5545
5558
  return attrs;
5546
5559
  });
5547
5560
  const defaultEdgeSize = isLargeGraph ? EDGE_SIZE_DEFAULT_LINE : EDGE_SIZE_DEFAULT;
5548
- graph.updateEachEdgeAttributes((_id, attrs, source, target) => {
5549
- const linkKey = `${source}-${target}`;
5550
- const isHighlighted = highlightLinks.has(linkKey);
5551
- const baseColor = getLinkColor2(attrs.label);
5552
- if (hasHighlight) {
5553
- attrs.color = isHighlighted ? baseColor : dimColor(baseColor, EDGE_OPACITY_DIMMED);
5554
- attrs.size = isHighlighted ? EDGE_SIZE_HIGHLIGHTED : EDGE_SIZE_DIMMED;
5555
- attrs.zIndex = isHighlighted ? 1 : 0;
5556
- } else {
5557
- attrs.color = dimColor(baseColor, EDGE_OPACITY_DEFAULT);
5558
- attrs.size = defaultEdgeSize;
5559
- attrs.zIndex = 0;
5560
- }
5561
- return attrs;
5562
- });
5561
+ graph.updateEachEdgeAttributes(
5562
+ (_id, attrs, source, target) => {
5563
+ const linkKey = `${source}-${target}`;
5564
+ const isHighlighted = highlightLinks.has(linkKey);
5565
+ const baseColor = getLinkColor2(attrs.label);
5566
+ if (hasHighlight) {
5567
+ attrs.color = isHighlighted ? baseColor : dimColor(baseColor, EDGE_OPACITY_DIMMED);
5568
+ attrs.size = isHighlighted ? EDGE_SIZE_HIGHLIGHTED : EDGE_SIZE_DIMMED;
5569
+ attrs.zIndex = isHighlighted ? 1 : 0;
5570
+ } else {
5571
+ attrs.color = dimColor(baseColor, EDGE_OPACITY_DEFAULT);
5572
+ attrs.size = defaultEdgeSize;
5573
+ attrs.zIndex = 0;
5574
+ }
5575
+ return attrs;
5576
+ },
5577
+ { attributes: ["zIndex"] }
5578
+ );
5563
5579
  }, [graph, layoutReady, visualState, layoutConfig, isLargeGraph]);
5564
5580
  }
5565
5581
  function c(r, n2) {
@@ -6784,7 +6800,7 @@ const e = /* @__PURE__ */ getDefaultExportFromCjs(workerExports);
6784
6800
  function n(t2 = {}) {
6785
6801
  return c(e, t2);
6786
6802
  }
6787
- function zoomToNodes(sigma, nodeIds, duration = 600, padding = 0.1) {
6803
+ function zoomToNodes(sigma, nodeIds, duration = 600, padding = 0.2) {
6788
6804
  let minX = Infinity;
6789
6805
  let maxX = -Infinity;
6790
6806
  let minY = Infinity;
@@ -6801,21 +6817,29 @@ function zoomToNodes(sigma, nodeIds, duration = 600, padding = 0.1) {
6801
6817
  }
6802
6818
  if (count === 0) return;
6803
6819
  const camera = sigma.getCamera();
6804
- if (count === 1 || maxX - minX < 1 && maxY - minY < 1) {
6805
- camera.animate(
6806
- { x: (minX + maxX) / 2, y: (minY + maxY) / 2, ratio: 0.1 },
6807
- { duration }
6808
- );
6809
- return;
6810
- }
6811
6820
  const cx = (minX + maxX) / 2;
6812
6821
  const cy = (minY + maxY) / 2;
6822
+ if (count === 1 || maxX - minX < 1e-3 && maxY - minY < 1e-3) {
6823
+ camera.animate({ x: cx, y: cy, ratio: 0.1 }, { duration });
6824
+ return;
6825
+ }
6826
+ const refState = { x: 0.5, y: 0.5, ratio: 1, angle: 0 };
6813
6827
  const { width, height } = sigma.getDimensions();
6814
- const graphWidth = maxX - minX;
6815
- const graphHeight = maxY - minY;
6816
- const ratioX = graphWidth / (width * (1 - padding * 2));
6817
- const ratioY = graphHeight / (height * (1 - padding * 2));
6818
- const ratio = Math.max(ratioX, ratioY, 0.01);
6828
+ const topLeft = sigma.viewportToFramedGraph(
6829
+ { x: 0, y: 0 },
6830
+ { cameraState: refState }
6831
+ );
6832
+ const bottomRight = sigma.viewportToFramedGraph(
6833
+ { x: width, y: height },
6834
+ { cameraState: refState }
6835
+ );
6836
+ const fullW = Math.abs(bottomRight.x - topLeft.x);
6837
+ const fullH = Math.abs(topLeft.y - bottomRight.y);
6838
+ const bboxW = maxX - minX;
6839
+ const bboxH = maxY - minY;
6840
+ const scaleX = fullW > 0 ? bboxW / (fullW * (1 - 2 * padding)) : 1;
6841
+ const scaleY = fullH > 0 ? bboxH / (fullH * (1 - 2 * padding)) : 1;
6842
+ const ratio = Math.max(Math.max(scaleX, scaleY), 0.01);
6819
6843
  camera.animate({ x: cx, y: cy, ratio }, { duration });
6820
6844
  }
6821
6845
  function zoomToFit(sigma, duration = 400) {
@@ -7016,8 +7040,9 @@ function LayoutPipeline({
7016
7040
  });
7017
7041
  }
7018
7042
  const margin = layoutConfig.noverlapMargin * scale2;
7043
+ const iters = layoutConfig.noverlapCommunityIterations ?? 20;
7019
7044
  const nodeArr = [...subGraph.entries()];
7020
- for (let iter = 0; iter < 10; iter++) {
7045
+ for (let iter = 0; iter < iters; iter++) {
7021
7046
  for (let i = 0; i < nodeArr.length; i++) {
7022
7047
  const [, a] = nodeArr[i];
7023
7048
  for (let j2 = i + 1; j2 < nodeArr.length; j2++) {
@@ -7093,6 +7118,10 @@ function LayoutPipeline({
7093
7118
  }, [layoutReady, optimizeTick, layoutConfig, start, stop, sigma]);
7094
7119
  return null;
7095
7120
  }
7121
+ let _hoveredNodeKey = null;
7122
+ function setHoveredNodeKey(key) {
7123
+ _hoveredNodeKey = key;
7124
+ }
7096
7125
  let cached = null;
7097
7126
  function resolveThemeColors() {
7098
7127
  const root = document.documentElement;
@@ -7108,7 +7137,8 @@ function resolveThemeColors() {
7108
7137
  return cached;
7109
7138
  }
7110
7139
  function drawNodeHover(context, data, settings) {
7111
- data.key;
7140
+ const key = data.key;
7141
+ if (key && _hoveredNodeKey !== null && key !== _hoveredNodeKey) return;
7112
7142
  const size = settings.labelSize;
7113
7143
  const font = settings.labelFont;
7114
7144
  const weight = settings.labelWeight;
@@ -7208,18 +7238,35 @@ function GraphEventHandler({
7208
7238
  useEffect(() => {
7209
7239
  const container = sigma.getContainer();
7210
7240
  const graph = sigma.getGraph();
7241
+ const mouseCanvas = container.querySelector(
7242
+ ".sigma-mouse"
7243
+ );
7244
+ let overNode = false;
7245
+ let overEdge = false;
7246
+ function updateCursor() {
7247
+ const value = overNode || overEdge ? "pointer" : "grab";
7248
+ container.style.cursor = value;
7249
+ if (mouseCanvas) mouseCanvas.style.cursor = value;
7250
+ }
7251
+ updateCursor();
7211
7252
  const handlers = {
7212
- enterNode: () => {
7213
- container.style.cursor = "pointer";
7253
+ enterNode: ({ node }) => {
7254
+ setHoveredNodeKey(node);
7255
+ overNode = true;
7256
+ updateCursor();
7214
7257
  },
7215
7258
  leaveNode: () => {
7216
- container.style.cursor = "default";
7259
+ setHoveredNodeKey(null);
7260
+ overNode = false;
7261
+ updateCursor();
7217
7262
  },
7218
7263
  enterEdge: () => {
7219
- container.style.cursor = "pointer";
7264
+ overEdge = true;
7265
+ updateCursor();
7220
7266
  },
7221
7267
  leaveEdge: () => {
7222
- container.style.cursor = "default";
7268
+ overEdge = false;
7269
+ updateCursor();
7223
7270
  },
7224
7271
  clickNode: ({ node }) => {
7225
7272
  if (!onNodeClick) return;
@@ -7288,6 +7335,12 @@ const GraphCanvas = memo(
7288
7335
  selectedNodeId = null,
7289
7336
  hops = 2,
7290
7337
  getSubType = defaultGetSubType,
7338
+ highlightNodes: highlightNodesProp,
7339
+ highlightLinks: highlightLinksProp,
7340
+ labelNodes: labelNodesProp,
7341
+ availableSubTypes = EMPTY_SUB_TYPES,
7342
+ zIndex: zIndexEnabled = false,
7343
+ communityData: communityDataProp,
7291
7344
  onNodeClick,
7292
7345
  onEdgeClick,
7293
7346
  onStageClick,
@@ -7297,7 +7350,8 @@ const GraphCanvas = memo(
7297
7350
  } = props;
7298
7351
  const sigmaRef = useRef(null);
7299
7352
  const [optimizeTick, setOptimizeTick] = useState(0);
7300
- const communityData = useCommunities(nodes, links, layoutConfig);
7353
+ const internalCommunityData = useCommunities(nodes, links, layoutConfig);
7354
+ const communityData = communityDataProp ?? internalCommunityData;
7301
7355
  const filterState = useMemo(
7302
7356
  () => ({
7303
7357
  hiddenNodeTypes,
@@ -7318,10 +7372,10 @@ const GraphCanvas = memo(
7318
7372
  layoutReady,
7319
7373
  filterState,
7320
7374
  communityData.assignments,
7321
- EMPTY_SUB_TYPES,
7375
+ availableSubTypes,
7322
7376
  getSubType
7323
7377
  );
7324
- const highlights = useHighlights(
7378
+ const internalHighlights = useHighlights(
7325
7379
  graph,
7326
7380
  layoutReady,
7327
7381
  nodes,
@@ -7331,6 +7385,9 @@ const GraphCanvas = memo(
7331
7385
  hops,
7332
7386
  filterState
7333
7387
  );
7388
+ const effectiveHighlightNodes = highlightNodesProp ?? internalHighlights.highlightNodes;
7389
+ const effectiveHighlightLinks = highlightLinksProp ?? internalHighlights.highlightLinks;
7390
+ const effectiveLabelNodes = labelNodesProp ?? internalHighlights.labelNodes;
7334
7391
  const degreeMap = useMemo(() => {
7335
7392
  const map = /* @__PURE__ */ new Map();
7336
7393
  links.forEach((l) => {
@@ -7345,12 +7402,18 @@ const GraphCanvas = memo(
7345
7402
  const visualState = useMemo(
7346
7403
  () => ({
7347
7404
  colorMode,
7348
- highlightNodes: highlights.highlightNodes,
7349
- highlightLinks: highlights.highlightLinks,
7350
- labelNodes: highlights.labelNodes,
7405
+ highlightNodes: effectiveHighlightNodes,
7406
+ highlightLinks: effectiveHighlightLinks,
7407
+ labelNodes: effectiveLabelNodes,
7351
7408
  selectedNodeId: selectedNodeId ?? null
7352
7409
  }),
7353
- [colorMode, highlights, selectedNodeId]
7410
+ [
7411
+ colorMode,
7412
+ effectiveHighlightNodes,
7413
+ effectiveHighlightLinks,
7414
+ effectiveLabelNodes,
7415
+ selectedNodeId
7416
+ ]
7354
7417
  );
7355
7418
  useGraphVisuals(
7356
7419
  graph,
@@ -7360,6 +7423,34 @@ const GraphCanvas = memo(
7360
7423
  degreeMap,
7361
7424
  isLargeGraph
7362
7425
  );
7426
+ useEffect(() => {
7427
+ if (!zIndexEnabled) return;
7428
+ const container = sigmaRef.current?.getContainer?.();
7429
+ if (!container) return;
7430
+ const layers = [
7431
+ "sigma-edges",
7432
+ "sigma-edgeLabels",
7433
+ "sigma-nodes",
7434
+ "sigma-labels",
7435
+ "sigma-hovers",
7436
+ "sigma-hoverNodes",
7437
+ "sigma-mouse"
7438
+ ];
7439
+ const els = layers.map(
7440
+ (cls) => container.querySelector(`.${cls}`)
7441
+ );
7442
+ const hasSelection = effectiveHighlightNodes.size > 0;
7443
+ if (hasSelection) {
7444
+ const zMap = [2, 3, 1, 4, 6, 5, 7];
7445
+ els.forEach((el, i) => {
7446
+ if (el) el.style.zIndex = String(zMap[i]);
7447
+ });
7448
+ } else {
7449
+ els.forEach((el) => {
7450
+ if (el) el.style.zIndex = "";
7451
+ });
7452
+ }
7453
+ }, [zIndexEnabled, effectiveHighlightNodes]);
7363
7454
  const sigmaSettings = useMemo(
7364
7455
  () => ({
7365
7456
  defaultNodeType: "circle",
@@ -7375,9 +7466,10 @@ const GraphCanvas = memo(
7375
7466
  labelSize: LABEL_SIZE,
7376
7467
  defaultDrawNodeHover: drawNodeHover,
7377
7468
  allowInvalidContainer: true,
7469
+ zIndex: zIndexEnabled,
7378
7470
  zoomToSizeRatioFunction: (ratio) => Math.pow(ratio, ZOOM_SIZE_EXPONENT)
7379
7471
  }),
7380
- [isLargeGraph]
7472
+ [isLargeGraph, zIndexEnabled]
7381
7473
  );
7382
7474
  const handleSigmaReady = useCallback(
7383
7475
  (sigma) => {
@@ -7444,6 +7536,24 @@ const GraphCanvas = memo(
7444
7536
  },
7445
7537
  optimize: () => {
7446
7538
  setOptimizeTick((t2) => t2 + 1);
7539
+ },
7540
+ zoomIn: (duration = 300) => {
7541
+ if (sigmaRef.current) {
7542
+ const camera = sigmaRef.current.getCamera();
7543
+ camera.animatedZoom({ duration });
7544
+ }
7545
+ },
7546
+ zoomOut: (duration = 300) => {
7547
+ if (sigmaRef.current) {
7548
+ const camera = sigmaRef.current.getCamera();
7549
+ camera.animatedUnzoom({ duration });
7550
+ }
7551
+ },
7552
+ resetCamera: (duration = 400) => {
7553
+ if (sigmaRef.current) {
7554
+ const camera = sigmaRef.current.getCamera();
7555
+ camera.animatedReset({ duration });
7556
+ }
7447
7557
  }
7448
7558
  }),
7449
7559
  [nodes, links, hops, onNodeClick]
@@ -8676,6 +8786,7 @@ export {
8676
8786
  FA2_GRAVITY,
8677
8787
  FA2_SCALING_RATIO,
8678
8788
  FilterPanel,
8789
+ GraphCanvas as Graph,
8679
8790
  GraphBadge,
8680
8791
  GraphCanvas,
8681
8792
  GraphLegend,
@@ -8697,6 +8808,7 @@ export {
8697
8808
  getCommunityColor,
8698
8809
  getLinkColor,
8699
8810
  getNodeColor,
8811
+ setHoveredNodeKey,
8700
8812
  s as shouldHideNode,
8701
8813
  useCommunities,
8702
8814
  useGraphFilters,