vasturiano / force-graph

Force-directed graph rendered on HTML5 canvas
https://vasturiano.github.io/force-graph/example/directional-links-particles/
MIT License
1.53k stars 246 forks source link

swap "circle nodes to image nodes" or swap "image nodes to circle nodes" #188

Open HeeYong2 opened 3 years ago

HeeYong2 commented 3 years ago

H.....i !Have a nice day! I have a question.

At first, I was initialized with default 'circle'. (force-graph 2d) The speed was quite fast and the functions worked well.

and then, when I pressed the key, I want swapped to circle nodes were image nodes. (just nodes) (Data, functions, etc. were all the same.)

swap function is nice and apply well. but, after about 20 repetitions swap function, the fps started to drop. Is it the wrong way to change it like this?

https://codepen.io/heeyong2/pen/ZELgror?editors=1000 (but, it was uncomfotable....)

vasturiano commented 3 years ago

@HeeYong2 that's probably because you're re-instantiating the ForceGraph each time. So you start to have multiple instances of ForceGraph running simultaneously which leads to unpredictable behavior and poor performance.

Easy to fix, basically only do this once:

const myGraph = ForceGraph()(myCanvas);

For further changes just invoke methods on your single instance myGraph, like:

myGraph.nodeCanvasObject(...)
HeeYong2 commented 3 years ago

@HeeYong2 that's probably because you're re-instantiating the ForceGraph each time. So you start to have multiple instances of ForceGraph running simultaneously which leads to unpredictable behavior and poor performance.

Easy to fix, basically only do this once:

const myGraph = ForceGraph()(myCanvas);

For further changes just invoke methods on your single instance myGraph, like:

myGraph.nodeCanvasObject(...)

Hi, thank you for reply. I understand what you mean.

then, i try do once at init function

init = () => {
   myGraph = ForceGraph()(myCanvas)
              .graphData(nowgData)
              .nodeRelSize(8)
              .nodeCanvasObjectMode(node => highlightNodes.has(node) ? 'before' : undefined)
              .nodeCanvasObject((node, ctx) => {
                  ctx.beginPath();
                  ctx.arc(node.x, node.y, NODE_R * 1.4, 0, 2 * Math.PI, false);
                  ctx.fillStyle = node === hoverNode ? 'red' : 'orange';
                  ctx.fill();
              });
}

after then, at swap function( circle to image )

swap = () => {
    let gData = myGraph.graphData();
    const nowgData = {
                nodes: [...gData.nodes],
                links: [...gData.links]
            }

    myGraph
                .graphData(nowgData)
                .linkDirectionalParticles(zoomLevel)
                .nodeCanvasObject(({ id, x, y }, ctx) => {
                 console.log("nodeCanvasObject log");
                    const _size = 100;
                    let imgCnt = id % 4;
                    ctx.drawImage(imgs[imgCnt], x - _size / 2, y - _size / 2, _size, _size);
                })
                .nodePointerAreaPaint((node, color, ctx) => {
                    const size = 100;
                    ctx.fillStyle = color;
                    ctx.fillRect(node.x - size / 2, node.y - size / 2, size, size); // draw square as pointer trap
                })
}

but, There was no reaction. at the swap function.. and seemed that nodeCanvasObject was not called. (-> because console.log() is not execute)

haha.... Why did this happen?? where is wrong? thank you!

vasturiano commented 3 years ago

@HeeYong2 one thing I noticed is that you don't need to call .graphData again if the data hasn't changed.

As for the rest, it's difficult without broader context. Can you update your codepen with your latest version?

HeeYong2 commented 3 years ago

@HeeYong2 one thing I noticed is that you don't need to call .graphData again if the data hasn't changed.

As for the rest, it's difficult without broader context. Can you update your codepen with your latest version?

oh my.. I find something. if I call nodeCanvasObjectMode() and nodeCanvasObject() => strange screen

and if I call just nodeCanvasObject() => That's exactly what I wanted at swap image (but, highlightNodes function is broken)

What's the reason?

.nodeCanvasObjectMode(node => highlightNodes.has(node) ? 'before' : undefined)
.nodeCanvasObject((node, ctx) => {
    // add ring just for highlighted nodes
    ctx.beginPath();
    ctx.arc(node.x, node.y, NODE_R * 1.4, 0, 2 * Math.PI, false);
    ctx.fillStyle = node === hoverNode ? 'red' : 'orange';
    ctx.fill();
});