@opentrace/components 0.1.1-rc.66 → 0.1.1-rc.78

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.
@@ -2,7 +2,7 @@ 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
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-CmOAWaLE.js";
4
4
  import { s } from "./useHighlights-CmOAWaLE.js";
5
- import { A, I, d, n } from "./urlNormalize-KY4ngwCQ.js";
5
+ import { A, I, d, n } from "./urlNormalize-D4tuih2G.js";
6
6
  function _toPrimitive$1(t2, r) {
7
7
  if ("object" != typeof t2 || !t2) return t2;
8
8
  var e2 = t2[Symbol.toPrimitive];
@@ -7194,6 +7194,68 @@ function LayoutPipeline({
7194
7194
  }, [layoutReady, optimizeTick, layoutConfig, start, stop, sigma]);
7195
7195
  return null;
7196
7196
  }
7197
+ let cached$1 = null;
7198
+ function resolveLabelColor() {
7199
+ const root = document.documentElement;
7200
+ const key = `${root.dataset.theme ?? ""}_${root.dataset.mode ?? ""}`;
7201
+ if (cached$1 && cached$1.key === key) return cached$1.fg;
7202
+ const style = getComputedStyle(root);
7203
+ const fg = style.getPropertyValue("--foreground").trim() || "#e2e8f0";
7204
+ cached$1 = { fg, key };
7205
+ return fg;
7206
+ }
7207
+ let renderedBoxes = [];
7208
+ let hoverBoxes = [];
7209
+ function resetLabelGrid() {
7210
+ renderedBoxes = [];
7211
+ }
7212
+ function resetHoverGrid() {
7213
+ hoverBoxes = [];
7214
+ }
7215
+ function overlaps(boxes, x, y, w2, h2) {
7216
+ for (const box of boxes) {
7217
+ if (x < box.x + box.w && x + w2 > box.x && y < box.y + box.h && y + h2 > box.y) {
7218
+ return true;
7219
+ }
7220
+ }
7221
+ return false;
7222
+ }
7223
+ function overlapsExistingHover(x, y, w2, h2) {
7224
+ return overlaps(hoverBoxes, x, y, w2, h2);
7225
+ }
7226
+ function pushHoverBox(x, y, w2, h2) {
7227
+ hoverBoxes.push({ x, y, w: w2, h: h2 });
7228
+ }
7229
+ function drawNodeLabel(context, data, settings) {
7230
+ if (!data.label) return;
7231
+ const extras = data;
7232
+ if (extras.highlighted) return;
7233
+ const size = settings.labelSize;
7234
+ const font = settings.labelFont;
7235
+ const weight = settings.labelWeight;
7236
+ const fg = resolveLabelColor();
7237
+ context.font = `${weight} ${size}px ${font}`;
7238
+ const textWidth = context.measureText(data.label).width;
7239
+ const x = data.x + data.size + 3;
7240
+ const y = data.y + size / 3;
7241
+ const boxX = x - 1;
7242
+ const boxY = y - size;
7243
+ const boxW = textWidth + 2;
7244
+ const boxH = size + 4;
7245
+ if (overlaps(renderedBoxes, boxX, boxY, boxW, boxH)) {
7246
+ return;
7247
+ }
7248
+ renderedBoxes.push({ x: boxX, y: boxY, w: boxW, h: boxH });
7249
+ context.save();
7250
+ context.strokeStyle = "rgba(0,0,0,0.7)";
7251
+ context.lineWidth = 3;
7252
+ context.lineJoin = "round";
7253
+ context.strokeText(data.label, x, y);
7254
+ context.restore();
7255
+ context.font = `${weight} ${size}px ${font}`;
7256
+ context.fillStyle = fg;
7257
+ context.fillText(data.label, x, y);
7258
+ }
7197
7259
  let _hoveredNodeKey = null;
7198
7260
  function setHoveredNodeKey(key) {
7199
7261
  _hoveredNodeKey = key;
@@ -7212,15 +7274,73 @@ function resolveThemeColors() {
7212
7274
  };
7213
7275
  return cached;
7214
7276
  }
7277
+ let tooltipBuffer = [];
7278
+ let tooltipContext = null;
7279
+ let flushScheduled = false;
7280
+ function flushTooltips() {
7281
+ const ctx = tooltipContext;
7282
+ if (!ctx || tooltipBuffer.length === 0) return;
7283
+ const colors = resolveThemeColors();
7284
+ for (const cmd of tooltipBuffer) {
7285
+ const radius = 4;
7286
+ ctx.fillStyle = colors.bg;
7287
+ ctx.shadowOffsetX = 0;
7288
+ ctx.shadowOffsetY = 2;
7289
+ ctx.shadowBlur = 8;
7290
+ ctx.shadowColor = "rgba(0,0,0,0.5)";
7291
+ ctx.beginPath();
7292
+ ctx.roundRect(cmd.x, cmd.y, cmd.w, cmd.h, radius);
7293
+ ctx.fill();
7294
+ if (cmd.isHovered) {
7295
+ ctx.shadowBlur = 0;
7296
+ ctx.strokeStyle = cmd.color;
7297
+ ctx.lineWidth = 2;
7298
+ ctx.stroke();
7299
+ }
7300
+ ctx.shadowOffsetX = 0;
7301
+ ctx.shadowOffsetY = 0;
7302
+ ctx.shadowBlur = 0;
7303
+ const textX = cmd.x + 4;
7304
+ const centerY = cmd.y + cmd.h / 2;
7305
+ if (cmd.label) {
7306
+ ctx.fillStyle = colors.fg;
7307
+ ctx.font = `${cmd.weight} ${cmd.labelSize}px ${cmd.font}`;
7308
+ ctx.fillText(
7309
+ cmd.label,
7310
+ textX,
7311
+ centerY + (cmd.subtitle ? -cmd.lineHeight / 2 + cmd.labelSize * 0.35 : cmd.labelSize / 3)
7312
+ );
7313
+ }
7314
+ if (cmd.subtitle) {
7315
+ ctx.fillStyle = colors.muted;
7316
+ ctx.font = `${cmd.smallSize}px ${cmd.font}`;
7317
+ ctx.fillText(
7318
+ cmd.subtitle,
7319
+ textX,
7320
+ centerY + cmd.lineHeight / 2
7321
+ );
7322
+ }
7323
+ }
7324
+ tooltipBuffer = [];
7325
+ tooltipContext = null;
7326
+ }
7327
+ let lastHoverFrameTime = 0;
7215
7328
  function drawNodeHover(context, data, settings) {
7216
- const key = data.key;
7217
- if (key && _hoveredNodeKey !== null && key !== _hoveredNodeKey) return;
7329
+ const now = performance.now();
7330
+ if (now - lastHoverFrameTime > 8) {
7331
+ resetHoverGrid();
7332
+ tooltipBuffer = [];
7333
+ lastHoverFrameTime = now;
7334
+ }
7335
+ tooltipContext = context;
7336
+ const extras = data;
7337
+ const key = extras.key;
7338
+ const isActuallyHovered = key != null && _hoveredNodeKey != null && key === _hoveredNodeKey;
7339
+ const isSelected = extras.borderSize != null && extras.borderSize > 0;
7218
7340
  const size = settings.labelSize;
7219
7341
  const font = settings.labelFont;
7220
7342
  const weight = settings.labelWeight;
7221
- const colors = resolveThemeColors();
7222
7343
  const PADDING = 4;
7223
- const extras = data;
7224
7344
  const label = typeof data.label === "string" ? data.label : typeof extras._originalLabel === "string" ? extras._originalLabel : "";
7225
7345
  const nodeType = extras.nodeType;
7226
7346
  const communityName = extras._communityName;
@@ -7234,63 +7354,58 @@ function drawNodeHover(context, data, settings) {
7234
7354
  subtitleWidth = context.measureText(subtitle).width;
7235
7355
  }
7236
7356
  const textWidth = Math.max(labelWidth, subtitleWidth);
7237
- if (textWidth === 0 && !subtitle) {
7238
- context.beginPath();
7239
- context.arc(data.x, data.y, data.size + PADDING, 0, Math.PI * 2);
7240
- context.closePath();
7241
- context.fillStyle = colors.bg;
7242
- context.shadowBlur = 10;
7243
- context.shadowColor = "rgba(0,0,0,0.5)";
7244
- context.fill();
7245
- context.shadowBlur = 0;
7246
- context.beginPath();
7247
- context.arc(data.x, data.y, data.size, 0, Math.PI * 2);
7248
- context.closePath();
7249
- context.fillStyle = data.color;
7250
- context.fill();
7251
- return;
7252
- }
7253
7357
  const boxWidth = Math.round(textWidth + 8);
7254
7358
  const lineHeight = size + 2;
7255
7359
  const lines = subtitle ? 2 : 1;
7256
7360
  const boxHeight = Math.round(lineHeight * lines + PADDING * 2);
7257
- const nodeRadius = Math.max(data.size, size / 2) + PADDING;
7258
- const angleRadian = Math.asin(Math.min(1, boxHeight / 2 / nodeRadius));
7259
- const xDelta = Math.sqrt(
7260
- Math.abs(Math.pow(nodeRadius, 2) - Math.pow(boxHeight / 2, 2))
7261
- );
7262
- context.fillStyle = colors.bg;
7263
- context.shadowOffsetX = 0;
7264
- context.shadowOffsetY = 2;
7265
- context.shadowBlur = 10;
7266
- context.shadowColor = "rgba(0,0,0,0.5)";
7267
- context.beginPath();
7268
- context.moveTo(data.x + xDelta, data.y + boxHeight / 2);
7269
- context.lineTo(data.x + nodeRadius + boxWidth, data.y + boxHeight / 2);
7270
- context.lineTo(data.x + nodeRadius + boxWidth, data.y - boxHeight / 2);
7271
- context.lineTo(data.x + xDelta, data.y - boxHeight / 2);
7272
- context.arc(data.x, data.y, nodeRadius, angleRadian, -angleRadian);
7273
- context.closePath();
7274
- context.fill();
7275
- context.shadowOffsetX = 0;
7276
- context.shadowOffsetY = 0;
7277
- context.shadowBlur = 0;
7278
- const textX = data.x + nodeRadius + 4;
7279
- if (label) {
7280
- context.fillStyle = colors.fg;
7281
- context.font = `${weight} ${size}px ${font}`;
7282
- context.fillText(label, textX, data.y + (subtitle ? -1 : size / 3));
7283
- }
7284
- if (subtitle) {
7285
- context.fillStyle = colors.muted;
7286
- context.font = `${smallSize}px ${font}`;
7287
- context.fillText(subtitle, textX, data.y + lineHeight - 2);
7361
+ const tooltipGap = 4;
7362
+ const tx = data.x + data.size + tooltipGap;
7363
+ const ty = data.y - boxHeight / 2;
7364
+ const hasTooltip = textWidth > 0 || subtitle;
7365
+ let drawTooltip = hasTooltip;
7366
+ const pad = 8;
7367
+ const cullX = data.x - data.size - pad;
7368
+ const cullY = data.y - Math.max(boxHeight / 2, data.size) - pad;
7369
+ const cullW = data.size * 2 + boxWidth + tooltipGap + pad * 2;
7370
+ const cullH = Math.max(boxHeight, data.size * 2) + pad * 2;
7371
+ if (hasTooltip && !isActuallyHovered && !isSelected) {
7372
+ if (overlapsExistingHover(cullX, cullY, cullW, cullH)) {
7373
+ drawTooltip = false;
7374
+ } else {
7375
+ pushHoverBox(cullX, cullY, cullW, cullH);
7376
+ }
7377
+ } else if (hasTooltip) {
7378
+ pushHoverBox(cullX, cullY, cullW, cullH);
7288
7379
  }
7289
7380
  context.beginPath();
7290
7381
  context.arc(data.x, data.y, data.size, 0, Math.PI * 2);
7291
7382
  context.closePath();
7292
7383
  context.fillStyle = data.color;
7293
7384
  context.fill();
7385
+ if (drawTooltip) {
7386
+ tooltipBuffer.push({
7387
+ x: tx,
7388
+ y: ty,
7389
+ w: boxWidth,
7390
+ h: boxHeight,
7391
+ label,
7392
+ subtitle,
7393
+ labelSize: size,
7394
+ smallSize,
7395
+ font,
7396
+ weight,
7397
+ lineHeight,
7398
+ color: data.color,
7399
+ isHovered: isActuallyHovered
7400
+ });
7401
+ }
7402
+ if (!flushScheduled) {
7403
+ flushScheduled = true;
7404
+ queueMicrotask(() => {
7405
+ flushScheduled = false;
7406
+ flushTooltips();
7407
+ });
7408
+ }
7294
7409
  }
7295
7410
  function SigmaRefCapture({
7296
7411
  onReady
@@ -7303,6 +7418,14 @@ function SigmaRefCapture({
7303
7418
  onReady(sigma);
7304
7419
  }
7305
7420
  }, [sigma, onReady]);
7421
+ useEffect(() => {
7422
+ const s2 = sigma;
7423
+ const handler = () => resetLabelGrid();
7424
+ s2.on("beforeRender", handler);
7425
+ return () => {
7426
+ s2.off("beforeRender", handler);
7427
+ };
7428
+ }, [sigma]);
7306
7429
  return null;
7307
7430
  }
7308
7431
  function GraphEventHandler({
@@ -7556,6 +7679,7 @@ const GraphCanvas = memo(
7556
7679
  labelFont: LABEL_FONT,
7557
7680
  labelColor: { color: LABEL_COLOR },
7558
7681
  labelSize: LABEL_SIZE,
7682
+ defaultDrawNodeLabel: drawNodeLabel,
7559
7683
  defaultDrawNodeHover: drawNodeHover,
7560
7684
  allowInvalidContainer: true,
7561
7685
  zIndex: zIndexEnabled,
@@ -9111,10 +9235,13 @@ export {
9111
9235
  buildCommunityNames,
9112
9236
  d as detectProvider,
9113
9237
  drawNodeHover,
9238
+ drawNodeLabel,
9239
+ flushTooltips,
9114
9240
  getCommunityColor,
9115
9241
  getLinkColor,
9116
9242
  getNodeColor,
9117
9243
  n as normalizeRepoUrl,
9244
+ resetLabelGrid,
9118
9245
  setHoveredNodeKey,
9119
9246
  s as shouldHideNode,
9120
9247
  useCommunities,