Sometimes you might want to constrain a dragged item to a circular path...
Last active
April 19, 2023 21:16
-
-
Save tomgp/f39ccb9d4c17ced4e3d2 to your computer and use it in GitHub Desktop.
drag circles around in a ring
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Very useful but now outdated. I tried updating to the latest version (5), but cannot seem to get it to work.
Updated to the following;
But that shows
Uncaught TypeError: Cannot read properties of null (reading 'on') at drawHandles (73:9)