【问题标题】:Rotate canvas 90 degrees clockwise and update width height将画布顺时针旋转 90 度并更新宽度高度
【发布时间】:2014-01-06 20:12:34
【问题描述】:

假设我们有一个画布:

<canvas id="one" width="100" height="200"></canvas>

点击按钮后,画布会顺时针旋转 90 度(围绕中心),并且画布的尺寸也会更新,因此在某种意义上它看起来像这样:

<canvas id="one" width="200" height="100"></canvas>

注意画布的id是一样的。

想象一下,只是顺时针旋转图像而不被裁剪或填充。

在创建新画布以及逐像素旋转和复制之前,有什么建议吗?

更新带有 cmets 建议的示例代码仍然无法正常工作:

function imageRotatecw90(){

    var canvas = document.getElementById("one");
    var context = canvas.getContext("2d");

    var cw=canvas.width;
    var ch=canvas.height;

    var myImageData = context.getImageData(0,0, cw,ch);

    context.save();

    context.translate(cw / 2, ch / 2);
    context.rotate(Math.PI/2);

    context.putImageData(myImageData, 0, 0);

    context.restore();

    canvas.width=ch;
    canvas.height=cw;
}

FiddleJS

【问题讨论】:

  • 为什么要逐像素复制?为什么不将图像作为图像数据抓取,调整画布大小,旋转上下文,然后将画布的图像设置为先前的图像数据?大约有十几行非常简单的代码。
  • @Stephen 我会试试的。希望没有陷阱。
  • @Stephen 我试过使用 ImageData 但它没有做任何改变画布尺寸的部分

标签: javascript image-processing canvas


【解决方案1】:

看看这个DEMO

为了达到演示中看到的结果,我使用canvas.toDataURL 将画布缓存到图像中,然后将画布重置为新尺寸,正确翻译和旋转上下文,最后将缓存的图像绘制回修改画布。

这样您就可以轻松地旋转画布,而无需重新绘制所有内容。但是由于浏览器使用了anti-aliasing 方法,每次执行此操作时,您都会注意到结果有些模糊。如果您不喜欢这种行为,我能想到的唯一解决方案是重新绘制所有内容,这更难跟踪。

代码如下:

var canvas = document.getElementById("one");
var context = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;

// Sample graphic
context.beginPath();
context.rect(10, 10, 20, 50);
context.fillStyle = 'yellow';
context.fill();
context.lineWidth = 7;
context.strokeStyle = 'black';
context.stroke();

// create button
var button = document.getElementById("rotate");
button.onclick = function () {
    // rotate the canvas 90 degrees each time the button is pressed
    rotate();
}

var myImageData, rotating = false;   

var rotate = function () {
    if (!rotating) {
        rotating = true;            
        // store current data to an image
        myImageData = new Image();
        myImageData.src = canvas.toDataURL();

       myImageData.onload = function () {
            // reset the canvas with new dimensions
            canvas.width = ch;
            canvas.height = cw;
            cw = canvas.width;
            ch = canvas.height;

            context.save();
            // translate and rotate
            context.translate(cw, ch / cw);
            context.rotate(Math.PI / 2);
            // draw the previows image, now rotated
            context.drawImage(myImageData, 0, 0);               
            context.restore();

            // clear the temporary image
            myImageData = null;

            rotating = false;               
        }
    }
}

【讨论】:

  • 谢谢。我设法获得了与您的想法非常相似的工作代码。我没有使用中间图像,而是使用辅助画布来保存像素。这避免了加载复杂性,我的代码只有 5 行长。
  • 不错。我也用这种方式编写了一些代码。使用辅助画布的另一大优势是避免不断创建图像对象,从而减少垃圾收集器操作。
【解决方案2】:

轮换

请注意,不能旋转单个元素。

ctx.save();
ctx.rotate(0.17);

// Clear the current drawings.
ctx.fillRect()

// draw your object
ctx.restore();

宽度/高度调整

我发现正确处理显示比例、屏幕尺寸等的唯一方法:

canvas.width = 20;// DO NOT USE PIXELS
canvas.height = 40; // AGAIN NO PIXELS

请注意,我故意使用canvas.style.widthcanvas.style.height。同样对于可调整的画布,不要依赖 CSS 或媒体查询来进行转换,由于像素比率的差异,它们会让人头疼。 JavaScript 会自动考虑这些。

更新

您还必须在绘制之前更新宽度和高度。不确定您要达到的目标,但我想这不是问题:

Demo here

var canvas = document.getElementById("one");
var context = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;

canvas.width = 200;
canvas.height = 400;

// Sample graphic
context.beginPath();
context.rect(10,10,20,50);
context.fillStyle = 'yellow';
context.fill();
context.lineWidth = 7;
context.strokeStyle = 'black';
context.stroke();


var myImageData = context.getImageData(0, 0, cw, ch);

context.save();

context.translate(cw / 2, ch / 2);
context.putImageData(myImageData, 0, 0);
context.rotate(0.20);

【讨论】:

  • 谢谢。我添加了一些不起作用的示例代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-05
  • 1970-01-01
  • 2017-10-19
  • 2016-06-29
  • 1970-01-01
  • 1970-01-01
  • 2021-03-18
相关资源
最近更新 更多