Built with blockbuilder.org
Last active
November 28, 2016 21:29
-
-
Save larsvers/36bca23bdaf669ca0fe0a8213a57147c to your computer and use it in GitHub Desktop.
Force split and unite on canvas
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
license: mit |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<title>winter force</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<script src="http://d3js.org/d3.v4.js"></script> | |
<link rel="stylesheet" type="text/css" href="force.css"> | |
<style type="text/css"> | |
/* === Meyer Reset & border box (in moderation) === */ | |
html, body { | |
margin: 0; | |
padding: 0; | |
border: 0; | |
font-family: Arial; | |
font-size: 100%; | |
vertical-align: baseline; | |
height: 100%; | |
box-sizing: border-box; | |
} | |
*, *:before, *:after{ | |
box-sizing: inherit; | |
} | |
a:link, a:visited, a:hover, a:active { | |
color: #000; | |
} | |
/* === Canvas === */ | |
canvas { | |
border: 1px solid #ccc; | |
margin: 50px; | |
margin-bottom: 10px; | |
} | |
button#split { | |
margin-left: 50px; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="container"></div> | |
<button id="split">Split</button> | |
<button id="unite">Unite</button> | |
<script> | |
// === Globals === // | |
var width = 500, height = 250; | |
var simulation; | |
// === Set up canvas === // | |
var canvas = d3.select('#container').append('canvas').attr('width', width).attr('height', height); | |
var context = canvas.node().getContext('2d'); | |
// === Start the simulation === // | |
getSimulationData(); | |
// === Get simulation data === // | |
function getSimulationData() { | |
var nodes = []; | |
d3.range(200).forEach(function(el, i) { | |
var obj = {}; | |
obj.cluster = 0; | |
obj.radius = 5; | |
obj.colour = '#9CCFE5'; | |
obj.x = width/2 + (Math.random() - 10); // slightly left-skewed position | |
obj.y = height/2 + (Math.random()); | |
nodes.push(obj); | |
}); // get men nodes | |
d3.range(50).forEach(function(el, i) { | |
var obj = {}; | |
obj.cluster = 1; | |
obj.radius = 5; | |
obj.colour = '#9FE789'; | |
obj.x = width/2 + (Math.random() + 10); // slightly right-skewed position | |
obj.y = height/2 + (Math.random()); | |
nodes.push(obj); | |
}); // get women nodes | |
initSimulation(nodes); // kick off simulation | |
} // getSimulationData() | |
// === Set up simulation params === // | |
function initSimulation(nodes) { | |
simulation = d3.forceSimulation(nodes) | |
.alpha(.02) | |
.force('charge', d3.forceManyBody().strength(-30)) | |
.force('xPos', d3.forceX(width/2).strength(1)) | |
.force('yPos', d3.forceY(height/2).strength(1)); | |
simulation.on('tick', ticked); | |
function ticked() { | |
context.clearRect(0, 0, width, height); | |
context.save(); | |
nodes.forEach(drawNode); | |
context.restore() | |
} // ticked() | |
function drawNode(d) { | |
context.beginPath(); | |
context.moveTo(d.x + d.radius, d.y); | |
context.arc(d.x, d.y, d.radius, 0, 2 * Math.PI); | |
context.fillStyle = d.colour; | |
context.fill(); | |
} // drawNode() | |
} // Set up the simulation | |
// === Button handler === // | |
d3.select('button#split').on('mousedown', function(d) { | |
simulation.stop(); | |
simulation | |
.force('charge', d3.forceManyBody().strength(-5)) | |
.force('xPos', d3.forceX(function(d) { return d.cluster === 0 ? width * 0.3 : width * 0.7; }) ) | |
.force('yPos', d3.forceY(height/2)); | |
simulation.alpha(0.5); | |
simulation.restart(); | |
}); // button listener/handler | |
d3.select('button#unite').on('mousedown', function(d) { | |
simulation.stop(); | |
simulation | |
.force('charge', d3.forceManyBody().strength(-5)) | |
.force('xPos', d3.forceX(function(d) { return d.cluster === 0 ? width * 0.5 : width * 0.4; }) ) | |
.force('yPos', d3.forceY(height/2)) | |
.force('collision', d3.forceCollide(5)); | |
simulation.alpha(0.5); | |
simulation.restart(); | |
}); // button listener/handler | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment