Skip to content

Instantly share code, notes, and snippets.

@eesur
Last active November 28, 2017 15:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eesur/4a3417d04efa084df6acea2acea1be65 to your computer and use it in GitHub Desktop.
Save eesur/4a3417d04efa084df6acea2acea1be65 to your computer and use it in GitHub Desktop.
d3 | force grouping 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)
<!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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment