@cyber-harbour/ui 1.0.69 → 1.0.70
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.
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +143 -143
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +132 -132
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/Graph2D/Graph2D.tsx +74 -18
- package/src/Graph2D/types.ts +2 -0
package/package.json
CHANGED
package/src/Graph2D/Graph2D.tsx
CHANGED
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
} from 'd3';
|
|
28
28
|
import { styled, useTheme } from 'styled-components';
|
|
29
29
|
import GraphLoader from './GraphLoader';
|
|
30
|
+
import { hexToRgba } from '../Theme';
|
|
30
31
|
|
|
31
32
|
const RATIO = window.devicePixelRatio || 1;
|
|
32
33
|
// Завантаження та підготовка зображень кнопок
|
|
@@ -365,6 +366,44 @@ export const Graph2D: any = forwardRef<Graph2DRef, Graph2DProps>(
|
|
|
365
366
|
[config, theme.graph2D.link]
|
|
366
367
|
);
|
|
367
368
|
|
|
369
|
+
const drawIconWithOptionalCounter = (
|
|
370
|
+
ctx: CanvasRenderingContext2D,
|
|
371
|
+
icon: HTMLImageElement,
|
|
372
|
+
iconX: number,
|
|
373
|
+
iconY: number,
|
|
374
|
+
iconSize: number,
|
|
375
|
+
counter: number | null | undefined,
|
|
376
|
+
textColor?: string
|
|
377
|
+
) => {
|
|
378
|
+
try {
|
|
379
|
+
if (counter !== null && counter !== undefined) {
|
|
380
|
+
const fontSize = iconSize * 0.8;
|
|
381
|
+
ctx.font = `${fontSize}px sans-serif`;
|
|
382
|
+
ctx.textBaseline = 'middle';
|
|
383
|
+
ctx.textAlign = 'left';
|
|
384
|
+
|
|
385
|
+
const counterText = new Intl.NumberFormat('en', {
|
|
386
|
+
notation: 'compact',
|
|
387
|
+
maximumFractionDigits: 1,
|
|
388
|
+
minimumFractionDigits: 0,
|
|
389
|
+
compactDisplay: 'short',
|
|
390
|
+
}).format(counter);
|
|
391
|
+
|
|
392
|
+
const textWidth = ctx.measureText(counterText).width;
|
|
393
|
+
const spacing = iconSize * 0.3;
|
|
394
|
+
const totalWidth = iconSize + spacing + textWidth;
|
|
395
|
+
const offsetX = totalWidth / 2;
|
|
396
|
+
|
|
397
|
+
ctx.drawImage(icon, iconX - offsetX, iconY - iconSize / 2, iconSize, iconSize);
|
|
398
|
+
ctx.fillStyle = textColor || '#99989C';
|
|
399
|
+
ctx.fillText(counterText, iconX - offsetX + iconSize + spacing, iconY);
|
|
400
|
+
} else {
|
|
401
|
+
ctx.drawImage(icon, iconX - iconSize / 2, iconY - iconSize / 2, iconSize, iconSize);
|
|
402
|
+
}
|
|
403
|
+
} catch (error) {
|
|
404
|
+
console.warn('Error rendering icon:', error);
|
|
405
|
+
}
|
|
406
|
+
};
|
|
368
407
|
// Функція для рендерингу кнопок навколо вузла
|
|
369
408
|
const renderNodeButtons = useCallback(
|
|
370
409
|
(node: NodeObject, ctx: CanvasRenderingContext2D) => {
|
|
@@ -410,32 +449,49 @@ export const Graph2D: any = forwardRef<Graph2DRef, Graph2DProps>(
|
|
|
410
449
|
|
|
411
450
|
// Вибираємо відповідну іконку залежно від стану наведення
|
|
412
451
|
const buttonImage = buttonImages[i];
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
452
|
+
// Якщо кнопка в лоадінгу — малюємо спінер
|
|
453
|
+
if (buttonImage.loading) {
|
|
454
|
+
const spinnerRadius = iconSize / 3;
|
|
455
|
+
const spinnerLineLength = iconSize / 3;
|
|
456
|
+
const spinnerLineWidth = 1;
|
|
457
|
+
|
|
458
|
+
ctx.save();
|
|
459
|
+
ctx.translate(iconX, iconY);
|
|
460
|
+
|
|
461
|
+
// Малюємо кілька променів (ліній) по колу
|
|
462
|
+
for (let j = 0; j < 12; j++) {
|
|
463
|
+
const alpha = j / 12;
|
|
464
|
+
ctx.beginPath();
|
|
465
|
+
ctx.strokeStyle = hexToRgba(theme.colors.primary.main, alpha);
|
|
466
|
+
ctx.lineWidth = spinnerLineWidth;
|
|
467
|
+
ctx.moveTo(0, -spinnerRadius);
|
|
468
|
+
ctx.lineTo(0, -spinnerRadius - spinnerLineLength);
|
|
469
|
+
ctx.stroke();
|
|
470
|
+
ctx.rotate((Math.PI * 2) / 12);
|
|
421
471
|
}
|
|
472
|
+
|
|
473
|
+
ctx.restore();
|
|
422
474
|
} else {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
475
|
+
const icon = isHovered ? buttonImage.hoverImg : buttonImage.normalImg;
|
|
476
|
+
//каунтер може не існувати
|
|
477
|
+
const counter = buttonImage.count ? buttonImage.count(node) : null;
|
|
478
|
+
// Малюємо іконку
|
|
479
|
+
if (icon.complete) {
|
|
480
|
+
drawIconWithOptionalCounter(ctx, icon, iconX, iconY, iconSize, counter, theme.colors?.text?.lighter);
|
|
481
|
+
} else {
|
|
482
|
+
// Встановлюємо обробник onload, якщо зображення ще не завантажено
|
|
483
|
+
icon.onload = () => {
|
|
484
|
+
if (ctx2dRef.current) {
|
|
485
|
+
drawIconWithOptionalCounter(ctx, icon, iconX, iconY, iconSize, counter, theme.colors?.text?.lighter);
|
|
430
486
|
}
|
|
431
|
-
}
|
|
432
|
-
}
|
|
487
|
+
};
|
|
488
|
+
}
|
|
433
489
|
}
|
|
434
490
|
}
|
|
435
491
|
|
|
436
492
|
ctx.restore();
|
|
437
493
|
},
|
|
438
|
-
[buttonImages, theme.graph2D?.button]
|
|
494
|
+
[buttonImages, theme.graph2D?.button, theme.colors?.text?.lighter]
|
|
439
495
|
);
|
|
440
496
|
|
|
441
497
|
const renderNodes = useCallback(
|