javascript - 如何在 Canvas 上绘制平滑的线条而不清除它?

标签 javascript canvas

我有一个 Canvas ,在加载时动态添加到页面。 我想在 Canvas 上绘制用户的鼠标路径,但我发现如果我在绘制之前清除 Canvas ,它将绘制平滑的线条,否则,它将绘制丑陋的线条,如下图所示! enter image description here

要测试该问题,请取消代码中 draw_on_canvas 函数第一行的注释以查看差异。

$(document).ready(function() {
  //Create DRAWING environment
  var canvasWidth = 400;
  var canvasHeight = 200;
  var drawn_shape_list = [];
  var current_shape_info = {};
  var is_painting = false;

  function add_path_to_drawn_shape_list() {
    if (current_shape_info.path && current_shape_info.path.length > 0) {
      drawn_shape_list.push(current_shape_info);
    }

    current_shape_info = {};
  }

  function add_path(x, y) {
    current_shape_info.color = "#000000";
    current_shape_info.size = 2;

    if (!current_shape_info.path) {
      current_shape_info.path = [];
    }

    current_shape_info.path.push({
      "x": x,
      "y": y
    });
  }

  function draw_on_canvas() {
    //Uncomment following line to have smooth drawing!
    //context.clearRect(0, 0, context.canvas.width, context.canvas.height); //clear canvas
    context.strokeStyle = current_shape_info.color;
    context.lineWidth = current_shape_info.size;

    context.beginPath();
    context.moveTo(current_shape_info.path[0].x, current_shape_info.path[0].y);

    for (var i = 1; i < current_shape_info.path.length; i++) {
      context.lineTo(current_shape_info.path[i].x, current_shape_info.path[i].y);
    }
    context.stroke();
  }

  //Create canvas node
  var canvas_holder = document.getElementById('canvas_holder');
  canvas = document.createElement('canvas');
  canvas.setAttribute('width', canvasWidth);
  canvas.setAttribute('height', canvasHeight);
  canvas.setAttribute('id', 'whitboard_canvas');
  canvas_holder.appendChild(canvas);
  if (typeof G_vmlCanvasManager != 'undefined') {
    canvas = G_vmlCanvasManager.initElement(canvas);
  }
  context = canvas.getContext("2d");

  $('#canvas_holder').mousedown(function(e) {
    var mouseX = e.pageX - this.offsetLeft;
    var mouseY = e.pageY - this.offsetTop;

    is_painting = true;
    add_path(mouseX, mouseY, false);
    draw_on_canvas();
  });

  $('#canvas_holder').mousemove(function(e) {
    if (is_painting) {
      var mouseX = e.pageX - this.offsetLeft;
      var mouseY = e.pageY - this.offsetTop;

      var can = $('#whitboard_canvas');
      add_path(mouseX, mouseY, true);
      draw_on_canvas();
    }
  });

  $('#canvas_holder').mouseup(function(e) {
    is_painting = false;
    add_path_to_drawn_shape_list();
  });

  $('#canvas_holder').mouseleave(function(e) {
    is_painting = false;
    add_path_to_drawn_shape_list();
  });
});
#canvas_holder {
  border: solid 1px #eee;
}

canvas {
  border: solid 1px #ccc;
}
<HTML>

<body>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  <div id="canvas_holder"></div>
</body>

</HTML>

您可以查看我的代码示例 here有两个 Canvas 。

我尝试过 context.lineJoin = "round";context.lineCap = 'round';,但结果没有改变。

这是正常的 Canvas 行为还是我应该设置一些东西?

最佳答案

how to draw smooth lines on canvas without clearing it?

你不知道。清除和重新绘制是要走的路。

Is it normal canvas behavior

是的,完全可以。除非您执行一些应该清除 Canvas 的操作,否则它不会被清除。因此,当您使用半透明颜色在同一区域多次绘制时,像素会变得越来越暗。

不要害怕性能,必须处理以前绘图的合成甚至可能比绘制单个更复杂的路径更慢。

为了提高性能,您可以做的一件事是使用单个路径,以便在每一帧仅发生一次绘制操作:

const canvas = document.getElementById( 'canvas' );
const ctx = canvas.getContext( '2d' );
const path = new Path2D();
const mouse = {};

function draw() {
  // clear all
  ctx.clearRect( 0, 0, canvas.width, canvas.height );
  // draw the single path
  ctx.stroke( path );
  // tell we need to redraw next frame
  mouse.dirty = false;
}

canvas.onmousedown = (evt) => {
  mouse.down = true;
  // always use the same path
  path.moveTo( evt.offsetX, evt.offsetY );
};
document.onmouseup = (evt) => {
  mouse.down = false;
};
document.onmousemove = (evt) => {
  if( mouse.down ) {
    const rect = canvas.getBoundingClientRect();
    path.lineTo( evt.clientX - rect.left, evt.clientY - rect.top );
  }
  if( !mouse.dirty ) {
    mouse.dirty = true;
    requestAnimationFrame(draw);
  }
};
canvas { border: 1px solid }
<canvas id="canvas" width="500" height="500"></canvas>

如果您需要不同的路径样式,则可以为每种样式创建一个路径。

const canvas = document.getElementById( 'canvas' );
const ctx = canvas.getContext( '2d' );
const makePath = (color) => ({
  color,
  path2d: new Path2D()
});
const pathes = [makePath('black')];

const mouse = {};

function draw() {
  // clear all
  ctx.clearRect( 0, 0, canvas.width, canvas.height );
  pathes.forEach( (path) => {
    // draw the single path
    ctx.strokeStyle = path.color;
    ctx.stroke( path.path2d );
  } );
  // tell we need to redraw next frame
  mouse.dirty = false;
}

document.getElementById('inp').onchange = (evt) =>
  pathes.push( makePath( evt.target.value ) );

canvas.onmousedown = (evt) => {
  mouse.down = true;
  const path = pathes[ pathes.length - 1 ].path2d;
  // always use the same path
  path.moveTo( evt.offsetX, evt.offsetY );
};
document.onmouseup = (evt) => {
  mouse.down = false;
};
document.onmousemove = (evt) => {
  if( mouse.down ) {
    const rect = canvas.getBoundingClientRect();
    const path = pathes[ pathes.length - 1 ].path2d;
    path.lineTo( evt.clientX - rect.left, evt.clientY - rect.top );
  }
  if( !mouse.dirty ) {
    mouse.dirty = true;
    requestAnimationFrame(draw);
  }
};
canvas { border: 1px solid }
<input type="color" id="inp"><br>
<canvas id="canvas" width="500" height="500"></canvas>

关于javascript - 如何在 Canvas 上绘制平滑的线条而不清除它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57956116/

相关文章:

c# - 将带有 alpha channel 的图像复制到带有自定义背景颜色的剪贴板?

javascript - 如何在给定用户输入 X、Y 点的情况下绘制 HTML5 Canvas 线?

JavaScript Canvas——是否可以依赖Math.random进行绘制?

javascript - 我应该使用 JSON 还是 AJAX 作为响应数据?

javascript - 在该对象的函数中迭代该对象的所有成员

javascript - 用 div 包装链接组? (PHP 是一种选择)

javascript - Richeditor Onlyoffice 编辑和保存文档

javascript - Node.js - Socket.IO 1.0 - 超时事件

javascript - 如何在canvas(javascript)中获得随机1或-1?

javascript - 第一次加载页面时图像未显示在 Canvas 上