force-graph 1.49.5 → 1.50.0
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/README.md +10 -6
- package/dist/force-graph.d.ts +7 -1
- package/dist/force-graph.js +25 -8
- package/dist/force-graph.js.map +1 -1
- package/dist/force-graph.min.js +3 -3
- package/dist/force-graph.mjs +22 -5
- package/example/dag-yarn/index.html +1 -1
- package/package.json +10 -10
- package/src/canvas-force-graph.js +12 -4
- package/src/force-graph.js +6 -0
- package/src/index.d.ts +5 -0
package/dist/force-graph.mjs
CHANGED
|
@@ -418,6 +418,11 @@ var CanvasForceGraph = Kapsule({
|
|
|
418
418
|
triggerUpdate: false
|
|
419
419
|
},
|
|
420
420
|
// in link length ratio per frame
|
|
421
|
+
linkDirectionalParticleOffset: {
|
|
422
|
+
"default": 0,
|
|
423
|
+
triggerUpdate: false
|
|
424
|
+
},
|
|
425
|
+
// starting position offset along the link's length, like a pre-delay. Values between [0, 1]
|
|
421
426
|
linkDirectionalParticleWidth: {
|
|
422
427
|
"default": 4,
|
|
423
428
|
triggerUpdate: false
|
|
@@ -425,6 +430,9 @@ var CanvasForceGraph = Kapsule({
|
|
|
425
430
|
linkDirectionalParticleColor: {
|
|
426
431
|
triggerUpdate: false
|
|
427
432
|
},
|
|
433
|
+
linkDirectionalParticleCanvasObject: {
|
|
434
|
+
triggerUpdate: false
|
|
435
|
+
},
|
|
428
436
|
globalScale: {
|
|
429
437
|
"default": 1,
|
|
430
438
|
triggerUpdate: false
|
|
@@ -746,6 +754,7 @@ var CanvasForceGraph = Kapsule({
|
|
|
746
754
|
function paintPhotons() {
|
|
747
755
|
var getNumPhotons = accessorFn(state.linkDirectionalParticles);
|
|
748
756
|
var getSpeed = accessorFn(state.linkDirectionalParticleSpeed);
|
|
757
|
+
var getOffset = accessorFn(state.linkDirectionalParticleOffset);
|
|
749
758
|
var getDiameter = accessorFn(state.linkDirectionalParticleWidth);
|
|
750
759
|
var getVisibility = accessorFn(state.linkVisibility);
|
|
751
760
|
var getColor = accessorFn(state.linkDirectionalParticleColor || state.linkColor);
|
|
@@ -759,6 +768,7 @@ var CanvasForceGraph = Kapsule({
|
|
|
759
768
|
if (!start || !end || !start.hasOwnProperty('x') || !end.hasOwnProperty('x')) return; // skip invalid link
|
|
760
769
|
|
|
761
770
|
var particleSpeed = getSpeed(link);
|
|
771
|
+
var particleOffset = Math.abs(getOffset(link));
|
|
762
772
|
var photons = link.__photons || [];
|
|
763
773
|
var photonR = Math.max(0, getDiameter(link) / 2) / Math.sqrt(state.globalScale);
|
|
764
774
|
var photonColor = getColor(link) || 'rgba(0,0,0,0.28)';
|
|
@@ -771,7 +781,7 @@ var CanvasForceGraph = Kapsule({
|
|
|
771
781
|
photons.forEach(function (photon) {
|
|
772
782
|
var singleHop = !!photon.__singleHop;
|
|
773
783
|
if (!photon.hasOwnProperty('__progressRatio')) {
|
|
774
|
-
photon.__progressRatio = singleHop ? 0 : cyclePhotonIdx / numCyclePhotons;
|
|
784
|
+
photon.__progressRatio = singleHop ? 0 : (cyclePhotonIdx + particleOffset) / numCyclePhotons;
|
|
775
785
|
}
|
|
776
786
|
!singleHop && cyclePhotonIdx++; // increase regular photon index
|
|
777
787
|
|
|
@@ -791,9 +801,13 @@ var CanvasForceGraph = Kapsule({
|
|
|
791
801
|
x: start.x + (end.x - start.x) * photonPosRatio || 0,
|
|
792
802
|
y: start.y + (end.y - start.y) * photonPosRatio || 0
|
|
793
803
|
};
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
804
|
+
if (state.linkDirectionalParticleCanvasObject) {
|
|
805
|
+
state.linkDirectionalParticleCanvasObject(coords.x, coords.y, link, ctx, state.globalScale);
|
|
806
|
+
} else {
|
|
807
|
+
ctx.beginPath();
|
|
808
|
+
ctx.arc(coords.x, coords.y, photonR, 0, 2 * Math.PI, false);
|
|
809
|
+
ctx.fill();
|
|
810
|
+
}
|
|
797
811
|
});
|
|
798
812
|
if (needsCleanup) {
|
|
799
813
|
// remove expired single hop photons
|
|
@@ -945,7 +959,7 @@ var DRAG_CLICK_TOLERANCE_PX = 5; // How many px can a node be accidentally dragg
|
|
|
945
959
|
// Expose config from forceGraph
|
|
946
960
|
var bindFG = linkKapsule('forceGraph', CanvasForceGraph);
|
|
947
961
|
var bindBoth = linkKapsule(['forceGraph', 'shadowGraph'], CanvasForceGraph);
|
|
948
|
-
var linkedProps = Object.assign.apply(Object, _toConsumableArray(['nodeColor', 'nodeAutoColorBy', 'nodeCanvasObject', 'nodeCanvasObjectMode', 'linkColor', 'linkAutoColorBy', 'linkLineDash', 'linkWidth', 'linkCanvasObject', 'linkCanvasObjectMode', 'linkDirectionalArrowLength', 'linkDirectionalArrowColor', 'linkDirectionalArrowRelPos', 'linkDirectionalParticles', 'linkDirectionalParticleSpeed', 'linkDirectionalParticleWidth', 'linkDirectionalParticleColor', 'dagMode', 'dagLevelDistance', 'dagNodeFilter', 'onDagError', 'd3AlphaMin', 'd3AlphaDecay', 'd3VelocityDecay', 'warmupTicks', 'cooldownTicks', 'cooldownTime', 'onEngineTick', 'onEngineStop'].map(function (p) {
|
|
962
|
+
var linkedProps = Object.assign.apply(Object, _toConsumableArray(['nodeColor', 'nodeAutoColorBy', 'nodeCanvasObject', 'nodeCanvasObjectMode', 'linkColor', 'linkAutoColorBy', 'linkLineDash', 'linkWidth', 'linkCanvasObject', 'linkCanvasObjectMode', 'linkDirectionalArrowLength', 'linkDirectionalArrowColor', 'linkDirectionalArrowRelPos', 'linkDirectionalParticles', 'linkDirectionalParticleSpeed', 'linkDirectionalParticleOffset', 'linkDirectionalParticleWidth', 'linkDirectionalParticleColor', 'linkDirectionalParticleCanvasObject', 'dagMode', 'dagLevelDistance', 'dagNodeFilter', 'onDagError', 'd3AlphaMin', 'd3AlphaDecay', 'd3VelocityDecay', 'warmupTicks', 'cooldownTicks', 'cooldownTime', 'onEngineTick', 'onEngineStop'].map(function (p) {
|
|
949
963
|
return _defineProperty({}, p, bindFG.linkProp(p));
|
|
950
964
|
})).concat(_toConsumableArray(['nodeRelSize', 'nodeId', 'nodeVal', 'nodeVisibility', 'linkSource', 'linkTarget', 'linkVisibility', 'linkCurvature'].map(function (p) {
|
|
951
965
|
return _defineProperty({}, p, bindBoth.linkProp(p));
|
|
@@ -1539,6 +1553,9 @@ var forceGraph = Kapsule({
|
|
|
1539
1553
|
|
|
1540
1554
|
// Handle click/touch events on nodes/links
|
|
1541
1555
|
container.addEventListener('pointerup', function (ev) {
|
|
1556
|
+
if (!state.isPointerPressed) {
|
|
1557
|
+
return; // don't trigger click events if pointer is not pressed on the canvas
|
|
1558
|
+
}
|
|
1542
1559
|
state.isPointerPressed = false;
|
|
1543
1560
|
if (state.isPointerDragging) {
|
|
1544
1561
|
state.isPointerDragging = false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "force-graph",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.50.0",
|
|
4
4
|
"description": "2D force-directed graph rendered on HTML5 canvas",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"unpkg": "dist/force-graph.min.js",
|
|
@@ -59,24 +59,24 @@
|
|
|
59
59
|
"d3-scale-chromatic": "1 - 3",
|
|
60
60
|
"d3-selection": "2 - 3",
|
|
61
61
|
"d3-zoom": "2 - 3",
|
|
62
|
-
"float-tooltip": "^1.
|
|
62
|
+
"float-tooltip": "^1.7",
|
|
63
63
|
"index-array-by": "1",
|
|
64
64
|
"kapsule": "^1.16",
|
|
65
65
|
"lodash-es": "4"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
|
-
"@babel/core": "^7.
|
|
69
|
-
"@babel/preset-env": "^7.
|
|
68
|
+
"@babel/core": "^7.28.0",
|
|
69
|
+
"@babel/preset-env": "^7.28.0",
|
|
70
70
|
"@rollup/plugin-babel": "^6.0.4",
|
|
71
|
-
"@rollup/plugin-commonjs": "^28.0.
|
|
72
|
-
"@rollup/plugin-node-resolve": "^16.0.
|
|
71
|
+
"@rollup/plugin-commonjs": "^28.0.6",
|
|
72
|
+
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
73
73
|
"@rollup/plugin-terser": "^0.4.4",
|
|
74
|
-
"postcss": "^8.5.
|
|
74
|
+
"postcss": "^8.5.6",
|
|
75
75
|
"rimraf": "^6.0.1",
|
|
76
|
-
"rollup": "^4.
|
|
77
|
-
"rollup-plugin-dts": "^6.
|
|
76
|
+
"rollup": "^4.44.1",
|
|
77
|
+
"rollup-plugin-dts": "^6.2.1",
|
|
78
78
|
"rollup-plugin-postcss": "^4.0.2",
|
|
79
|
-
"typescript": "^5.8.
|
|
79
|
+
"typescript": "^5.8.3"
|
|
80
80
|
},
|
|
81
81
|
"engines": {
|
|
82
82
|
"node": ">=12"
|
|
@@ -78,8 +78,10 @@ export default Kapsule({
|
|
|
78
78
|
linkDirectionalArrowRelPos: { default: 0.5, triggerUpdate: false, onChange: notifyRedraw }, // value between 0<>1 indicating the relative pos along the (exposed) line
|
|
79
79
|
linkDirectionalParticles: { default: 0, triggerUpdate: false, onChange: updDataPhotons }, // animate photons travelling in the link direction
|
|
80
80
|
linkDirectionalParticleSpeed: { default: 0.01, triggerUpdate: false }, // in link length ratio per frame
|
|
81
|
+
linkDirectionalParticleOffset: { default: 0, triggerUpdate: false }, // starting position offset along the link's length, like a pre-delay. Values between [0, 1]
|
|
81
82
|
linkDirectionalParticleWidth: { default: 4, triggerUpdate: false },
|
|
82
83
|
linkDirectionalParticleColor: { triggerUpdate: false },
|
|
84
|
+
linkDirectionalParticleCanvasObject: { triggerUpdate: false },
|
|
83
85
|
globalScale: { default: 1, triggerUpdate: false },
|
|
84
86
|
d3AlphaMin: { default: 0, triggerUpdate: false},
|
|
85
87
|
d3AlphaDecay: { default: 0.0228, triggerUpdate: false, onChange(alphaDecay, state) { state.forceLayout.alphaDecay(alphaDecay) }},
|
|
@@ -365,6 +367,7 @@ export default Kapsule({
|
|
|
365
367
|
function paintPhotons() {
|
|
366
368
|
const getNumPhotons = accessorFn(state.linkDirectionalParticles);
|
|
367
369
|
const getSpeed = accessorFn(state.linkDirectionalParticleSpeed);
|
|
370
|
+
const getOffset = accessorFn(state.linkDirectionalParticleOffset);
|
|
368
371
|
const getDiameter = accessorFn(state.linkDirectionalParticleWidth);
|
|
369
372
|
const getVisibility = accessorFn(state.linkVisibility);
|
|
370
373
|
const getColor = accessorFn(state.linkDirectionalParticleColor || state.linkColor);
|
|
@@ -382,6 +385,7 @@ export default Kapsule({
|
|
|
382
385
|
if (!start || !end || !start.hasOwnProperty('x') || !end.hasOwnProperty('x')) return; // skip invalid link
|
|
383
386
|
|
|
384
387
|
const particleSpeed = getSpeed(link);
|
|
388
|
+
const particleOffset = Math.abs(getOffset(link));
|
|
385
389
|
const photons = link.__photons || [];
|
|
386
390
|
const photonR = Math.max(0, getDiameter(link) / 2) / Math.sqrt(state.globalScale);
|
|
387
391
|
const photonColor = getColor(link) || 'rgba(0,0,0,0.28)';
|
|
@@ -399,7 +403,7 @@ export default Kapsule({
|
|
|
399
403
|
const singleHop = !!photon.__singleHop;
|
|
400
404
|
|
|
401
405
|
if (!photon.hasOwnProperty('__progressRatio')) {
|
|
402
|
-
photon.__progressRatio = singleHop ? 0 : cyclePhotonIdx / numCyclePhotons;
|
|
406
|
+
photon.__progressRatio = singleHop ? 0 : (cyclePhotonIdx + particleOffset) / numCyclePhotons;
|
|
403
407
|
}
|
|
404
408
|
|
|
405
409
|
!singleHop && cyclePhotonIdx++; // increase regular photon index
|
|
@@ -424,9 +428,13 @@ export default Kapsule({
|
|
|
424
428
|
y: start.y + (end.y - start.y) * photonPosRatio || 0
|
|
425
429
|
};
|
|
426
430
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
431
|
+
if(state.linkDirectionalParticleCanvasObject) {
|
|
432
|
+
state.linkDirectionalParticleCanvasObject(coords.x, coords.y, link, ctx, state.globalScale);
|
|
433
|
+
} else {
|
|
434
|
+
ctx.beginPath();
|
|
435
|
+
ctx.arc(coords.x, coords.y, photonR, 0, 2 * Math.PI, false);
|
|
436
|
+
ctx.fill();
|
|
437
|
+
}
|
|
430
438
|
});
|
|
431
439
|
|
|
432
440
|
if (needsCleanup) {
|
package/src/force-graph.js
CHANGED
|
@@ -36,8 +36,10 @@ const linkedProps = Object.assign(
|
|
|
36
36
|
'linkDirectionalArrowRelPos',
|
|
37
37
|
'linkDirectionalParticles',
|
|
38
38
|
'linkDirectionalParticleSpeed',
|
|
39
|
+
'linkDirectionalParticleOffset',
|
|
39
40
|
'linkDirectionalParticleWidth',
|
|
40
41
|
'linkDirectionalParticleColor',
|
|
42
|
+
'linkDirectionalParticleCanvasObject',
|
|
41
43
|
'dagMode',
|
|
42
44
|
'dagLevelDistance',
|
|
43
45
|
'dagNodeFilter',
|
|
@@ -547,6 +549,10 @@ export default Kapsule({
|
|
|
547
549
|
|
|
548
550
|
// Handle click/touch events on nodes/links
|
|
549
551
|
container.addEventListener('pointerup', ev => {
|
|
552
|
+
if (!state.isPointerPressed) {
|
|
553
|
+
return; // don't trigger click events if pointer is not pressed on the canvas
|
|
554
|
+
}
|
|
555
|
+
|
|
550
556
|
state.isPointerPressed = false;
|
|
551
557
|
if (state.isPointerDragging) {
|
|
552
558
|
state.isPointerDragging = false;
|
package/src/index.d.ts
CHANGED
|
@@ -29,6 +29,7 @@ type CanvasCustomRenderMode = 'replace' | 'before' | 'after';
|
|
|
29
29
|
export type CanvasCustomRenderModeFn<T> = (obj: T) => CanvasCustomRenderMode | any;
|
|
30
30
|
export type CanvasCustomRenderFn<T> = (obj: T, canvasContext: CanvasRenderingContext2D, globalScale: number) => void;
|
|
31
31
|
export type CanvasPointerAreaPaintFn<T> = (obj: T, paintColor: string, canvasContext: CanvasRenderingContext2D, globalScale: number) => void;
|
|
32
|
+
export type CanvasLinkParticleRenderFn<L> = (x: number, y: number, link: L, canvasContext: CanvasRenderingContext2D, globalScale: number) => void;
|
|
32
33
|
|
|
33
34
|
type DagMode = 'td' | 'bu' | 'lr' | 'rl' | 'radialout' | 'radialin';
|
|
34
35
|
|
|
@@ -110,10 +111,14 @@ export declare class ForceGraphGeneric<ChainableInstance, N extends NodeObject =
|
|
|
110
111
|
linkDirectionalParticles(numParticlesAccessor: LinkAccessor<number, N, L>): ChainableInstance;
|
|
111
112
|
linkDirectionalParticleSpeed(): LinkAccessor<number, N, L>;
|
|
112
113
|
linkDirectionalParticleSpeed(relDistancePerFrameAccessor: LinkAccessor<number, N, L>): ChainableInstance;
|
|
114
|
+
linkDirectionalParticleOffset(): LinkAccessor<number, N, L>;
|
|
115
|
+
linkDirectionalParticleOffset(relOffset: LinkAccessor<number, N, L>): ChainableInstance;
|
|
113
116
|
linkDirectionalParticleWidth(): LinkAccessor<number, N, L>;
|
|
114
117
|
linkDirectionalParticleWidth(widthAccessor: LinkAccessor<number, N, L>): ChainableInstance;
|
|
115
118
|
linkDirectionalParticleColor(): LinkAccessor<string, N, L>;
|
|
116
119
|
linkDirectionalParticleColor(colorAccessor: LinkAccessor<string, N, L>): ChainableInstance;
|
|
120
|
+
linkDirectionalParticleCanvasObject(): CanvasLinkParticleRenderFn<L>;
|
|
121
|
+
linkDirectionalParticleCanvasObject(renderFn: CanvasLinkParticleRenderFn<L>): ChainableInstance;
|
|
117
122
|
emitParticle(link: L): ChainableInstance;
|
|
118
123
|
linkPointerAreaPaint(): CanvasPointerAreaPaintFn<L>;
|
|
119
124
|
linkPointerAreaPaint(renderFn: CanvasPointerAreaPaintFn<L>): ChainableInstance;
|