block by jwilber 9f69026c4a5cc02beb60baa6622231c5

force-to-histogram transition

Full Screen

Built with blockbuilder.org

index.html

<!DOCTYPE html>
<html>
<head>
	<script src='https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js'></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/rough.js/2.2.5/rough.min.js"></script>
</head>
<button id="clickMe" type="button">Move Nodes</button>
<body>
	<svg id="svg" width="1200" height="500"></svg>

	<script>
	const width = 500
    const height = 500
    const radius = 25;
    const svgd3 = d3.select("svg")

    const trtCenter = width / 5
	const cntrlCenter = width / 1.5
	var rc = rough.svg(svg)
    
    const sampleData = d3.range(200).map(() => ({r: radius,
                                                value: width/2 + d3.randomNormal(0, 1.5)() * 50}))


    
    // define force
    let force = d3.forceSimulation()
    	.force('charge', d3.forceManyBody().strength(1))
    	force.force('x', d3.forceX().strength(.3).x( width / 2))
		force.force('y', d3.forceY().strength(.3).y(height / 3.5))
    	.force('collision', d3.forceCollide(d => 12))    	
    	.nodes(sampleData)
    	.on('tick', changeNetwork)

    let dots = svgd3.selectAll('.dot')
    	.data(sampleData)
    	.enter()
    	.append('g')
    	.attr('class', 'dot')
    	.attr('group', (d,i) => i % 2 == 0 ? 'trt' : 'ctrl')

    function nodeTreatmentPos(d) {
	  return d.index % 2 == 0 ? trtCenter : cntrlCenter;
	}


   	function changeNetwork() {
      d3.selectAll('g.dot')
      	.attr('transform', d=> `translate(${d.x}, ${d.y})`)
    }

    d3.selectAll('.dot').append('g').attr('class', 'testStat')
    	.append('circle')
    	.style('opacity', .9)
      .attr('fill' ,'pink')
      .attr('r', 8)
      .attr('stroke-width', .51)
      .attr('stroke', 'black')
  
    // 
	function moveNodes() {
		d3.selectAll('.dot').select('path').attr('visibility', 'visibile')
	  force.force('center', null)
		.force('collision', d3.forceCollide(d => 12))
		.alphaDecay(.0005)
		.velocityDecay(0.6)
		force.force('x', d3.forceX().strength(1).x(nodeTreatmentPos))
		force.force('y', d3.forceY().strength(1).y(height / 3.5))
        force.alpha(.1).restart();
	}

	// force for center
	function moveCenter() {
	force//.force('center', null)
		.force('collision', d3.forceCollide(d => 20))
		.alphaDecay(.0005)
		.velocityDecay(0.6)
		force.force('x', d3.forceX().strength(1).x( width / 2))
		force.force('y', d3.forceY().strength(1).y(height / 3.5))
		force.alpha(.1).restart();
		}
	
	function moveHist(){
	  force.force('center', null)
	  .force('collision', d3.forceCollide(d => d.r /1.5).strength(1))
	  .alphaDecay(.025)	
// 	  .velocityDecay(0.3)
      .force('x', d3.forceX((d,i) => d.value).strength(5))
      .force('y', d3.forceY(height - radius).strength(.7))
      .on('tick', changeNetwork2)
      force.alpha(.2).restart()
	}

	function changeNetwork2() {
      d3.selectAll('.dot')
      	.attr('transform', d => `translate(${d.x}, ${Math.min(d.y, height - radius - 1)})`)
    }

	// resolve locations of node on cliks
	let toCenter = true;

	d3.select('#clickMe')
		.on('click', function() {
			toCenter === true ? moveNodes() : moveHist()
			toCenter = !toCenter
		})
  </script>
</body>
</html>