Guest User

Untitled

a guest
Feb 21st, 2018
63
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.90 KB | None | 0 0
  1. <!doctype html>
  2. <meta charset="utf-8">
  3. <body>
  4. <script src="//d3js.org/d3.v4.min.js"></script>
  5. <script>
  6.  
  7. let margin = {top: 100, right: 100, bottom: 100, left: 100};
  8.  
  9. let width = 960,
  10. height = 500,
  11. padding = 1.5, // separation between same-color circles
  12. clusterPadding = 6, // separation between different-color circles
  13. maxRadius = 12;
  14.  
  15. let n = 200, // total number of nodes
  16. m = 10, // number of distinct clusters
  17. z = d3.scaleOrdinal(d3.schemeCategory20),
  18. clusters = new Array(m);
  19.  
  20. let svg = d3.select('body')
  21. .append('svg')
  22. .attr('height', height)
  23. .attr('width', width)
  24. .append('g').attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
  25.  
  26. let nodes = d3.range(200).map(() => {
  27. let i = Math.floor(Math.random() * m),
  28. radius = Math.sqrt((i + 1) / m * -Math.log(Math.random())) * maxRadius,
  29. d = {cluster: i, r: radius};
  30. if (!clusters[i] || (radius > clusters[i].r)) clusters[i] = d;
  31. return d;
  32. });
  33.  
  34. let circles = svg.append('g')
  35. .datum(nodes)
  36. .selectAll('.circle')
  37. .data(d => d)
  38. .enter().append('circle')
  39. .attr('r', (d) => d.r)
  40. .attr('fill', (d) => z(d.cluster))
  41. .attr('stroke', 'black')
  42. .attr('stroke-width', 0);
  43.  
  44. let simulation = d3.forceSimulation(nodes)
  45. .velocityDecay(0.2)
  46. .force("x", d3.forceX().strength(.0005))
  47. .force("y", d3.forceY().strength(.0005))
  48. .force("collide", collide)
  49. .force("cluster", clustering)
  50. .on("tick", ticked);
  51.  
  52. function ticked() {
  53. circles
  54. .attr('cx', (d) => d.x)
  55. .attr('cy', (d) => d.y);
  56. }
  57.  
  58. // These are implementations of the custom forces.
  59. function clustering(alpha) {
  60. nodes.forEach(function(d) {
  61. var cluster = clusters[d.cluster];
  62. if (cluster === d) return;
  63. var x = d.x - cluster.x,
  64. y = d.y - cluster.y,
  65. l = Math.sqrt(x * x + y * y),
  66. r = d.r + cluster.r;
  67. if (l !== r) {
  68. l = (l - r) / l * alpha;
  69. d.x -= x *= l;
  70. d.y -= y *= l;
  71. cluster.x += x;
  72. cluster.y += y;
  73. }
  74. });
  75. }
  76.  
  77. function collide(alpha) {
  78. var quadtree = d3.quadtree()
  79. .x((d) => d.x)
  80. .y((d) => d.y)
  81. .addAll(nodes);
  82.  
  83. nodes.forEach(function(d) {
  84. var r = d.r + maxRadius + Math.max(padding, clusterPadding),
  85. nx1 = d.x - r,
  86. nx2 = d.x + r,
  87. ny1 = d.y - r,
  88. ny2 = d.y + r;
  89. quadtree.visit(function(quad, x1, y1, x2, y2) {
  90.  
  91. if (quad.data && (quad.data !== d)) {
  92. var x = d.x - quad.data.x,
  93. y = d.y - quad.data.y,
  94. l = Math.sqrt(x * x + y * y),
  95. r = d.r + quad.data.r + (d.cluster === quad.data.cluster ? padding : clusterPadding);
  96. if (l < r) {
  97. l = (l - r) / l * alpha;
  98. d.x -= x *= l;
  99. d.y -= y *= l;
  100. quad.data.x += x;
  101. quad.data.y += y;
  102. }
  103. }
  104. return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
  105. });
  106. });
  107. }
  108. </script>
Add Comment
Please, Sign In to add comment