【问题标题】:Javascript Canvas draw rectangles or circlesJavascript Canvas 绘制矩形或圆形
【发布时间】:2017-07-14 20:29:26
【问题描述】:

我正在寻找一种在画布上“实时”绘制矩形或圆形的方法。

我用fillRect() 找到了各种方法来绘制矩形,但不是实时的。我的意思是,能够在一个点上mouseDown() 并将其移动到画布中的另一个点,这定义了画布的大小,就像在 Microsoft Paint、OneNote 等中一样。

任何人都可以帮助我并就如何开始给我一些建议吗?我可能正在考虑如何做到这一点,而不会看到矩形(或圆形)大小发生变化,例如:

 $("canvas").mousedown(function(event){
     var ctx = this.getContext("2d");
     ctx.clearRect(0,0,$(this).width(),$(this).height());
     var initialX = event.clientX - this.getBoundingClientRect().left;
     var initialY = event.clientY - this.getBoundingClientRect().top;

     $(this).mousemove(function(evt) {
         ctx.strokeRect(initialX, initialY, evt.clientX - event.clientX, evt.clientY - event.clientY);
     });
 });

但我想实时看到它,所以当用户移动鼠标时矩形大小如何变化。

【问题讨论】:

  • 使用window.requestAnimationFrame()经常刷新画布
  • @randnum-1 和?您的意思是在setInterval() 中每 50 毫秒或类似的时间重绘一次画布,直到mouseUp
  • 我假设你想要这样的东西 jsfiddle.net/jk607fqn/3 点击画布绘制红色方块
  • 补充一点,如果你想要更复杂的东西,最好按照 randnum-1 的建议做,并收集帧之间的事件数据,然后有一个间隔调用的“渲染”例程.另一方面,如果你想要的只是一个一次性的页面效果,你可以不使用事件。我现在更新了上面的内容来处理一些基本的点击和拖动:jsfiddle.net/b8rq8u4f/1

标签: javascript html canvas rectangles


【解决方案1】:

https://jsfiddle.net/zb66mxra/2/

要做到这一点,您需要保持 Canvas 的恒定图像。这很容易实现,方法是保留一组对象,让您的 JavaScript 一遍又一遍地绘制。

let drawArr = [];

示例对象包含开始绘制的 x 和 y 坐标、宽度和高度:

 { x: 100,
  y: 100,
  w: 10,
  h: 10  }

当您的鼠标在画布上移动时,您只希望它在鼠标按下时更改数组。这意味着您需要设置一个标志来查看这种情况是真还是假:

  let mousedown = false;
  canvas.addEventListener('mousedown', function(e) {
    mousedown = true;
  ...
  });
  canvas.addEventListener('mouseup', function(e) {
    mousedown = false;
  });

当您的鼠标按下时,您想添加一个项目以绘制到数组中:

  canvas.addEventListener('mousedown', function(e) {
  mousedown = true;
  drawArr.push({
    x: e.pageX,
    y: e.pageY,
    w: 0,
    h: 0
  });
});

高度和宽度最初设置为 0。如果您可以想象,我们现在要做的是在我们将鼠标拖到画布上并且鼠标向下时创建矩形的高度和宽度。我们想动态调整它,以便在重新渲染屏幕时可以看到它正在绘制。

操作高度和宽度很容易,因为只要您一次只能绘制一个,它就始终是添加到绘图数组中的最新对象。

  canvas.addEventListener('mousemove', function(e) {
  if (mousedown) {
    let i = drawArr.length -1;

    let {
      x,
      y
    } = drawArr[i];
    drawArr[i].w = e.pageX - x;
    drawArr[i].h = e.pageY - y;
  }
});

最后,我们使用 requestAnimationFrame 不断地在绘图数组中绘制任何对象。我们通过在页面加载时调用它来做到这一点:

requestAnimationFrame(draw);

然后在draw函数内递归:

function draw() {
...
requestAnimationFrame(draw);
}

然后我们只需要清除之前的屏幕渲染并迭代绘制数组并再次将所有内容绘制到屏幕上。

  function draw() {
    ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
    for (let obj of drawArr) {
    let {
      x,
      y,
      w,
      h
     } = obj;
      ctx.strokeRect(x, y, w, h);
    }
    requestAnimationFrame(draw);
  }

瞧。

【讨论】:

  • 感谢回答,看起来不错,正是我想要的,我会尽快尝试的,一个问题:用这样的代码画一个圆圈很难吗?那么会不会有很大的改变呢?同样的原理,只是一个圆圈
  • @nameless 会非常相似。您需要使用 arc 上下文方法,然后使用 stroke() 而不是 strokeRect。您还需要在您的绘图对象中存储一个半径,并在拖到画布上时调整它。
  • medium.com/wdstack/quick-blurb-2d-canvas-app-setup-5e6f13e12884 前阵子写的这篇文章,可以帮助你更好的理解2d canvas的基本方法和架构。此外,如果这是您要查找的内容,请单击旁边的绿色复选框接受此答案。
  • 现在只是尝试集成它,但对我来说似乎并不那么容易......就像在我的画布中一样,您已经可以正常绘制(就像只是移动鼠标来绘制一样)并且只有在单击按钮时,您应该能够绘制矩形,然后移回正常线条,有什么建议可以做到这一点吗?
  • @nameless 好吧,如果您没有将绘图信息存储在对象数组中,那么您应该这样做。我建议为每个对象添加一个附加键,以允许程序解释它应该如何在画布上绘制对象。比如type:circle,会使用arc方法,type:square,fillRect,type:line,moveTo/lineTo方法等