事件处理程序的某些部分如何不起作用?

How does certain part of an event handler not work?

我正在使用状态设计模式制作一个简单的绘画应用程序作为家庭作业。 我从 website 中获取了一个代码示例,它解释了如何通过不同的工具在 canvas 上自由绘图。

点画部分说明如下:

var el = document.getElementById('c');
var ctx = el.getContext('2d');

ctx.lineWidth = 10;
ctx.lineJoin = ctx.lineCap = 'round';

var isDrawing, points = [ ];

el.onmousedown = function(e) {
  isDrawing = true;
  points.push({ x: e.clientX, y: e.clientY });
};

el.onmousemove = function(e) {
  if (!isDrawing) return;

  ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  points.push({ x: e.clientX, y: e.clientY });

  ctx.beginPath();
  ctx.moveTo(points[0].x, points[0].y);
  for (var i = 1; i < points.length; i++) {
    ctx.lineTo(points[i].x, points[i].y);
  }
  ctx.stroke();
};

el.onmouseup = function() {
  isDrawing = false;
  points.length = 0;
};

我无法理解的部分是事件处理程序设置为 el.onmousemove

Afaic,事件处理程序在我们的手处于鼠标按下状态时继续运行。那么如何在不通过以下行清除 canvas 的情况下绘制一条跟随光标的线:

ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);

更进一步,函数本身对我来说没有意义。因为它应该工作因此不停地刷新状态。所以它没有时间通过​​以下行累积要绘制的点:

ctx.stroke();

我不确定我是否可以清楚地说明这一点让你理解。

是的,

ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);

在每次鼠标移动时发生,清除当前 canvas。

这里发生的是,每次鼠标移动时:

  • canvas已清除
  • 一个新的坐标对象被推送到 points(这个 points 数组是 persistent - 它跟踪所有访问过的点,从用户的第一次鼠标点击)
  • 2d 上下文在所有已访问的点上创建路径 - 这就是 beginPathmoveTolineTo 方法所做的
  • 构建好的路径然后用ctx.stroke渲染,将路径变成用户可以看到的可见线

So there is no time for it to accumulate the points to be drawn for later via the following line:

每次鼠标移动时,都会将一个新对象推送到 points 数组。一旦数组中有几个对象(或更多),

  ctx.moveTo(points[0].x, points[0].y);
  for (var i = 1; i < points.length; i++) {
    ctx.lineTo(points[i].x, points[i].y);
  }
  ctx.stroke();

然后将在所有这些点之间画一条线。

唯一一次什么都不可见是在初始点击时,当时 points 数组只有一个对象(并且没有任何其他点可以画线)。