如何使用 JavaScript 和 Raphael 旋转先前拖动的 SVG 对象?

发布于 2024-12-09 07:49:55 字数 2034 浏览 1 评论 0原文

我正在使用 Raphael 库来旋转和拖动图像。我正确地拖动了它,并且我有一个按钮,每次按下它时它都会正确旋转 90 度。但是,当我旋转图像、拖动它,然后尝试再次旋转它时,我遇到了问题。

HTML 中的唯一元素是用于保存 Raphael 画布的 div 和用于旋转图像的按钮。 JavaScript 在这里:

var gboard;
var piece;

window.onload = function () 
{
    gboard = Raphael("gameboard", 800, 500);    
    // piece = gboard.rect(100, 100, 50, 50).attr({fill: "#0CF", "fill-opacity": 1, stroke: "none", cursor: "move"});
    piece = gboard.image("piece.gif", 100, 100, 50, 50).attr({cursor: "move"});
    piece.drag(dragMove, dragStart, dragStop);  
    var angle = 0;

    document.getElementById('btn').onclick = function () {
        angle += 90;
        var cx = piece.attr('x') + 25;
        var cy = piece.attr('y') + 25;
        piece.animate({transform: "R" + angle + ", " + cx + ", " + cy + ""}, 500, "<>");
        // piece.transform("R90," + cx + "," + cy);
    };

}

// Set up the object for dragging
function dragStart() 
{
    this.ox = this.attr("x");
    this.oy = this.attr("y");
}

// Clean up after dragging ends
function dragStop() {}

/**
 * Handle the moving of objects when dragging 
 * Check the current angle to compensate for rotated coordinate system.
 */
function dragMove(dx, dy) 
{
    var angle = getAngle(this._['deg']);
    if (angle == 90)
        this.attr({x: this.ox + dy, y: this.oy - dx});
    else if (angle == 180)
        this.attr({x: this.ox - dx, y: this.oy - dy});
    else if (angle == 270)
        this.attr({x: this.ox - dy, y: this.oy + dx});
    else // angle == 0
        this.attr({x: this.ox + dx, y: this.oy + dy});
}

/** 
 * Get the simplified equivalent angle (0 <= angle <= 360) for the given angle. 
 *
 * @param deg   The angle in degrees
 * @return  The equivalent angle between 0 and 360
 */
function getAngle(deg)
{
    if (deg % 360 == 0)
        return 0;   
    else if (deg < 0)
    {
        while (deg < 0)
            deg += 360;
    }
    else if (deg > 360)
    {
        while (deg > 360)
            deg -= 360;
    }

    return deg;
}

I'm using the Raphael library to rotate and drag an image. I have it correctly dragging and I have a button that correctly rotates it 90 degrees each time it's pressed. However I'm having a problem when I rotate the image, drag it, and then try to rotate it again.

The only elements in the HTML are the div to hold the Raphael canvas and the button that rotates the image. The JavaScript is here:

var gboard;
var piece;

window.onload = function () 
{
    gboard = Raphael("gameboard", 800, 500);    
    // piece = gboard.rect(100, 100, 50, 50).attr({fill: "#0CF", "fill-opacity": 1, stroke: "none", cursor: "move"});
    piece = gboard.image("piece.gif", 100, 100, 50, 50).attr({cursor: "move"});
    piece.drag(dragMove, dragStart, dragStop);  
    var angle = 0;

    document.getElementById('btn').onclick = function () {
        angle += 90;
        var cx = piece.attr('x') + 25;
        var cy = piece.attr('y') + 25;
        piece.animate({transform: "R" + angle + ", " + cx + ", " + cy + ""}, 500, "<>");
        // piece.transform("R90," + cx + "," + cy);
    };

}

// Set up the object for dragging
function dragStart() 
{
    this.ox = this.attr("x");
    this.oy = this.attr("y");
}

// Clean up after dragging ends
function dragStop() {}

/**
 * Handle the moving of objects when dragging 
 * Check the current angle to compensate for rotated coordinate system.
 */
function dragMove(dx, dy) 
{
    var angle = getAngle(this._['deg']);
    if (angle == 90)
        this.attr({x: this.ox + dy, y: this.oy - dx});
    else if (angle == 180)
        this.attr({x: this.ox - dx, y: this.oy - dy});
    else if (angle == 270)
        this.attr({x: this.ox - dy, y: this.oy + dx});
    else // angle == 0
        this.attr({x: this.ox + dx, y: this.oy + dy});
}

/** 
 * Get the simplified equivalent angle (0 <= angle <= 360) for the given angle. 
 *
 * @param deg   The angle in degrees
 * @return  The equivalent angle between 0 and 360
 */
function getAngle(deg)
{
    if (deg % 360 == 0)
        return 0;   
    else if (deg < 0)
    {
        while (deg < 0)
            deg += 360;
    }
    else if (deg > 360)
    {
        while (deg > 360)
            deg -= 360;
    }

    return deg;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦太阳 2024-12-16 07:49:55

我通过在值发生变化时重新应用所有转换来解决这个问题。

http://alias.io/raphael/free_transform/

来源:https://github.com/ElbertF/Raphael.FreeTransform

I solved this by re-applying all transformations when a value changes.

http://alias.io/raphael/free_transform/

Source: https://github.com/ElbertF/Raphael.FreeTransform

甜尕妞 2024-12-16 07:49:55

您可以使用变换工具来处理两者,而不是使用 x/y 属性操作位置和使用变换旋转,从而大大简化您的项目。

由于我们在翻译中使用大写“T”,它会忽略同一字符串中先前的翻译命令,因此我们在拖动时不再需要担心当前角度。

var gboard, 
    piece;

gboard = Raphael("gameboard", 800, 500);    

var angle = 0,
    x = 100,
    y = 100;

//note that this now starts at 0,0 and is immediately translated to 100,100
piece = gboard.image("piece.gif", 0, 0, 50, 50).attr({cursor: "move", transform: "R" + angle + "T" + x + "," + y });

piece.drag(dragMove, dragStart, dragStop);

document.getElementById('btn').onclick = function () {  
  angle += 90;
  piece.animate({transform: "R" + angle + "T" + x + "," + y}, 500, "<>");
};

// Set up the object for dragging
function dragStart() 
{
    this.ox = x;
    this.oy = y;
}

// Clean up after dragging ends
function dragStop() {}

//Since we're using a capital 'T' in the translation, which ignores previous translation commands in the same string, we no longer have to worry about the current angle here    
function dragMove(dx, dy) {
  x = this.ox + dx;
  y = this.oy + dy;
  piece.attr({ transform: "R" + angle + "T" + x + "," + y });
}

jsFiddle

Instead of manipulating the position with the x/y attributes and the rotation with a transform, you can use the transform tool to handle both, simplifying your project quite a bit.

Since we're using a capital 'T' in the translation, which ignores previous translation commands in the same string, we no longer have to worry about the current angle when dragging.

var gboard, 
    piece;

gboard = Raphael("gameboard", 800, 500);    

var angle = 0,
    x = 100,
    y = 100;

//note that this now starts at 0,0 and is immediately translated to 100,100
piece = gboard.image("piece.gif", 0, 0, 50, 50).attr({cursor: "move", transform: "R" + angle + "T" + x + "," + y });

piece.drag(dragMove, dragStart, dragStop);

document.getElementById('btn').onclick = function () {  
  angle += 90;
  piece.animate({transform: "R" + angle + "T" + x + "," + y}, 500, "<>");
};

// Set up the object for dragging
function dragStart() 
{
    this.ox = x;
    this.oy = y;
}

// Clean up after dragging ends
function dragStop() {}

//Since we're using a capital 'T' in the translation, which ignores previous translation commands in the same string, we no longer have to worry about the current angle here    
function dragMove(dx, dy) {
  x = this.ox + dx;
  y = this.oy + dy;
  piece.attr({ transform: "R" + angle + "T" + x + "," + y });
}

jsFiddle

怪我入戏太深 2024-12-16 07:49:55

好奇的;看起来旋转实际上改变了 x 和 y 值。因此,如果旋转 90 度,则将框向右移动 100 像素实际上会将其向上移动 100 像素,然后将其转换为向右移动。这会抛弃 cx 和 cy 值,它们决定了盒子旋转的点。

要明白我的意思,请旋转一次,然后拖动框,同时在检查器中观察 X 和 Y 值。

我可以看到两种方法来解决它:您可以进行数学计算以在每次旋转时重新计算“真实”x 和 y,或者您可以通过附加数据属性(这就是我的方法)自行跟踪 x 和 y会推荐)。祝你好运!

Curious; it looks like the rotation actually alters the x and y values. So if you rotate 90 degrees, moving the box 100 pixels to the right actually moves it 100 pixels up, which is then translated as being to the right. This is throwing off the cx and cy values, which determine the point around which to rotate the box.

To see what I mean, rotate once, then drag the box while watching the X and Y values in the inspector.

I can see two ways to fix it: you can either do the math to recalculate the "real" x and y on every rotation, or you can keep track of the x and y on your own by attaching data attributes (which is what I would recommend). Good luck!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文