gpt4 book ai didi

javascript - 使用转换时在 HTML5 Canvas 上绘制清晰的 1px 线条

转载 作者:行者123 更新时间:2023-12-01 01:30:51 27 4
gpt4 key购买 nike

我在代码中的 HTML5 Canvas 元素上绘制了许多 1px 线。绘图代码大致如下所示,本例中的 transform 变量使用 d3-zoom 设置。 instructions.f32 是一个 Float32Array,其中包含我用于绘制线条的坐标。

 context.setTransform(
transform.k,
0,
0,
transform.k,
transform.x,
transform.y
);
context.lineWidth = 1 / transform.k;
context.beginPath();
for (let i = from; i < to; ++i) {

let v1 = instructions.f32[i * 4 + 1];
let v2 = instructions.f32[i * 4 + 2];

// execute some moveTo/lineTo commands using v1 and v2 as coordinates
}
context.stroke();

此代码的一个问题是 1px 线模糊,因为我正在跨越像素边界进行绘制。我尝试调整代码以将线条捕捉到最近的像素,如下所示:

let v1 = (Math.round(instructions.f32[i * 4 + 1] * transform.k) + 0.5) / transform.k;
let v2 = (Math.round(instructions.f32[i * 4 + 2] * transform.k) + 0.5) / transform.k;

但这仍然会导致线条模糊,如下图所示(放大图像的屏幕截图):

enter image description here

如果我没有任何变换集,据我所知,我只需将坐标舍入到最近的像素并添加 0.5 即可获得清晰的线条。但我不确定当我的整个 Canvas 被变换时如何实现这一点,并且我没有绘制到最终的坐标系中。由于到目前为止我尝试纠正此问题的尝试都失败了,所以看起来我在这里遗漏了一些东西,或者在途中犯了一些其他错误。

使用 setTransform 转换整个 Canvas 时,如何在 Canvas 中绘制清晰的 1px 线条?我到底该如何舍入坐标才能将结果线捕捉到像素?

最佳答案

由于您的变换似乎没有倾斜或旋转属性,因此最简单的方法可能是不变换您的上下文,而是缩放和平移所有坐标。

目前,您将 lineWidth 设置为 1/缩放,考虑到编译器在数学精度方面的表现如何,您将很难用它来绘制完美的 1px 笔画,只有几个缩放值可以,如果您愿意的话要将缩放限制在这些值,您会得到不稳定的缩放。

相反,始终将线宽保持在 1 像素,缩放并平移所有坐标,然后将它们四舍五入到最近的像素边界。

context.setTransform(1,0,0,1,0,0);
context.lineWidth = 1;
context.beginPath();
for (let i = from; i < to; ++i) {

let v1 = instructions.f32[i * 4 + 1];
let v2 = instructions.f32[i * 4 + 2];
// scale and translate
v1 = (v1 + transform.x) * transform.k;
v2 = (v2 + transform.y) * transfrom.k;
// round
const r1 = Math.round(v1);
const r2 = Math.round(v2);
// to nearest px boundary
v1 = r1 + (0.5 * Math.sign(r1 - v1) || 0.5);
v2 = r2 + (0.5 * Math.sign(r2 - v2) || 0.5);

// lineTo...
}

const pts = [60, 60, 60, 110, 100,110, 100, 90, 220, 90];
const zoom = d3.behavior.zoom()
.scaleExtent([1, 10])
.on("zoom", zoomed);
const transform = {k: 1, x: 0, y: 0};
const context = canvas.getContext('2d');
d3.select('canvas')
.call(zoom);
draw();
function draw() {

context.setTransform(1,0,0,1,0,0);
context.clearRect(0,0,canvas.width, canvas.height);
context.lineWidth = 1;
context.beginPath();
for (let i = 0; i < pts.length; i+=2) {

let v1 = pts[i];
let v2 = pts[i + 1];
// scale and translate
v1 = (v1 + transform.x) * transform.k;
v2 = (v2 + transform.y) * transform.k;
// round
const r1 = Math.round(v1);
const r2 = Math.round(v2);
// to nearest px boundary
v1 = r1 + (0.5 * Math.sign(r1 - v1) || 0.5);
v2 = r2 + (0.5 * Math.sign(r2 - v2) || 0.5);

context.lineTo(v1, v2);
}
context.stroke();
}
function zoomed() {
const evt = d3.event;
transform.k = evt.scale;
transform.x = evt.translate[0];
transform.y = evt.translate[1];
draw();
}
canvas {border: 1px solid}
zoom with mousewheel and pan by dragging<br>
<canvas id="canvas"></canvas>
<script src="//d3js.org/d3.v3.min.js"></script>

但您可能更喜欢不太精确但锯齿较少且更简单的地板:

  v1 = (v1 + transform.x) * transform.k;
v2 = (v2 + transform.y) * transform.k;
// floor
v1 = Math.floor(v1) + 0.5;
v2 = Math.floor(v2) + 0.5;

// lineTo

const pts = [60, 60, 60, 110, 100,110, 100, 90, 220, 90];
const zoom = d3.behavior.zoom()
.scaleExtent([1, 10])
.on("zoom", zoomed);
const transform = {k: 1, x: 0, y: 0};
const context = canvas.getContext('2d');
d3.select('canvas')
.call(zoom);
draw();
function draw() {

context.setTransform(1,0,0,1,0,0);
context.clearRect(0,0,canvas.width, canvas.height);
context.lineWidth = 1;
context.beginPath();
for (let i = 0; i < pts.length; i+=2) {

let v1 = pts[i];
let v2 = pts[i + 1];
// scale and translate
v1 = (v1 + transform.x) * transform.k;
v2 = (v2 + transform.y) * transform.k;
// floor
v1 = Math.floor(v1) + 0.5;
v2 = Math.floor(v2) + 0.5;
context.lineTo(v1, v2);
}
context.stroke();
}
function zoomed() {
const evt = d3.event;
transform.k = evt.scale;
transform.x = evt.translate[0];
transform.y = evt.translate[1];
draw();
}
canvas {border: 1px solid}
zoom with mousewheel and pan by dragging<br>
<canvas id="canvas"></canvas>
<script src="//d3js.org/d3.v3.min.js"></script>

关于javascript - 使用转换时在 HTML5 Canvas 上绘制清晰的 1px 线条,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53288682/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com