Sean McClure
Sean McClure

Reputation: 112

Add node specific links to forceSimulation force-directed graph in d3.js

I have this force graph. I want to have each circle contain a link to a different page, such that when clicked the viewer is redirected.

Is there a way to do this?

Further, it would be nice to have text attached (inside) each node too, but this is much less of a priority.

var numNodes = 12
var nodes = d3.range(numNodes).map(function(d) {
  return {
    radius: Math.random() * 20 + 40
  }
})

var simulation = d3.forceSimulation(nodes)
  .force('charge', d3.forceManyBody().strength(4))
  .force('center', d3.forceCenter(400, 250))
  .force('collision', d3.forceCollide().radius(function(d) {
    return d.radius
  }))
  .on('tick', ticked);

function orb() {
  var u = d3.select('svg')
    .selectAll('circle')
    .data(nodes)

  u.enter()
    .append('circle')
    .attr('r', function(d) {
      return d.radius
    })
    .merge(u)
    .attr('cx', function(d) {
      return d.x
    })
    .attr('cy', function(d) {
      return d.y
    })

  u.exit().remove()
}

function ticked() {
  orb()
}
circle:hover {
  fill: red;
  stroke: #444;
  stroke-width: 0.5;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.5.0/d3.min.js"></script>

<svg width="800" height="800" class=''>
  <g>
  </g>
</svg>

Upvotes: 0

Views: 342

Answers (1)

Mark
Mark

Reputation: 108512

See if this answers both your questions. I've commented it well; let me know if anything is unclear:

<!DOCTYPE html>

<html>
  <head>
    <style>
      circle:hover {
        fill: red;
        stroke: #444;
        stroke-width: 0.5;
      }
      text {
        fill: #fff;
      }
    </style>
  </head>

  <body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.5.0/d3.min.js"></script>

    <svg width="800" height="800" class="">
      <g></g>
    </svg>

    <script>
      var numNodes = 12;
      var nodes = d3.range(numNodes).map(function (d) {
        return {
          radius: Math.random() * 20 + 40,
          link:
            Math.random() < 0.5
              ? 'https://www.wikipedia.org'
              : 'https://www.google.com',
          text: Math.random() < 0.5 ? 'text' : 'string'
        };
      });

      var simulation = d3
        .forceSimulation(nodes)
        .force('charge', d3.forceManyBody().strength(4))
        .force('center', d3.forceCenter(400, 250))
        .force(
          'collision',
          d3.forceCollide().radius(function (d) {
            return d.radius;
          })
        )
        .on('tick', ticked);

      function orb() {

        // update selection
        let g = d3.select('svg')
          .selectAll('g')
          .data(nodes);

        // enter selection
        let ge = 
          g.enter()
          .append('g');
        
        // on enter append `a`
        // around the circle
        ge
          .append('a')
          .attr('href', function (d) {
            return d.link;
          })
          .attr('target', '_blank')
          .append('circle')
          .attr('r', function (d) {
            return d.radius;
          });

        // on enter create text element
        // for each circle
        ge
          .append('text')
          .attr('text-anchor', 'middle')
          .text(function(d){
            return d.text;
          })

        // merge update and enter
        g = ge.merge(g);

        // position circle
        g
          .selectAll('circle')
          .attr('cx', function (d) {
            return d.x;
          })
          .attr('cy', function (d) {
            return d.y;
          })

        // position text "in" circle
        g.selectAll('text')
          .attr('transform', function(d){
            return 'translate(' + d.x + ',' + d.y + ')';
          })

        g.exit().remove();
      }

      function ticked() {
        orb();
      }
    </script>
  </body>
</html>

Upvotes: 1

Related Questions