block by Rich-Harris 2c73ce834dcc50faf7051fe7a8ffdf81

force-layout

Full Screen

index.html

<!doctype html>
<head>
	<link rel='stylesheet' href='styles.css'>
</head>
<body>
	<svg viewBox='0 0 100 100'>
		<g class='nodes' transform='translate(50,50)'></g>
	</svg>

	<button data-handler='create'>create layout</button>
	<button data-handler='save'>save layout</button>
	<button data-handler='restore'>restore layout</button>

	<script src='d3.v3.min.js'></script>
	<script src='app.js'></script>
</body>

app.js

var WIDTH = 100;
var HEIGHT = 100;
var SIZE = 2;

var nodes;
var force;

var handlers = {
	create () {
		nodes = [];

		for ( let i = 0; i < 100; i += 1 ) {
			nodes.push({
				state: 'yellow',
				x: ( Math.random() - 0.5 ) * WIDTH / 2,
				y: ( Math.random() - 0.5 ) * HEIGHT / 2
			});
		}

		init( nodes );

		force.start();
	},

	save () {
		var saved = nodes.map( node => {
			return {
				state: node.state,
				x: node.x,
				y: node.y
			};
		});

		console.log( 'saving nodes', saved );
		localStorage.setItem( 'nodes', JSON.stringify( saved ) );
	},

	restore () {
		nodes = JSON.parse( localStorage.getItem( 'nodes' ) );
		console.log( 'restored nodes', nodes );

		init( nodes );
	}
};

var buttons = [].slice.call( document.querySelectorAll( 'button' ) );
buttons.forEach( button => {
	const handler = button.getAttribute( 'data-handler' );
	button.addEventListener( 'click', () => {
		handlers[ handler ]();
	});
});

function init ( nodes ) {
	if ( force ) force.stop();

	d3.select( '.nodes' )
		.selectAll( 'circle' )
		.data( nodes )
		.attr( 'cx', d => d.x )
		.attr( 'cy', d => d.y )
	.enter().append( 'circle' )
		.attr( 'cx', d => d.x )
		.attr( 'cy', d => d.y )
		.attr( 'r', SIZE * 1.5 )
		.attr( 'class', d => d.state )
		.on( 'click', function ( d ) {
			d.state = 'red';
			d3.select( this ).attr( 'class', 'red' );
			force.start();
		});

	force = d3.layout.force()
		.nodes( nodes )
		.size([ SIZE, SIZE ])
		.charge( ( n, i ) => {
			return -( n.state === 'red' ? SIZE * 3 : SIZE );
		})
		.on( 'tick', tick );

	function tick () {
		d3.selectAll( 'circle' )
			.data( nodes )
			.attr( 'cx', d => d.x )
			.attr( 'cy', d => d.y );
	}
}

styles.css

svg {
	position: absolute;
	left: 0;
	top: 0;
	width: 100%;
	height: 100%;
}

.red {
	fill: #b51800;
}

.yellow {
	fill: #ffce4b;
}

button {
	position: relative;
}