为什么以下代码会将行的宽度更改为2像素而不是最终为1?
var canvas = document.getElementById('c');
var context = canvas.getContext('2d');
function clear() {
context.clearRect(0, 0, canvas.width, canvas.height);
}
function draw() {
context.save();
context.beginPath();
context.scale(zoom, zoom);
context.moveTo(100, 50);
context.lineTo(100, 100);
context.restore();
context.stroke();
}
var zoom = 1.0;
$('#c').mousewheel(function(e) {
if (e.originalEvent.deltaY < 0) {
zoom *= 1.1;
} else {
zoom /= 1.1;
}
clear();
draw();
});
draw();
你可以在这里试试 - https://jsfiddle.net/818j0646/。
只是尝试放大/缩小,你会注意到我在说什么:
我该如何避免这种行为?我需要我的线总是保持1个宽度,没有这样的&#34;抗锯齿&#34;效果。
答案 0 :(得分:2)
您可以添加相对于缩放的行宽支持(只需确保在笔划后应用 >或在绘制任何内容之前返回所有设置):
restore()
<强> Modified fiddle 强>
如果你想保留大约1个像素而不管比例,你可以反转线宽公式:
var lineWidth = 1; // line width
function draw() {
context.save();
context.beginPath();
context.scale(zoom, zoom);
context.lineWidth = zoom * lineWidth; // line-width * zoom
context.moveTo(100, 50);
context.lineTo(100, 100);
context.stroke();
context.restore(); // restore last
}
<强> Result 强>
但是,在某些尺度上会出现影响抗锯齿处理的小舍入误差。
避免此问题的唯一真正方法是手动将矩阵应用于表示线的点,使值成为整数,然后使用Bresenham或IMO将这些值的结果呈现为一行,更好更快{{ 3}}算法和via context.lineWidth = 1 / (zoom * lineWidth);
,逐像素,最后将其推送到位图。当然,您可以将所有这些包装成单个函数。
这也意味着您需要跟踪矩阵。在较新的浏览器中,您可以使用ImageData
并尽快使用currentTransform
来获取当前转换,或者您可以使用自定义矩阵解决方案来实现跨浏览器和向后兼容性(这里有很多,这里是{{3 }})。
目前无法为光栅化到画布的矢量关闭消除锯齿功能。
我没有在这个快速演示中实现边界检查,但这也是你需要实现的,所以线条不会缠绕(即只有当x> = 0&amp; &amp; x&lt; width etc. ..每像素。)
getTransform()
&#13;
window.onload = function() {
var canvas = document.getElementById('c');
var context = canvas.getContext('2d');
var matrix = new Matrix();
var zoom = 1.0;
function clear() {
context.clearRect(0, 0, canvas.width, canvas.height);
}
function draw() {
matrix.reset(); // replaces save/restore
matrix.scale(zoom, zoom);
// manually draw line via matrix and EFLA
line(context, 100, 50, 100, 100);
}
// custom line function
function line(context, x1, y1, x2, y2) {
// instead of transforming context, apply matrix to points:
var p1 = matrix.applyToPoint(x1, y1);
var p2 = matrix.applyToPoint(x2, y2);
// create a bitmap (for demo), or obtain an existing one (getImageData)
var idata = context.createImageData(canvas.width, canvas.height);
var data32 = new Uint32Array(idata.data.buffer);
_line(data32, p1.x|0, p1.y|0, p2.x|0, p2.y|0, canvas.width);
context.putImageData(idata, 0, 0);
}
// EFLA line algorithm
function _line(data, x1, y1, x2, y2, w) {
var dlt, mul,
sl = y2 - y1,
ll = x2 - x1,
yl = false,
lls = ll >> 31,
sls = sl >> 31,
i;
if ((sl ^ sls) - sls > (ll ^ lls) - lls) {
sl ^= ll;
ll ^= sl;
sl ^= ll;
yl = true
}
dlt = ll < 0 ? -1 : 1;
mul = (ll === 0) ? sl : sl / ll;
if (yl) {
x1 += 0.5;
for (i = 0; i !== ll; i += dlt)
setPixel(data, (x1 + i * mul)|0, y1 + i, w)
}
else {
y1 += 0.5;
for (i = 0; i !== ll; i += dlt)
setPixel(data, x1 + i, (y1 + i * mul)|0, w)
}
}
// Set a pixel (black for demo)
function setPixel(data, x, y, w) {data[y * w + x] = 0xff000000}
$('#c').mousewheel(function(e) {
e.preventDefault();
if (e.originalEvent.deltaY < 0) {
zoom *= 1.1;
} else {
zoom /= 1.1;
}
clear();
draw();
});
draw();
};
&#13;
body {overflow:hidden}
&#13;
<强> EFLA 强>