sketch using d3-force to split and join nodes via buttons
to help break this up, some sketches that show:
and this example shows user interaction to split and join via events
var data = [ | |
{ name: '01', group: 'one', value: 55 }, | |
{ name: '02', group: 'two', value: 21 }, | |
{ name: '03', group: 'two', value: 55 }, | |
{ name: '04', group: 'one', value: 89 }, | |
{ name: '05', group: 'one', value: 144 }, | |
{ name: '06', group: 'two', value: 144 }, | |
{ name: '07', group: 'one', value: 233 }, | |
{ name: '08', group: 'one', value: 377 }, | |
{ name: '09', group: 'two', value: 89 } | |
] | |
var svg = d3.select('svg') | |
var width = +svg.attr('width') | |
var height = +svg.attr('height') | |
var g = svg.select('g#vis') | |
var sqrtScale = d3.scaleSqrt() | |
.domain([1, 100]) | |
.range([5, 40]) | |
// when split move the items in group 'one' anchor at 200px | |
// and the remaining (group 'two') to anchor at 700px | |
var forceSplit = d3.forceX(function (d) { return (d.group === 'one') ? 200 : 700; }) | |
.strength(0.05) | |
// when using join bring all circles to the center of width | |
var forceJoin = d3.forceX(function (d) { return width / 2; }) | |
.strength(0.05) | |
// y is set to center of height for everything | |
var forceY = d3.forceY(height / 2) | |
.strength(0.05) | |
// https://github.com/d3/d3-force#forceSimulation | |
var simulation = d3.forceSimulation() | |
.force('x', forceJoin) | |
.force('y', forceY) | |
// spring out from the center instead of entering in from the top left | |
.force('center', d3.forceCenter(width / 2, height / 2)) | |
// stop the circles overlapping by passing in their size | |
.force('collide', d3.forceCollide(function (d) { return sqrtScale(d.value) + 2; })) | |
function render(data) { | |
var circles = g.selectAll('.node') | |
.data(data) | |
.enter().append('circle') | |
.attr('class', 'node') | |
.attr('r', function (d) { return sqrtScale(d.value); }) | |
.attr('fill', function (d) { return (d.group == 'one') ? '#7AC143' : '#FDBB30'; }) | |
.on('click', function(d) { | |
// example to show click events on circles | |
d3.select('#clickData').text(("name: " + (d.name) + " value: \n " + (d.value))) | |
}) | |
simulation.nodes(data) | |
.on('tick', ticked) | |
function ticked() { | |
circles | |
.attr('cx', function (d) { return d.x; }) | |
.attr('cy', function (d) { return d.y; }) | |
} | |
// events | |
d3.select('#split').on('click', function() { | |
console.log('split') | |
simulation | |
.force('x', forceSplit) | |
// smooth out transitions to eliminate jitter | |
.alphaTarget(0.3) | |
// “reheat” the simulation during interaction | |
// https://github.com/d3/d3-force#simulation_restart | |
.restart() | |
}) | |
d3.select('#join').on('click', function() { | |
console.log('join') | |
simulation | |
.force('x', forceJoin) | |
.alphaTarget(0.1) | |
.restart() | |
}) | |
} | |
render(data) |
sketch using d3-force to split and join nodes via buttons
to help break this up, some sketches that show:
and this example shows user interaction to split and join via events
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<style> | |
body{ | |
font-family: Consolas, monaco, monospace; | |
position: relative; | |
padding: 20px; | |
color: #FDBB30; | |
background: #130C0E; | |
} | |
button { | |
font-size: 18px; | |
background: #130C0E; | |
color: #7AC143; | |
border: none; | |
outline:none; | |
padding: 4px 8px; | |
margin-right: 10px; | |
letter-spacing: 5px; | |
} | |
button:hover { | |
background: #7AC143; | |
color: #130C0E; | |
} | |
circle:hover { | |
opacity: 0.8; | |
} | |
</style> | |
</head> | |
<body> | |
<header> | |
<button id='join'>JOIN</button> | |
<button id='split'>SPLIT</button> | |
</header> | |
<svg width="960" height="400"> | |
<g id="vis" transform="translate(10, 10)"></g> | |
</svg> | |
<footer> | |
<span id="clickData"></span> | |
</footer> | |
<script src="//d3js.org/d3.v4.min.js" charset="utf-8"></script> | |
<!-- d3 code --> | |
<script src=".script-compiled.js" charset="utf-8"></script> | |
</body> | |
</html> | |
const data = [ | |
{ name: '01', group: 'one', value: 55 }, | |
{ name: '02', group: 'two', value: 21 }, | |
{ name: '03', group: 'two', value: 55 }, | |
{ name: '04', group: 'one', value: 89 }, | |
{ name: '05', group: 'one', value: 144 }, | |
{ name: '06', group: 'two', value: 144 }, | |
{ name: '07', group: 'one', value: 233 }, | |
{ name: '08', group: 'one', value: 377 }, | |
{ name: '09', group: 'two', value: 89 } | |
] | |
const svg = d3.select('svg') | |
const width = +svg.attr('width') | |
const height = +svg.attr('height') | |
const g = svg.select('g#vis') | |
const sqrtScale = d3.scaleSqrt() | |
.domain([1, 100]) | |
.range([5, 40]) | |
// when split move the items in group 'one' anchor at 200px | |
// and the remaining (group 'two') to anchor at 700px | |
const forceSplit = d3.forceX(d => (d.group === 'one') ? 200 : 700) | |
.strength(0.05) | |
// when using join bring all circles to the center of width | |
const forceJoin = d3.forceX(d => width / 2) | |
.strength(0.05) | |
// y is set to center of height for everything | |
const forceY = d3.forceY(height / 2) | |
.strength(0.05) | |
// https://github.com/d3/d3-force#forceSimulation | |
const simulation = d3.forceSimulation() | |
.force('x', forceJoin) | |
.force('y', forceY) | |
// spring out from the center instead of entering in from the top left | |
.force('center', d3.forceCenter(width / 2, height / 2)) | |
// stop the circles overlapping by passing in their size | |
.force('collide', d3.forceCollide(d => sqrtScale(d.value) + 2)) | |
function render(data) { | |
const circles = g.selectAll('.node') | |
.data(data) | |
.enter().append('circle') | |
.attr('class', 'node') | |
.attr('r', d => sqrtScale(d.value)) | |
.attr('fill', d => (d.group == 'one') ? '#7AC143' : '#FDBB30') | |
.on('click', function(d) { | |
// example to show click events on circles | |
d3.select('#clickData').text(`name: ${d.name} value: | |
${d.value}`) | |
}) | |
simulation.nodes(data) | |
.on('tick', ticked) | |
function ticked() { | |
circles | |
.attr('cx', d => d.x) | |
.attr('cy', d => d.y) | |
} | |
// events | |
d3.select('#split').on('click', function() { | |
console.log('split') | |
simulation | |
.force('x', forceSplit) | |
// smooth out transitions to eliminate jitter | |
.alphaTarget(0.3) | |
// “reheat” the simulation during interaction | |
// https://github.com/d3/d3-force#simulation_restart | |
.restart() | |
}) | |
d3.select('#join').on('click', function() { | |
console.log('join') | |
simulation | |
.force('x', forceJoin) | |
.alphaTarget(0.1) | |
.restart() | |
}) | |
} | |
render(data) |