How to create multiple shapes on canvas on mouse drag and make them overlap?

huangapple go评论60阅读模式
英文:

How to create multiple shapes on canvas on mouse drag and make them overlap?

问题

在一个canvas元素内,我想要能够在鼠标拖动时绘制多个矩形(包括左键和右键)。到目前为止,我有以下代码:

class Waveform {
  constructor(container_selector) {
    this.render(container_selector);
  }

  render(container_selector) {
    this.canvas = document.querySelector(container_selector);
    this.canvas.width = 800;
    this.canvas.height = 150;
    this.canvas.style.border = '1px solid black';
    this.ctx = this.canvas.getContext('2d');
    this.ctx.fillStyle = 'rgba(200, 0, 0, 0.7)';

    this.canvas.addEventListener('mousedown', this.mouseDown);
    this.canvas.addEventListener('mousemove', this.mouseMove);
    this.canvas.addEventListener('mouseup', this.mouseUp);
  }

  mouseDown = e => {
    this.drag = true;
    this.rect = {};
    this.rect.x = e.clientX - this.canvas.offsetLeft;
    this.rect.y = 0;
    this.rect.w = 1;
    this.rect.h = this.canvas.height;
    this.ctx.fillRect(
      this.rect.x,
      this.rect.y,
      this.rect.w,
      this.rect.h
    );
  }

  mouseMove = e => {
    if (this.drag) {
      this.ctx.clearRect(this.rect.x, this.rect.y, this.rect.w, this.rect.h);
      this.rect.w = (e.clientX - this.canvas.offsetLeft) - this.rect.x;
      this.ctx.fillRect(
        this.rect.x,
        this.rect.y,
        this.rect.w,
        this.rect.h
      );
    }
  }

  mouseUp = e => {
    this.drag = false;
  }
}

let waveform = new Waveform('#waveform');

这段代码的问题在于,当我拖动一个矩形覆盖到已经存在的矩形上时,已经存在的部分会被擦除。我理解为什么会这样,但我希望矩形可以重叠,以便可以同时存在两个(或更多)。如何实现这一点?

如果要让矩形重叠而不是擦除已经存在的部分,你可以在绘制新矩形时不清除之前的矩形。修改mouseMove方法如下:

mouseMove = e => {
  if (this.drag) {
    this.rect.w = (e.clientX - this.canvas.offsetLeft) - this.rect.x;
    this.ctx.fillRect(
      this.rect.x,
      this.rect.y,
      this.rect.w,
      this.rect.h
    );
  }
}

这样,新的矩形将在鼠标拖动时重叠在已存在的矩形上,而不会擦除之前的矩形。

英文:

Inside a canvas element, I want to be able to draw multiple rectangles on mouse drag (both left and right). So far I have the following:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

class Waveform {
constructor(container_selector) {
this.render(container_selector)
}
render(container_selector) {
this.canvas = document.querySelector(container_selector)
this.canvas.width = 800
this.canvas.height = 150
this.canvas.style.border = &#39;1px solid black&#39;
this.ctx = this.canvas.getContext(&#39;2d&#39;)
this.ctx.fillStyle = &#39;rgba(200, 0, 0, 0.7)&#39;
this.canvas.addEventListener(&#39;mousedown&#39;, this.mouseDown)
this.canvas.addEventListener(&#39;mousemove&#39;, this.mouseMove)
this.canvas.addEventListener(&#39;mouseup&#39;, this.mouseUp)
}
mouseDown = e =&gt; {
this.drag = true
this.rect = {}
this.rect.x = e.clientX - this.canvas.offsetLeft
this.rect.y = 0
this.rect.w = 1
this.rect.h = this.canvas.height
this.ctx.fillRect(
this.rect.x,
this.rect.y,
this.rect.w,
this.rect.h,
)
}
mouseMove = e =&gt; {
if (this.drag) {
this.ctx.clearRect(this.rect.x, this.rect.y, this.rect.w, this.rect.h)
this.rect.w = (e.clientX - this.canvas.offsetLeft) - this.rect.x;
this.ctx.fillRect(
this.rect.x,
this.rect.y,
this.rect.w,
this.rect.h,
)
}
}
mouseUp = e =&gt; {
this.drag = false
}
}
let waveform = new Waveform(&#39;#waveform&#39;)

<!-- language: lang-html -->

&lt;html&gt;
&lt;head&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;canvas id=&quot;waveform&quot;&gt;&lt;/canvas&gt;
&lt;/body&gt;
&lt;/html&gt;

<!-- end snippet -->

The issue with this code is that when I drag a rectangle over an already existing one, the portion of the existing one will be erased. I understand why it is so, but I want the rectangles overlap instead, so that two (or more) can exist at the same time. How to achieve this?

答案1

得分: 0

这里提供了一个解决方案,我删除了你的clearReact行。

class Waveform {
  constructor(container_selector, logger_selector) {
    this.rects = []
    this.logger = new Logger(logger_selector)
    this.render(container_selector)
  }

  render(container_selector) {
    this.canvas = document.querySelector(container_selector)
    this.canvas.width = 800
    this.canvas.height = 150
    this.canvas.style.border = '1px solid black'
    this.ctx = this.canvas.getContext('2d')
    this.ctx.fillStyle = 'rgba(200, 0, 0, 0.7)'

    this.canvas.addEventListener('mousedown', this.mouseDown)
    this.canvas.addEventListener('mousemove', this.mouseMove)
    this.canvas.addEventListener('mouseup', this.mouseUp)
  }

  mouseDown = e => {
    this.drag = true
    this.rect = {}
    this.rect.x = e.clientX - this.canvas.offsetLeft
    this.rect.y = 0
    this.rect.w = 1
    this.rect.h = this.canvas.height
    this.ctx.fillRect(
      this.rect.x,
      this.rect.y,
      this.rect.w,
      this.rect.h,
    )
  }

  mouseMove = e => {
    if (this.drag) {
      this.rect.w = (e.clientX - this.canvas.offsetLeft) - this.rect.x;
      this.ctx.fillRect(
        this.rect.x,
        this.rect.y,
        this.rect.w,
        this.rect.h,
      )
    }
  }

  mouseUp = e => {
    this.drag = false
    this.rects.push(this.rect)
    this.logger.add(this.rect)
  }
  
  getRects() {
    return this.rects
  }
}

class Logger {
  constructor(container_selector) {
    this.list = document.querySelector(container_selector)
  }
  
  add(obj) {
    let li = document.createElement("li")
    li.textContent = JSON.stringify(obj)
    this.list.appendChild(li)
  }
}

let waveform = new Waveform('#waveform', '#list')

我建议你为每个插入到画布中的矩形更改填充颜色。

英文:

Here a solution where I removed your clearReact line.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

class Waveform {
constructor(container_selector, logger_selector) {
this.rects = []
this.logger = new Logger(logger_selector)
this.render(container_selector)
}
render(container_selector) {
this.canvas = document.querySelector(container_selector)
this.canvas.width = 800
this.canvas.height = 150
this.canvas.style.border = &#39;1px solid black&#39;
this.ctx = this.canvas.getContext(&#39;2d&#39;)
this.ctx.fillStyle = &#39;rgba(200, 0, 0, 0.7)&#39;
this.canvas.addEventListener(&#39;mousedown&#39;, this.mouseDown)
this.canvas.addEventListener(&#39;mousemove&#39;, this.mouseMove)
this.canvas.addEventListener(&#39;mouseup&#39;, this.mouseUp)
}
mouseDown = e =&gt; {
this.drag = true
this.rect = {}
this.rect.x = e.clientX - this.canvas.offsetLeft
this.rect.y = 0
this.rect.w = 1
this.rect.h = this.canvas.height
this.ctx.fillRect(
this.rect.x,
this.rect.y,
this.rect.w,
this.rect.h,
)
}
mouseMove = e =&gt; {
if (this.drag) {
this.rect.w = (e.clientX - this.canvas.offsetLeft) - this.rect.x;
this.ctx.fillRect(
this.rect.x,
this.rect.y,
this.rect.w,
this.rect.h,
)
}
}
mouseUp = e =&gt; {
this.drag = false
this.rects.push(this.rect)
this.logger.add(this.rect)
}
getRects() {
return this.rects
}
}
class Logger {
constructor(container_selector) {
this.list = document.querySelector(container_selector)
}
add(obj) {
let li = document.createElement(&quot;li&quot;)
li.textContent = JSON.stringify(obj)
this.list.appendChild(li)
}
}
let waveform = new Waveform(&#39;#waveform&#39;, &#39;#list&#39;)

<!-- language: lang-html -->

&lt;html&gt;
&lt;head&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;canvas id=&quot;waveform&quot;&gt;&lt;/canvas&gt;
&lt;/body&gt;
&lt;ul id=&quot;list&quot;&gt;
&lt;/ul&gt;
&lt;/html&gt;

<!-- end snippet -->

I suggest you to change fill color for each rect you insert in your canvas.

huangapple
  • 本文由 发表于 2020年1月6日 23:48:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/59615054.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定