图层旋转后KineticJS鼠标位置错误

Posted

技术标签:

【中文标题】图层旋转后KineticJS鼠标位置错误【英文标题】:KineticJS mouse position wrong after layer rotated 【发布时间】:2013-08-11 00:29:54 【问题描述】:

我的演示在这里http://jsfiddle.net/akuma/7NmXw/1/

    首先,在蓝色框中画一些东西。 然后,单击一次旋转按钮。 框旋转后,再次绘制一些东西。 最后draw poisitoin 错了。

如何解决这个问题,谢谢!

代码:

var stage = new Kinetic.Stage(
    container: 'container',
    width: 500,
    height: 500
);

var layer = new Kinetic.Layer(
    width: 400,
    height: 400
);

var rect = new Kinetic.Rect(
    x: 0,
    y: 0,
    width: 400,
    height: 300,
    fill: '#00D2FF',
    stroke: 'black',
    strokeWidth: 5
);

layer.add(rect);
stage.add(layer);

$(document).on('click', '#rotateBtn', function () 
    var w = layer.getWidth(),
        h = layer.getHeight();
    layer.setOffset(w / 2, h / 2);
    layer.setPosition(w / 2, h / 2);
    layer.rotateDeg(90);
    layer.draw();
);

var points = [],
    drawing = false;

stage.on('mousedown', function () 
    drawing = true;

    var pos = stage.getMousePosition();
    points.push([pos.x, pos.y]);

    var line = new Kinetic.Line(
        id: 'line',
        points: [
            [pos.x, pos.y],
            [pos.x + 1, pos.y + 1]
        ],
        stroke: 'white',
        strokeWidth: 5,
        lineCap: 'round',
        lineJoin: 'round'
    );

    layer.add(line);
    layer.drawScene();
);

stage.on('mousemove', function () 
    if (!drawing) 
        return;
    

    // Remove previous line
    layer.get('#line').remove();

    var pos = stage.getMousePosition();
    points.push([pos.x, pos.y]);

    // Redraw line
    var line = new Kinetic.Line(
        id: 'line',
        points: points,
        stroke: 'white',
        strokeWidth: 5,
        lineCap: 'round',
        lineJoin: 'round'
    );
    layer.add(line);
    layer.drawScene();
);

stage.on('mouseup', function () 
    drawing = false;
    points = [];
);

【问题讨论】:

【参考方案1】:

即使在旋转之后,Kinetic 仍会为您提供未旋转的鼠标坐标

那是因为你要求 stage.getMousePosition 并且舞台没有旋转。

没有像 layer.getMousePosition 这样的方法,所以你必须创建一个。

如果您将图层旋转 90 度,您还必须将舞台的鼠标坐标旋转 90 度。

以下是旋转舞台鼠标位置以匹配图层旋转的方法:

    // get the unrotated mouse position from Kinetic

    var pos=stage.getMousePosition();

    // rotate that point to match the layer rotation

    var x1 = rotationX 
              + (pos.x-rotationX)*rotationCos 
              + (pos.y-rotationY)*rotationSin;

    var y1 = rotationY 
              + (pos.y-rotationY)*rotationCos 
              - (pos.x-rotationX)*rotationSin;

由于您将在每次鼠标移动时进行此数学运算,因此您应该预先计算旋转值以最大限度地提高性能:

    // reset the current rotation information

    function setRotation(degrees)
        var radians=layer.getRotation();
        rotationX=layer.getOffsetX();
        rotationY=layer.getOffsetY();
        rotationCos=Math.cos(radians);
        rotationSin=Math.sin(radians);
    

另外,你的问题有点离题,但是......

您可以“回收”现有的行,而不是在每次鼠标移动时删除/重新创建新行:

  // set the points property of the line to your updated points array

  line.setPoints(points);

这是代码和小提琴:http://jsfiddle.net/m1erickson/cQATv/

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Prototype</title>
    <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
    <script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.5.5.min.js"></script>

<style>
#container
  border:solid 1px #ccc;
  margin-top: 10px;
  width:400px;
  height:400px;

</style>        
<script>
$(function()

    var stage = new Kinetic.Stage(
        container: 'container',
        width: 500,
        height: 500
    );
    var layer = new Kinetic.Layer(width:400,height:400);
    stage.add(layer);


    // vars to save the current rotation information
    var rotationX;
    var rotationY;
    var rotationCos;
    var rotationSin;
    setRotation(0);


    var rect = new Kinetic.Rect(
        x: 0,
        y: 0,
        width: 400,
        height: 300,
        fill: '#00D2FF',
        stroke: 'black',
        strokeWidth: 5
    );

    layer.add(rect);
    stage.add(layer);

    $(document).on('click', '#rotateBtn', function () 
        var w = layer.getWidth(),
            h = layer.getHeight();

        layer.setOffset(w / 2, h / 2);
        layer.setPosition(w / 2, h / 2);
        layer.rotateDeg(90);
        layer.draw();

        // set the info necessary to un-rotate the mouse position
        setRotation(layer.getRotationDeg())

    );

    var points = [],
        drawing = false;

    stage.on('mousedown', function () 
        drawing = true;

        // get the rotated mouse position
        pos=getPos();
        points.push([pos.x, pos.y]);

        var line = new Kinetic.Line(
            id: 'line',
            points: [
                [pos.x, pos.y],
                [pos.x + 1, pos.y + 1]
            ],
            stroke: 'white',
            strokeWidth: 5,
            lineCap: 'round',
            lineJoin: 'round'
        );

        layer.add(line);
        layer.drawScene();
    );

    stage.on('mousemove', function () 
        if (!drawing) 
            return;
        

        // Remove previous line
        layer.get('#line').remove();

        // get the rotated mouse position
        var pos = getPos();
        points.push([pos.x, pos.y]);

        // Redraw line
        var line = new Kinetic.Line(
            id: 'line',
            points: points,
            stroke: 'white',
            strokeWidth: 5,
            lineCap: 'round',
            lineJoin: 'round'
        );
        layer.add(line);
        layer.drawScene();

    );

    stage.on('mouseup', function () 
        drawing = false;
        points = [];
    );


    // reset to the current rotation information
    function setRotation(degrees)
        var radians=layer.getRotation();
        rotationX=layer.getOffsetX();
        rotationY=layer.getOffsetY();
        rotationCos=Math.cos(radians);
        rotationSin=Math.sin(radians);
    


    // rotate the stage mouse position
    // to match the layer rotation
    function getPos(x,y)

        // normal space, no adjustment necessary
        if(rotationCos==0)return; 

        var pos=stage.getMousePosition();

        var x1 = rotationX 
                  + (pos.x-rotationX)*rotationCos 
                  + (pos.y-rotationY)*rotationSin;

        var y1 = rotationY 
                  + (pos.y-rotationY)*rotationCos 
                  - (pos.x-rotationX)*rotationSin;

        return(x:x1,y:y1);
    


); // end $(function());

</script>       
</head>

<body>
    <button id="rotateBtn">rotate</button>
    <div id="container"></div>
</body>
</html>

【讨论】:

谢谢!这很好用。我之前使用过 line.setPoints(points) ,但它使绘图有点延迟。我不知道为什么。

以上是关于图层旋转后KineticJS鼠标位置错误的主要内容,如果未能解决你的问题,请参考以下文章

Unity:使用鼠标位置为我的相机制作角度以围绕对象旋转

如何保持鼠标相对于屏幕的位置并忽略组件旋转?

HTML5 Canvas 中旋转矩形内的鼠标位置

开始旋转bt。单击并通过鼠标位置进行控制

ActionScript 3 根据鼠标位置旋转项目

根据鼠标的位置旋转我的形状的角度。