HTML5 Canvas:我如何在旋转后处理反向翻译()?
Posted
技术标签:
【中文标题】HTML5 Canvas:我如何在旋转后处理反向翻译()?【英文标题】:HTML5 Canvas: how i can deal with inverted translate() after rotation? 【发布时间】:2022-01-04 21:57:57 【问题描述】:我需要在绘制形状之前应用几个矩阵变换,但是(如果在某处)我使用 rotate()
坐标被反转和/或反转,并且在不知道矩阵先前是否旋转的情况下无法继续。
如何解决这个问题?
示例:
<canvas ></canvas>
<script>
let canvas = document.querySelector("canvas");
let ctx = canvas.getContext("2d");
ctx.fillStyle = "silver";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.strokeStyle = "black";
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(0, canvas.height/2);
ctx.lineTo(canvas.width, canvas.height/2);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(canvas.width/2, 0);
ctx.lineTo(canvas.width/2, canvas.height);
ctx.stroke();
ctx.translate(150, 150);
ctx.rotate(-90 * 0.017453292519943295);
ctx.translate(-150, -150);
// move the red rectangle 100px to the left (top-left)
// but instead is moved on y axis (right-bottom)
ctx.translate(-100, 0);
// more matrix transformations
// ....
// ....
// now finally draw the shape
ctx.fillStyle = "red";
ctx.fillRect(150, 150, 100, 50);
</script>
这可以是Translation after rotation 的解决方案吗?
【问题讨论】:
先重置你的变换矩阵? 我正在构建一个UI,红色矩形属于一个灰色矩形,这个灰色矩形也属于另一个一个(假设是一个白色矩形),如果我需要平移灰色矩形或旋转白色矩形,我必须堆叠所有的转换,所以红色矩形 绘制正确。也许应该发布一个复杂的例子来更好地理解它。 记得put the details in your post。不在评论中。 又是一个例子,你没看懂第一个(关于问题) 是的,那应该是in your post,并提供更多指导文字:当人们要求澄清或更多细节,或发表评论让您认为有人误解了您的帖子时,这是一个信号您的帖子需要更多信息(然后您可以发表评论回复“我已更新帖子以解释这一点”或类似内容)因为 cmets 不是开始一对一的,他们是要求将您的帖子更新为足够完整的内容,以至于人们不会需要发布额外的 cmets,因为它已经非常清楚了。 【参考方案1】:您似乎没有在每次进行新转换时都重置画布矩阵。
Canvas API 具有 save()
和 restore()
方法。画布状态存储在堆栈中。每次调用save()
方法时,都会将当前绘制状态压入堆栈。绘图状态由已应用的转换以及fillStyle
之类的属性组成。当您拨打restore()
时,会恢复之前的设置。
// ...
ctx.save(); // save the current canvas state
ctx.translate(150, 150);
ctx.rotate(-90 * 0.017453292519943295);
ctx.translate(-150, -150);
ctx.restore(); // restore the last saved state
// now the rectangle should move the correct direction
ctx.translate(-100, 0);
查看此link,了解有关save
和restore
方法的更多信息。
【讨论】:
不起作用,请参阅https://***.com/a/70147286/2426646【参考方案2】:最后,我通过在应用之前旋转平移点解决了这个问题。这个函数可以解决问题:
function helperRotatePoint(point, angle)
let s = Math.sin(angle);
let c = Math.cos(angle);
return x: point.x * c - point.y * s, y: point.x * s + point.y * c;
使用倒角旋转平移点我得到校正的平移
helperRotatePoint(translation_point, -rotation_angle);
工作代码:
let canvas = document.querySelector("canvas");
// proper size on HiDPI displays
canvas.style.width = canvas.width;
canvas.style.height = canvas.height;
canvas.width = Math.floor(canvas.width * window.devicePixelRatio);
canvas.height = Math.floor(canvas.height * window.devicePixelRatio);
let ctx = canvas.getContext("2d");
ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
ctx.fillStyle = "whitesmoke";
ctx.fillRect(0, 0, canvas.width, canvas.height);
class UIElement
constructor(x, y, width, height, color)
// PoC
this.draw_pos = x, y;
this.draw_size = width, height;
this.color = color;
this.rotate = 0;
this.scale = x: 1, y: 1;
this.translate = x: 0, y: 0;
this.skew = x: 0, y: 0;
this.childs = [];
addChild(uielement)
this.childs.push(uielement);
helperRotatePoint(point, angle)
let s = Math.sin(angle);
let c = Math.cos(angle);
return
x: point.x * c - point.y * s,
y: point.x * s + point.y * c
;
draw(cnvs_ctx, parent_x, parent_y)
// backup current state
cnvs_ctx.save();
let elements_drawn = 1;// "this" UIElement
// step 1: calc absolute coordinates
let absolute_x = parent_x + this.draw_pos.x;
let absolute_y = parent_y + this.draw_pos.y;
// step 2: apply all transforms
if (this.rotate != 0)
cnvs_ctx.translate(absolute_x, absolute_y)
cnvs_ctx.rotate(this.rotate);
cnvs_ctx.translate(-absolute_x, -absolute_y);
// rotate translate point before continue
let tmp = this.helperRotatePoint(this.translate, -this.rotate);
// apply rotated translate
cnvs_ctx.translate(tmp.x, tmp.y);
else
cnvs_ctx.translate(this.translate.x, this.translate.y);
cnvs_ctx.scale(this.scale.x, this.scale.y);
cnvs_ctx.transform(1, this.skew.y, this.skew.x, 1, 0, 0);
// step 3: self draw (aka parent element)
cnvs_ctx.fillStyle = this.color;
cnvs_ctx.fillRect(absolute_x, absolute_y, this.draw_size.width, this.draw_size.height);
// step 4: draw childs elements
for (let i = 0; i < this.childs.length ; i++)
elements_drawn += this.childs[i].draw(
cnvs_ctx, absolute_x, absolute_y
);
// done, restore state
cnvs_ctx.restore();
return elements_drawn;
// spawn some ui elements
var ui_panel = new UIElement(120, 50, 240, 140, "#9b9a9e");
var ui_textlabel = new UIElement(10, 10, 130, 18, "#FFF");
var ui_image = new UIElement(165, 25, 90, 60, "#ea9e22");
var ui_textdesc = new UIElement(17, 46, 117, 56, "#ff2100");
var ui_icon = new UIElement(5, 5, 10, 10, "#800000");
ui_panel.addChild(ui_textlabel);
ui_panel.addChild(ui_image);
ui_panel.addChild(ui_textdesc);
ui_textdesc.addChild(ui_icon);
// add some matrix transformations
ui_textdesc.skew.x = -0.13;
ui_textdesc.translate.x = 13;
ui_image.rotate = -90 * 0.017453292519943295;
ui_image.translate.y = ui_image.draw_size.width;
ui_panel.rotate = 15 * 0.017453292519943295;
ui_panel.translate.x = -84;
ui_panel.translate.y = -50;
// all ui element elements
ui_panel.draw(ctx, 0, 0);
<canvas width="480" height="360"></canvas>
【讨论】:
以上是关于HTML5 Canvas:我如何在旋转后处理反向翻译()?的主要内容,如果未能解决你的问题,请参考以下文章
ios系统 竖屏拍照 canvas处理后 图片旋转(利用exif.js解决ios手机上传竖拍照片旋转90度问题)