@krainovsd/graph 0.14.0-beta.3 → 0.14.0-beta.4
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/lib/cjs/index.cjs +172 -1
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/esm/module/GraphCanvas/GraphCanvas.js +6 -0
- package/lib/esm/module/GraphCanvas/GraphCanvas.js.map +1 -1
- package/lib/esm/module/GraphCanvas/slices/init-draw.js +13 -0
- package/lib/esm/module/GraphCanvas/slices/init-draw.js.map +1 -1
- package/lib/esm/module/GraphCanvas/slices/init-pointer.js +1 -1
- package/lib/esm/module/GraphCanvas/slices/init-pointer.js.map +1 -1
- package/lib/esm/module/GraphCanvas/slices/init-selection.js +161 -0
- package/lib/esm/module/GraphCanvas/slices/init-selection.js.map +1 -0
- package/lib/esm/module/GraphCanvas/slices/init-zoom.js +3 -0
- package/lib/esm/module/GraphCanvas/slices/init-zoom.js.map +1 -1
- package/lib/index.d.ts +12 -0
- package/package.json +1 -1
package/lib/cjs/index.cjs
CHANGED
|
@@ -2098,6 +2098,19 @@ function initDraw() {
|
|
|
2098
2098
|
nodeRenders.forEach((render) => render());
|
|
2099
2099
|
textRenders.forEach((render) => render());
|
|
2100
2100
|
this.context.restore();
|
|
2101
|
+
/** selection rectangle */
|
|
2102
|
+
if (this.isSelecting && this.selectionRect) {
|
|
2103
|
+
const rect = this.selectionRect;
|
|
2104
|
+
const screenX = Math.min(rect.x1, rect.x2) * this.areaTransform.k + this.areaTransform.x;
|
|
2105
|
+
const screenY = Math.min(rect.y1, rect.y2) * this.areaTransform.k + this.areaTransform.y;
|
|
2106
|
+
const screenW = Math.abs(rect.x2 - rect.x1) * this.areaTransform.k;
|
|
2107
|
+
const screenH = Math.abs(rect.y2 - rect.y1) * this.areaTransform.k;
|
|
2108
|
+
this.context.fillStyle = "rgba(66, 133, 244, 0.2)";
|
|
2109
|
+
this.context.fillRect(screenX, screenY, screenW, screenH);
|
|
2110
|
+
this.context.strokeStyle = "rgba(66, 133, 244, 0.8)";
|
|
2111
|
+
this.context.lineWidth = 2;
|
|
2112
|
+
this.context.strokeRect(screenX, screenY, screenW, screenH);
|
|
2113
|
+
}
|
|
2101
2114
|
this.listeners.onDrawFinished?.call?.(this);
|
|
2102
2115
|
}
|
|
2103
2116
|
if (this.graphSettings.showDrawTime) {
|
|
@@ -2110,7 +2123,7 @@ function initPointer() {
|
|
|
2110
2123
|
if (!this.area || !this.nodes)
|
|
2111
2124
|
throw new Error("bad init data");
|
|
2112
2125
|
function onHover(event) {
|
|
2113
|
-
if (!this.area)
|
|
2126
|
+
if (!this.area || this.isSelecting)
|
|
2114
2127
|
return;
|
|
2115
2128
|
let currentNode;
|
|
2116
2129
|
let currentLink;
|
|
@@ -2322,6 +2335,156 @@ function initResize() {
|
|
|
2322
2335
|
observer.observe(this.area);
|
|
2323
2336
|
}
|
|
2324
2337
|
|
|
2338
|
+
function initSelection() {
|
|
2339
|
+
if (!this.area || !this.areaRect)
|
|
2340
|
+
throw new Error("bad init data");
|
|
2341
|
+
this.isSelecting = false;
|
|
2342
|
+
this.selectionRect = null;
|
|
2343
|
+
let selectedNodesSet = new Set();
|
|
2344
|
+
let selectedLinksSet = new Set();
|
|
2345
|
+
let localSelection = false;
|
|
2346
|
+
function onMouseDown(event) {
|
|
2347
|
+
if (event.button !== 0 || !event.shiftKey)
|
|
2348
|
+
return;
|
|
2349
|
+
if (!this.areaRect || !this.area)
|
|
2350
|
+
return;
|
|
2351
|
+
event.stopPropagation();
|
|
2352
|
+
event.preventDefault();
|
|
2353
|
+
const [startX, startY] = pointerGetter(event, this.areaRect, this.areaTransform);
|
|
2354
|
+
this.isSelecting = true;
|
|
2355
|
+
localSelection = true;
|
|
2356
|
+
this.selectionRect = { x1: startX, y1: startY, x2: startX, y2: startY };
|
|
2357
|
+
selectedNodesSet = new Set();
|
|
2358
|
+
selectedLinksSet = new Set();
|
|
2359
|
+
const controller = new AbortController();
|
|
2360
|
+
this.area.addEventListener("mousemove", onMouseMove.bind(this), {
|
|
2361
|
+
signal: controller.signal,
|
|
2362
|
+
});
|
|
2363
|
+
this.area.addEventListener("mouseup", () => {
|
|
2364
|
+
onMouseUp.call(this, controller);
|
|
2365
|
+
}, {
|
|
2366
|
+
signal: controller.signal,
|
|
2367
|
+
});
|
|
2368
|
+
window.addEventListener("keyup", (event) => {
|
|
2369
|
+
if (event.key === "Shift") {
|
|
2370
|
+
onMouseUp.call(this, controller);
|
|
2371
|
+
}
|
|
2372
|
+
}, { signal: controller.signal });
|
|
2373
|
+
}
|
|
2374
|
+
function onMouseMove(event) {
|
|
2375
|
+
if (!this.isSelecting || !this.selectionRect || !this.areaRect)
|
|
2376
|
+
return;
|
|
2377
|
+
event.stopPropagation();
|
|
2378
|
+
const [x, y] = pointerGetter(event, this.areaRect, this.areaTransform);
|
|
2379
|
+
this.selectionRect.x2 = x;
|
|
2380
|
+
this.selectionRect.y2 = y;
|
|
2381
|
+
const rect = normalizeRect(this.selectionRect);
|
|
2382
|
+
const newNodes = new Set();
|
|
2383
|
+
for (let i = 0; i < this.nodes.length; i++) {
|
|
2384
|
+
const node = this.nodes[i];
|
|
2385
|
+
if (node.x == undefined || node.y == undefined)
|
|
2386
|
+
continue;
|
|
2387
|
+
if (node.visible === false)
|
|
2388
|
+
continue;
|
|
2389
|
+
const cache = this.nodeOptionsCache[i];
|
|
2390
|
+
if (isNodeInRect(node, rect, cache)) {
|
|
2391
|
+
newNodes.add(node);
|
|
2392
|
+
}
|
|
2393
|
+
}
|
|
2394
|
+
const newLinks = new Set();
|
|
2395
|
+
for (const link of this.links) {
|
|
2396
|
+
const source = link.source;
|
|
2397
|
+
const target = link.target;
|
|
2398
|
+
if (newNodes.has(source) && newNodes.has(target)) {
|
|
2399
|
+
newLinks.add(link);
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2402
|
+
for (const node of selectedNodesSet) {
|
|
2403
|
+
if (!newNodes.has(node)) {
|
|
2404
|
+
node._selected = false;
|
|
2405
|
+
this.listeners.onSelectionOut?.call(this, node, undefined);
|
|
2406
|
+
}
|
|
2407
|
+
}
|
|
2408
|
+
for (const link of selectedLinksSet) {
|
|
2409
|
+
if (!newLinks.has(link)) {
|
|
2410
|
+
link._selected = false;
|
|
2411
|
+
this.listeners.onSelectionOut?.call(this, undefined, link);
|
|
2412
|
+
}
|
|
2413
|
+
}
|
|
2414
|
+
for (const node of newNodes) {
|
|
2415
|
+
if (!selectedNodesSet.has(node)) {
|
|
2416
|
+
node._selected = true;
|
|
2417
|
+
this.listeners.onSelectionIn?.call(this, node, undefined);
|
|
2418
|
+
}
|
|
2419
|
+
}
|
|
2420
|
+
for (const link of newLinks) {
|
|
2421
|
+
if (!selectedLinksSet.has(link)) {
|
|
2422
|
+
link._selected = true;
|
|
2423
|
+
this.listeners.onSelectionIn?.call(this, undefined, link);
|
|
2424
|
+
}
|
|
2425
|
+
}
|
|
2426
|
+
selectedNodesSet = newNodes;
|
|
2427
|
+
selectedLinksSet = newLinks;
|
|
2428
|
+
this.draw();
|
|
2429
|
+
}
|
|
2430
|
+
function onMouseUp(controller) {
|
|
2431
|
+
controller.abort();
|
|
2432
|
+
if (!this.isSelecting)
|
|
2433
|
+
return;
|
|
2434
|
+
const nodes = Array.from(selectedNodesSet);
|
|
2435
|
+
const links = Array.from(selectedLinksSet);
|
|
2436
|
+
for (const node of nodes) {
|
|
2437
|
+
node._selected = false;
|
|
2438
|
+
}
|
|
2439
|
+
for (const link of links) {
|
|
2440
|
+
link._selected = false;
|
|
2441
|
+
}
|
|
2442
|
+
this.isSelecting = false;
|
|
2443
|
+
this.selectionRect = null;
|
|
2444
|
+
selectedNodesSet = new Set();
|
|
2445
|
+
selectedLinksSet = new Set();
|
|
2446
|
+
this.listeners.onSelectionEnd?.call(this, nodes, links);
|
|
2447
|
+
this.tick();
|
|
2448
|
+
}
|
|
2449
|
+
function onSelectionEnd(event) {
|
|
2450
|
+
if (localSelection) {
|
|
2451
|
+
event.stopImmediatePropagation();
|
|
2452
|
+
localSelection = false;
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
this.area.addEventListener("mousedown", onMouseDown.bind(this), {
|
|
2456
|
+
signal: this.eventAbortController.signal,
|
|
2457
|
+
});
|
|
2458
|
+
this.area.addEventListener("click", onSelectionEnd, { signal: this.eventAbortController.signal });
|
|
2459
|
+
}
|
|
2460
|
+
function normalizeRect(rect) {
|
|
2461
|
+
const x = Math.min(rect.x1, rect.x2);
|
|
2462
|
+
const y = Math.min(rect.y1, rect.y2);
|
|
2463
|
+
const width = Math.abs(rect.x2 - rect.x1);
|
|
2464
|
+
const height = Math.abs(rect.y2 - rect.y1);
|
|
2465
|
+
return { x, y, width, height };
|
|
2466
|
+
}
|
|
2467
|
+
function isNodeInRect(node, rect, cache) {
|
|
2468
|
+
const nx = node.x;
|
|
2469
|
+
const ny = node.y;
|
|
2470
|
+
if (nx == undefined || ny == undefined)
|
|
2471
|
+
return false;
|
|
2472
|
+
if (cache?.shape === "circle") {
|
|
2473
|
+
const r = cache.radius ?? 0;
|
|
2474
|
+
const closestX = Math.max(rect.x, Math.min(nx, rect.x + rect.width));
|
|
2475
|
+
const closestY = Math.max(rect.y, Math.min(ny, rect.y + rect.height));
|
|
2476
|
+
const dx = nx - closestX;
|
|
2477
|
+
const dy = ny - closestY;
|
|
2478
|
+
return dx * dx + dy * dy <= r * r;
|
|
2479
|
+
}
|
|
2480
|
+
const hw = (cache?.width ?? 0) / 2;
|
|
2481
|
+
const hh = (cache?.height ?? 0) / 2;
|
|
2482
|
+
return (nx - hw >= rect.x &&
|
|
2483
|
+
nx + hw <= rect.x + rect.width &&
|
|
2484
|
+
ny - hh >= rect.y &&
|
|
2485
|
+
ny + hh <= rect.y + rect.height);
|
|
2486
|
+
}
|
|
2487
|
+
|
|
2325
2488
|
function updateLinkCache() {
|
|
2326
2489
|
if (!this.context)
|
|
2327
2490
|
return;
|
|
@@ -2574,6 +2737,9 @@ function initZoom(currentZoom) {
|
|
|
2574
2737
|
this._translateExtent = translateExtent;
|
|
2575
2738
|
const zoomInstance = d3Zoom.zoom()
|
|
2576
2739
|
.scaleExtent(zoomExtent)
|
|
2740
|
+
.filter((event) => {
|
|
2741
|
+
return !(event instanceof MouseEvent && event.shiftKey);
|
|
2742
|
+
})
|
|
2577
2743
|
.on("zoom", (event) => {
|
|
2578
2744
|
if (this._zoomAnimating)
|
|
2579
2745
|
return;
|
|
@@ -2816,6 +2982,8 @@ class GraphCanvas {
|
|
|
2816
2982
|
_lastNodeZoomK;
|
|
2817
2983
|
_lastLinkZoomK;
|
|
2818
2984
|
_zoomAnimating = false;
|
|
2985
|
+
isSelecting = false;
|
|
2986
|
+
selectionRect = null;
|
|
2819
2987
|
get simulationWorking() {
|
|
2820
2988
|
const simulationAlpha = this.simulation?.alpha?.() ?? 0;
|
|
2821
2989
|
const simulationAlphaMin = this.simulation?.alphaMin?.() ?? 0;
|
|
@@ -3099,6 +3267,8 @@ class GraphCanvas {
|
|
|
3099
3267
|
this.highlightProgress = 0;
|
|
3100
3268
|
this.highlightStart = null;
|
|
3101
3269
|
this.highlightPositive = false;
|
|
3270
|
+
this.isSelecting = false;
|
|
3271
|
+
this.selectionRect = null;
|
|
3102
3272
|
};
|
|
3103
3273
|
init = () => {
|
|
3104
3274
|
initArea.call(this);
|
|
@@ -3109,6 +3279,7 @@ class GraphCanvas {
|
|
|
3109
3279
|
initDnd.call(this);
|
|
3110
3280
|
initZoom.call(this);
|
|
3111
3281
|
initResize.call(this);
|
|
3282
|
+
initSelection.call(this);
|
|
3112
3283
|
initPointer.call(this);
|
|
3113
3284
|
updateNodeCache.call(this);
|
|
3114
3285
|
updateLinkCache.call(this);
|