簡體   English   中英

處理JavaScript中的單擊和拖動事件

[英]Handling click and drag events in JavaScript

我正在使用純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> 

我的第一個問題是:如何使用發生mousedown時調用的相同的dragStart()函數來拖動圓? 作為解決方案,我認為如果單擊圓圈,則必須確定要拖動它。 然后要找到光標的位置,我正在檢查hitTest() ,它給出了該位置是否在圓內,但是如果再次按下了圓,則需要將其拖動,為此如何與mousemove事件,以便可以說我想拖動圓圈而不是按照我的代碼在drag()所說的那樣繪制它?

我的第二個問題:我想我的代碼沒有處理雙擊事件,而是刪除一個圓圈而不是清除畫布。 我想擦除畫布,然后使用shapes數組重繪整個畫布。

我還沒有想到使用您的想法解決方案的解決方案,但我有一些建議可能會對您有所幫助。

1:如果要與要放置的形狀進行交互,我不建議您使用畫布,主要是因為畫布是為了有效地繪制,所以它僅包含像素信息。 您也可以嘗試使用SVG甚至是HTML 5的新功能來拖放元素( http://www.w3schools.com/html/html5_draganddrop.asp )。 但是,如果您希望繼續使用canvas和javascript ,則應嘗試使用onmousedown而不是onclick來觸發拖動功能,因為這些事件的順序是onmousedown,onmouseup然后onclick( http://www.w3schools.com/標簽/ev_onmousedown.asp )。

2:您可能需要制作一個動畫循環,也就是說,您要在固定的時間繪制並清除整個畫布,這樣就可以繪制“渲染器”數組中的每個形狀,如果要刪除一種形狀,您只需將其從數組中刪除。 另外,我還沒有找到雙擊的事件監聽器,是否嘗試將ondblclick =“ myFunction()”附加到畫布上? http://www.w3schools.com/jsref/event_ondblclick.asp

擁有一個專門的mousemove處理程序,而不是讓單個mousemove處理程序嘗試處理所有可能的動作,是有意義的。

  • 畫一個圓圈:在做任何事情之前先對畫布進行快照,然后附加一個mousemove處理程序,以恢復快照並在其頂部繪制一個所需大小的新圓圈。

  • 拖出一個圓圈:擦除畫布,繪制除要拖動的圓圈以外的所有圓圈,然后拍攝快照。 現在,附加一個mousemove處理程序,該處理程序將恢復快照並將圓畫在其新位置。

在每種情況下,您還應該分配一個mouseup處理程序,該操作將在完成拖動操作后分離mousemove處理程序和mouseup處理程序本身。

至於雙擊問題,您遇到了麻煩,因為您沒有正確擦除形狀。 您的函數從幾個shapes.pop()調用開始,因此從數組中刪除了最后兩個形狀,然后您的eraseCanvas函數丟棄了整個數組。 擦除畫布時,請勿篡改形狀數組。

要從數組中間刪除位置i處的形狀,請將所有數組元素向下移動一個,然后從末尾彈出最后一個元素:

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

完成此操作后,您可以擦除畫布並繪制數組中剩余的所有形狀。

我在以下代碼段中實現了這些更正。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM