HTML 5 Canvas拖放多个对象无法正常工作

时间:2018-01-16 13:36:40

标签: javascript html5 canvas

我有一个自定义代码,用于在HTML5画布上创建和渲染对象。

class Rectangle extends Shape {

  constructor(options, canvas, type = 'rectangle') {
    super(...); // derived from super class

    this._options = options;
    this._canvas = canvas;
    this._context = canvas.context2D;
    this._type = type;

    this._hovered = false;
    this._dragged = false;

    this.init();

    this.canvas.canvas.onmousemove = (e) => {
      this.onMouseHover(e);
    };

    this.canvas.canvas.onmousedown = (e) => {
      this.onMouseDrag(e);
      console.log('dragging');
    }

    this.canvas.canvas.onmouseup = (e) => {
      this.onMouseRelease(e);
      console.log('release');
    }
  }

  static draw(options, canvas) {
    return new Rectangle(options, canvas);
  }

  // Getter and setter


  init() {
    this.drawRectangle(...);
  }

  onMouseHover(e) {
    if( // mouse is in the above of shape position 
      e.clientX >= this.x &&
      e.clientX <= this.x + this.width &&
      e.clientY >= this.y &&
      e.clientY <= this.y + this.height
    ) {
      this.drawRectangle(...) // inverse the border color with background
      this.canvas.canvas.style.cursor = 'pointer';
    } else {
      this.drawRectangle(...) // revert to original
      this.canvas.canvas.style.cursor = 'default';
    }
  }

  onMouseDrag(e) {
    if( // mouse is in the above of shape position
      e.clientX >= this.x &&
      e.clientX <= this.x + this.width &&
      e.clientY >= this.y &&
      e.clientY <= this.y + this.height &&
      !this.isDragged
    ) {

      this.canvas.canvas.onmousemove = (drag) => {  // while dragging
        this.eraseRectangle(...); // erase the rectangle

        this.drawRectangle(...); // draw the rectangle while dragging

        this.x = drag.clientX; // set the new x position
        this.y = drag.clientY; // set the new y position
      }
      this.isDragged = true;
    }
  }

  onMouseRelease(e) {
    if(this.isDragged) {
      this.isDragged = false;
      this.canvas.canvas.onmousemove = (e) => { // reset it to original
        this.onMouseHover(e);
      }
    }
  }

  drawRectangle(width, height, x, y, fillStyle, strokeStyle) {
    this.context.beginPath();
    this.context.fillStyle = fillStyle;
    this.context.strokeStyle = strokeStyle;
    this.context.rect(x, y, width, height);
    this.context.fill();
    this.context.stroke();
  }

  eraseRectangle(width, height, x, y) {
    this.context.beginPath();
    this.context.clearRect(x-1, y-1, width+2, height+2);
  }

}

在主要班级。

class Main {

  static ready() {

    // Basic options
    const options = {
      width: window.innerWidth,
      height: window.innerHeight,
      background: 'black'
    }

    // Create the canvas object
    const canvas = HTMLCanvas.build('workspace', options);
    const context = canvas.context2D;

    const rect1 = Rectangle.draw({
      width: 200,
      height: 100,
      x: 100,
      y: 200,
      border: 'blue',
      background: 'white',
      label: 'rect1'
    }, canvas);

    const rect2 = Rectangle.draw({
      width: 300,
      height: 75,
      x: 200,
      y: 400,
      border: 'green',
      background: 'white',
      label: 'rect2'
    }, canvas);

  }
 }

// Initialize everything
Main.ready();

通过上面的代码,我能够在画布中呈现矩形形状。但是,问题是对象rect1正在丢失其引用。

rect1 lose reference to the canvas

我无法拖动或悬停rect1对象,但我仍然可以悬停并拖放rect2对象。当rect2 悬停拖过rect1时,rect2会删除rect1

Example output

我们如何跟踪每个HTML5画布对象的鼠标事件?大多数解决方案最终会迭代所有对象(将在画布中绘制)并将鼠标事件绑定到它。我希望它在对象本身内,而不是在工厂类中。

1 个答案:

答案 0 :(得分:0)

&#13;
&#13;
<!doctype html>
<html>
	<head>
		<meta charset="utf-8">
		<style>
			body {
				background-color: black;
			}
			
			canvas {
				position: absolute;
				margin-left: auto;
				margin-right: auto;
				left: 0;
				right: 0;
				border: solid 1px white;
				border-radius: 10px;
			}
		</style>
	</head>
	
	<body>
		<canvas id="canvas"></canvas>
		<script type="application/javascript">
			
			var imageWidth = 180;
			var imageHeight = 160;
			var canvas = null;
			var ctx = null;
			var bounds = null;
			var selectedBox = null;
			var panX = 0;
			var panY = 0;
			var mouseX = 0;
			var mouseY = 0;
			var oldMouseX = 0;
			var oldMouseY = 0;
			var mouseHeld = false;
			var boxArray = [];
			
			function DraggableBox(x,y,width,height,text) {
				this.x = x;
				this.y = y;
				this.width = width;
				this.height = height;
				this.text = text;
				this.isSelected = false;
			}
			
			DraggableBox.prototype.isCollidingWidthPoint = function(x,y) {
				return (x > this.x && x < this.x + this.width)
					&& (y > this.y && y < this.y + this.height);
			}
			
			DraggableBox.prototype.drag = function(newX,newY) {
				this.x = newX - this.width * 0.5;
				this.y = newY - this.height * 0.5;
			}
			
			DraggableBox.prototype.draw = function() {
				if (this.isSelected) {
					ctx.fillStyle = "darkcyan";
					ctx.fillRect(
						this.x - panX,
						this.y - panY,
						this.width,
						this.height
					);
					ctx.fillStyle = "black";
				} else {			
					ctx.fillRect(
						this.x - panX,
						this.y - panY,
						this.width,
						this.height
					);
				}
				
				ctx.fillStyle = "white";
				ctx.fillText(
					this.text,
					this.x + this.width * 0.5 - panX,
					this.y + this.height * 0.5 - panY,
					this.width
				);
				ctx.fillStyle = "black";
			}
			
			window.onmousedown = function(e) {
				mouseHeld = true;
			
				if (!selectedBox) {
					for (var i = boxArray.length - 1; i > -1; --i) {
						if (boxArray[i].isCollidingWidthPoint(mouseX + panX,mouseY + panY)) {
							selectedBox = boxArray[i];
							selectedBox.isSelected = true;
							requestAnimationFrame(draw);
							return;
						}
					}
				}
			}
			
			window.onmousemove = function(e) {
				mouseX = e.clientX - bounds.left;
				mouseY = e.clientY - bounds.top;
				
				if (mouseHeld) {
					if (!selectedBox) {
						panX += oldMouseX - mouseX;
						panY += oldMouseY - mouseY;
					} else {
						selectedBox.x = mouseX - selectedBox.width * 0.5 + panX;
						selectedBox.y = mouseY - selectedBox.height * 0.5 + panY;
					}
				}
				
				oldMouseX = mouseX;
				oldMouseY = mouseY;
				
				requestAnimationFrame(draw);
			}
			
			window.onmouseup = function(e) {
				mouseHeld = false;
				
				if (selectedBox) {
					selectedBox.isSelected = false;
					selectedBox = null;
					requestAnimationFrame(draw);
				}
			}
			
			function draw() {
				ctx.fillStyle = "gray";
				ctx.fillRect(0,0,imageWidth,imageHeight);
				
				var box = null;
				var xMin = 0;
				var xMax = 0;
				var yMin = 0;
				var yMax = 0;
				
				ctx.fillStyle = "black";
				
				for (var i = 0; i < boxArray.length; ++i) {
					box = boxArray[i];
					
					xMin = box.x - panX;
					xMax = box.x + box.width - panX;
					yMin = box.y - panY;
					yMax = box.y + box.height - panY;
					
					if (xMax > 0 && xMin < imageWidth && yMax > 0 && yMin < imageHeight) {
						box.draw();
					}
				}
			}
			
			window.onload = function() {
				canvas = document.getElementById("canvas");
				canvas.width = imageWidth;
				canvas.height = imageHeight;
				
				bounds = canvas.getBoundingClientRect();
				ctx = canvas.getContext("2d");
				ctx.textAlign = "center";
				ctx.font = "15px Arial"
				
				boxArray.push(new DraggableBox(Math.random() * 320,Math.random() * 240,100,25,"This is a draggable text box"));
				boxArray.push(new DraggableBox(Math.random() * 320,Math.random() * 240,100,50,"Another text box"));
				boxArray.push(new DraggableBox(Math.random() * 320,Math.random() * 240,100,50,"Text in a box"));
				boxArray.push(new DraggableBox(Math.random() * 320,Math.random() * 240,100,50,"I find this box quite texing"));
				boxArray.push(new DraggableBox(Math.random() * 320,Math.random() * 240,150,50,"You weren't supposed to find this box"));
				requestAnimationFrame(draw);
			}
			
			window.onunload = function() {
				canvas = null;
				ctx = null;
				bounds = null;
				selectedBox = null;
				boxArray = null;
			}
			
		</script>
	</body>
</html>
&#13;
&#13;
&#13;