在画布中平滑用户绘制的线条

15

我正在使用<canvas>来捕获用户签名输入,并试图找出如何平滑鼠标的输入。

我认为我需要逐个处理用户的鼠标移动,并对每个部分进行平滑处理,我不是要超级平滑,但任何有改进的地方都是好的。

谢谢, 马克


1
你需要一份在法律上有效的签名,比如说,用于合同目的吗?如果需要,那么由此生成的签名是否足够? - user287466
6个回答

20
你需要的是:
ctx.lineCap = 'round';

这是一个如何使用的示例:
试一试 http://jsbin.com/ateho3 标记:
<canvas id="canvas"></canvas> 

JavaScript

window.onload = function() {
    var canvas = document.getElementById('canvas');
    var ctx = canvas.getContext('2d');
    var width  = window.innerWidth;
    var height = window.innerHeight;
    canvas.height = height;
    canvas.width = width;
    canvas.addEventListener('mousedown', function(e) {
      this.down = true;  
      this.X = e.pageX ;
      this.Y = e.pageY ;
      this.color = rgb();
    }, 0);
    canvas.addEventListener('mouseup', function() {
      this.down = false;      
    }, 0);
    canvas.addEventListener('mousemove', function(e) {
      this.style.cursor = 'pointer';
      if(this.down) {
          ctx.beginPath();
          ctx.moveTo(this.X, this.Y);
          ctx.lineCap = 'round';
           ctx.lineWidth = 3;
          ctx.lineTo(e.pageX , e.pageY );
          ctx.strokeStyle = this.color;
          ctx.stroke();

         this.X = e.pageX ;
         this.Y = e.pageY ;
      }
    }, 0);

    function rgb() {
      color = 'rgb(';
      for(var i = 0; i< 3; i++) {
        color += Math.floor(Math.random() * 255)+',';
      }
      return color.replace(/\,$/,')');
    }    
  };

3
这与曲线拟合/平滑无关 - 它只是绘制连接线段的直线。 - nicholaswmin
这可以通过多项式曲线拟合来改进。 - Steven Varga

9

我知道这是一个10年前的问题,但我认为答案并不完整。为了获得平滑线条效果,您需要在画布上下文中设置两个属性:

context.lineCap = 'round'
context.lineJoin = 'round'

第一个是用于路径的极端点,第二个是用于路径的拐角。
一些关于lineJoin的文档
一些关于lineCap的文档

这非常有用!除了进行复杂的数学运算之外,这对我们非常有帮助! - Mikhail
1
最好的评论在这里! 解决了我的问题,因为我没有使用lineJoin。 非常感谢! - Blackfaded

5
我不得不为移动Web应用程序制作平滑的画布绘图,并学到了一些东西。 Avinash的答案很好,但如果增加线宽,当你绘制时会看到断裂的线条。这是因为默认情况下线帽是矩形的。
为了使线条更平滑,你需要微调一些东西。
ctx.lineCap = 'round';
这个小调整将给你一个超级平滑的线条。
要了解更多信息,请尝试以下链接。

https://developer.mozilla.org/samples/canvas-tutorial/4_6_canvas_linecap.html


3

1
我修改了Avinash的例子,使用bezierCurveTo替代了lineTo。如果您每隔一个点进行采样,则平滑效果会更明显。即使没有平滑,我的签名也不会特别“锯齿状”。签名最不准确的部分是大体变化,这些变化并不能通过平滑得到真正的改善。 - user287466
3
嗨@unclebrad,你把修改后的例子发到哪里了吗?我们遇到了同样的问题。谢谢! - Crashalot

1

我没有进行过任何测试,但你可以尝试使用径向渐变填充绘制小圆圈。


0
考虑自动地使用线连接点,甚至可以使用quadraticCurveTo,但你必须自己计算中间点。

抽样几个像素,然后画一条线?而不是绘制记录的每个点? - dakine
我尝试使用quadraticCurveTo,必须说它比人们想象的要复杂一些。如果仅在每个下一个线段上使用控制点(计算为前一个线段的一半),则可能会导致呈弧形的演示。为了真正做出平滑曲线,每个新线段都需要从头到尾重新计算整个路径(或至少在每个新线段添加时影响前一个线段)-供您参考。 - GullerYA

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接