使用转换时,在HTML5画布上绘制清晰的1px行


=_=
2025-03-17 02:44:18 (1小时前)
  1. 只需要将坐标舍入到最近的像素并添加0.5即可



</跨度>
线。但是当我的整个画布被转换时,我不确定如何实现这一点,而且我没有进入 最终坐标系。到目前为止,我试图纠正这个问题已经失败了,看起来我在这里遗漏了一些东西,或者在路上犯了一些其他的错误。

我该怎么画


</跨度>
1中1px行

2 条回复
  1. 0# 纾潆锦袖迷子 | 2019-08-31 10-32



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



    目前,你将lineWidth设置为1 / zoom,考虑到编码器对数学精度的好处,你将很难用最终画出一个完美的1px笔画,只有几个缩放值,如果你想限制你的缩放到这些值,你会得到不稳定的变焦。



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




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

    2. 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);

    3. // lineTo…
      }

    4. </code>







    1. 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() {

    2. context.setTransform(1,0,0,1,0,0);
    3. context.clearRect(0,0,canvas.width, canvas.height);
    4. context.lineWidth = 1;
    5. context.beginPath();
    6. for (let i = 0; i < pts.length; i+=2) {
    7.   let v1 = pts[i];
    8.   let v2 = pts[i + 1];
    9.   // scale and translate
    10.   v1 = (v1 + transform.x) * transform.k;
    11.   v2 = (v2 + transform.y) * transform.k;
    12.   // round
    13.   const r1 = Math.round(v1);
    14.   const r2 = Math.round(v2);
    15.   // to nearest px boundary
    16.   v1 = r1 + (0.5 * Math.sign(r1 - v1) || 0.5);
    17.   v2 = r2 + (0.5 * Math.sign(r2 - v2) || 0.5);
    18.   context.lineTo(v1, v2);
    19. }
    20. context.stroke();
    21. }
      function zoomed() {
      const evt = d3.event;
      transform.k = evt.scale;
      transform.x = evt.translate[0];
      transform.y = evt.translate[1];
      draw();
      }




    1. canvas {border: 1px solid}




    1. zoom with mousewheel and pan by dragging









    但是你可能更喜欢不那么精确但也不那么锯齿和更简单的地板:




    1. 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;

    2. // lineTo

    3. </code>







    1. 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() {

    2. context.setTransform(1,0,0,1,0,0);
    3. context.clearRect(0,0,canvas.width, canvas.height);
    4. context.lineWidth = 1;
    5. context.beginPath();
    6. for (let i = 0; i < pts.length; i+=2) {
    7.   let v1 = pts[i];
    8.   let v2 = pts[i + 1];
    9.   // scale and translate
    10.   v1 = (v1 + transform.x) * transform.k;
    11.   v2 = (v2 + transform.y) * transform.k;
    12.   // floor
    13.   v1 = Math.floor(v1) + 0.5;
    14.   v2 = Math.floor(v2) + 0.5;
    15.   context.lineTo(v1, v2);
    16. }
    17. context.stroke();
    18. }
      function zoomed() {
      const evt = d3.event;
      transform.k = evt.scale;
      transform.x = evt.translate[0];
      transform.y = evt.translate[1];
      draw();
      }




    1. canvas {border: 1px solid}




    1. zoom with mousewheel and pan by dragging








登录 后才能参与评论