@krainovsd/graph 0.14.0-beta.2 → 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 +180 -9
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/esm/module/GraphCanvas/GraphCanvas.js +14 -8
- 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 +16 -4
- 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;
|
|
@@ -2900,16 +3068,16 @@ class GraphCanvas {
|
|
|
2900
3068
|
}
|
|
2901
3069
|
this.animateZoom(area, target, this.areaTransform, duration);
|
|
2902
3070
|
};
|
|
2903
|
-
changeData = (options, alpha = 0.5, clearCache = true) => {
|
|
3071
|
+
changeData = (options, alpha = 0.5, clearCache = true, precompute = false) => {
|
|
2904
3072
|
if (options.links != undefined)
|
|
2905
3073
|
this.links = options.links;
|
|
2906
3074
|
if (options.nodes != undefined)
|
|
2907
3075
|
this.nodes = options.nodes;
|
|
2908
3076
|
if (options.nodes != undefined || options.links != undefined) {
|
|
2909
|
-
this.updateData(alpha, clearCache);
|
|
3077
|
+
this.updateData(alpha, clearCache, precompute);
|
|
2910
3078
|
}
|
|
2911
3079
|
};
|
|
2912
|
-
changeSettings = (options, clearCache = true) => {
|
|
3080
|
+
changeSettings = (options, clearCache = true, precompute = false) => {
|
|
2913
3081
|
if (options.graphSettings) {
|
|
2914
3082
|
this.graphSettings = graphSettingsGetter(options.graphSettings, this.graphSettings);
|
|
2915
3083
|
this.draw = initDraw.call(this);
|
|
@@ -2956,7 +3124,7 @@ class GraphCanvas {
|
|
|
2956
3124
|
initCollideForce.call(this, true);
|
|
2957
3125
|
}
|
|
2958
3126
|
if (options.forceSettings) {
|
|
2959
|
-
return void this.updateSimulation();
|
|
3127
|
+
return void this.updateSimulation(precompute);
|
|
2960
3128
|
}
|
|
2961
3129
|
this.tick();
|
|
2962
3130
|
};
|
|
@@ -3085,10 +3253,10 @@ class GraphCanvas {
|
|
|
3085
3253
|
this.eventAbortController.abort();
|
|
3086
3254
|
this.eventAbortController = new AbortController();
|
|
3087
3255
|
};
|
|
3088
|
-
updateSimulation = () => {
|
|
3256
|
+
updateSimulation = (precompute = false) => {
|
|
3089
3257
|
if (this.simulation) {
|
|
3090
3258
|
initSimulationForces.call(this);
|
|
3091
|
-
this.restart(1);
|
|
3259
|
+
this.restart(1, { precompute });
|
|
3092
3260
|
}
|
|
3093
3261
|
};
|
|
3094
3262
|
clearState = () => {
|
|
@@ -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,12 +3279,13 @@ 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);
|
|
3115
3286
|
this.tick();
|
|
3116
3287
|
};
|
|
3117
|
-
updateData = (alpha = 0.5, clearCache = true) => {
|
|
3288
|
+
updateData = (alpha = 0.5, clearCache = true, precompute = false) => {
|
|
3118
3289
|
if (clearCache) {
|
|
3119
3290
|
this.clearCache(clearCache);
|
|
3120
3291
|
}
|
|
@@ -3131,7 +3302,7 @@ class GraphCanvas {
|
|
|
3131
3302
|
.iterations(this.forceSettings.forces && this.forceSettings.linkForce
|
|
3132
3303
|
? this.forceSettings.linkIterations
|
|
3133
3304
|
: 0));
|
|
3134
|
-
this.restart(alpha);
|
|
3305
|
+
this.restart(alpha, { precompute });
|
|
3135
3306
|
initZoom.call(this, this.areaTransform);
|
|
3136
3307
|
}
|
|
3137
3308
|
};
|