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

问题描述

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

解释基于点的绘图的部分如下所示:

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,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,当我们的手放在鼠标上时,事件处理程序会继续进行。那么它是如何通过以下行在不清除画布的情况下绘制一条跟随我们光标的线的:

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

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

ctx.stroke();

我不确定我是否能把这一点解释得足够让你理解。

解决方法

是的

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

每次鼠标移动时都会发生,清除当前画布。

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

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

因此它没有时间通过​​以下行累积要绘制的点数:

每次鼠标移动时,都会将一个新对象推送到 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 数组只有一个对象(并且没有任何其他可以画线的点)时。