Reputation: 1035
I am trying to create a rectangle where I can resize and rotate it using handlers (small circles) located on the top of the rectangle. Similar to the most of the drawing tools that allow us to resize and rotate the shapes.
I added three circles on the top of my rectangle. One circle is for resizing the width of the rectangle (circle on the right side). Another rectangle is for resizing the height of the bar (circle on the top). Resizing the rectangle works perfectly.
margin = {top: 40, right: 20, bottom: 30, left: 70},
width = 600 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var svg = d3.select('#canvas').attr("width",width).attr("height",height);
gContainer = svg.append('g')
.attr("class", "gContainer")
.attr("transform", function(d,i){
return "translate("+300+","+200+")"
})
gBars = gContainer.append('g').attr("class", "gBar");
gBars.append("rect")
.attr("class", "Bar")
.attr("fill","black")
.attr("width", 40)
.attr("height", function(d) { return height - 200})
.style("opacity", 0.5);
var handlerRadius = 3.5;
handlerPointsPosition=[];
elementWidth = Number(d3.select(".Bar").attr("width"));
elementHeight = Number(d3.select(".Bar").attr("height"));
x0 = 0 + (elementWidth/2) ;
y0 = 0 ;
x1 = 0 + (elementWidth);
y1 = 0 +(elementHeight/2) ;
x2= 0 + (elementWidth/2) ;
y2= -20;
handlerPointsPosition = [[x0,y0],[x1,y1],[x2,y2]];
var rectangleHandlers = d3.behavior.drag()
.origin(function(d) { return d; })
.on("dragstart", dragstarted)
.on("drag", dragged)
gHandlerPoints= gContainer.selectAll("g.HandlerPoint")
.data(handlerPointsPosition)
.enter().append('g')
.attr("class", "gHandlerPoint")
.attr("id", function(d,i){return "gHandlerPoint_id_"+i;})
.attr("transform", function(d,i){
//console.log(d);
return "translate("+d[0]+","+d[1]+")"
})
.call(rectangleHandlers);
gHandlerPoints.append("circle")
.attr("class", "handlerPoint")
.style("fill", "white")
.style("stroke", "blue")
.attr("stroke","")
.attr("r",function(d,i){return (i == 2 ? 4: 3.5);})
.attr("id", function(d,i){return "HandlerPointId_"+i;})
gContainer.append("line")
.attr("class","handlerLine")
.attr("x1", (elementWidth/2) )
.attr("y1", 0- handlerRadius)
.attr("x2", (elementWidth/2) )
.attr("y2", -20 + handlerRadius)
.attr("stroke-width", 1)
.attr("stroke", "blue");
function updateHandlerPosition(id, dX, dY)
{
d3.select(id).attr("transform", function(d,i){
return "translate(" + [ dX, dY] + ")"
})
}
function dragstarted(d,i) {
dragIconX = d3.transform(d3.select(this).attr("transform")).translate[0];
dragIconY = d3.transform(d3.select(this).attr("transform")).translate[1];
barStartWidth = d3.select(".Bar").attr("width");
}
function dragged(d,i) {
barHeight = d3.select(".Bar").attr("height");
if(i == 0) // circle on the top edge of the bar
{
dragIconY = dragIconY + d3.mouse(this)[1];
updateHandlerPosition("#gHandlerPoint_id_"+i, dragIconX, dragIconY );
updateHandlerPosition("#gHandlerPoint_id_1", (barStartWidth), (barHeight/2) );
var x = d3.transform(d3.select(".gContainer").attr("transform")).translate[0];
var y = d3.transform(d3.select(".gContainer").attr("transform")).translate[1];
d3.select(".gContainer").attr("transform", function(d,i){
y = y + dragIconY;
return "translate(" + [ x , y] + ")"
})
console.log(height, barHeight, barHeight - Number(dragIconY));
d3.select(".Bar").attr("height", barHeight - Number(dragIconY));
}
else if (i==1) // circle on the right side of the bar
{
oldMouseX = dragIconX;
dragIconX = d3.mouse(this)[0]+dragIconX;
barWidth = dragIconX;
updateHandlerPosition("#gHandlerPoint_id_"+i, dragIconX, dragIconY );
updateHandlerPosition("#gHandlerPoint_id_0", (barWidth/2), 0 );
updateHandlerPosition("#gHandlerPoint_id_2", (barWidth/2), -20);
d3.select(".handlerLine").attr("x1",(barWidth/2)).attr("x2", (barWidth/2));
d3.select(".Bar").attr("width", Math.abs(dragIconX));
}
else if(i==3) //circle on very top
{
// code for rotation should come here.
}
}
Link to jsFiddle: http://jsfiddle.net/Q5Jag/2103/
I put the third circle for rotation (the circle on the very top). However, I have no idea how to fix the rotation. I want the rectangle to rotate when I drag the circle on the very top. I also want to be able to resize the circle accordingly when it is rotated.
Any idea?
Upvotes: 3
Views: 842
Reputation: 2303
You can calculate the rotation with respect to the center of your rectangle. Consider v1
as vector from center of rectangle to the rotation handle before rotation and v2
as a vector from center of rectangle to the rotation handle after rotation. Read here to know the math behind it.
// old vector
v1 = {};
v1.x = oldMouseX-gCenterX;
v1.y = oldMouseY-gCenterY;
// new vector
v2 = {};
v2.x = dragHandleX-gCenterX;
v2.y = dragHandleY-gCenterY;
angle = Math.atan2(v2.y,v2.x) - Math.atan2(v1.y,v1.x);
where
gCenterX
and gCenterY
are coordinates of the center of rectangleoldMouseX
and oldMouseY
are coordinates of mouse pointer prior to rotationdragHandleX
and dragHandleY
are coordinates of mouse pointer after rotationHere is the complete code: http://jsfiddle.net/Q5Jag/2109/ (But it fails if you mix rotation and resizing)
Upvotes: 1