我正在开发html5的canvas元素。我有以下代码,它是可拖动和可调整大小的图像。如何通过锚将其旋转?如何通过锚提供实时旋转。我看到了其他代码示例,但不知道如何实现它。 采样器工作: http://jsfiddle.net/LAS8L/588/
<canvas id="canvas" width=350 height=350></canvas>
的Javascript
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var startX;
var startY;
var isDown = false;
var pi2 = Math.PI * 2;
var resizerRadius = 8;
var rr = resizerRadius * resizerRadius;
var draggingResizer = {
x: 0,
y: 0
};
var imageX = 50;
var imageY = 50;
var imageWidth, imageHeight, imageRight, imageBottom;
var draggingImage = false;
var startX;
var startY;
var cx = canvas.width / 2;
var cy = canvas.height / 2;
var w;
var h;
var r = 0;
var img = new Image();
img.onload = function () {
imageWidth = img.width;
imageHeight = img.height;
imageRight = imageX + imageWidth;
imageBottom = imageY + imageHeight
draw(true, false);
}
img.src = "https://dl.dropboxusercontent.com/u/139992952/stackoverflow/facesSmall.png";
function draw(withAnchors, withBorders) {
// clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// draw the image
ctx.drawImage(img, 0, 0, img.width, img.height, imageX, imageY, imageWidth, imageHeight);
// optionally draw the draggable anchors
if (withAnchors) {
drawDragAnchor(imageX, imageY);
drawDragAnchor(imageRight, imageY);
drawDragAnchor(imageRight, imageBottom);
drawDragAnchor(imageX, imageBottom);
}
// optionally draw the connecting anchor lines
if (withBorders) {
ctx.beginPath();
ctx.moveTo(imageX, imageY);
ctx.lineTo(imageRight, imageY);
ctx.lineTo(imageRight, imageBottom);
ctx.lineTo(imageX, imageBottom);
ctx.closePath();
ctx.stroke();
}
}
function drawDragAnchor(x, y) {
ctx.beginPath();
ctx.arc(x, y, resizerRadius, 0, pi2, false);
ctx.closePath();
ctx.fill();
}
function anchorHitTest(x, y) {
var dx, dy;
// top-left
dx = x - imageX;
dy = y - imageY;
if (dx * dx + dy * dy <= rr) {
return (0);
}
// top-right
dx = x - imageRight;
dy = y - imageY;
if (dx * dx + dy * dy <= rr) {
return (1);
}
// bottom-right
dx = x - imageRight;
dy = y - imageBottom;
if (dx * dx + dy * dy <= rr) {
return (2);
}
// bottom-left
dx = x - imageX;
dy = y - imageBottom;
if (dx * dx + dy * dy <= rr) {
return (3);
}
return (-1);
}
function desenhe() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawRotationHandle(true);
drawRect();
}
function drawRect() {
ctx.save();
ctx.translate(cx, cy);
ctx.rotate(r);
ctx.drawImage(img, 0, 0, img.width, img.height, -imageWidth, -imageheight, w, h);
// ctx.fillStyle="yellow";
// ctx.fillRect(-w/2,-h/2,w,h);
ctx.restore();
}
function drawRotationHandle(withFill) {
ctx.save();
ctx.translate(cx, cy);
ctx.rotate(r);
ctx.beginPath();
ctx.moveTo(0, -1);
ctx.lineTo(imageWidth + 20, -1);
ctx.lineTo(imageWidth + 20, -7);
ctx.lineTo(imageWidth + 30, -7);
ctx.lineTo(imageWidth + 30, 7);
ctx.lineTo(imageWidth + 20, 7);
ctx.lineTo(imageWidth + 20, 1);
ctx.lineTo(0, 1);
ctx.closePath();
if (withFill) {
ctx.fillStyle = "blue";
ctx.fill();
}
ctx.restore();
}
function hitImage(x, y) {
return (x > imageX && x < imageX + imageWidth && y > imageY && y < imageY + imageHeight);
}
function handleMouseDown(e) {
startX = parseInt(e.clientX - offsetX);
startY = parseInt(e.clientY - offsetY);
draggingResizer = anchorHitTest(startX, startY);
draggingImage = draggingResizer < 0 && hitImage(startX, startY);
}
function handleMouseUp(e) {
draggingResizer = -1;
draggingImage = false;
draw(true, false);
}
function handleMouseOut(e) {
handleMouseUp(e);
}
function handleMouseMove(e) {
if (draggingResizer > -1) {
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
// resize the image
switch (draggingResizer) {
case 0:
//top-left
imageX = mouseX;
imageWidth = imageRight - mouseX;
imageY = mouseY;
imageHeight = imageBottom - mouseY;
break;
case 1:
//top-right
imageY = mouseY;
imageWidth = mouseX - imageX;
imageHeight = imageBottom - mouseY;
break;
case 2:
//bottom-right
imageWidth = mouseX - imageX;
imageHeight = mouseY - imageY;
break;
case 3:
//bottom-left
imageX = mouseX;
imageWidth = imageRight - mouseX;
imageHeight = mouseY - imageY;
break;
}
if(imageWidth<25){imageWidth=25;}
if(imageHeight<25){imageHeight=25;}
// set the image right and bottom
imageRight = imageX + imageWidth;
imageBottom = imageY + imageHeight;
// redraw the image with resizing anchors
draw(true, true);
} else if (draggingImage) {
imageClick = false;
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
// move the image by the amount of the latest drag
var dx = mouseX - startX;
var dy = mouseY - startY;
imageX += dx;
imageY += dy;
imageRight += dx;
imageBottom += dy;
// reset the startXY for next time
startX = mouseX;
startY = mouseY;
// redraw the image with border
draw(false, true);
}
}
$("#canvas").mousedown(function (e) {
handleMouseDown(e);
});
$("#canvas").mousemove(function (e) {
handleMouseMove(e);
});
$("#canvas").mouseup(function (e) {
handleMouseUp(e);
});
$("#canvas").mouseout(function (e) {
handleMouseOut(e);
});
我想以这种方式工作:http://jsfiddle.net/m1erickson/QqwKR/但我不知道如何合并代码。有人可以帮帮我吗?
答案 0 :(得分:1)
这是一个函数,它将设置变换以缩放旋转并平移矩形或任何东西。
function setTransform(ctx,x,y,scale,rotate){
var xdx = Math.cos(rotate) * scale; // create the x axis
var xdy = Math.sin(rotate) * scale;
ctx.setTransform(xdx, xdy, - xdy, xdx, x, y);
}
之后设置画布变换。现在只需在本地空间坐标中绘制对象。
例如在画布双重刻度和45度旋转中心绘制
setTransform(ctx,canvas.width/2,canvas.height/2,2,Math.PI /4);
ctx.strokeRect(-100,-100,200,200);
您会注意到坐标为负数。这是因为我希望盒子的中心位于画布的中心。如果我希望盒子的左上角位于中心
ctx.strokeRect(0,0,200,200);
或右下角
ctx.strokeRect(-200,-200,200,200);
回到居中的框我可以移动到任何地方
setTransform(
ctx,
Math.random() * canvas.width, // random x pos
Math.random() * canvas.height, // random y pos
Math.random() * 10 + 0.1, // random scale
Math.random() * Math.PI * 2 // random rotation
);
变换是随机的,但我不需要关心我仍然可以在局部坐标中绘制框。
ctx.strokeRect(-100,-100,200,200);
它将在变换设置的地方绘制。
使用ctx.setTransform
可以省去使用保存和恢复的麻烦。
如果在任何阶段你需要返回默认转换
ctx.setTransform(1,0,0,1,0,0);
接下来将面临的问题是,当对象位于其本地空间时,鼠标坐标位于画布坐标中。您需要将鼠标坐标转换为本地对象坐标。
这是通过将鼠标坐标乘以矩阵的倒数来完成的。这里有点数学。
function getMouseLocal(mousex,mouseY,x,y,scale,rot){
var xdx = Math.cos(rotate) * scale; // create the x axis
var xdy = Math.sin(rotate) * scale;
// get the cross product of the two axies
var cross = xdx * xdx - xdy * -xdy;
// or
var cross = Math.pow(xdx,2) + Math.pow(xdy,2);
// then create the inverted axies
var ixdx = xdx / cross; // create inverted x axis
var ixdy = -xdy / cross;
var iydx = xdy / cross; // create inverted y axis
var iydy = xdx / cross;
// now remove the origin from the mouse coords
mouseX -= x;
mouseY -= y;
// multiply by the invers matrix
var localMouseX = mouseX * ixdx + mouseY * iydx;
var localMouseY = mouseX * ixdy + mouseY * iydy;
// and return the result
return {x : localMouseX, y : localMouseY};
}
现在您在本地空间中拥有鼠标坐标。如果你需要找出鼠标是否在你的框内
setTransform(ctx,100,100,2,Math.PI/4);
ctx.strokeRect(-100,-100,200,200);
var localMouse= getMouseLocal(mouseX,mouseY,100,100,2,Math.PI/4);
if(localMouse.x > -100 && localMouse.x < -100 + 200 && localMouse.y > -100 && localMouse.y < -100 + 200){
// mouse is inside the box
}
这应该可以满足您的需求。
<强>更新强>
我忘了你想要缩放x和y ..所以下面是用于缩放X和Y轴的修改函数
// sx and sy are scale x and y
function setTransform(ctx,x,y,sx,sy,rotate){
var xdx = Math.cos(rotate); // create the x axis
var xdy = Math.sin(rotate);
ctx.setTransform(xdx * sx, xdy * sx, - xdy * sy, xdx * sy, x, y);
}
将鼠标移至本地
function getMouseLocal(mousex,mouseY,x,y,sx,sy,rot){
var xdx = Math.cos(rotate); // create the x axis
var xdy = Math.sin(rotate);
// get the cross product of the two axies
var cross = xdx * sx * xdx * sy - xdy *sx * -xdy * sy;
// or
// this shortcut does not work now.
// var cross = Math.pow(xdx,2) + Math.pow(xdy,2);
// then create the inverted axies
var ixdx = (xdx * sy) / cross; // create inverted x axis
var ixdy = (-xdy * sx) / cross;
var iydx = (xdy * sy) / cross; // create inverted y axis
var iydy = (xdx * sx) / cross;
// now remove the origin from the mouse coords
mouseX -= x;
mouseY -= y;
// multiply by the invers matrix
var localMouseX = mouseX * ixdx + mouseY * iydx;
var localMouseY = mouseX * ixdy + mouseY * iydy;
// and return the result
return {x : localMouseX, y : localMouseY};
}