tomgp
10/7/2014 - 5:34 PM

drag circles around in a ring

drag circles around in a ring

Sometimes you might want to constrain a dragged item to a circular path...

<html>
<head>
	<title>ring control</title>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
	<style type="text/css">
	.handle{
		fill:#FFF;
		stroke:#000;
		stroke-width:4;
		cursor: all-scroll;
	}

	.handle.active{
		stroke:#F00;
	}

	.ring{
		fill:none;
		stroke:#000;
		stroke-width:4;
	}
	</style>
</head>
<body>
<div class="ring-input"></div>
</body>

<script type="text/javascript">
var values  = [
	{value:33, label:'A' },
	{value:33, label:'B' },
	{value:33, label:'C' },
	{value:33, label:'D' },
	{value:33, label:'E' }
];
var total = 0;
var dragging = null;

values.forEach(function(d){
 	d.absoluteValue = total;
 	total += d.value;
});

console.log(values);
var height = 300, width = 300, margin = {top:20,left:20,bottom:20,right:20};
var radius = (height - margin.top - margin.bottom)/2;

var parent = d3.select('.ring-input').append('svg')
	.attr({
		height:height,
		width:width
	}).append('g').attr('transform','translate('+margin.left+','+margin.top+')')

parent.append('line').attr('id','test-line')

var angularScale = d3.scale.linear().range([0,360]).domain([0,total]);

var ring = parent.append('g').attr('id','rim').attr('transform','translate('+radius+','+radius+')');
ring.append('circle').attr({
	r:radius,
	'class':'ring'
})

var handles = parent.append('g').attr('id','handles').attr('transform','translate('+radius+','+radius+')');
var drag = d3.behavior.drag()
    .origin(function(d) { return d; })
    .on("drag", dragmove)
    .on('dragend', function(){ d3.select(this).classed('active',false); });

//position the handles based on the input values
function drawHandles(){
	var join = handles.selectAll('circle').data(values);
	join.enter()
		.append('circle').attr({
			r:10,
			'class':'handle'
		}).on("mouseover", function(){
    		d3.select(this).classed('active',true);
    	})
    	.on("mouseout", function(){
    		d3.select(this).classed('active',false);
    	})
		.call(drag);

	join.attr({
		transform:function(d){
			return 'rotate(' + angularScale(d.absoluteValue) + ') translate(' +radius + ',0)'
		}
	})
}

drawHandles();

function dragmove(d,i) {
	d3.select(this).classed('active',true);
	var coordinates = d3.mouse(parent.node());
 	var x = coordinates[0]-radius;
 	var y = coordinates[1]-radius;
  	var newAngle = Math.atan2( y , x )* 57.2957795;
  	if(newAngle<0){
  		newAngle = 360 + newAngle;
  	}
 	d.absoluteValue = angularScale.invert(newAngle);
  	//REDRAW HANDLES
  	drawHandles()
}

</script>
</html>