javascript - Chrome94&95 画布错误
问题描述
Chrome 浏览器在 Canvas 绘图中有明显的 bug。以下代码
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.setTransform(2, 0, 0, 2, 0, 0);
ctx.beginPath();
const arr = [
["moveTo",7,209],
["lineTo",6318,403],
["lineTo",15786,453],
["lineTo",18942,451],
["lineTo",22098,28]
];
ctx.beginPath();
arr.forEach(item => {
if (item[0] === 'lineTo') {
ctx.lineTo(item[1], item[2]);
} else if (item[0] === 'moveTo') {
ctx.moveTo(item[1], item[2]);
}
})
ctx.strokeStyle = 'red'
ctx.stroke();
<canvas
id="canvas"
width=800
height=800
style="width: 400px; height: 400px"
>
</canvas>
Chrome94 中的结果是这样的: Chrome94&95
Safari 中的相同代码是这样的: Safari
那么有没有办法避免chrome中的这个错误?
解决方案
此错误已在最新的 Canary 97 中修复。
这显然是您巨大坐标的舍入问题。所以为了避免它,如果可以的话,请避免使用那个大坐标。
否则,如果您确实必须使用解决方法,您可以强制画布使用软件渲染。但这会完全减慢画布的速度,应尽可能避免。
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d', {
willReadFrequently: true // force software rendering (in 95+?)
});
ctx.setTransform(2, 0, 0, 2, 0, 0);
ctx.beginPath();
const arr = [
["moveTo",7,209],
["lineTo",6318,403],
["lineTo",15786,453],
["lineTo",18942,451],
["lineTo",22098,28]
];
ctx.beginPath();
arr.forEach(item => {
if (item[0] === 'lineTo') {
ctx.lineTo(item[1], item[2]);
} else if (item[0] === 'moveTo') {
ctx.moveTo(item[1], item[2]);
}
})
ctx.strokeStyle = 'red';
// in case willReadFrequently didn't make it
if (ctx.getContextAttributes && !ctx.getContextAttributes().willReadFrequently) {
ctx.getImageData(0, 0, 1, 1);
}
ctx.stroke();
<canvas
id="canvas"
width=800
height=800
style="width: 400px; height: 400px"
>
</canvas>
因此,最好的办法是尝试重现错误并事先检查您是否使用有错误的浏览器:
const isBuggyBrowser = (() => {
const ctx = document.createElement("canvas").getContext('2d');
// move the bug toward the top left corner
ctx.setTransform(2, 0, 0, 2, -900, -900);
// removed some fluff
const arr = [
[7,209],
[6318,403],
[15786,453],
[18942,451],
[22098,28]
];
// lineTo from an empty subpath is auto-converted to moveTo
arr.forEach(([x,y]) => ctx.lineTo(x, y));
ctx.stroke();
// not transparent
return !!ctx.getImageData(0, 1, 1, 1).data[3]
})();
console.log( "is your browser buggy?", isBuggyBrowser );
现在您可以有条件地应用解决方法:
const isBuggyBrowser = (() => {
const ctx = document.createElement("canvas").getContext('2d');
// move the bug toward the top left corner
ctx.setTransform(2, 0, 0, 2, -900, -900);
// removed some fluff
const arr = [
[7,209],
[6318,403],
[15786,453],
[18942,451],
[22098,28]
];
// lineTo from an empty subpath is auto-converted to moveTo
arr.forEach(([x,y]) => ctx.lineTo(x, y));
ctx.stroke();
// not transparent
return !!ctx.getImageData(0, 1, 1, 1).data[3]
})();
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d', {
willReadFrequently: isBuggyBrowser
});
ctx.setTransform(2, 0, 0, 2, 0, 0);
ctx.beginPath();
const arr = [
["moveTo",7,209],
["lineTo",6318,403],
["lineTo",15786,453],
["lineTo",18942,451],
["lineTo",22098,28]
];
ctx.beginPath();
arr.forEach(item => {
if (item[0] === 'lineTo') {
ctx.lineTo(item[1], item[2]);
} else if (item[0] === 'moveTo') {
ctx.moveTo(item[1], item[2]);
}
})
ctx.strokeStyle = 'red';
// in case willReadFrequently didn't make it
if (isBuggyBrowser && ctx.getContextAttributes &&
!ctx.getContextAttributes().willReadFrequently) {
ctx.getImageData(0, 0, 1, 1);
}
ctx.stroke();
<canvas
id="canvas"
width=800
height=800
style="width: 400px; height: 400px"
>
</canvas>
推荐阅读
- c# - 我想在数据表中添加新行而不对现有数据产生任何影响
- string - 如果列表中包含特定单词,如何从列表中删除字符串
- c++11 - 用于 constexpr 深度和 IEEE 754 指数计算的 NVIDIA nvcc 编译标志
- c# - 无法创建 X 类型的常量值
- visual-studio-code - 如何测试我为 vscode 创建的 webview 扩展?
- javascript - JQuery'OR'运算符组合两个变量
- matlab - (Matlab)奇怪的精度损失,同时将复数矩阵分配给局部变量
- django - 在 django 中同时使用浏览量计数器和缓存的问题
- node.js - istanbul-middleware 显示“未收集到覆盖信息”
- vba - 删除行+根据列中的部分文本匹配上移