Absolute Translation After Rotation

98 views
Skip to first unread message

Chris

unread,
Jul 23, 2009, 5:42:58 PM7/23/09
to Raphaël
If you rotate a shape, and then translate by modifying the x or y
attributes, the shape will be translated along the rotated axis. How
do you translate a shape along the absolute axis, as though there were
no rotation, but still preserve the existing rotation?

I tried saving the rotation, applying the translation, and then re-
applying the rotation, but the rotation seems to get lost and isn't
restored properly:

// Save rotation and reset.
var r0 = shape.attr('rotation');
shape.attr('rotation', 0);

// Translate.
shape.attr('x', 10);
shape.attr('y', 10);

// Restore rotation.
shape.attr('rotation', r0);

I'm trying to make a widget to dynamically translate and rotate a
shape based on mouse movement. So after the user rotates the shape,
they should be able to translate it along the default axis.

Chris

unread,
Jul 24, 2009, 9:40:21 AM7/24/09
to Raphaël
Note, this behavior is inconsistent between IE and FF. In IE, it works
correctly, and translates the same regardless of rotation. In FF, the
rotation effects translation.

Chris

charles thomas

unread,
Jul 24, 2009, 9:56:47 AM7/24/09
to raph...@googlegroups.com
Chris
any chance you could send some "Playground ready" code so we could poke around with it/find work around/ post a bug in github?

--- On Fri, 7/24/09, Chris <chri...@gmail.com> wrote:

Yahoo! Canada Toolbar : Search from anywhere on the web and bookmark your favourite sites. Download it now!

Chris

unread,
Jul 24, 2009, 10:39:23 AM7/24/09
to Raphaël
On Jul 24, 9:56 am, charles thomas <charles...@yahoo.com> wrote:
> Chris
> any chance you could send some "Playground ready" code so we could poke around with it/find work around/ post a bug in github?

Certainly. I've encapsulated the functionality in a simple jQuery
plugin: http://www.chrisspen.com/imagemanip/test.html

Click on the image to change the editing mode (move, zoom, rotate).
Drag to edit using that mode.

You can reproduce the problem by first rotating the image, and then
attempting to move it.

Chris

chasbeen

unread,
Jul 24, 2009, 11:17:42 AM7/24/09
to Raphaël
Hi Chris

So your psuedo translation inside the manipulation js and it almost
works but FF is going in the exactly opposite direction with mouse
movement (but at leastit's proportional)

The calculation is not generic enough for the method you are using.

Have you tried using javascript to get the correct coordinate result
for all browsers?

(Eg:Math.abs?)
case 1: // Translate.
if(mouseDown){
var xOff = onMouseDownMousePosition.x -
onMouseDownImgPosition.x;
var yOff = onMouseDownMousePosition.y -
onMouseDownImgPosition.y;
img.attr('x', x - xOff);
img.attr('y', y - yOff);

Chris

unread,
Jul 24, 2009, 12:15:55 PM7/24/09
to Raphaël
I'm not sure what you're saying. The way Raphael is currently coded
for canvas, attr('x', x) gets any current rotation applied to it
before actually translating the shape.

If you rotated the image 180 degrees, then yes, this would move it in
the opposite direction, but simply using Math.abs() would not fix it,
and would actually only allow the image to be moved in one direction.

Try rotating the image 45 degrees. Moving the image will then slide it
along the x-axis at a 45 degree slant.

Chris

charles thomas

unread,
Jul 24, 2009, 1:06:25 PM7/24/09
to raph...@googlegroups.com
Chris,
 
I tried to adapt a drag and drop example I have on my website and found the same with that method. FF assumes horizontal and verticle movement relative to it's rotated position.
 
However I adapted the example a bit and the mouse does stay with the primitives if you
alter the rotation at the point the user selects the object and then (finally) inverts the temporary change when the user drops the primitive.
 
The crude hack below spins the object as you drag it but at least it stays with the mouse.
 
The below works in playground..
 
  /*Drag and Drop aggregate objects demo from the project page(Key:Performance-DragDrop)*/
  var isDrag = false;
  var boxWithLines=new Array();
  var rectangles=new Array();
  var lines=new Array();
  var texts=new Array();
  var shapes=new Array();
  var nextColour="";
  var textMessage=null;
  paper.text(300, 300,"Select one of the boxes and drop it where you like.").attr("fill", "BLUE").attr("font-size", "14");
     /*Captures the event object*/
     var dragger = function (e) {
  this.dx = e.clientX;
  this.dy = e.clientY;
  isDrag = this;
  this.animate({"fill-opacity": .2}, 500);
    };
 for(var i=0; i<5;i++)
 {
  nextColour = Raphael.getColor();
        boxWithLines[i] = paper.set();
        rectangles[i]=paper.rect(90 + (i*60), 80, 60, 40, 10);
        lines[i]=paper.path({stroke: nextColour}).moveTo(90 + (i*60), 100).lineTo(150 + (i*60), 100);
        texts[i]=paper.text(120 + (i*60), 90,"#"+i).attr("fill", nextColour).attr("font-size", "14");;
        boxWithLines[i].push(rectangles[i]);
        boxWithLines[i].push(lines[i]);
        boxWithLines[i].push(texts[i]);
        shapes.push( rectangles[i] );
    shapes[i].rotate(10*i);
 }  
    for (var i = 0, ii = shapes.length; i < ii; i++) {
        nextColour = Raphael.getColor();
        shapes[i].attr({fill: nextColour, stroke: nextColour, "fill-opacity": 0, "stroke-width": 2});
        shapes[i].node.style.cursor = "move";
        shapes[i].mousedown(dragger);
        //Add an index variable to all the shape objects
        shapes[i].index=i;
    }
    /*Playground note 1 of 3-'parent' prefix*/
    parent.document.onmousemove = function (e) {
 /*Playground note 2 of 3-'window.event' transposed with 'event'*/
 e = e || event;
 if (isDrag) {
isDrag.rotate(isDrag.index*-10);
     isDrag.translate(e.clientX - isDrag.dx, e.clientY - isDrag.dy);
            /*Have to move the associated objects relatively and the image as only the rectangle would move*/
            lines[isDrag.index].translate(e.clientX - isDrag.dx, e.clientY - isDrag.dy);
            texts[isDrag.index].translate(e.clientX - isDrag.dx, e.clientY - isDrag.dy);
   paper.safari();
            isDrag.dx = e.clientX;
            isDrag.dy = e.clientY;
        }
    };
    /*Playground note 3 of 3-'parent' prefix*/
    /*Setup the 'drop' for the mouse release*/
    parent.document.onmouseup = function () {
 if(isDrag)
 {
 if(textMessage!=null)textMessage.remove();
isDrag.rotate(isDrag.index*10);
 textMessage=paper.text(300, 320,"You just dropped box #"+ isDrag.index + " and you nearly broke it!").attr("fill", "RED").attr("font-size", "16");
 }   
 isDrag && isDrag.animate({"fill-opacity": 0}, 500);
 isDrag = false;
};


--- On Fri, 7/24/09, Chris <chri...@gmail.com> wrote:

From: Chris <chri...@gmail.com>
Subject: Re: Absolute Translation After Rotation
To: "Raphaël" <raph...@googlegroups.com>
Received: Friday, July 24, 2009, 6:40 AM

Chris

unread,
Sep 9, 2009, 6:16:35 PM9/9/09
to Raphaël
A hackish fix is to transform your x/y coordinates by rotating by the
opposite amount of the current rotation.

This is my modified translate() function:

function translate(x, y){
if(!document.all){
// If not IE, apply reverse rotation to compensate
// for reverse application of rotation->translation.
var deg = img.rotate()//attr('rotation');
console.log('rev:'+deg)
var rad = -(deg * Math.PI / 180);
var xtemp = (x * Math.cos(rad)) - (y * Math.sin(rad));
y = (x * Math.sin(rad)) + (y * Math.cos(rad));
x = xtemp;
}
img.attr('x', x);
img.attr('y', y);
}
Reply all
Reply to author
Forward
0 new messages