Javascript 在画布上旋转现有图像

Javascript 在画布上旋转现有图像,javascript,html,canvas,html5-canvas,Javascript,Html,Canvas,Html5 Canvas,我尝试旋转已在HTML画布上绘制的图像,如下所示: var canvas = document.getElementById("editorCanvas"); var ctx = canvas.getContext("2d"); var canvasOffset = $("#editorCanvas").offset(); var offsetX = canvasOffset.left; var offsetY = canvasOffset.top; var startX; var star

我尝试旋转已在HTML画布上绘制的图像,如下所示:

var canvas = document.getElementById("editorCanvas");
var ctx = canvas.getContext("2d");

var canvasOffset = $("#editorCanvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;

var startX;
var startY;
var isDown = false;


var pi2 = Math.PI * 2;
var resizerRadius = 4;
var rr = resizerRadius * resizerRadius;
var draggingResizer = {
    x: 0,
    y: 0
};
var imageX = 0;
var imageY;
var imageWidth, imageHeight, imageRight, imageBottom;
var draggingImage = false;
var startX;
var startY;



var img = new Image();
img.crossOrigin='anonymous';
img.onload = function () {

    var ratio = img.width / img.height;

    imageWidth = 71;
    imageHeight = imageWidth / ratio;
    imageY = (245-imageHeight)/2;
    if (imageHeight > 245) {
        imageHeight = 245;
        imageWidth = imageHeight * ratio;
        imageY = 0;
    }

    imageX = ((canvas.width-imageWidth)/2);
    imageY = ((canvas.height-imageHeight)/2);

    imageRight = imageX + imageWidth;
    imageBottom = imageY + imageHeight;

    draw(true, false);
}

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 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);

    }


}


$("#editorCanvas").mousedown(function (e) {
    handleMouseDown(e);
});
$("#editorCanvas").mousemove(function (e) {
    handleMouseMove(e);
});
$("#editorCanvas").mouseup(function (e) {
    handleMouseUp(e);
});
$("#editorCanvas").mouseout(function (e) {
    handleMouseOut(e);
});
但我认为唯一的办法是通过重画图像


有没有办法在画布上旋转图像而不重新绘制它,如果没有,我该如何在画布上旋转图像?

正是斯宾塞所说的,画布更像是你在上面绘制的一张纸。如果你画一个圆,你不能只是旋转它,你必须擦除它,然后在它的新位置画它

您必须跟踪对象状态(旋转、位置、颜色等),然后使用这些状态重新绘制画布


如果您想为移动对象提供一个更完善的解决方案,请尝试使用。它提供了一个处理对象而不是绘制像素的框架。这是从标准画布向上的一个步骤,而不会变得复杂。

如果不想存储重新创建画布所需的所有命令,可以使用第二个内存画布来旋转现有画布内容

  • 创建第二个内存画布
  • 将主画布复制到第二个画布上
  • 清理主画布
  • 将旋转点设置为主画布的中心
  • (但可以设置所需的任何旋转点)
  • 旋转90度(=π/2)
  • 将第二个画布重新绘制回(现在已旋转)主画布
  • 清理--取消旋转并取消转换主画布

示例代码和演示:

var canvas=document.getElementById(“canvas”);
var ctx=canvas.getContext(“2d”);
var cw=画布宽度;
var ch=画布高度;
var img=新图像();
img.onload=启动;
img.src=”https://dl.dropboxusercontent.com/u/139992952/multple/leftarrow.png";
函数start(){
ctx.drawImage(图像,cw/2-img.width/2,ch/2-img.width/2);
$(“#旋转”)。单击(函数(){
旋转(cw/2,ch/2,90);
});
}
函数旋转(rotationPointX、rotationPointY、degreeRotation){
//创建第二个内存画布:
var mCanvas=document.createElement('canvas');
mCanvas.width=canvas.width;
mCanvas.height=canvas.height;
var mctx=mCanvas.getContext('2d');
//将画布绘制到第二个画布上
mctx.drawImage(画布,0,0);
//清除主画布
clearRect(0,0,canvas.width,canvas.height);
//旋转主画布
//将旋转点设置为画布的中心
//(但可以设置所需的任何旋转点)
平移(旋转点x,旋转点y);
//旋转90度(=π/2)
var弧度=脱脂/180*Math.PI;
ctx.旋转(弧度);
//将第二个画布绘制回(现在已旋转)主画布:
ctx.drawImage(mCanvas,-canvas.width/2,-canvas.height/2);
//清理-不旋转和不转换
ctx.旋转(-弧度);
ctx.translate(-canvas.width/2,-canvas.height/2);
}
body{背景色:象牙;}
#画布{边框:1px纯红;}

旋转现有图像。


最简单的方法是使用“复制”复合模式绘制画布。“复制”将在绘制新内容时清除背景:

例子
var ctx=document.querySelector(“canvas”).getContext(“2d”);
ctx.moveTo(75,10);//一些图形。。。
ctx.lineTo(30140);
ctx.lineTo(120140);
ctx.fill();
//为下一步操作准备画布
ctx.translate(75,75);//转换到画布中心
ctx.旋转(数学PI*0.5);//添加旋转变换
ctx.globalCompositeOperation=“复制”//设置补偿。“复制”模式
//每次单击时旋转
document.querySelector(“按钮”).onclick=function(){
//画布将自身用作源、源区域和目标偏移量
//补偿上面的平移,使其围绕中心旋转:
drawImage(ctx.canvas,0,0,150,150,-75,75,150,150);
};
body{background:#eee}


旋转
图像只是在画布上绘制,而不是“附加”到画布上。因此,如果你想改变它,移动或旋转,你需要擦除画布并重新绘制。您可以不重新绘制,但您将看到未擦除的旧图像的位置,旋转后的图像位于顶部。感谢您的回答,同时我可以看到它在示例中工作,以及当我复制代码行时。但是,当我试图将其集成到上面的代码中时,它要么不起作用,要么只是导致画布上的图像被隐藏。有什么提示吗?@AlexSaidani刚刚重置了转换和合成模式。简单的方法是在应用任何恢复之前使用ctx.save(),完成后使用restore()。或者,使用setTransform(1,0,0,1,0,0)手动重置,并将补偿模式设置回“源代码结束”。上面显示的设置步骤可以移动到按钮处理程序内部。@Alexaidani添加了第二个示例,如下所示:感谢您的回答,同时我可以看到它在示例中起作用,并且当我将代码行复制到下一行时。但是,当我试图将其集成到上面的代码中时,它要么不起作用,要么只是导致画布上的图像被隐藏。有什么提示吗?你没有设置任何img.src,所以你的代码不会显示任何图像!在我添加了一个图像源之后,我的答案中的旋转函数确实会旋转您的图像(请参见添加到答案)。但是,请注意,draw()函数会重新绘制原始图像并在不旋转的情况下定位。这将撤消旋转效果,因此您必须调整这些处理程序以绘制图像&锚定为零旋转,而不是新的旋转。我建议保存当前的旋转角度,并将您的drawImage和drawAnchors包装在适当的平移/旋转中,以便它们以新的角度绘制。回到这里,感谢您提供详细的答案。不过我还是没能让它正常工作。它现在会旋转,但正如您所提到的,draw函数会将图像重置回其原始角度。你知道如何在不重置它的情况下让它工作吗?
    function rotateImage() {
        var rotateCanvas = document.getElementById('editorCanvas');
        var rotateContext = canvas.getContext('2d');
        rotateContext.rotate(90 * Math.PI / 180);
    }