如何使HTML5可拖动对象在画布上? [英] How to make HTML5 draggable objects over canvas?
问题描述
我刚开始学习html5,我试图用可拖动的船创建一个战舰界面。我需要帮助,使我的拖动方法工作。我故意不使用库,因为我需要使船可拖动在另一个画布界面(战舰板),我不知道如何做的Kinetic库。我觉得我很近,但我不知道最后一点。
这是我的clode:
<!doctype html>
< html>
< head>
< meta charset =UTF-8/>
< title>画布拖放测试< / title>
< / head>
< body>
< section>
< div align = center>
< canvas id =canvaswidth =550height =550>
如果您的浏览器不支持HTML5 Canvas,则会显示此文本。
< / canvas>
< / div>
< script type =text / javascript>
var canvas;
var ctx;
var x = 75;
var y = 50;
var WIDTH = 550;
var HEIGHT = 550;
var dragok = false;
var ships = [];
var ship;
var shipFill =#FF0000;
//定义
//可拖动运营商
var caRectX = 100;
var caRectY = 50;
var caRectHeight = 50;
var caRectWidth = 5 * 50;
var carrier = {
x:caRectX,
y:caRectY,
width:caRectWidth,
height:caRectHeight,
fill:shipFill,
dragging:false,
offsetX:0,
offsetY:0,
};
ships.push(carrier);
// Draggable战舰
var bsRectX = 100;
var bsRectY = 150;
var bsRectHeight = 50;
var bsRectWidth = 4 * 50;
var battleship = {
x:bsRectX,
y:bsRectY,
width:bsRectWidth,
height:bsRectHeight,
fill:shipFill,
dragging:false,
offsetX:0,
offsetY:0,
};
ships.push(battleship);
// Draggable Patrolboat
var pbRectX = 100;
var pbRectY = 250;
var pbRectHeight = 50;
var pbRectWidth = 2 * 50;
var patrolboat = {
x:pbRectX,
y:pbRectY,
width:pbRectWidth,
height:pbRectHeight,
fill:shipFill,
dragging:false,
offsetX:0,
offsetY:0,
};
ships.push(patrolboat);
// Draggable潜艇
var suRectX = 100;
var suRectY = 350;
var suRectHeight = 50;
var suRectWidth = 3 * 50;
var submarine = {
x:suRectX,
y:suRectY,
width:suRectWidth,
height:suRectHeight,
fill:shipFill,
dragging:false,
offsetX:0,
offsetY:0,
};
ships.push(submarine);
//可拖动驱逐舰
var deRectX = 100;
var deRectY = 450;
var deRectHeight = 50;
var deRectWidth = 3 * 50;
var destroyer = {
x:deRectX,
y:deRectY,
width:deRectWidth,
height:deRectHeight,
dragging:
fill:shipFill
};
ships.push(destroyer)
function rect(x,y,w,h){
ctx.beginPath();
ctx.rect(x,y,w,h);
ctx.closePath();
ctx.fill();
}
函数clear(){
ctx.clearRect(0,0,WIDTH,HEIGHT);
}
function init(){
canvas = document.getElementById(canvas);
ctx = canvas.getContext(2d);
return setInterval(draw,10);
}
function draw(){
clear();
ctx.fillStyle =#FAF7F8;
rect(0,0,WIDTH,HEIGHT);
ctx.fillStyle =#444444;
for(var i = 0; i< ships.length; i ++){
rect(ships [i] .x,ships [i] .y,ships [i] .width,ships [ i] .height);
}
}
function myMove(e){
if(ship.dragging){
ship.x = e.pageX - canvas.offsetLeft ;
ship.y = e.pageY - canvas.offsetTop;
draw()
}
}
function myDown(e){
ship = getClickedShip(e.pageX,e.pageY);
if(ship!= null){
ship.x = e.pageX - canvas.offsetLeft;
ship.y = e.pageY - canvas.offsetTop;
ship.dragging = true;
canvas.onmousemove = myMove();
}
}
function myUp(){
ship.dragging = false;
canvas.onmousemove = null;
}
function getClickedShip(sx,sy){
for(var i = 0; i< ships.length; i ++){
if(sx> ;(ships [i] .x)+ canvas.offsetLeft&& sx<(ships [i] .x + ships [i] .width + canvas.offsetLeft)&& .y + canvas.offsetTop)&& sy<(ships [i] .y + ships [i] .height))
return ships [i];
}
}
init();
canvas.onmousedown = myDown
canvas.onmouseup = myUp;
< / script>
< / section>
< / body>
< / html>
形状可拖动
请注意,这在SO之前已经回答过了但这个答案说明了新的context.isPointInPath方法来测试一个点是否在一个html画布路径内。
希望这种新的命中测试方法将是新的&对于OP和其他人有用:)
下面是在html canvas中拖动形状的一般过程:
在mouseDown:
- 将此mouseX位置保存在变量中(lastX)
- 在变量(lastY)中保存此鼠标Y位置
- 将mouseIsDown标记设置为true
On mouseUp
- 将mouseIsDown标记设置为false
在mouseMove
- 点击测试每艘船是否应该拖动。
- 如果最后一个X / lastY在船内,则会拖动该船
- 将拖动的船只移动鼠标刚移动的距离
MouseDown处理程式码:
function handleMouseDown (e){
//获取相对于画布的当前鼠标位置
mouseX = parseInt(e.clientX-offsetX);
mouseY = parseInt(e.clientY-offsetY);
//保存最后一个mouseX / mouseY
lastX = mouseX;
lastY = mouseY;
//设置mouseIsDown标志
mouseIsDown = true;
}
MouseUp处理程序代码:
function handleMouseUp(e){
//清除mouseIsDown标志
mouseIsDown = false ;
}
MouseMove处理程序代码:
此代码说明使用 context.isPointInPath
命中测试html画布路径
这样做的过程是:
- 定义一个路径(但不能绘制它 - 没有填充, li>
- 使用
context.isPointInPath(x,y)
测试x,y是否在上述路径内。
这里是使用context.isPointInPath
的mouseMove处理程序 handleMouseMove(e){
//如果mouseIsDown标志没有设置,没有工作
if(!mouseIsDown){return; }
// get mouseX / mouseY
mouseX = parseInt(e.clientX-offsetX);
mouseY = parseInt(e.clientY-offsetY);
//在ships数组中的每个ship
//使用context.isPointInPath测试是否被拖动
for(var i = 0; i< ships.length; i ++){
var ship = ships [i];
drawShip(ship);
if(ctx.isPointInPath(lastX,lastY)){
//如果这艘船被拖动,
//通过鼠标位置从lastXY改变到currentXY
ship.x + =(mouseX-lastX);
ship.y + =(mouseY-lastY);
ship.right = ship.x + ship.width;
ship.bottom = ship.y + ship.height;
}
}
//将lastXY更新为当前鼠标位置
lastX = mouseX;
lastY = mouseY;
//绘制所有船舶的新位置
drawAllShips();
}
注意增强效果:
- 在生产中,您需要让mouseMove仅保存鼠标位置。
- 然后,另一个过程检索保存的位置,
p>这里是代码和小提琴: http://jsfiddle.net/m1erickson/sEBAC/ p>
<!doctype html>
< html>
< head>
< link rel =stylesheettype =text / cssmedia =allhref =css / reset.css/> <! - reset css - >
< script type =text / javascriptsrc =http://code.jquery.com/jquery.min.js>< / script>
< style>
body {background-color:ivory; }
canvas {border:1px solid red;}
< / style>
< script>
$(function(){
var canvas = document.getElementById(canvas);
var ctx = canvas.getContext(2d);
ctx.strokeStyle =lightgray;
var canvasOffset = $(#canvas)。offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset .top;
var mouseIsDown = false;
var lastX = 0;
var lastY = 0;
var ships = [];
// make some ship
makeShip(20,30,50,25,skyblue);
makeShip(20,100,30,25,skyblue);
makeShip(20,170,50,25,salmon);
makeShip(20,240,30,25,salmon);
function makeShip(x,y,width, fill){
var ship = {
x:x,
y:y,
width:width,
height:height,
right:x + width ,
bottom:y + height,
fill:fill
}
ships.push(ship);
return(ship);
}
drawAllShips();
function drawAllShips(){
ctx.clearRect(0,0,canvas.width,canvas.height);
for(var i = 0; i< ships.length; i ++){
var ship = ships [i]
drawShip(ship);
ctx.fillStyle = ship.fill;
ctx.fill();
ctx.stroke();
}
}
function drawShip(ship){
ctx.beginPath();
ctx.moveTo(ship.x,ship.y);
ctx.lineTo(ship.right,ship.y);
ctx.lineTo(ship.right + 10,ship.y + ship.height / 2);
ctx.lineTo(ship.right,ship.bottom);
ctx.lineTo(ship.x,ship.bottom);
ctx.closePath();
}
function handleMouseDown(e){
mouseX = parseInt(e.clientX-offsetX);
mouseY = parseInt(e.clientY-offsetY);
//这里的mousedown东西
lastX = mouseX;
lastY = mouseY;
mouseIsDown = true;
}
function handleMouseUp(e){
mouseX = parseInt(e.clientX-offsetX);
mouseY = parseInt(e.clientY-offsetY);
// mouseup stuff here
mouseIsDown = false;
}
function handleMouseMove(e){
if(!mouseIsDown){return; }
mouseX = parseInt(e.clientX-offsetX);
mouseY = parseInt(e.clientY-offsetY);
//这里的mousemove东西
for(var i = 0; i< ships.length; i ++){
var ship = ships [i]
drawShip(ship);
if(ctx.isPointInPath(lastX,lastY)){
ship.x + =(mouseX-lastX);
ship.y + =(mouseY-lastY);
ship.right = ship.x + ship.width;
ship.bottom = ship.y + ship.height;
}
}
lastX = mouseX;
lastY = mouseY;
drawAllShips();
}
$(#canvas)。mousedown(function(e){handleMouseDown(e);});
$(#canvas)。mousemove(function(e){handleMouseMove(e);});
$(#canvas)mouseup(function(e){handleMouseUp(e);});
}); // end $(function(){});
< / script>
< / head>
< body>
< canvas id =canvaswidth = 300 height = 300>< / canvas>
< / body>
< / html>
I just started learning html5 and I am trying to create a battleship interface with draggable ships. I need help making my dragging methods work. I am purposely not using a library because I need make the ships draggable over another canvas interface (the battleship board), which I could not figure out how to do with the Kinetic library. I feel like I am close, but I cannot figure out the last bit. The ships should be smoothly dragged but they seem to snap to the location of the mouse when clicked...
Here is my clode:
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Canvas Drag and Drop Test</title>
</head>
<body>
<section>
<div align=center>
<canvas id="canvas" width="550" height="550">
This text is displayed if your browser does not support HTML5 Canvas.
</canvas>
</div>
<script type="text/javascript">
var canvas;
var ctx;
var x = 75;
var y = 50;
var WIDTH = 550;
var HEIGHT = 550;
var dragok = false;
var ships = [];
var ship;
var shipFill = "#FF0000";
//Definitions
//Draggable Carrier
var caRectX = 100;
var caRectY = 50;
var caRectHeight = 50;
var caRectWidth = 5 * 50;
var carrier = {
x : caRectX,
y : caRectY,
width : caRectWidth,
height : caRectHeight,
fill : shipFill,
dragging : false,
offsetX : 0,
offsetY : 0,
};
ships.push(carrier);
//Draggable Battleship
var bsRectX = 100;
var bsRectY = 150;
var bsRectHeight = 50;
var bsRectWidth = 4 * 50;
var battleship = {
x : bsRectX,
y : bsRectY,
width : bsRectWidth,
height : bsRectHeight,
fill : shipFill,
dragging : false,
offsetX : 0,
offsetY : 0,
};
ships.push(battleship);
//Draggable Patrolboat
var pbRectX = 100;
var pbRectY = 250;
var pbRectHeight = 50;
var pbRectWidth = 2 * 50;
var patrolboat = {
x : pbRectX,
y : pbRectY,
width : pbRectWidth,
height : pbRectHeight,
fill : shipFill,
dragging : false,
offsetX : 0,
offsetY : 0,
};
ships.push(patrolboat);
//Draggable Submarine
var suRectX = 100;
var suRectY = 350;
var suRectHeight = 50;
var suRectWidth = 3 * 50;
var submarine = {
x : suRectX,
y : suRectY,
width : suRectWidth,
height : suRectHeight,
fill : shipFill,
dragging : false,
offsetX : 0,
offsetY : 0,
};
ships.push(submarine);
//Draggable destroyer
var deRectX = 100;
var deRectY = 450;
var deRectHeight = 50;
var deRectWidth = 3 * 50;
var destroyer = {
x : deRectX,
y : deRectY,
width : deRectWidth,
height : deRectHeight,
dragging : false,
fill : shipFill
};
ships.push(destroyer)
function rect(x, y, w, h) {
ctx.beginPath();
ctx.rect(x, y, w, h);
ctx.closePath();
ctx.fill();
}
function clear() {
ctx.clearRect(0, 0, WIDTH, HEIGHT);
}
function init() {
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
return setInterval(draw, 10);
}
function draw() {
clear();
ctx.fillStyle = "#FAF7F8";
rect(0, 0, WIDTH, HEIGHT);
ctx.fillStyle = "#444444";
for (var i = 0; i < ships.length; i++) {
rect(ships[i].x, ships[i].y, ships[i].width, ships[i].height);
}
}
function myMove(e) {
if (ship.dragging) {
ship.x = e.pageX - canvas.offsetLeft;
ship.y = e.pageY - canvas.offsetTop;
draw()
}
}
function myDown(e) {
ship = getClickedShip(e.pageX,e.pageY);
if (ship!=null) {
ship.x = e.pageX - canvas.offsetLeft;
ship.y = e.pageY - canvas.offsetTop;
ship.dragging = true;
canvas.onmousemove = myMove();
}
}
function myUp() {
ship.dragging = false;
canvas.onmousemove = null;
}
function getClickedShip(sx,sy){
for (var i = 0; i < ships.length; i++){
if(sx > (ships[i].x )+ canvas.offsetLeft && sx < (ships[i].x+ships[i].width+ canvas.offsetLeft) && sy > (ships[i].y + canvas.offsetTop) && sy < (ships[i].y+ships[i].height))
return ships[i];
}
}
init();
canvas.onmousedown = myDown;
canvas.onmouseup = myUp;
</script>
</section>
</body>
</html>
This is the procedure for making an html shape draggable
Note that this has been answered before on SO (many times!)
But this answer illustrates the new context.isPointInPath method to hit-test whether a point is inside an html canvas path.
Hopefully, this new hit-testing method will be new & useful to the OP and others :)
Here's the general procedure for dragging shapes in html canvas:
On mouseDown:
- save this mouseX position in a variable (lastX)
- save this mouseY position in a variable (lastY)
- set the mouseIsDown flag to true
On mouseUp
- set the mouseIsDown flag to false
On mouseMove
- Hit-test each ship to see if it should be dragged.
- If the lastX/lastY was inside a ship, that ship is being dragged
- Move dragging ships by the distance the mouse has just moved
MouseDown handler code:
function handleMouseDown(e){
// get the current mouse position relative to the canvas
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// save this last mouseX/mouseY
lastX=mouseX;
lastY=mouseY;
// set the mouseIsDown flag
mouseIsDown=true;
}
MouseUp handler code:
function handleMouseUp(e){
// clear the mouseIsDown flag
mouseIsDown=false;
}
MouseMove handler code:
This code illustrates using context.isPointInPath
to hit-test an html canvas path
The procedure to do that is:
- define a path (but not draw it -- no fill, no stroke)
- use
context.isPointInPath(x,y)
to test if x,y are inside the path defined above.
Here's the mouseMove handler using context.isPointInPath
function handleMouseMove(e){
// if the mouseIsDown flag is’nt set, no work to do
if(!mouseIsDown){ return; }
// get mouseX/mouseY
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// for each ship in the ships array
// use context.isPointInPath to test if it’s being dragged
for(var i=0;i<ships.length;i++){
var ship=ships[i];
drawShip(ship);
if(ctx.isPointInPath(lastX,lastY)){
// if this ship’s being dragged,
// move it by the change in mouse position from lastXY to currentXY
ship.x+=(mouseX-lastX);
ship.y+=(mouseY-lastY);
ship.right=ship.x+ship.width;
ship.bottom=ship.y+ship.height;
}
}
// update the lastXY to the current mouse position
lastX=mouseX;
lastY=mouseY;
// draw all ships in their new positions
drawAllShips();
}
Note about enhancing performance:
- In production, you'll want to have the mouseMove just save the mouse positions.
- Then have another procedure retrieve those saved positions and do hit-testing/redrawing.
- That other procedure will probably be inside a timed loop like requestAnimationFrame.
Here’s code and a Fiddle: http://jsfiddle.net/m1erickson/sEBAC/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
ctx.strokeStyle="lightgray";
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var mouseIsDown=false;
var lastX=0;
var lastY=0;
var ships=[];
// make some ship
makeShip(20,30,50,25,"skyblue");
makeShip(20,100,30,25,"skyblue");
makeShip(20,170,50,25,"salmon");
makeShip(20,240,30,25,"salmon");
function makeShip(x,y,width,height,fill){
var ship={
x:x,
y:y,
width:width,
height:height,
right:x+width,
bottom:y+height,
fill:fill
}
ships.push(ship);
return(ship);
}
drawAllShips();
function drawAllShips(){
ctx.clearRect(0,0,canvas.width,canvas.height);
for(var i=0;i<ships.length;i++){
var ship=ships[i]
drawShip(ship);
ctx.fillStyle=ship.fill;
ctx.fill();
ctx.stroke();
}
}
function drawShip(ship){
ctx.beginPath();
ctx.moveTo(ship.x,ship.y);
ctx.lineTo(ship.right,ship.y);
ctx.lineTo(ship.right+10,ship.y+ship.height/2);
ctx.lineTo(ship.right,ship.bottom);
ctx.lineTo(ship.x,ship.bottom);
ctx.closePath();
}
function handleMouseDown(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// mousedown stuff here
lastX=mouseX;
lastY=mouseY;
mouseIsDown=true;
}
function handleMouseUp(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// mouseup stuff here
mouseIsDown=false;
}
function handleMouseMove(e){
if(!mouseIsDown){ return; }
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// mousemove stuff here
for(var i=0;i<ships.length;i++){
var ship=ships[i];
drawShip(ship);
if(ctx.isPointInPath(lastX,lastY)){
ship.x+=(mouseX-lastX);
ship.y+=(mouseY-lastY);
ship.right=ship.x+ship.width;
ship.bottom=ship.y+ship.height;
}
}
lastX=mouseX;
lastY=mouseY;
drawAllShips();
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
这篇关于如何使HTML5可拖动对象在画布上?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!