我有这个问题,我不知道如何处理它。 我花了将近 2 个小时才修复它。我尝试了各种方法,但没有运气。如果这是一个无聊的问题,请原谅我并深入解释你所做的每一步。
我创建了一个 Canvas ,并在其中画了一个圆圈。现在,我想用鼠标移动圆圈,但鼠标按住。有什么办法可以做到,还是我只是在浪费时间? 这是代码:
<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>
我尝试过的一些方法。这些留在备注/**/。其他的我都删掉了。
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);
}
}
最佳答案
动画和用户界面
当您在 Canvas 上拖动任何东西时,您实际上是在为 Canvas 设置动画。为获得最佳结果,您需要停止思考如何使用 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()
KISS IO 事件。
鼠标、键盘、触摸等事件处理程序不应执行任何功能逻辑。这些事件可以非常快速地触发,但显示每 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
函数,它获取鼠标下方的圆圈。它将返回鼠标下的最小圆圈。如果鼠标下没有任何内容,它将返回未定义。
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;
}
}
如何拖动。
拖动对象涉及很多内容。您需要一个函数来找到离鼠标最近的对象。您需要提供反馈,以便用户可以看到可以拖动的内容。
您最终可能会遇到许多不同的拖动类型事件。拖动以创建、拖动以移动、将某物拖到 Canvas 上或操作自定义呈现的 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>
Note this is written in ES6 and will not run on IE without some type of compiler.
关于javascript - 如何用鼠标(按住时)从 Canvas 上移动一个圆圈?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41333845/