循环中调用HTML Canvas绘制圆角矩形失效问题
问题分析与修复
你的代码存在两个核心问题,导致渲染循环中画布完全空白:
1. 重复循环与实例属性篡改
Letter类的render方法内部嵌套了rows和cols的双重循环,而外部全局render函数已经在遍历整个grid数组调用每个Letter实例的render方法。这意味着每个Letter实例会重复绘制25个圆角矩形,更严重的是,每次调用render时都会把实例的r属性从初始数字(16)改成对象,第二次渲染时this.r已经是对象,再执行this.r = { tl: this.r, tr: this.r, br: this.r, bl: this.r }会生成嵌套对象,导致坐标计算完全错误,最终无法绘制任何图形。
2. 笔误导致坐标失效
绘制右下角圆角的二次贝塞尔曲线时,错误使用了this.t.br——t是你传入的字母(如'B'),没有br属性,这会让undefined参与坐标计算,直接导致路径失效。
修正后的完整代码
const c = document.createElement('canvas'); c.width = innerHeight / 2; c.height = innerHeight / 2; document.getElementById('app').appendChild(c); const ctx = c.getContext('2d'); class Letter { i; x; y; w; h; r; t; constructor(i, x, y, w, h, r, t) { this.i = i; this.x = x; this.y = y; this.w = w; this.h = h; // 初始化圆角配置对象,避免后续类型篡改 this.r = { tl: r, tr: r, br: r, bl: r }; this.t = t; } render() { ctx.beginPath(); // 左上角到右上角 ctx.moveTo(this.x + this.r.tl, this.y); ctx.lineTo(this.x + this.w - this.r.tr, this.y); ctx.quadraticCurveTo(this.x + this.w, this.y, this.x + this.w, this.y + this.r.tr); // 右上角到右下角 ctx.lineTo(this.x + this.w, this.y + this.h - this.r.br); ctx.quadraticCurveTo(this.x + this.w, this.y + this.h, this.x + this.w - this.r.br, this.y + this.h); // 右下角到左下角 ctx.lineTo(this.x + this.r.bl, this.y + this.h); ctx.quadraticCurveTo(this.x, this.y + this.h, this.x, this.y + this.h - this.r.bl); // 左下角到左上角 ctx.lineTo(this.x, this.y + this.r.tl); ctx.quadraticCurveTo(this.x, this.y, this.x + this.r.tl, this.y); ctx.closePath(); ctx.fillStyle = 'red'; ctx.fill(); } } const rows = 5, cols = 5; var grid = []; var counter = 0; for (let row = 0; row < rows; row++) { grid[row] = []; for (let col = 0; col < cols; col++) { grid[row][col] = new Letter( counter++, ((c.width / rows) * col), ((c.height / cols) * row), Math.round((c.width / rows) - 8), Math.round((c.height / cols) - 8), 16, 'B', ); } } function render() { ctx.clearRect(0, 0, c.width, c.height); for (let row = 0; row < rows; row++) { for (let col = 0; col < cols; col++) { const l = grid[row][col]; l.render(); } } requestAnimationFrame(render); } requestAnimationFrame(render);
关键修改说明
- 移除
Letter.render方法内部的双重循环,每个实例仅负责绘制自身对应的圆角矩形 - 在
constructor中直接将r初始化为包含四个角的配置对象,避免后续类型篡改 - 修正笔误:将
this.t.br改为this.r.br,确保坐标计算正确 - 保留原有网格布局逻辑,保证每个圆角矩形的位置和尺寸准确
内容的提问来源于stack exchange,提问作者MickeyMGK
相关产品推荐
相关产品推荐

