block by nitaku 8febbba771f563ade993575413ef4a11

Collision

Full Screen

This example shows how to define a force to avoid collision between circles of different radii in d3 v4 force layout.

index.js

// Generated by CoffeeScript 1.10.0
(function() {
  var MIN_PADDING, data, en_nodes, height, nodes, simulation, svg, width;

  svg = d3.select('svg');

  width = svg.node().getBoundingClientRect().width;

  height = svg.node().getBoundingClientRect().height;

  MIN_PADDING = 3;

  data = [
    {
      r: 5
    }, {
      r: 10
    }, {
      r: 20
    }, {
      r: 30
    }, {
      r: 30
    }, {
      r: 10
    }, {
      r: 20
    }, {
      r: 30
    }, {
      r: 30
    }, {
      r: 10
    }, {
      r: 20
    }, {
      r: 30
    }, {
      r: 30
    }, {
      r: 50
    }
  ];

  simulation = d3.forceSimulation().force('center', d3.forceCenter(width / 2, height / 2)).force('collision', d3.forceCollide(function(d) {
    return d.r + MIN_PADDING;
  }));

  nodes = svg.selectAll('.node').data(data);

  en_nodes = nodes.enter().append('circle').attrs({
    "class": 'node',
    r: function(d) {
      return d.r;
    }
  });

  simulation.nodes(data).on('tick', function() {
    return en_nodes.attrs({
      transform: function(d) {
        return "translate(" + d.x + ", " + d.y + ")";
      }
    });
  });

}).call(this);

index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Collision</title>
  <link type="text/css" href="index.css" rel="stylesheet"/>
  <script src="https://d3js.org/d3.v4.min.js"></script>
  <script src="https://d3js.org/d3-selection-multi.v0.4.min.js"></script>
</head>
<body>
  <svg></svg>
  <script src="index.js"></script>
</body>
</html>

index.coffee

svg = d3.select 'svg'
width = svg.node().getBoundingClientRect().width
height = svg.node().getBoundingClientRect().height

MIN_PADDING = 3

data = [
  {r: 5}
  {r: 10}
  {r: 20}
  {r: 30}
  {r: 30}
  {r: 10}
  {r: 20}
  {r: 30}
  {r: 30}
  {r: 10}
  {r: 20}
  {r: 30}
  {r: 30}
  {r: 50}
]

# Layout
simulation = d3.forceSimulation()
  .force('center', d3.forceCenter(width/2, height/2))
  .force 'collision', d3.forceCollide (d) -> d.r + MIN_PADDING
  
nodes = svg.selectAll '.node'
  .data data
  
en_nodes = nodes.enter().append 'circle'
  .attrs
    class: 'node'
    r: (d) -> d.r
  
# Simulation
simulation
  .nodes(data)
  .on 'tick', () ->
    en_nodes.attrs
      transform: (d) -> "translate(#{d.x}, #{d.y})"

index.css

body, html {
  padding: 0;
  margin: 0;
  height: 100%;
}
svg {
  width: 100%;
  height: 100%;
  background: white;
}

.node {
  fill: teal;
}