Skip to content

Commit 54884fa

Browse files
committed
fix: 修复 Canvas 在高分屏(DPI>1)上的错位与模糊
问题根因:fitCanvas/fitSquare 把 canvas 内部尺寸乘了 devicePixelRatio, 但绘制代码仍用 CSS 像素坐标、且未对 context 做 setTransform, 导致在 Retina / Windows 缩放 / 手机屏上画面缩在左上角、其余错乱。 修复: 1. lab.js / arcade.js 的 canvas 尺寸统一改为「直接等于 CSS 像素」, 不再乘 devicePixelRatio,绘制坐标与画布像素严格一致 2. 清理 lab.js 生命游戏 draw() 中残留的无用 dpr 变量 3. lab.js 切到「双摆 / 傅里叶 / 曼德博」tab 时重新测量画布尺寸, 避免面板从 display:none 变为可见后仍用旧的 0 宽度 影响范围:实验室(4 个实验)、游戏厅(贪吃蛇/俄罗斯方块)全部适配高分屏。
1 parent f90d262 commit 54884fa

2 files changed

Lines changed: 16 additions & 10 deletions

File tree

‎assets/js/arcade.js‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,13 @@
3333

3434
/* ==================== 工具 ==================== */
3535
function fitSquare(canvas, w, h) {
36-
var dpr = window.devicePixelRatio || 1;
3736
var width = w, height = h || w;
38-
canvas.width = width * dpr;
39-
canvas.height = height * dpr;
37+
// 用 CSS 像素作为画布内部尺寸(不乘 devicePixelRatio),避免高分屏错位
38+
canvas.width = width;
39+
canvas.height = height;
4040
canvas.style.width = width + 'px';
4141
canvas.style.height = height + 'px';
42-
return { w: width, h: height, dpr: dpr };
42+
return { w: width, h: height };
4343
}
4444

4545
function store(key, val) {

‎assets/js/lab.js‎

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
tabs.forEach(function (t) {
2929
t.addEventListener('click', function () {
3030
activate(t.getAttribute('data-lab'));
31+
// 面板从 display:none 变为可见后,重新测量画布尺寸(之前测得 0)
3132
if (active === 'mandel') { mandel.render(); }
33+
if (active === 'pendulum') { pendulum.relayout && pendulum.relayout(); }
3234
if (active === 'fourier') { fourier.render(); }
3335
});
3436
});
@@ -37,12 +39,13 @@
3739
function fitCanvas(canvas) {
3840
var rect = canvas.parentNode.getBoundingClientRect();
3941
var w = Math.max(280, Math.floor(rect.width));
40-
var dpr = window.devicePixelRatio || 1;
41-
canvas.width = w * dpr;
42-
canvas.height = w * dpr;
42+
// 用 CSS 像素作为画布内部尺寸(不乘 devicePixelRatio),
43+
// 避免高分屏上绘制坐标与画布像素错位。轻微锐度损失可接受,换取绝对正确。
44+
canvas.width = w;
45+
canvas.height = w;
4346
canvas.style.width = w + 'px';
4447
canvas.style.height = w + 'px';
45-
return { w: w, h: w, dpr: dpr };
48+
return { w: w, h: w };
4649
}
4750

4851
/* ==================== 1. 生命游戏 ==================== */
@@ -98,7 +101,6 @@
98101
function draw() {
99102
ctx.clearRect(0, 0, canvas.width, canvas.height);
100103
ctx.fillStyle = 'rgba(0,0,0,0)';
101-
var dpr = window.devicePixelRatio || 1;
102104
var cellW = canvas.width / COLS;
103105
var cellH = canvas.height / ROWS;
104106
ctx.fillStyle = getComputedStyle(document.documentElement).getPropertyValue('--link').trim() || '#267cb9';
@@ -199,7 +201,7 @@
199201

200202
function render() {
201203
var d = fitCanvas(canvas);
202-
var w = d.w, h = d.h, dpr = d.dpr;
204+
var w = d.w, h = d.h;
203205
var img = ctx.createImageData(w, h);
204206
var data = img.data;
205207

@@ -389,6 +391,10 @@
389391
last = 0;
390392
raf = requestAnimationFrame(loop);
391393
},
394+
relayout: function () {
395+
resize();
396+
draw();
397+
},
392398
reset: function () {
393399
a1 = Math.PI * 0.75; a2 = Math.PI * 0.75;
394400
v1 = 0; v2 = 0;

0 commit comments

Comments
 (0)