I have this problem, and I don't know how to deal with it. I struggled almost 2 hours to fix it. I tried various methods, but with no luck. If it's a nobbish question please forgive me and explain me in depth every step you do.
I have created a canvas, and I drew a circle in it. Now, I want to move the circle with the mouse, but while the mouse is hold. Is there any way to do it, or I'm just wasting time? Here is the code:
<canvas draggable="true" id="canv" name="canv" width="600" height="500" style="border:1px solid #000000;" onclick="">Your browser does not support the HTML5 canvas tag.</canvas> <!-- < -- the canvas -->
<script>
var canv = document.getElementById("canv");
var context = canv.getContext("2d");
var width = canv.offsetWidth-1;
var height = canv.offsetHeight-1;
context.beginPath();
context.arc(width/2, height/2, 75, 0, 2*Math.PI);
context.stroke();
</script>
Some methods I have tried. These one are left in remarks /**/. Other ones I deleted them.
1.
<canvas draggable="true" id="canv" name="canv" width="600" height="500" style="border:1px solid #000000;" onclick="circle_move()"></canvas>
function circle_move(event){
var x = event.clientX;
var y = event.clientY;
document.getElementById("txt").setAttribute("value", "X: "+x+" and Y: "+y);
document.getElementById("canv").addEventListener("onmousemove", function(){
context.beginPath();
context.clearRect(0, 0, width, height);
context.arc(x, y, 75, 0, 2*Math.PI);
context.stroke();
});
}
2.
document.getElementById("canv").addEventListener("mousedown",
function(event){
var x = event.clientX;
var y = event.clientY;
document.getElementById("txt").setAttribute("value", "X: "+x+" and Y: "+y);
context.beginPath();
context.clearRect(0, 0, width, height);
context.arc(x, y, 75, 0, 2*Math.PI);
context.stroke();
}
);
3.
<canvas draggable="true" id="canv" name="canv" width="600" height="500" style="border:1px solid #000000;" onmousedown="launch"></canvas>
function loop(event){
var x = event.clientX;
var y = event.clientY;
document.getElementById("txt").setAttribute("value", "X: "+x+" and Y: "+y);
context.beginPath();
context.clearRect(0, 0, width, height);
context.arc(x, y, 75, 0, 2*Math.PI);
context.stroke();
}
function launch(event){
loop();
if(event.which !== 1 || event.which !== 2 || event.which !== 3){
launch(event);
}
}
答案 0 :(得分:1)
您可以从评论和代码中看到发生了什么。基本上你需要一个全局鼠标键状态变量,让函数知道鼠标键是否被按下。我使用了mousemove事件来实际开始绘制圆圈。最后,你需要光标和圆心之间的距离小于半径,否则你可以从圆圈外面拖动圆圈(我认为这不是你想要的)。
//keep track of previous x and y coordinates
var x0 = 200;
var y0 = 300;
//keep track of mouse key state
var down = false;
var x;
var y;
//draw the initial circle someplace random
var context = document.getElementById("canv").getContext("2d");
context.clearRect(0, 0, 600, 500);
context.arc(200,300, 75, 0, 2*Math.PI);
context.stroke();
document.addEventListener("mousedown", function()
{
//if mousedown event is logged and we are within the area of the circle then state of down is true
if(getDistance(x, x0, y, y0) < 75) down = true;
});
document.addEventListener("mouseup", function()
{
//if mouseup event is logged then down is now false
down = false;
});
document.getElementById("canv").addEventListener("mousemove",
function(event){
x = event.clientX;
y = event.clientY;
//we need to be in "down" state in order for a redraw to be necessary
if(down)
{
//set the previous coordinates to the new coordinates we are drawing.
x0 = x;
y0 = y;
//draw the darn thing
context.beginPath();
context.clearRect(0, 0, 600, 500);
context.arc(x, y, 75, 0, 2*Math.PI);
context.stroke();
}
}
);
function getDistance(x0, x1, y0, y1)
{
return Math.sqrt(Math.pow(x1-x0,2) + Math.pow(y1-y0, 2));
}
<canvas id="canv" name="canv" width="600" height="500" style="border:1px solid #000000;" onclick="">Your browser does not support the HTML5 canvas tag.</canvas>
答案 1 :(得分:1)
当您在画布上拖动任何内容时,您实际上是为画布设置动画。为了获得最佳效果,您需要停止思考如何使用DOM完成任务并开始编写类似于编写游戏的代码。
要协调所有正在进行的操作,您需要一个处理所有动画的函数。有时在游戏圈中称为mainLoop,这使得处理动画内容变得更加容易。
主循环
function mainLoop(time){ // this is called 60 times a second if there is no delay
// clear the canvas ready to be rendered on.
ctx.clearRect(0,0,canvas.width,canvas.height);
updateDisplay(); // call the function that is rendering the display
// get the next frame
requestAnimationFrame(mainLoop);
}
requestAnimationFrame(mainLoop);
在主循环中,您可以检查当前的应用状态并调用相应的功能。在这个例子中,它只是调用updateDisplay()
鼠标,键盘,触摸等事件处理程序不应该执行任何功能逻辑。这些事件可以非常快速地发射,但是显示器每隔60秒就会更新一次。当用户只能看到CPU正在执行的工作量的10%以上时,从一秒钟内可以触发500次的事件无法呈现。
编写IO事件的最佳方法就像数据记录器一样。尽快获取尽可能快的信息并离开,不要为每种类型的事件编写不同的事件监听器,保持代码简单,只编写一个事件处理程序来尽可能多地处理。如果您需要键盘将其添加到同一个侦听器。
var mouse = (function(){
var bounds;
var m = {x:0,y:0,button:false};
function mouseEvent(event){
bounds = event.currentTarget.getBoundingClientRect();
m.x = event.pageX - bounds.left + scrollX;
m.y = event.pageY - bounds.top + scrollY;
if(event.type === "mousedown"){
m.button = true;
}else if(event.type === "mouseup"){
m.button = false;
}
}
m.start = function(element){
["mousemove","mousedown","mouseup"].forEach(eventType => element.addEventListener(eventType, mouseEvent));
}
return m;
}())
mouse.start(canvas);
现在,您可以通过简单的鼠标界面随时访问鼠标。
如果没有什么可以移动的话,没有必要添加一个漂亮的界面。以下是帮助管理圈子的对象。它创建,绘制和定位圆圈。
包含findClosest
函数,它获取鼠标下的圆圈。它将返回鼠标下方的最小圆圈。如果鼠标下没有任何内容,它将返回undefined。
var circles = {
items [],
drawCircle(){ // function for the circle
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.stroke();
},
each(callback){ // iterator
var i;
for(i = 0; i < this.items.length; i++){
callBack(this.items[i],i);
}
},
drawCircles(){
this.each(c => {
c.draw();
})
},
addCircle(x,y,radius){
var circle = {x, y, radius, draw : this.drawCircle};
this.items.push(circle);
return circle;
},
getClosest(pos){
var minDist, i, dist, x, y, foundCircle;
minDist = Infinity;
this.each(c =>{
x = pos.x - c.x;
y = pos.y - c.y;
dist = Math.sqrt(x * x + y * y);
if(dist <= c.radius && dist < minDist){
minDist = dist;
foundCircle = c;
}
})
return foundCircle;
}
}
拖动对象涉及很多内容。您需要一个函数来查找与鼠标最近的对象。您需要提供反馈,以便用户可以看到可以拖动的内容。
您最终可能会遇到许多不同的拖动类型事件。拖动以创建,拖动以移动,将某些内容拖动到画布上,或者操纵自定义呈现的UI对象。如果您从一个对象管理拖动状态,则可以确保在拖动圆圈时不会意外地单击UI项目。
当拖动开始时,您将检查拖动将执行的操作。然后标记您正在拖动,并指出拖动要执行的操作。 (请参阅updateDisplay函数)
当拖动处于活动状态时执行该操作。当鼠标启动时,只需停用拖动
var dragging = {
started : false, // true if dragging
type : null, // string with the type of drag event
currentObj : null, // what we are dragging
startX : 0, // info about where the drag started
startY : 0,
start(type, obj){ // called at the start of a drag.
this.startX = mouse.x;
this.startY = mouse.y;
this.started = true;
this.type = type;
this.currentObj = obj;
}
}
然后是渲染功能。每帧调用一次。我检查鼠标按钮是否关闭,如果是这样做,设置光标以便人们知道该做什么,并绘制圆圈。
var cursor = "default"; // to hold the cursor
var overCircle = null; // this holds whatever circle happens to be under the mouse when not dragging
function updateDisplay(){
var x,y, c;
cursor = "default"; // set default cursor
// check that the mouse if over the canvas
if(mouse.x >= 0 && mouse.x < canvas.width && mouse.y >= 0 && mouse.y < canvas.height){
cursor = "crosshair";
}
// is the mouse button down
if(mouse.button){ // the button is down
if(!dragging.started){ // if not dragging start
if(overCircle){ // start a move drag if over a circle
dragging.start("move",overCircle)
overCircle = null;
}else{ // start a create drag
dragging.start("create",circles.addCircle(mouse.x, mouse.y, 1));
}
}
c = dragging.currentObj;
// Update the drag state o fthe object being draged and the type of drag
if(dragging.type === "create"){
x = c.x - mouse.x;
y = c.y - mouse.y;
c.radius = Math.sqrt(x * x + y * y);
}else if(dragging.type === "move"){
x = dragging.startX - mouse.x;
y = dragging.startY - mouse.y;
c.x -= x;
c.y -= y;
dragging.startX = mouse.x;
dragging.startY = mouse.y;
}
cursor = "none";
} else { // button must be up
if(dragging.started){ // have we been dragging something.
dragging.started = false; // drop it
}
}
// draw the circles
ctx.strokeStyle = "black";
circles.draw();
// if not dragging
if(!dragging.started){
// find circle under the mouse
c = circles.getClosest(mouse);
if(c !== undefined){ // if there is a circle under the mouse highlight it
cursor = "move";
ctx.strokeStyle = "red";
ctx.fillStyle = "rgba(0,255,255,0.1)";
c.draw();
ctx.fill();
overCircle = c;
}else{
overCircle = null;
}
}
// set the cursor.
canvas.style.cursor = cursor;
}
var canvas = document.createElement("canvas");
canvas.style.border = "1px black solid";
canvas.width = 512;
canvas.height = 200;
var ctx = canvas.getContext("2d");
document.body.appendChild(canvas);
function mainLoop(time){ // this is called 60 times a second if there is no delay
ctx.clearRect(0,0,canvas.width,canvas.height);
updateDisplay(); // call the function that is rendering the display
// get the next frame
requestAnimationFrame(mainLoop);
}
// request the first frame. It will not start untill all the code below has been run
requestAnimationFrame(mainLoop);
var mouse = (function(){
var bounds;
var m = {x:0,y:0,button:false};
function mouseEvent(event){
bounds = event.currentTarget.getBoundingClientRect();
m.x = event.pageX - bounds.left + scrollX;
m.y = event.pageY - bounds.top + scrollY;
if(event.type === "mousedown"){
m.button = true;
}else if(event.type === "mouseup"){
m.button = false;
}
}
m.start = function(element){
["mousemove","mousedown","mouseup"].forEach(eventType => element.addEventListener(eventType, mouseEvent));
}
return m;
}())
mouse.start(canvas);
var circles = {
items : [],
drawCircle(){ // function for the circle
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.stroke();
},
each(callback){ // iterator
var i;
for(i = 0; i < this.items.length; i++){
callback(this.items[i],i);
}
},
draw(){
this.each(c => {
c.draw();
})
},
addCircle(x,y,radius){
var circle = {x, y, radius, draw : this.drawCircle};
this.items.push(circle);
return circle;
},
getClosest(pos){
var minDist, i, dist, x, y, foundCircle;
minDist = Infinity;
this.each(c =>{
x = pos.x - c.x;
y = pos.y - c.y;
dist = Math.sqrt(x * x + y * y);
if(dist <= c.radius){
if(foundCircle === undefined || (foundCircle && c.radius < foundCircle.radius)){
minDist = dist;
foundCircle = c;
}
}
})
return foundCircle;
}
}
var dragging = {
started : false,
type : null,
currentObj : null, // what we are dragging
startX : 0,
startY : 0,
start(type, obj){
this.startX = mouse.x;
this.startY = mouse.y;
this.started = true;
this.type = type;
this.currentObj = obj;
}
}
var cursor = "default";
var overCircle = null;
function updateDisplay(){
var x,y, c;
cursor = "default"
if(mouse.x >= 0 && mouse.x < canvas.width && mouse.y >= 0 && mouse.y < canvas.height){
cursor = "crosshair";
}
if(mouse.button){ // the button is down
if(!dragging.started){
if(overCircle){
dragging.start("move",overCircle)
overCircle = null;
}else{
dragging.start("create",circles.addCircle(mouse.x, mouse.y, 1));
}
}
c = dragging.currentObj;
if(dragging.type === "create"){
x = c.x - mouse.x;
y = c.y - mouse.y;
c.radius = Math.sqrt(x * x + y * y);
}else if(dragging.type === "move"){
x = dragging.startX - mouse.x;
y = dragging.startY - mouse.y;
c.x -= x;
c.y -= y;
dragging.startX = mouse.x;
dragging.startY = mouse.y;
}
cursor = "none";
} else { // button must be up
if(dragging.started){ // have we been dragging something.
dragging.started = false; // drop it
}
}
ctx.strokeStyle = "black";
circles.draw();
if(!dragging.started){
c = circles.getClosest(mouse);
if(c !== undefined){
cursor = "move";
ctx.strokeStyle = "red";
ctx.fillStyle = "rgba(0,255,255,0.1)";
c.draw();
ctx.fill();
overCircle = c;
}else{
overCircle = null;
}
}
canvas.style.cursor = cursor;
}
<div style="font-family:12px arial;">Click drag to create circle</div>
请注意,这是在ES6中编写的,如果没有某种类型的编译器,则无法在IE上运行。
答案 2 :(得分:0)
var offsetx,offsety,posx,posy,run;
window.onmousedown=function(e){
run=true;
offsetx=e.clientX;
offsety=e.clientY;
};
window.onmouseup=function(){
run=false;
};
window.onmousemove=function(e){
if(run){
movedx=e.clientX-offsetx;//mouse moved this value
movedy=e.clientY-offsety;
posx+=movedx;
posy+=movedyy;
offsetx=e.clientX;
offsety=e.clientY
//todo draw at posx,posy
}
};
//todo draw circle+set posx,posy to its position