@cyber-harbour/ui 1.0.67 → 1.0.69
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 +0 -4
- package/dist/index.d.ts +0 -4
- package/dist/index.js +150 -150
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +170 -170
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/Graph2D/Graph2D.tsx +107 -44
- package/src/Graph2D/types.ts +0 -4
- package/src/Theme/themes/dark.ts +2 -2
package/package.json
CHANGED
package/src/Graph2D/Graph2D.tsx
CHANGED
|
@@ -90,10 +90,8 @@ export const Graph2D: any = forwardRef<Graph2DRef, Graph2DProps>(
|
|
|
90
90
|
highlightLinks: new Set(),
|
|
91
91
|
lastMousePos: { x: 0, y: 0 },
|
|
92
92
|
mustBeStoppedPropagation: false,
|
|
93
|
-
lastHoveredNode: null,
|
|
94
93
|
mouseStartPos: null,
|
|
95
94
|
isDragging: false,
|
|
96
|
-
lastHoveredNodeRef: null,
|
|
97
95
|
width: width * RATIO,
|
|
98
96
|
height: height * RATIO,
|
|
99
97
|
});
|
|
@@ -1062,13 +1060,10 @@ export const Graph2D: any = forwardRef<Graph2DRef, Graph2DProps>(
|
|
|
1062
1060
|
const handleNodeHover = useCallback(
|
|
1063
1061
|
(node: NodeObject | null) => {
|
|
1064
1062
|
// Перевіряємо, чи вузол той самий, що і останній вузол, на який наводили
|
|
1065
|
-
if (node === stateRef.current.
|
|
1063
|
+
if (node === stateRef.current.hoveredNode) {
|
|
1066
1064
|
return; // Пропускаємо обробку, якщо це той самий вузол
|
|
1067
1065
|
}
|
|
1068
1066
|
|
|
1069
|
-
// Оновлюємо посилання на останній наведений вузол
|
|
1070
|
-
stateRef.current.lastHoveredNodeRef = node;
|
|
1071
|
-
|
|
1072
1067
|
const newHighlightNodes = new Set<NodeObject>();
|
|
1073
1068
|
const newHighlightLinks = new Set<any>();
|
|
1074
1069
|
|
|
@@ -1181,6 +1176,49 @@ export const Graph2D: any = forwardRef<Graph2DRef, Graph2DProps>(
|
|
|
1181
1176
|
[getNodeAtPosition]
|
|
1182
1177
|
);
|
|
1183
1178
|
|
|
1179
|
+
const getHoveredIndex = useCallback(
|
|
1180
|
+
(x: number, y: number) => {
|
|
1181
|
+
let hoveredIndex = null;
|
|
1182
|
+
if (canvasRef.current && stateRef.current && buttonImages.length > 0) {
|
|
1183
|
+
const buttonRadius = (config.nodeSizeBase * config.nodeAreaFactor) / 2;
|
|
1184
|
+
const rect = canvasRef.current.getBoundingClientRect();
|
|
1185
|
+
|
|
1186
|
+
// Масштабуємо координати відносно розміру відображення полотна
|
|
1187
|
+
const canvasScaleX = canvasRef.current.width / rect.width;
|
|
1188
|
+
const canvasScaleY = canvasRef.current.height / rect.height;
|
|
1189
|
+
|
|
1190
|
+
// Масштабовані координати миші в системі координат полотна
|
|
1191
|
+
const scaledMouseX = x * canvasScaleX;
|
|
1192
|
+
const scaledMouseY = y * canvasScaleY;
|
|
1193
|
+
|
|
1194
|
+
// Застосовуємо поточну трансформацію для отримання світових координат
|
|
1195
|
+
const worldX = (scaledMouseX - stateRef.current.transform.x) / stateRef.current.transform.k;
|
|
1196
|
+
const worldY = (scaledMouseY - stateRef.current.transform.y) / stateRef.current.transform.k;
|
|
1197
|
+
|
|
1198
|
+
// Node position
|
|
1199
|
+
const nodeX = stateRef.current.selectedNode?.x || 0;
|
|
1200
|
+
const nodeY = stateRef.current.selectedNode?.y || 0;
|
|
1201
|
+
|
|
1202
|
+
// Обчислюємо кількість кнопок та їхні сектори
|
|
1203
|
+
const buttonCount = Math.min(buttonImages.length, 8);
|
|
1204
|
+
const sectorAngle = Math.min((Math.PI * 2) / buttonCount, Math.PI);
|
|
1205
|
+
|
|
1206
|
+
// Перевіряємо, чи вказівник миші знаходиться над будь-яким сектором кнопок
|
|
1207
|
+
for (let i = 0; i < buttonCount; i++) {
|
|
1208
|
+
const startAngle = i * sectorAngle;
|
|
1209
|
+
const endAngle = (i + 1) * sectorAngle;
|
|
1210
|
+
|
|
1211
|
+
if (isPointInButtonSector(worldX, worldY, nodeX, nodeY, buttonRadius, startAngle, endAngle)) {
|
|
1212
|
+
hoveredIndex = i;
|
|
1213
|
+
break;
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
return hoveredIndex;
|
|
1218
|
+
},
|
|
1219
|
+
[buttonImages]
|
|
1220
|
+
);
|
|
1221
|
+
|
|
1184
1222
|
// Обробка руху миші для перетягування та наведення
|
|
1185
1223
|
const handleMouseMove = useCallback(
|
|
1186
1224
|
(event: React.MouseEvent<HTMLCanvasElement>) => {
|
|
@@ -1274,40 +1312,7 @@ export const Graph2D: any = forwardRef<Graph2DRef, Graph2DProps>(
|
|
|
1274
1312
|
|
|
1275
1313
|
// Логіка виявлення наведення на кнопки
|
|
1276
1314
|
if (stateRef.current.selectedNode && canvasRef.current && buttonImages.length > 0) {
|
|
1277
|
-
const
|
|
1278
|
-
|
|
1279
|
-
// Масштабуємо координати відносно розміру відображення полотна
|
|
1280
|
-
const canvasScaleX = canvasRef.current.width / rect.width;
|
|
1281
|
-
const canvasScaleY = canvasRef.current.height / rect.height;
|
|
1282
|
-
|
|
1283
|
-
// Масштабовані координати миші в системі координат полотна
|
|
1284
|
-
const scaledMouseX = x * canvasScaleX;
|
|
1285
|
-
const scaledMouseY = y * canvasScaleY;
|
|
1286
|
-
|
|
1287
|
-
// Застосовуємо поточну трансформацію для отримання світових координат
|
|
1288
|
-
const worldX = (scaledMouseX - stateRef.current.transform.x) / stateRef.current.transform.k;
|
|
1289
|
-
const worldY = (scaledMouseY - stateRef.current.transform.y) / stateRef.current.transform.k;
|
|
1290
|
-
|
|
1291
|
-
// Node position
|
|
1292
|
-
const nodeX = stateRef.current.selectedNode.x || 0;
|
|
1293
|
-
const nodeY = stateRef.current.selectedNode.y || 0;
|
|
1294
|
-
|
|
1295
|
-
// Обчислюємо кількість кнопок та їхні сектори
|
|
1296
|
-
const buttonCount = Math.min(buttonImages.length, 8);
|
|
1297
|
-
const sectorAngle = Math.min((Math.PI * 2) / buttonCount, Math.PI);
|
|
1298
|
-
|
|
1299
|
-
let hoveredIndex = null;
|
|
1300
|
-
|
|
1301
|
-
// Перевіряємо, чи вказівник миші знаходиться над будь-яким сектором кнопок
|
|
1302
|
-
for (let i = 0; i < buttonCount; i++) {
|
|
1303
|
-
const startAngle = i * sectorAngle;
|
|
1304
|
-
const endAngle = (i + 1) * sectorAngle;
|
|
1305
|
-
|
|
1306
|
-
if (isPointInButtonSector(worldX, worldY, nodeX, nodeY, buttonRadius, startAngle, endAngle)) {
|
|
1307
|
-
hoveredIndex = i;
|
|
1308
|
-
break;
|
|
1309
|
-
}
|
|
1310
|
-
}
|
|
1315
|
+
const hoveredIndex = getHoveredIndex(x, y);
|
|
1311
1316
|
if (hoveredIndex !== null) hoveredNode = stateRef.current.selectedNode; // Set hoveredNode to selectedNode for further processing
|
|
1312
1317
|
if (hoveredIndex !== stateRef.current.hoveredButtonIndex) {
|
|
1313
1318
|
shouldRender = true; // Only render if hovered button index has changed
|
|
@@ -1340,8 +1345,8 @@ export const Graph2D: any = forwardRef<Graph2DRef, Graph2DProps>(
|
|
|
1340
1345
|
|
|
1341
1346
|
if (shouldRenderLink) {
|
|
1342
1347
|
renderCanvas2D();
|
|
1348
|
+
return;
|
|
1343
1349
|
}
|
|
1344
|
-
return;
|
|
1345
1350
|
}
|
|
1346
1351
|
}
|
|
1347
1352
|
|
|
@@ -1371,6 +1376,7 @@ export const Graph2D: any = forwardRef<Graph2DRef, Graph2DProps>(
|
|
|
1371
1376
|
handleLinkHover,
|
|
1372
1377
|
renderCanvas2D,
|
|
1373
1378
|
isPointInButtonSector,
|
|
1379
|
+
getHoveredIndex,
|
|
1374
1380
|
]
|
|
1375
1381
|
);
|
|
1376
1382
|
|
|
@@ -1396,7 +1402,9 @@ export const Graph2D: any = forwardRef<Graph2DRef, Graph2DProps>(
|
|
|
1396
1402
|
if (rect) {
|
|
1397
1403
|
const x = event.clientX - rect.left;
|
|
1398
1404
|
const y = event.clientY - rect.top;
|
|
1399
|
-
|
|
1405
|
+
if (buttonImages.length > 0 && stateRef.current.hoveredButtonIndex === null) {
|
|
1406
|
+
stateRef.current.hoveredButtonIndex = getHoveredIndex(x, y);
|
|
1407
|
+
}
|
|
1400
1408
|
// Спочатку перевіряємо, чи ми клікаємо на кнопку обраного вузла
|
|
1401
1409
|
let isButtonClick = false;
|
|
1402
1410
|
if (
|
|
@@ -1409,6 +1417,7 @@ export const Graph2D: any = forwardRef<Graph2DRef, Graph2DProps>(
|
|
|
1409
1417
|
if (button && button.onClick) {
|
|
1410
1418
|
button.onClick(stateRef.current.selectedNode);
|
|
1411
1419
|
isButtonClick = true;
|
|
1420
|
+
stateRef.current.hoveredButtonIndex = null;
|
|
1412
1421
|
}
|
|
1413
1422
|
}
|
|
1414
1423
|
|
|
@@ -1465,7 +1474,16 @@ export const Graph2D: any = forwardRef<Graph2DRef, Graph2DProps>(
|
|
|
1465
1474
|
|
|
1466
1475
|
renderCanvas2D();
|
|
1467
1476
|
},
|
|
1468
|
-
[
|
|
1477
|
+
[
|
|
1478
|
+
buttons,
|
|
1479
|
+
renderCanvas2D,
|
|
1480
|
+
handleNodeClick,
|
|
1481
|
+
handleBackgroundClick,
|
|
1482
|
+
getLinkAtPosition,
|
|
1483
|
+
handleLinkClick,
|
|
1484
|
+
getHoveredIndex,
|
|
1485
|
+
buttonImages,
|
|
1486
|
+
]
|
|
1469
1487
|
);
|
|
1470
1488
|
|
|
1471
1489
|
// Обробляємо подію колеса миші для масштабування
|
|
@@ -1509,6 +1527,47 @@ export const Graph2D: any = forwardRef<Graph2DRef, Graph2DProps>(
|
|
|
1509
1527
|
[renderCanvas2D]
|
|
1510
1528
|
);
|
|
1511
1529
|
|
|
1530
|
+
//Обробка подій на тачскрін девайсах
|
|
1531
|
+
const convertTouchToMouseEvent = (
|
|
1532
|
+
e: TouchEvent | React.TouchEvent<HTMLCanvasElement>,
|
|
1533
|
+
callback: (event: React.MouseEvent<HTMLCanvasElement>) => void
|
|
1534
|
+
) => {
|
|
1535
|
+
const touch = e.touches[0];
|
|
1536
|
+
if (touch) {
|
|
1537
|
+
// Create a synthetic React.MouseEvent-like object
|
|
1538
|
+
const syntheticEvent = {
|
|
1539
|
+
clientX: touch.clientX,
|
|
1540
|
+
clientY: touch.clientY,
|
|
1541
|
+
} as React.MouseEvent<HTMLCanvasElement>;
|
|
1542
|
+
callback(syntheticEvent);
|
|
1543
|
+
}
|
|
1544
|
+
};
|
|
1545
|
+
const handleTouchStart = useCallback(
|
|
1546
|
+
(e: React.TouchEvent<HTMLCanvasElement>) => {
|
|
1547
|
+
convertTouchToMouseEvent(e, handleMouseDown);
|
|
1548
|
+
},
|
|
1549
|
+
[handleMouseDown]
|
|
1550
|
+
);
|
|
1551
|
+
|
|
1552
|
+
const handleTouchEnd = useCallback(
|
|
1553
|
+
(e: TouchEvent) => {
|
|
1554
|
+
if (stateRef.current.mustBeStoppedPropagation) {
|
|
1555
|
+
e.preventDefault();
|
|
1556
|
+
e.stopPropagation();
|
|
1557
|
+
}
|
|
1558
|
+
stateRef.current.mustBeStoppedPropagation = false;
|
|
1559
|
+
convertTouchToMouseEvent(e, handleMouseUp);
|
|
1560
|
+
},
|
|
1561
|
+
[handleMouseUp]
|
|
1562
|
+
);
|
|
1563
|
+
|
|
1564
|
+
const handleTouchMove = useCallback(
|
|
1565
|
+
(e: React.TouchEvent<HTMLCanvasElement>) => {
|
|
1566
|
+
convertTouchToMouseEvent(e, handleMouseMove);
|
|
1567
|
+
},
|
|
1568
|
+
[handleMouseMove]
|
|
1569
|
+
);
|
|
1570
|
+
|
|
1512
1571
|
useImperativeHandle(
|
|
1513
1572
|
ref,
|
|
1514
1573
|
() => ({
|
|
@@ -1647,12 +1706,14 @@ export const Graph2D: any = forwardRef<Graph2DRef, Graph2DProps>(
|
|
|
1647
1706
|
|
|
1648
1707
|
// Add event listener with passive: false to allow preventDefault
|
|
1649
1708
|
canvas.addEventListener('wheel', handleWheel, { passive: false });
|
|
1709
|
+
canvas.addEventListener('touchend', handleTouchEnd, { passive: false });
|
|
1650
1710
|
|
|
1651
1711
|
// Clean up when component unmounts
|
|
1652
1712
|
return () => {
|
|
1653
1713
|
canvas.removeEventListener('wheel', handleWheel);
|
|
1714
|
+
canvas.removeEventListener('touchend', handleTouchEnd);
|
|
1654
1715
|
};
|
|
1655
|
-
}, [handleWheel]);
|
|
1716
|
+
}, [handleWheel, handleTouchEnd]);
|
|
1656
1717
|
|
|
1657
1718
|
return (
|
|
1658
1719
|
<Wrapper>
|
|
@@ -1665,6 +1726,8 @@ export const Graph2D: any = forwardRef<Graph2DRef, Graph2DProps>(
|
|
|
1665
1726
|
onMouseUp={handleMouseUp}
|
|
1666
1727
|
onMouseLeave={handleMouseUp}
|
|
1667
1728
|
onClick={handleClick}
|
|
1729
|
+
onTouchStart={handleTouchStart}
|
|
1730
|
+
onTouchMove={handleTouchMove}
|
|
1668
1731
|
/>
|
|
1669
1732
|
</Wrapper>
|
|
1670
1733
|
);
|
package/src/Graph2D/types.ts
CHANGED
|
@@ -57,10 +57,6 @@ export interface GraphState {
|
|
|
57
57
|
lastMousePos: { x: number; y: number };
|
|
58
58
|
/** Флаг необходимости остановки распространения события */
|
|
59
59
|
mustBeStoppedPropagation: boolean;
|
|
60
|
-
/** Последний узел, над которым был курсор */
|
|
61
|
-
lastHoveredNode: NodeObject | null;
|
|
62
|
-
/** Кэшированная ссылка на последний узел, над которым был курсор (для избежания лишних вычислений) */
|
|
63
|
-
lastHoveredNodeRef: NodeObject | null;
|
|
64
60
|
/** Начальная позиция курсора при начале перетаскивания */
|
|
65
61
|
mouseStartPos: { x: number; y: number } | null;
|
|
66
62
|
/** Флаг режима перетаскивания */
|