处理JavaScript

时间:2015-08-27 16:41:28

标签: javascript html canvas graphics

我使用纯JavaScript来使用canvas元素开发一个简单的绘图应用程序。当用户拖动屏幕时,该应用会创建圈子。其次,双击圆圈将删除特定圆圈。第三,我想点击它时拖动一个圆圈。

var canvas,
context, shapes,
dragging = false, draggingtoMove = false,dragstopped = 0,
    dragStartLocation,dragEndLocation,
    snapshot;
 var numShapes;
function initiate() {
    numShapes = 100;
    shapes = [];
    canvas = document.getElementById('canvas');
    context = canvas.getContext('2d');
    canvas.addEventListener('mousedown', dragStart, false);
    canvas.addEventListener('mousemove', drag, false);
    canvas.addEventListener('mouseup', dragStop, false);
    canvas.addEventListener('dblclick', dblclickerase);
}
function dblclickerase(evt){
    dragstopped = 0;
    shapes.pop();
    shapes.pop();
        var i, j;
		var highestIndex = -1;
		
		//getting mouse position correctly, being mindful of resizing that may have occured in the browser:
		var bRect = canvas.getBoundingClientRect();
		mouseX = (evt.clientX - bRect.left)*(canvas.width/bRect.width);
		mouseY = (evt.clientY - bRect.top)*(canvas.height/bRect.height);
				
		//Now find which shape was clicked
		for (i=0; i < shapes.length; i++) {
			if	(hitTest(shapes[i], mouseX, mouseY)) {
                // That particular circle is I am going to delete at position i
			    shapes[i].x = -1;
                shapes[i].y = -1;
                shapes[i].rad = -1;
                shapes[i].color = -1;                
			    eraseCanvas(); // clear canvas
			}
		}
		redraw();
}
function redraw() {
    var j;
    eraseCanvas(); // clear canvas and redraw it
            for(j= 0; j< shapes.length; j++)
                {
                    if(shapes[j].x != -1)
                    {
                   
			        context.beginPath();
			        context.arc(shapes[j].x, shapes[j].y, shapes[j].rad, 0, 2*Math.PI, false);
                    context.fillStyle = shapes[j].color;
			        context.fill();
                    }
                }
}
function getCanvasCoordinates(event) {
    var x = event.clientX - canvas.getBoundingClientRect().left,
        y = event.clientY - canvas.getBoundingClientRect().top;
    return {
        x: x,
        y: y
    };
}
function takeSnapshot() {
    snapshot = context.getImageData(0, 0, canvas.width, canvas.height);
}
function restoreSnapshot() {
    context.putImageData(snapshot, 0, 0);
}
function draw(position) {
     var radius = Math.sqrt(Math.pow((dragStartLocation.x - position.x), 2) + Math.pow((dragStartLocation.y - position.y), 2));
        var i=0;
		var tempX;
		var tempY;
		var tempRad;
		var tempR;
		var tempG;
		var tempB;
		var tempColor;
			tempRad = radius;
			tempX = dragStartLocation.x;
			tempY = dragStartLocation.y;
			tempColor = getRndColor();
			tempShape = {x:tempX, y:tempY, rad:tempRad, color:tempColor};
			if (dragstopped) { shapes.push(tempShape); }
			context.beginPath();
			context.arc(tempX, tempY, tempRad, 0, 2*Math.PI, false);
			//context.closePath();
            context.fillStyle = tempColor;
			context.fill();
			i++;
}
function dragStart(evt) {
   
    //// Here I will check whether if circle overlaps then drag the circle else draw new one.
        var i, j;
		var highestIndex = -1;
		
		//getting mouse position correctly, being mindful of resizing that may have occured in the browser:
		var bRect = canvas.getBoundingClientRect();
		mouseX = (evt.clientX - bRect.left)*(canvas.width/bRect.width);
		mouseY = (evt.clientY - bRect.top)*(canvas.height/bRect.height);
				
		//Now find which shape was clicked
		for (i=0; i < shapes.length; i++) {
			if	(hitTest(shapes[i], mouseX, mouseY)) {
                // That particular circle is I am going to delete at position i                
			    //eraseCanvas(); // clear canvas
			    console.log("clicking on circle");
			   // return;
			}
		}
    
    //Draw Circle
            dragging = true;
            dragstopped = 0;
            dragStartLocation = getCanvasCoordinates(evt);
            takeSnapshot();
             } 

 function hitTest(shape,mx,my) {
		var dx;
		var dy;
		dx = Math.abs(mx - shape.x);
		dy = Math.abs(my - shape.y);
		//if it is inside any circle radius will let us know	
		return (Math.sqrt(dx*dx + dy*dy) < shape.rad);
	}

function drag(event) {
    dragstopped = 0;
    var position;
    if (dragging === true) {
        restoreSnapshot();
        position = getCanvasCoordinates(event);
        draw(position);
    }
}

function dragStop(event) {
    dragstopped += 1;
    dragging = false;
    restoreSnapshot();
   var position = getCanvasCoordinates(event);
  dragEndLocation = getCanvasCoordinates(event);
    draw(position);
}

function getRndColor() {
    var r = 255 * Math.random() | 0,
        g = 255 * Math.random() | 0,
        b = 255 * Math.random() | 0;
    return 'rgb(' + r + ',' + g + ',' + b + ')';
}

function eraseCanvas() {
    context.clearRect(0, 0, canvas.width, canvas.height);
    shapes = [];
}

addEventListener("load",initiate);

 
body {
}

canvas{
    border: 1px solid gray;
}
button {
    font-size: 128%;
    margin-right: -12px;
    position: absolute;
}
<canvas id="canvas" width="600" height="400"></canvas>

我的第一个问题是:如何使用在dragStart()发生时调用的相同mousedown函数拖动一个圆圈?作为解决方案,我在想,如果我点击圆圈,那么我需要将其拖动。然后找到光标的位置我正在检查hitTest()是否给出了位置是否在圆圈内,但是如果圆圈被击中那么我又需要拖动它,因为我怎么能绑定使用mousemove事件,以便我可以说我想拖动圆圈而不是像我的代码在drag()中所说的那样绘制它?

我的第二个问题:我猜我的代码没有处理双击事件,而是删除了一个清除画布的圆圈。我想删除画布并使用shapes数组重绘整个画布。

2 个答案:

答案 0 :(得分:1)

我没有想到使用你的想法来解决这个项目,但我有一些可能对你有帮助的评论。

1:如果您想要与放置的形状进行交互,我建议不要使用画布,主要是因为画布在绘图时效率很高,所以它只保存像素信息。您也可以尝试使用SVG甚至新的HTML 5功能来拖放元素(http://www.w3schools.com/html/html5_draganddrop.asp)。但是,如果您希望继续使用画布和 javascript ,您应该尝试使用 onmousedown 而不是 onclick 来触发拖动功能,因为订单那些事件是onmousedown,onmouseup然后onclick(http://www.w3schools.com/tags/ev_onmousedown.asp)。

2:也许您可以制作动画循环,也就是说,您在固定时间绘制并清除整个画布,这样您就可以在“渲染器”数组中绘制每个形状,如果您希望删除一个形状,只需将其从数组中删除即可。 另外,我没有找到双击的事件监听器,你是否尝试将 ondblclick =“myFunction()”附加到画布上? (http://www.w3schools.com/jsref/event_ondblclick.asp

答案 1 :(得分:1)

不是让一个mousemove处理程序试图处理所有可能的操作,而是拥有专门的mousemove处理程序是有意义的。

  • 制作一个圆圈:在做任何事情之前拍摄画布的快照,然后附上一个mousemove处理程序,用于恢复快照并在顶部绘制一个所需大小的新圆圈。

    < / LI>
  • 拖动圆圈:擦除画布,绘制除要拖动的圆圈以外的所有圆圈,然后拍摄快照。现在附上一个mousemove处理程序,用于恢复快照并将圆圈绘制在新位置。

在每种情况下,您还应该分配一个mouseup处理程序,在拖动操作结束时将mousemove处理程序和mouseup处理程序本身分开。

至于双击问题,你遇到了麻烦,因为你没有正确地擦除形状。您的函数以几个shapes.pop()调用开始,因此从数组中删除最后两个形状,然后您的eraseCanvas函数丢弃整个数组。擦除画布时,请勿篡改形状阵列。

要从数组中间删除位置i的形状,请将所有数组元素向下移动一步,然后将最后一个元素弹出结尾:

      for (var j = i + 1; j < shapes.length; ++j) {
        shapes[j - 1] = shapes[j];
      }
      shapes.pop();

完成后,您可以擦除画布并绘制阵列中剩余的所有形状。

我已在以下代码段中实施了这些更正。

&#13;
&#13;
var canvas,
context, shapes,
dragging = false, draggingtoMove = false,dragstopped = 0,
    dragStartLocation,dragEndLocation,
    snapshot;
 var numShapes;
function initiate() {
    numShapes = 100;
    shapes = [];
    canvas = document.getElementById('canvas');
    context = canvas.getContext('2d');
    canvas.addEventListener('mousedown', click, false);
    canvas.addEventListener('dblclick', dblclickerase);
}
function dblclickerase(evt){
    var coordinates = getCanvasCoordinates(event),
        clickX = coordinates.x,
        clickY = coordinates.y;
				
		//Now find which shape was clicked
		for (var i = 0; i < shapes.length; ++i) {
			if	(hitTest(shapes[i], clickX, clickY)) {
			    console.log('double-clicked on circle ' + i);
          // Delete this shape from the array.
          for (var j = i + 1; j < shapes.length; ++j) {
            shapes[j - 1] = shapes[j];
          }
          shapes.pop();
          // Redraw the other shapes.
          eraseCanvas();
          for (var j = 0; j < shapes.length; ++j) {
            paintCircle(shapes[j]);
          }
          return;
			}
		}
}

function getCanvasCoordinates(event) {
    var x = event.clientX - canvas.getBoundingClientRect().left,
        y = event.clientY - canvas.getBoundingClientRect().top;
    return {
        x: x,
        y: y
    };
}
function takeSnapshot() {
    snapshot = context.getImageData(0, 0, canvas.width, canvas.height);
}
function restoreSnapshot() {
    context.putImageData(snapshot, 0, 0);
}
function draw(position) {
     var radius = Math.sqrt(Math.pow((dragStartLocation.x - position.x), 2) + Math.pow((dragStartLocation.y - position.y), 2));
        var i=0;
		var tempX;
		var tempY;
		var tempRad;
		var tempR;
		var tempG;
		var tempB;
		var tempColor;
			tempRad = radius;
			tempX = dragStartLocation.x;
			tempY = dragStartLocation.y;
			tempColor = getRndColor();
			tempShape = {x:tempX, y:tempY, rad:tempRad, color:tempColor};
			if (dragstopped) { shapes.push(tempShape); }
      paintCircle(tempShape);
			i++;
}
function click(event) {
   
    // Here I will check whether if circle overlaps then drag the circle else draw new one.
    var i, j;
		var highestIndex = -1;
		
		//getting mouse position correctly, being mindful of resizing that may have occured in the browser:
    var coordinates = getCanvasCoordinates(event),
        clickX = coordinates.x,
        clickY = coordinates.y;
				
		//Now find which shape was clicked
		for (i=0; i < shapes.length; i++) {
      var shape = shapes[i];
			if	(hitTest(shape, clickX, clickY)) {
			    console.log('clicked on circle ' + i);

          // Erase this circle and take a snapshot.
          eraseCanvas();
          for (var j = 0; j < shapes.length; ++j) {
            if (j != i) {
              paintCircle(shapes[j]);
            }
          }
          takeSnapshot();
          paintCircle(shape);

          var originalX = shape.x,
              originalY = shape.y;

          canvas.onmousemove = function (dragEvent) {
            var dragCoordinates = getCanvasCoordinates(dragEvent),
                dx = dragCoordinates.x - clickX,
                dy = dragCoordinates.y - clickY;
            shape.x = originalX + dx;
            shape.y = originalY + dy;
            restoreSnapshot();
            paintCircle(shape);
          };
          canvas.onmouseup = function (upEvent) {
            canvas.onmousemove = undefined;
            canvas.onmouseup = undefined;
          };

			    return;
			}
		}
    
    //Draw Circle
    dragging = true;
    dragstopped = 0;
    dragStartLocation = getCanvasCoordinates(event);
    takeSnapshot();
    canvas.onmousemove = makeCircle;
    canvas.onmouseup = finishCircle;
} 

function hitTest(shape,mx,my) {
    var dx;
    var dy;
    dx = Math.abs(mx - shape.x);
    dy = Math.abs(my - shape.y);
    //if it is inside any circle radius will let us know	
    return (Math.sqrt(dx*dx + dy*dy) < shape.rad);
}

function paintCircle(shape) {
  context.fillStyle = shape.color;
  context.beginPath();
  context.arc(shape.x, shape.y, shape.rad, 0, 2 * Math.PI);
  context.closePath();
  context.fill();
}

function makeCircle(event) {
    dragstopped = 0;
    var position;
    if (dragging === true) {
        restoreSnapshot();
        position = getCanvasCoordinates(event);
        draw(position);
    }
}

function finishCircle(event) {
    canvas.onmousemove = undefined;
    canvas.onmouseup = undefined;
    dragstopped += 1;
    dragging = false;
    restoreSnapshot();
    var position = getCanvasCoordinates(event);
    dragEndLocation = getCanvasCoordinates(event);
    draw(position);
}

function getRndColor() {
    var r = 255 * Math.random() | 0,
        g = 255 * Math.random() | 0,
        b = 255 * Math.random() | 0;
    return 'rgb(' + r + ',' + g + ',' + b + ')';
}

function eraseCanvas() {
    context.clearRect(0, 0, canvas.width, canvas.height);
}

addEventListener("load",initiate);
&#13;
body {
}

canvas{
    border: 1px solid gray;
}
button {
    font-size: 128%;
    margin-right: -12px;
    position: absolute;
}
&#13;
<canvas id="canvas" width="600" height="400"></canvas>
&#13;
&#13;
&#13;