Search code examples
graphthree.jshyperlinknodes

3d-force-graph node caption behave like a (single) clickable url link


I try to make the captions behave like hyperlinks on click. I followed an answer given here in stack overflow:

Attach link to 3d-force-graph node

But it only works on double click, the caption doesn't look like a link (not underline) and, only the node sphere is clickable, not the node caption. All in all, it's hard for the user to tell it's not a read-only network.

So, is there a way I can get those 3 requirements ?

  1. single (short) click to redirect
  2. link on the node caption (node.id) rather than on the node sphere
  3. style node caption when hovered (underline or color change)?

Here is my html file:

<head>
    <script src="//unpkg.com/three"></script>
    <script src="//unpkg.com/three/examples/js/renderers/CSS2DRenderer.js"></script>
    <script src="//unpkg.com/3d-force-graph"></script>
    <!--  <script src="../../dist/3d-force-graph.js"></script>-->
</head>

<body>
    <div id="3d-graph"></div>

    <script>
        const Graph = ForceGraph3D({
            extraRenderers: [new THREE.CSS2DRenderer()]
        })
       (document.getElementById('3d-graph'))
           .jsonUrl('./datasets/data.json')
           .nodeThreeObject(node => {
               const nodeEl = document.createElement('div');
               nodeEl.textContent = node.id;
               nodeEl.style.color = 'white';
               nodeEl.className = 'node-label';
               return new THREE.CSS2DObject(nodeEl);
           })
          .nodeThreeObjectExtend(true)
          .onNodeClick(function(node){
              window.location.href = node.link;
          });
    </script>
</body>

Here is how the dataset is structured:

{
    "nodes": [
        {"id": "Math", "group": 1,"link": "test1.html"},
        {"id": "Algebra", "group": 1,"link": "test2.html"},
         ....
    ],
    "links": [
        {"source": "Math", "target": 'Algebra',"value": "2"},
         ....
    ]
}

Last thing I tried in order to change the target for the node.link (node.id instead of node sphere) was to use "node.id" as the parameter for the onNodeCLick function but then I get an exception.

And in order to style the captions (underline or color change), I gave a class to the container (".node-label:hover") and tried to style it with css but it doesn't work neither.

And for the single click, I have absolutely no clue.

Thank you for your help.


Solution

  • Probably a little bit late, but as I encountered similar problems and found a solution (at least for the second problem) I wanted to share it.

    All CSS2DObejects live in a div with the style tag "pointer-events:none". This I belive is needed to enable the camera movement, but prevents us to interact with the nodes.

    To be able to use the pointer events you need to enable them on the CSS2DOBEJCTS by "pointer-events:all".

    .nodeThreeObject(node => {
               const nodeEl = document.createElement('div');
               nodeEl.textContent = node.id;
               nodeEl.style.color = 'white';
               nodeEl.style.pointer-events= 'all';
               nodeEl.className = 'node-label';
               nodeEl.addEventListener('pointerdown', event => console.log( event ))
    
               return new THREE.CSS2DObject(nodeEl);
           })
    

    Now you can add your event listeners like shown above.