수색…
모양과 이미지가 실제로 캔버스에서 "이동"하는 방법 (!)
문제 : 캔버스는 모양이나 이미지가 아닌 픽셀 만 기억합니다.
이것은 순환 해변 공의 이미지이며 물론 이미지 주위에 공을 드래그 할 수 없습니다.
캔버스에 서클을 그릴 경우 캔버스에서 그 원을 드래그 할 수 없습니다. 캔버스가 원을 그린 위치를 기억하지 않기 때문입니다.
// this arc (==circle) is not draggable!!
context.beginPath();
context.arc(20, 30, 15, 0, Math.PI*2);
context.fillStyle='blue';
context.fill();
Canvas가 알지 못하는 것 ...
- ... 당신이 원을 그렸던 곳 (그것은 x, y = [20,30]을 모릅니다).
- ... 원의 크기 (반지름 = 15을 알지 못함).
- ... 원의 색깔. (그것은 원이 파란색이라는 것을 모릅니다).
캔버스가 아는 것 ...
캔버스는 드로잉 표면에있는 모든 픽셀의 색상을 알고 있습니다.
캔버스는 x, y == [20,30]에 파란색 픽셀이 있음을 알 수 있지만이 파란색 픽셀이 원의 일부인지 여부는 알 수 없습니다.
이게 무슨 뜻이야...
이것은 Canvas에 그려지는 모든 것이 영구적이라는 것을 의미합니다 : 움직이지 않고 변경할 수 없습니다.
- 캔버스는 원을 이동하거나 원의 크기를 조정할 수 없습니다.
- Canvas는 원을 다시 칠하거나 원을 지울 수 없습니다.
- Canvas는 마우스가 서클 위로 마우스를 가져 갔는지 여부를 말할 수 없습니다.
- Canvas는 원이 다른 원과 충돌하는지 말할 수 없습니다.
- 캔버스는 사용자가 캔버스 주위로 원을 끌 수 없도록합니다.
그러나 Canvas는 ILLUSION의 움직임을 줄 수 있습니다.
캔버스는 연속적으로 원을 지우고 다른 위치로 다시 그려 이동 의 환상을 줄 수 있습니다. 초당 캔버스를 여러 번 다시 그리면 눈은 캔버스에서 원이 움직이는 것을 보게됩니다.
캔버스 지우기
서클의 위치 업데이트
새 위치에 서클을 다시 그립니다.
반복, 반복, 반복 ...
이 코드는 새로운 위치에 서클을 계속해서 다시 그려줌으로써 움직이는 것처럼 보입니다 .
// create a canvas
var canvas=document.createElement("canvas");
var ctx=canvas.getContext("2d");
ctx.fillStyle='red';
document.body.appendChild(canvas);
// a variable indicating a circle's X position
var circleX=20;
// start animating the circle across the canvas
// by continuously erasing & redrawing the circle
// in new positions
requestAnimationFrame(animate);
function animate(){
// update the X position of the circle
circleX++;
// redraw the circle in it's new position
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.beginPath();
ctx.arc( circleX, 30,15,0,Math.PI*2 );
ctx.fill();
// request another animate() loop
requestAnimationFrame(animate);
}
캔버스 주위에서 원형 및 직사각형 끌기
"모양"이란 무엇입니까?
일반적으로 각 모양을 나타내는 JavaScript "shape"객체를 만들어서 모양을 저장합니다.
var myCircle = { x:30, y:20, radius:15 };
물론, 당신은 실제로 도형을 저장하지 않습니다. 대신 모양을 그리는 방법의 정의를 저장하고 있습니다.
그런 다음 각 쉐이프 객체를 쉽게 참조 할 수 있도록 배열에 배치하십시오.
// save relevant information about shapes drawn on the canvas
var shapes=[];
// define one circle and save it in the shapes[] array
shapes.push( {x:10, y:20, radius:15, fillcolor:'blue'} );
// define one rectangle and save it in the shapes[] array
shapes.push( {x:10, y:100, width:50, height:35, fillcolor:'red'} );
마우스 이벤트를 사용하여 드래그하기
모양이나 이미지를 드래그하면 다음 마우스 이벤트에 응답해야합니다.
mousedown에서 :
마우스 아래에 도형이 있는지 테스트하십시오. 셰이프가 마우스 아래에 있으면 사용자가 해당 셰이프를 끌려고합니다. 따라서 해당 모양에 대한 참조를 유지하고 끌기가 진행 중임을 나타내는 true / false isDragging
플래그를 설정합니다.
mousemove에서 :
마지막 mousemove
이벤트 이후 마우스가 드래그 된 거리를 계산하고 드래그 된 모양의 위치를 그 거리만큼 변경하십시오. 도형의 위치를 변경하려면 해당 도형의 객체에서 x,y
위치 속성을 변경합니다.
마우스 업 또는 마우스 아웃시 :
사용자가 드래그 작업을 중지하려고하므로 "isDragging"플래그를 지 웁니다. 끌기가 완료되었습니다.
데모 : 캔버스에서 원형 및 직사각형 드래그
이 데모는 마우스 이벤트에 응답하고 지우기 및 다시 그리기로 움직이는듯한 환상을주는 것으로 캔버스에서 원형 및 직사각형을 드래그합니다.
// canvas related vars
var canvas=document.createElement("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
document.body.appendChild(canvas);
canvas.style.border='1px solid red';
// used to calc canvas position relative to window
function reOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
window.onresize=function(e){ reOffset(); }
canvas.onresize=function(e){ reOffset(); }
// save relevant information about shapes drawn on the canvas
var shapes=[];
// define one circle and save it in the shapes[] array
shapes.push( {x:30, y:30, radius:15, color:'blue'} );
// define one rectangle and save it in the shapes[] array
shapes.push( {x:100, y:-1, width:75, height:35, color:'red'} );
// drag related vars
var isDragging=false;
var startX,startY;
// hold the index of the shape being dragged (if any)
var selectedShapeIndex;
// draw the shapes on the canvas
drawAll();
// listen for mouse events
canvas.onmousedown=handleMouseDown;
canvas.onmousemove=handleMouseMove;
canvas.onmouseup=handleMouseUp;
canvas.onmouseout=handleMouseOut;
// given mouse X & Y (mx & my) and shape object
// return true/false whether mouse is inside the shape
function isMouseInShape(mx,my,shape){
if(shape.radius){
// this is a circle
var dx=mx-shape.x;
var dy=my-shape.y;
// math test to see if mouse is inside circle
if(dx*dx+dy*dy<shape.radius*shape.radius){
// yes, mouse is inside this circle
return(true);
}
}else if(shape.width){
// this is a rectangle
var rLeft=shape.x;
var rRight=shape.x+shape.width;
var rTop=shape.y;
var rBott=shape.y+shape.height;
// math test to see if mouse is inside rectangle
if( mx>rLeft && mx<rRight && my>rTop && my<rBott){
return(true);
}
}
// the mouse isn't in any of the shapes
return(false);
}
function handleMouseDown(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// calculate the current mouse position
startX=parseInt(e.clientX-offsetX);
startY=parseInt(e.clientY-offsetY);
// test mouse position against all shapes
// post result if mouse is in a shape
for(var i=0;i<shapes.length;i++){
if(isMouseInShape(startX,startY,shapes[i])){
// the mouse is inside this shape
// select this shape
selectedShapeIndex=i;
// set the isDragging flag
isDragging=true;
// and return (==stop looking for
// further shapes under the mouse)
return;
}
}
}
function handleMouseUp(e){
// return if we're not dragging
if(!isDragging){return;}
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// the drag is over -- clear the isDragging flag
isDragging=false;
}
function handleMouseOut(e){
// return if we're not dragging
if(!isDragging){return;}
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// the drag is over -- clear the isDragging flag
isDragging=false;
}
function handleMouseMove(e){
// return if we're not dragging
if(!isDragging){return;}
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// calculate the current mouse position
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// how far has the mouse dragged from its previous mousemove position?
var dx=mouseX-startX;
var dy=mouseY-startY;
// move the selected shape by the drag distance
var selectedShape=shapes[selectedShapeIndex];
selectedShape.x+=dx;
selectedShape.y+=dy;
// clear the canvas and redraw all shapes
drawAll();
// update the starting drag position (== the current mouse position)
startX=mouseX;
startY=mouseY;
}
// clear the canvas and
// redraw all shapes in their current positions
function drawAll(){
ctx.clearRect(0,0,cw,ch);
for(var i=0;i<shapes.length;i++){
var shape=shapes[i];
if(shape.radius){
// it's a circle
ctx.beginPath();
ctx.arc(shape.x,shape.y,shape.radius,0,Math.PI*2);
ctx.fillStyle=shape.color;
ctx.fill();
}else if(shape.width){
// it's a rectangle
ctx.fillStyle=shape.color;
ctx.fillRect(shape.x,shape.y,shape.width,shape.height);
}
}
}
캔버스 주위의 불규칙한 도형 드래그
대부분의 캔버스 도면은 직사각형 (직사각형, 이미지, 텍스트 블록) 또는 원형 (원)입니다.
원과 사각형에는 마우스가 안에 있는지 확인하는 수학적 테스트가 있습니다. 따라서 원과 직사각형을 쉽고 빠르게 테스트 할 수 있습니다. 수백 초의 원이나 직사각형을 "히트 테스트"할 수 있습니다.
불규칙한 도형을 끌 수도 있습니다. 그러나 불규칙한 형태는 빠른 수학적 히트 - 테스트가 없습니다. 다행히 불규칙한 모양에는 점 (마우스)이 모양 안에 있는지 확인하기위한 히트 테스트가 내장되어 있습니다 ( context.isPointInPath
. isPointInPath
는 잘 작동하지만 순전히 수학적 히트 테스트만큼 효율적이지는 않습니다. 순수 수학적 히트 테스트보다 최대 10 배 느린 경우가 많습니다.
isPointInPath
를 사용할 때 하나의 요구 사항은 isPointInPath
를 호출하기 전에 테스트중인 Path를 "재정의"해야한다는 것입니다. "재정의"란 위와 같이 패스 드로잉 명령을 실행해야 함을 의미하지만 isPointInPath
패스를 테스트하기 전에 패스를 stroke () 또는 fill () 할 필요가 없습니다. 이렇게하면 Canvas 자체에서 이전 경로를 덮어 쓰지 않고 (획 / 채우기) 수행 할 필요없이 이전에 그린 패스를 테스트 할 수 있습니다.
불규칙한 모양은 일상의 삼각형만큼 일반적 일 필요는 없습니다. 격렬하게 불규칙한 경로를 치는 것도 가능합니다.
이 주석 된 예제는 불규칙한 패스 모양과 원과 직사각형을 드래그하는 방법을 보여줍니다.
// canvas related vars
var canvas=document.createElement("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
document.body.appendChild(canvas);
canvas.style.border='1px solid red';
// used to calc canvas position relative to window
function reOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
window.onresize=function(e){ reOffset(); }
canvas.onresize=function(e){ reOffset(); }
// save relevant information about shapes drawn on the canvas
var shapes=[];
// define one circle and save it in the shapes[] array
shapes.push( {x:20, y:20, radius:15, color:'blue'} );
// define one rectangle and save it in the shapes[] array
shapes.push( {x:100, y:-1, width:75, height:35, color:'red'} );
// define one triangle path and save it in the shapes[] array
shapes.push( {x:0, y:0, points:[{x:50,y:30},{x:75,y:60},{x:25,y:60}],color:'green'} );
// drag related vars
var isDragging=false;
var startX,startY;
// hold the index of the shape being dragged (if any)
var selectedShapeIndex;
// draw the shapes on the canvas
drawAll();
// listen for mouse events
canvas.onmousedown=handleMouseDown;
canvas.onmousemove=handleMouseMove;
canvas.onmouseup=handleMouseUp;
canvas.onmouseout=handleMouseOut;
// given mouse X & Y (mx & my) and shape object
// return true/false whether mouse is inside the shape
function isMouseInShape(mx,my,shape){
if(shape.radius){
// this is a circle
var dx=mx-shape.x;
var dy=my-shape.y;
// math test to see if mouse is inside circle
if(dx*dx+dy*dy<shape.radius*shape.radius){
// yes, mouse is inside this circle
return(true);
}
}else if(shape.width){
// this is a rectangle
var rLeft=shape.x;
var rRight=shape.x+shape.width;
var rTop=shape.y;
var rBott=shape.y+shape.height;
// math test to see if mouse is inside rectangle
if( mx>rLeft && mx<rRight && my>rTop && my<rBott){
return(true);
}
}else if(shape.points){
// this is a polyline path
// First redefine the path again (no need to stroke/fill!)
defineIrregularPath(shape);
// Then hit-test with isPointInPath
if(ctx.isPointInPath(mx,my)){
return(true);
}
}
// the mouse isn't in any of the shapes
return(false);
}
function handleMouseDown(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// calculate the current mouse position
startX=parseInt(e.clientX-offsetX);
startY=parseInt(e.clientY-offsetY);
// test mouse position against all shapes
// post result if mouse is in a shape
for(var i=0;i<shapes.length;i++){
if(isMouseInShape(startX,startY,shapes[i])){
// the mouse is inside this shape
// select this shape
selectedShapeIndex=i;
// set the isDragging flag
isDragging=true;
// and return (==stop looking for
// further shapes under the mouse)
return;
}
}
}
function handleMouseUp(e){
// return if we're not dragging
if(!isDragging){return;}
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// the drag is over -- clear the isDragging flag
isDragging=false;
}
function handleMouseOut(e){
// return if we're not dragging
if(!isDragging){return;}
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// the drag is over -- clear the isDragging flag
isDragging=false;
}
function handleMouseMove(e){
// return if we're not dragging
if(!isDragging){return;}
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// calculate the current mouse position
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// how far has the mouse dragged from its previous mousemove position?
var dx=mouseX-startX;
var dy=mouseY-startY;
// move the selected shape by the drag distance
var selectedShape=shapes[selectedShapeIndex];
selectedShape.x+=dx;
selectedShape.y+=dy;
// clear the canvas and redraw all shapes
drawAll();
// update the starting drag position (== the current mouse position)
startX=mouseX;
startY=mouseY;
}
// clear the canvas and
// redraw all shapes in their current positions
function drawAll(){
ctx.clearRect(0,0,cw,ch);
for(var i=0;i<shapes.length;i++){
var shape=shapes[i];
if(shape.radius){
// it's a circle
ctx.beginPath();
ctx.arc(shape.x,shape.y,shape.radius,0,Math.PI*2);
ctx.fillStyle=shape.color;
ctx.fill();
}else if(shape.width){
// it's a rectangle
ctx.fillStyle=shape.color;
ctx.fillRect(shape.x,shape.y,shape.width,shape.height);
}else if(shape.points){
// its a polyline path
defineIrregularPath(shape);
ctx.fillStyle=shape.color;
ctx.fill();
}
}
}
function defineIrregularPath(shape){
var points=shape.points;
ctx.beginPath();
ctx.moveTo(shape.x+points[0].x,shape.y+points[0].y);
for(var i=1;i<points.length;i++){
ctx.lineTo(shape.x+points[i].x,shape.y+points[i].y);
}
ctx.closePath();
}
캔버스 주위의 이미지 끌기
캔버스 주위로 도형을 드래그하는 일반적인 방법은이 예제 를 참조하십시오.
이 주석 된 예제는 캔버스 주위에 이미지를 드래그하는 방법을 보여줍니다.
// canvas related vars
var canvas=document.createElement("canvas");
var ctx=canvas.getContext("2d");
canvas.width=378;
canvas.height=378;
var cw=canvas.width;
var ch=canvas.height;
document.body.appendChild(canvas);
canvas.style.border='1px solid red';
// used to calc canvas position relative to window
function reOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
window.onresize=function(e){ reOffset(); }
canvas.onresize=function(e){ reOffset(); }
// save relevant information about shapes drawn on the canvas
var shapes=[];
// drag related vars
var isDragging=false;
var startX,startY;
// hold the index of the shape being dragged (if any)
var selectedShapeIndex;
// load the image
var card=new Image();
card.onload=function(){
// define one image and save it in the shapes[] array
shapes.push( {x:30, y:10, width:127, height:150, image:card} );
// draw the shapes on the canvas
drawAll();
// listen for mouse events
canvas.onmousedown=handleMouseDown;
canvas.onmousemove=handleMouseMove;
canvas.onmouseup=handleMouseUp;
canvas.onmouseout=handleMouseOut;
};
// put your image src here!
card.src='https://dl.dropboxusercontent.com/u/139992952/stackoverflow/card.png';
// given mouse X & Y (mx & my) and shape object
// return true/false whether mouse is inside the shape
function isMouseInShape(mx,my,shape){
// is this shape an image?
if(shape.image){
// this is a rectangle
var rLeft=shape.x;
var rRight=shape.x+shape.width;
var rTop=shape.y;
var rBott=shape.y+shape.height;
// math test to see if mouse is inside image
if( mx>rLeft && mx<rRight && my>rTop && my<rBott){
return(true);
}
}
// the mouse isn't in any of this shapes
return(false);
}
function handleMouseDown(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// calculate the current mouse position
startX=parseInt(e.clientX-offsetX);
startY=parseInt(e.clientY-offsetY);
// test mouse position against all shapes
// post result if mouse is in a shape
for(var i=0;i<shapes.length;i++){
if(isMouseInShape(startX,startY,shapes[i])){
// the mouse is inside this shape
// select this shape
selectedShapeIndex=i;
// set the isDragging flag
isDragging=true;
// and return (==stop looking for
// further shapes under the mouse)
return;
}
}
}
function handleMouseUp(e){
// return if we're not dragging
if(!isDragging){return;}
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// the drag is over -- clear the isDragging flag
isDragging=false;
}
function handleMouseOut(e){
// return if we're not dragging
if(!isDragging){return;}
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// the drag is over -- clear the isDragging flag
isDragging=false;
}
function handleMouseMove(e){
// return if we're not dragging
if(!isDragging){return;}
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// calculate the current mouse position
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// how far has the mouse dragged from its previous mousemove position?
var dx=mouseX-startX;
var dy=mouseY-startY;
// move the selected shape by the drag distance
var selectedShape=shapes[selectedShapeIndex];
selectedShape.x+=dx;
selectedShape.y+=dy;
// clear the canvas and redraw all shapes
drawAll();
// update the starting drag position (== the current mouse position)
startX=mouseX;
startY=mouseY;
}
// clear the canvas and
// redraw all shapes in their current positions
function drawAll(){
ctx.clearRect(0,0,cw,ch);
for(var i=0;i<shapes.length;i++){
var shape=shapes[i];
if(shape.image){
// it's an image
ctx.drawImage(shape.image,shape.x,shape.y);
}
}
}