JavaScript canvas 的缩放在旋转后看起来很奇怪
Scaling of JavaScript canvas looks strange after rotation
我有一个 html canvas 在 JS 脚本中延伸到浏览器 window 维度。我想保持 canvas 适合 window 尺寸(通过 ctx.scale 或 ctx.setTransform),但当 window 是垂直,即 window.innerHeight > window.innerWidth。但是,我在垂直情况下看到一些奇怪的行为,不知道我错过了什么。
我的 JavaScript 代码如下:
var canvas = document.getElementById("GameCanvas");
var ctx = canvas.getContext("2d");
canv_start_w = canvas.width;
canv_start_h = canvas.height;
// drawing functions
function set_canvas_bg() {
ctx.fillStyle = "lightblue";
ctx.fillRect(0,0,canvas.width, canvas.height);
}
function draw_line() {
ctx.beginPath();
ctx.lineWidth="3";
ctx.strokeStyle="black";
ctx.moveTo(canv_start_w/16, canv_start_h/2);
ctx.lineTo(15*canv_start_w/16, canv_start_h/2);
ctx.stroke();
ctx.closePath();
}
function draw_circ() {
ctx.beginPath();
ctx.fillStyle="black";
ctx.arc(canv_start_w/2, canv_start_h/2, canv_start_w/10, 0, 2*Math.PI);
ctx.fill();
ctx.closePath();
}
// canvas transformation functions
function resize_canvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
function scale_ctx() {
var smaller_dim = Math.min(canvas.width, canvas.height);
var larger_dim = Math.max(canvas.width, canvas.height)
var xscale = larger_dim/canv_start_w;
var yscale = smaller_dim/canv_start_h;
ctx.setTransform(xscale, 0, 0, yscale, 0, 0);
}
function rotate_ctx(deg) {
ctx.rotate((deg/360)*(2*Math.PI));
}
function update() {
resize_canvas();
scale_ctx();
// distinction: vertical or horizontal window?
if (window.innerWidth < window.innerHeight) {
// CASE 1: vertical
rotate_ctx(90);
ctx.translate(0, -canvas.width); // move back into view
} else {
// CASE 2: horizontal
rotate_ctx(0);
ctx.translate(0, 0); // move back into view
}
// drawing elements to canvas
set_canvas_bg();
draw_circ();
draw_line();
requestAnimationFrame(update);
}
update();
每次更改 canvas 维度时,都会删除上下文转换(即旋转、缩放)。可以在此处找到工作脚本并进行试验:https://jsfiddle.net/nicoa47/3fsan6c0/
三部分解决方案是
(1) 到 在每个更新循环开始时重置转换 通过
ctx.setTransform(1, 0, 0, 1, 0, 0);
(2) 到 将上下文翻译到 window 中心并在 rotating/scaling 之后翻译回 (这确保围绕 window 的旋转中心)通过
ctx.translate(window.innerWidth/2, window.innerHeight/2);
// rotate...
// scale...
ctx.translate(-window.innerWidth/2, -window.innerHeight/2);
在垂直情况下,需要交换第二个翻译的参数。
(3) 至 根据当前比例更改缩放函数。也就是说,创建新变量
var canv_current_w = window.innerWidth;
var canv_current_h = window.innerHeight;
跟踪最后一帧的尺寸,即在更新循环结束时设置:
canv_current_w = window.innerWidth;
canv_current_h = window.innerHeight;
再次,交换垂直大小写的值。用缩放函数中的这些新变量替换 canv_start_w、canv_start_h。
我有一个 html canvas 在 JS 脚本中延伸到浏览器 window 维度。我想保持 canvas 适合 window 尺寸(通过 ctx.scale 或 ctx.setTransform),但当 window 是垂直,即 window.innerHeight > window.innerWidth。但是,我在垂直情况下看到一些奇怪的行为,不知道我错过了什么。
我的 JavaScript 代码如下:
var canvas = document.getElementById("GameCanvas");
var ctx = canvas.getContext("2d");
canv_start_w = canvas.width;
canv_start_h = canvas.height;
// drawing functions
function set_canvas_bg() {
ctx.fillStyle = "lightblue";
ctx.fillRect(0,0,canvas.width, canvas.height);
}
function draw_line() {
ctx.beginPath();
ctx.lineWidth="3";
ctx.strokeStyle="black";
ctx.moveTo(canv_start_w/16, canv_start_h/2);
ctx.lineTo(15*canv_start_w/16, canv_start_h/2);
ctx.stroke();
ctx.closePath();
}
function draw_circ() {
ctx.beginPath();
ctx.fillStyle="black";
ctx.arc(canv_start_w/2, canv_start_h/2, canv_start_w/10, 0, 2*Math.PI);
ctx.fill();
ctx.closePath();
}
// canvas transformation functions
function resize_canvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
function scale_ctx() {
var smaller_dim = Math.min(canvas.width, canvas.height);
var larger_dim = Math.max(canvas.width, canvas.height)
var xscale = larger_dim/canv_start_w;
var yscale = smaller_dim/canv_start_h;
ctx.setTransform(xscale, 0, 0, yscale, 0, 0);
}
function rotate_ctx(deg) {
ctx.rotate((deg/360)*(2*Math.PI));
}
function update() {
resize_canvas();
scale_ctx();
// distinction: vertical or horizontal window?
if (window.innerWidth < window.innerHeight) {
// CASE 1: vertical
rotate_ctx(90);
ctx.translate(0, -canvas.width); // move back into view
} else {
// CASE 2: horizontal
rotate_ctx(0);
ctx.translate(0, 0); // move back into view
}
// drawing elements to canvas
set_canvas_bg();
draw_circ();
draw_line();
requestAnimationFrame(update);
}
update();
每次更改 canvas 维度时,都会删除上下文转换(即旋转、缩放)。可以在此处找到工作脚本并进行试验:https://jsfiddle.net/nicoa47/3fsan6c0/
三部分解决方案是
(1) 到 在每个更新循环开始时重置转换 通过
ctx.setTransform(1, 0, 0, 1, 0, 0);
(2) 到 将上下文翻译到 window 中心并在 rotating/scaling 之后翻译回 (这确保围绕 window 的旋转中心)通过
ctx.translate(window.innerWidth/2, window.innerHeight/2);
// rotate...
// scale...
ctx.translate(-window.innerWidth/2, -window.innerHeight/2);
在垂直情况下,需要交换第二个翻译的参数。
(3) 至 根据当前比例更改缩放函数。也就是说,创建新变量
var canv_current_w = window.innerWidth;
var canv_current_h = window.innerHeight;
跟踪最后一帧的尺寸,即在更新循环结束时设置:
canv_current_w = window.innerWidth;
canv_current_h = window.innerHeight;
再次,交换垂直大小写的值。用缩放函数中的这些新变量替换 canv_start_w、canv_start_h。