Kineticjs - 在图像上自由旋转

时间:2013-12-08 09:37:07

标签: javascript html5-canvas kineticjs

我只需要有旋转锚的帮助。现在有五个锚点,我不知道除了旋转之外如何摆脱所有这些锚点。我也只想在用户将鼠标悬停在图像上时显示锚点

这是我的代码

<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<body onmousedown="return false;">
<div id="container"></div>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.7.4.min.js">     
</script>
<script>

function update(activeAnchor) {
var group = activeAnchor.getParent();

var topLeft = group.get('.topLeft')[0];
var topRight = group.get('.topRight')[0];
var bottomRight = group.get('.bottomRight')[0];
var bottomLeft = group.get('.bottomLeft')[0];

var rotateAnchor = group.get('.rotateAnchor')[0];
var image = group.get('Image')[0];

var anchorX = activeAnchor.getX();
var anchorY = activeAnchor.getY();
var imageWidth = image.getWidth();
var imageHeight = image.getHeight();

var offsetX = Math.abs((topLeft.getX() + bottomRight.getX() + 10) / 2);
var offsetY = Math.abs((topLeft.getY() + bottomRight.getY() + 10) / 2);

// update anchor positions
switch (activeAnchor.getName()) {
    case 'rotateAnchor':
        group.setOffset(offsetX, offsetY);
        break;
    case 'topLeft':
        topRight.setY(anchorY);
        bottomLeft.setX(anchorX);
        break;
    case 'topRight':
        topLeft.setY(anchorY);
        bottomRight.setX(anchorX);
        break;
    case 'bottomRight':
        topRight.setX(anchorX);
        bottomLeft.setY(anchorY);
        break;
    case 'bottomLeft':
        topLeft.setX(anchorX);
        bottomRight.setY(anchorY);
        break;
}
rotateAnchor.setX(topRight.getX() + 5);
rotateAnchor.setY(topRight.getY() + 20);

image.setPosition((topLeft.getPosition().x + 20), (topLeft.getPosition().y + 20));
var width = topRight.getX() - topLeft.getX() - 30;
var height = bottomLeft.getY() - topLeft.getY() - 30;
if (width && height) {
    image.setSize(width, height);
}
}
function addAnchor(group, x, y, name, dragBound) {
var stage = group.getStage();
var layer = group.getLayer();

var anchor = new Kinetic.Circle({
                                x: x,
                                y: y,
                                stroke: '#666',
                                fill: '#ddd',
                                strokeWidth: 2,
                                radius: 8,
                                name: name,
                                draggable: true,
                                dragOnTop: false
                                });

if (dragBound == 'rotate') {
    anchor.setAttrs({
                    dragBoundFunc: function (pos) {
                    return getRotatingAnchorBounds(pos, group);
                    }
                    });
}

anchor.on('dragmove', function() {
          update(this);
          layer.draw();
          });
anchor.on('mousedown touchstart', function() {
          group.setDraggable(false);
          this.moveToTop();
          });
anchor.on('dragend', function() {
          group.setDraggable(true);
          layer.draw();
          });
// add hover styling
anchor.on('mouseover', function() {
          var layer = this.getLayer();
          document.body.style.cursor = 'pointer';
          this.setStrokeWidth(4);
          layer.draw();
          });
anchor.on('mouseout', function() {
          var layer = this.getLayer();
          document.body.style.cursor = 'default';
          this.setStrokeWidth(2);
          layer.draw();
          });

group.add(anchor);
}
function loadImages(sources, callback) {
var images = {};
var loadedImages = 0;
var numImages = 0;
for(var src in sources) {
    numImages++;
}
for(var src in sources) {
    images[src] = new Image();
    images[src].onload = function() {
        if(++loadedImages >= numImages) {
            callback(images);
        }
    };
    images[src].src = sources[src];
}
}
function getRotatingAnchorBounds(pos, group) {
var topLeft = group.get('.topLeft')[0];
var bottomRight = group.get('.bottomRight')[0];
var topRight = group.get('.topRight')[0];

var absCenterX = Math.abs((topLeft.getAbsolutePosition().x + 5 +     bottomRight.getAbsolutePosition().x + 5) / 2);
var absCenterY = Math.abs((topLeft.getAbsolutePosition().y + 5 + bottomRight.getAbsolutePosition().y + 5) / 2);

var relCenterX = Math.abs((topLeft.getX() + bottomRight.getX()) / 2);
var relCenterY = Math.abs((topLeft.getY() + bottomRight.getY()) / 2);

var radius = distance(relCenterX, relCenterY, topRight.getX() + 5, topRight.getY() + 20);

var scale = radius / distance(pos.x, pos.y, absCenterX, absCenterY);

var realRotation = Math.round(degrees(angle(relCenterX, relCenterY, topRight.getX() + 5, topRight.getY() + 20)));
var rotation = Math.round(degrees(angle(absCenterX, absCenterY, pos.x, pos.y)));
rotation -= realRotation;

group.setRotationDeg(rotation);

return {
y: Math.round((pos.y - absCenterY) * scale + absCenterY),
x: Math.round((pos.x - absCenterX) * scale + absCenterX)
};
}
function radians(degrees) { return degrees * (Math.PI / 180); }
function degrees(radians) { return radians * (180 / Math.PI); }

// Calculate the angle between two points.
function angle(cx, cy, px, py) {
var x = cx - px;
var y = cy - py;
return Math.atan2(-y, -x);
}

// Calculate the distance between two points.
function distance(p1x, p1y, p2x, p2y) {
return Math.sqrt(Math.pow((p2x - p1x), 2) + Math.pow((p2y - p1y), 2));
}

function initStage(images) {
var stage = new Kinetic.Stage({
                              container: 'container',
                              width: 578,
                              height: 400
                              });
var darthVaderGroup = new Kinetic.Group({
                                        x: 270,
                                        y: 100,
                                        draggable: true
                                        });
var yodaGroup = new Kinetic.Group({
                                  x: 100,
                                  y: 110,
                                  draggable: true
                                  });
var layer = new Kinetic.Layer();

/*
 * go ahead and add the groups
 * to the layer and the layer to the
 * stage so that the groups have knowledge
 * of its layer and stage
 */
layer.add(darthVaderGroup);
layer.add(yodaGroup);
stage.add(layer);

// darth vader
var darthVaderImg = new Kinetic.Image({
                                      x: 0,
                                      y: 0,
                                      image: images.darthVader,
                                      width: 200,
                                      height: 138,
                                      name: 'image'
                                      });

darthVaderGroup.add(darthVaderImg);
addAnchor(darthVaderGroup, -20, -20, 'topLeft', 'none');
addAnchor(darthVaderGroup, 220, -20, 'topRight', 'none');
addAnchor(darthVaderGroup, 220, 158, 'bottomRight', 'none');
addAnchor(darthVaderGroup, -20, 158, 'bottomLeft','none');
addAnchor(darthVaderGroup, 225, 0, 'rotateAnchor','rotate');

darthVaderGroup.on('dragstart', function() {
                   this.moveToTop();
                   });
stage.draw();
}

var sources = {
darthVader: 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg'
};
loadImages(sources, initStage);

</script>
</body>
</html>

1 个答案:

答案 0 :(得分:1)

您可以在图像mouseenter / mouseleave事件中使用每个锚点显示/隐藏方法,以在鼠标进入图像时显示锚点:

image.on("mouseleave",function(){ anchor1.hide();  }

image.on("mouseenter",function(){ anchor1.show(); layer.draw(); }

问题是,由于您的锚点部分位于图像之外,因此当鼠标离开图像时隐藏锚点可能会使锚点在用户打算使用时“消失”。

理想的解决方案是在包含图像的组上侦听mouseenter / mouseleave事件,但也扩展到包括锚点的外部部分。不幸的是,Kinetic.Group不会响应mouseenter / mouseleave事件。

解决方法是为组创建Kinetic.Rect背景,其中包括图像和锚点。 rect将监听mouseenter / mouseleave事件并显示/隐藏锚点。如果您不希望背景矩形可见,只需将其不透明度设置为.001即可。 rect仍然会监听事件,但是不可见。

groupBackgroundRect.on("mouseleave",function(){ anchor1.hide();  }

groupBackgroundRect.on("mouseenter",function(){ anchor1.show(); layer.draw(); }

相关说明:

使用KineticJS,将旋转与调整大小相结合比使用它更困难,因为KineticJS使用offsetX / offsetY作为 对象的旋转点和作为其位置的偏移量。使其工作的关键是在调整大小后重新定位偏移点,以便您的旋转发生在新的中心点周围 - 而不是前一个中心点。 (或将偏移参考点重置为您想要旋转的任何其他点。)