To drag shapes drawn on canvas same as paint - javascript

I have tool similar to paint where i allow user to draw different shapes on canvas using mouse events.I want to allow the user to drag the shapes(same as paint) once they are drawn on canvas. Did anyone done like this before? I have already tried using OOPDragging but that didn't work in my case.Also my tool include all kind of shapes like Line,elbow connector,oval,text,image and not just circles and rectangles. Can anyone please suggest some easy to achieve solution for this as i need it ASAP.
Thanks in advance.

A Demo: http://jsfiddle.net/m1erickson/JrzM2/
Assume you've created this triangle in your paint program
And the points for that triangle are in an array like this:
[{x:0,y:20},{x:30,y:0},{x:70,y:45}]
To move that triangle to [20,35], you need to first offset the triangle by x:20 & y:35
var myTriangle={
x:20,
y:35,
points:[{x:0,y:20},{x:30,y:0},{x:70,y:45}]
}
Then you can draw the triangle at [20,35] like this:
Note that the offsets (20,35) are added to each point in the triangle's position
function draw(myTriangle){
var x=myTriangle.x;
var y=myTriangle.y;
var points=myTriangle.points;
ctx.beginPath();
ctx.moveTo( x+points[0].x, y+points[0].y );
for(var i=1;i<points.length;i++){
ctx.lineTo( x+points[i].x, y+points[i].y );
}
ctx.closePath();
ctx.fill();
}
To drag the triangle, you listen for mouse events
In mousedown, check if the mouse is over the triangle. If yes, start the drag.
In mousemove, add the distance the user dragged since the last mousemove to the triangle's position.
In mouseup, stop the drag
In mousedown
Canvas has a nice built-in function to test if any specified point is inside a path like the triangle.
This function is context.isPointInPath(mouseX,mouseY) and it tests if mouseX/mouseY is inside the last drawn path.
If the mouse was pressed over the triangle, we set the isSelected flag to indicate the triangle should be dragged with every mousemove.
So the mousedown function looks like this:
function handleMouseDown(e){
// tell the browser we're using mousedown,
// so don't bother doing any browser stuff with this event
e.preventDefault();
// get the current mouseX,mouseY position
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// test if mouseX,mouseY is inside the triangle
if(ctx.isPointInPath(startX,startY)){
// if yes, set the "isSelected" flag
// which indicates that the triangle should
// move with the mouse
isSelected=true;
}
}
In mousemove
The mousemove event is triggered about 20-30 times per second as the user moves the mouse.
In mousemove, if the triangle isSelected, we want to calculate how far the mouse has moved since the last mousemove event.
Then we want to change the x,y position of the triangle by the distance that the mouse has moved.
So the mousemove function looks like this:
function handleMouseMove(e){
// if the triangle wasn't selected during mousedown
// there's nothing to do, so just return
if(!isSelected){return;}
e.preventDefault();
// get the current mouse position
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// calculate how far the mouse has moved since the last mousemove
var dx=mouseX-startX;
var dy=mouseY-startY;
// for next mousemove, reset the starting XY to the current XY
startX=mouseX;
startY=mouseY;
// move the triangle by the change in mouse position
myTriangle.x+=dx;
myTriangle.y+=dy;
// clear the canvas and
// redraw the triangle at its new position
context.clearRect(0,0,canvas.width,canvas.height);
draw(myTriangle);
}
In mouseup
In mouseup, the isSelected flag is cleared since the drag is over:
function handleMouseUp(e){
e.preventDefault();
isSelected=false;
}
Here's code for a more complex example with multiple shapes:
<!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(){
// vars related to canvas
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var $canvas=$("#canvas");
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var scrollX=$canvas.scrollLeft();
var scrollY=$canvas.scrollTop();
var cw=canvas.width;
var ch=canvas.height;
// vars related to dragging
var isDown=false;
var startX;
var startY;
// save your shape-points in
var shapes=[];
var selectedShape=null;
// test shapes
addShape(50,50,[{x:0,y:20},{x:30,y:0},{x:70,y:45}],"blue","red");
addShape(100,100,
[{x:0,y:10},{x:30,y:10},{x:30,y:0},
{x:45,y:15},{x:30,y:30},{x:30,y:20},{x:0,y:20}],
"green","red");
// begin...
drawAll();
function addShape(x,y,points,fill,stroke){
shapes.push({x:x,y:y,points:points,fill:fill,stroke:stroke});
}
function define(shape){
var x=shape.x;
var y=shape.y;
var points=shape.points;
ctx.beginPath();
ctx.moveTo(x+points[0].x,y+points[0].y);
for(var i=1;i<points.length;i++){
ctx.lineTo(x+points[i].x,y+points[i].y);
}
ctx.closePath();
}
function draw(shape){
define(shape);
ctx.fillStyle=shape.fill;
ctx.fill();
ctx.strokeStyle=shape.stroke;
ctx.stroke();
}
function drawAll(){
ctx.clearRect(0,0,cw,ch);
for(var i=0;i<shapes.length;i++){
draw(shapes[i]);
}
}
function handleMouseDown(e){
e.preventDefault();
startX=parseInt(e.clientX-offsetX);
startY=parseInt(e.clientY-offsetY);
for(var i=0;i<shapes.length;i++){
define(shapes[i]);
if(ctx.isPointInPath(startX,startY)){
selectedShape=shapes[i];
isDown=true;
}
}
}
function handleMouseUp(e){
e.preventDefault();
isDown=false;
selectedShape=null;
}
function handleMouseOut(e){
e.preventDefault();
isDown=false;
selectedShape=null;
}
function handleMouseMove(e){
if(!isDown){return;}
e.preventDefault();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
var dx=mouseX-startX;
var dy=mouseY-startY;
startX=mouseX;
startY=mouseY;
selectedShape.x+=dx;
selectedShape.y+=dy;
drawAll();
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
$("#canvas").mouseout(function(e){handleMouseOut(e);});
}); // end $(function(){});
</script>
</head>
<body>
<h4>Drag the shapes around the canvas</h4>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

I had the same problem some time ago, but I only needed lines, but I think you can use my solution for all the different shapes.
Basically you'll need to overlapping canvases, one that listens to the mouse events and draws the temporary shape, once the user releases the mouse button, you get the values and draw the shape on the original canvas. Here's a link to what I did: http://www.zhereicome.com/experiments/statics/drawtogether/
and the main js file:
http://www.zhereicome.com/experiments/statics/drawtogether/js/main.js
The important part is:
temp_canvas.onmousemove = function(e) {
//console.log(e);
if ( self.mouseDown ) {
self.drawTempLine(e.clientX, e.clientY);
}
}
temp_canvas.onmousedown = function(e) {
start = {
x: e.clientX,
y: e.clientY
}
self.mouseDown = true;
}
temp_canvas.onmouseup = function(e) {
end = {
x: e.clientX,
y: e.clientY
}
self.mouseDown = false;
self.sendToServer(); //When the user has finished drawing the line, send it to the server
}
I have a function sendToServer() because my project was a realtime multiplayer drawing app. In your case you'll have to replace it with a drawOnFinalCanvas();

Related

How to redraw mouse movement on a canvas?

I have an array of tuples in javascript. Is there an existing library that lets me view the mouse movements the user performed?
Ideally something that lets me replay the captured data from the beginning to the end. It would look like a video player (ie play, pause, adjust replay speed), but instead of a video you would see how the mouse cursor moved. This visualization would be on HTML5 canvas (ie. a square of white pixels representing the cursor that's moving through in a black HTML canvas).
Simple enough to accomplish without a library.
Listen for mousemove events
On mousemove, add each mouse position to a points array
When requested, run an requestAnimationFrame loop that redraws each point from the points array.
Example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
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(); }
var isDown=false;
var points=[];
var nextTime=0;
var nextN=0;
var duration=1000/60;
ctx.lineCap='round';
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUpOut(e);});
$("#canvas").mouseout(function(e){handleMouseUpOut(e);});
$('#fast').on('click',function(){ duration=1000/60; beginRedrawing(); });
$('#slow').on('click',function(){ duration=1000/15; beginRedrawing(); });
function beginRedrawing(){
if(points.length<2){return;}
nextN=1;
ctx.lineWidth=3;
ctx.strokeStyle=randomColor();
requestAnimationFrame(redraw);
}
function handleMouseDown(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// get current mouse position
ctx.lineWidth=7;
ctx.strokeStyle='black';
points.length=0;
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
points.push({x:mouseX,y:mouseY});
// Set dragging flag
isDown=true;
}
function handleMouseUpOut(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// get current mouse position
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Clear dragging flag
isDown=false;
}
function handleMouseMove(e){
if(!isDown){return;}
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// get current mouse position
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
points.push({x:mouseX,y:mouseY});
var n=points.length-1;
lineSegment(points[n-1],points[n]);
}
function lineSegment(p0,p1){
ctx.beginPath();
ctx.moveTo(p0.x,p0.y);
ctx.lineTo(p1.x,p1.y);
ctx.stroke();
}
function redraw(time){
if(nextN>points.length-1){return;}
if(time<nextTime){requestAnimationFrame(redraw);return;}
nextTime=time+duration;
lineSegment(points[nextN-1],points[nextN]);
nextN++;
requestAnimationFrame(redraw);
}
function randomColor(){
return('#'+Math.floor(Math.random()*16777215).toString(16));
}
body{ background-color: ivory; }
#canvas{border:1px solid red; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Drag to create polyline then click a redraw button below.</h4>
<button id=fast>Fast Redraw</button>
<button id=slow>Slow Redraw</button>
<br>
<canvas id="canvas" width=512 height=512></canvas>
I don't know of any libraries that do what you described, but creating an array of the positions and then using that should do roughly what you want.
//Capture all mouse movements on the browser window.
document.onmousemove = mousePos;
//Store all previous mouse locations
var ary = [];
function mousePos (e) {
//Log the current mouse position
ary.push({X: e.pageX, Y: e.pageY});
}
Now you can loop through the array to get your mouse movement.
function replay() {
for (var i = 0; i < ary.length; i++) {
//Draw a point wherever the mouse moved.
ctx.fillRect(ary[i].X, ary[i].Y, 2, 2);
}
}
You can add in a delay of your duration to playback at whichever speed you like.

How to create your own interactive panoramic website

I want to make a website that will be a room, and I want users to be able to look at that room in limited panoramic view, e.g. up/down 30 degrees, left/right 45 degrees, and I want to put objects in that panoramic view that user could interact with.
I have found that google street view could give the panoramic effect, but I'm not quite sure if it would suit my needs as I would want to put objects in it.
Are there any alternative panoramic libraries that are good and could give me tools to support what I want to achieve?
You are basically talking about panning around a view.
You can do that by drawing the view with horizontal & vertical offsets.
Here's annotated code and a Demo: http://jsfiddle.net/m1erickson/32Y5A/
<!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; padding:20px;}
#canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
ctx.strokeStyle="red";
ctx.lineWidth=5;
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var lastX=0;
var lastY=0;
var panX=0;
var panY=0;
var dragging=[];
var isDown=false;
// create "draggable" rects
var images=[];
images.push({x:200,y:150,width:25,height:25,color:"green"});
images.push({x:80,y:235,width:25,height:25,color:"gold"});
// load the tiger image
var tiger=new Image();
tiger.onload=function(){
draw();
}
tiger.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/tiger.png";
function draw(){
ctx.clearRect(0,0,canvas.width,canvas.height);
// draw tiger
ctx.globalAlpha=0.25;
ctx.drawImage(tiger,panX,panY,tiger.width,tiger.height);
// draw color images
ctx.globalAlpha=1.00;
for(var i=0;i<images.length;i++){
var img=images[i];
ctx.beginPath();
ctx.rect(img.x+panX,img.y+panY,img.width,img.height);
ctx.fillStyle=img.color;
ctx.fill();
ctx.stroke();
}
}
// create an array of any "hit" colored-images
function imagesHitTests(x,y){
// adjust for panning
x-=panX;
y-=panY;
// create var to hold any hits
var hits=[];
// hit-test each image
// add hits to hits[]
for(var i=0;i<images.length;i++){
var img=images[i];
if(x>img.x && x<img.x+img.width && y>img.y && y<img.y+img.height){
hits.push(i);
}
}
return(hits);
}
function handleMouseDown(e){
// get mouse coordinates
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// set the starting drag position
lastX=mouseX;
lastY=mouseY;
// test if we're over any of the images
dragging=imagesHitTests(mouseX,mouseY);
// set the dragging flag
isDown=true;
}
function handleMouseUp(e){
// clear the dragging flag
isDown=false;
}
function handleMouseMove(e){
// if we're not dragging, exit
if(!isDown){return;}
//get mouse coordinates
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// calc how much the mouse has moved since we were last here
var dx=mouseX-lastX;
var dy=mouseY-lastY;
// set the lastXY for next time we're here
lastX=mouseX;
lastY=mouseY;
// handle drags/pans
if(dragging.length>0){
// we're dragging images
// move all affected images by how much the mouse has moved
for(var i=0;i<dragging.length;i++){
img=images[dragging[i]];
img.x+=dx;
img.y+=dy;
}
}else{
// we're panning the tiger
// set the panXY by how much the mouse has moved
panX+=dx;
panY+=dy;
}
draw();
}
// use jQuery to handle mouse events
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
}); // end $(function(){});
</script>
</head>
<body>
<h4>Drag the tiger and<br>independently drag the rectangles.</h4>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

drag image after dropping it in canvas element

To perform drag & drop functionality, with canvas element, I have to actually draw the image in the element of destination using this line,
ctx.drawImage(imgElement,dropX, dropY);
Because it's drawed, I found a difficulty in dragging it again. It's like I can't make it move anymore
I'm working on the basis of this code here : http://jsfiddle.net/m1erickson/cyur7/
What modifications do I have to make, in order to drag again a dropped image?
Keep in mind that canvas is just a bitmap.
Once your images are drawn on the canvas they cannot be repositioned.
To reposition your image, you must clear the canvas and redraw your image in a new position.
To move and redraw your image, you will need to save at least this basic information about the image:
var image1={
x:50,
y:30,
image:imageObject
}
You can let the user drag your image around the canvas by listening to mouse events
In mousedown, check if the mouse is over the image. If yes, start the drag.
In mousemove, add the distance the user dragged since the last mousemove to the images x,y position.
In mouseup, stop the drag.
Here's example code and a Demo: http://jsfiddle.net/m1erickson/L3VjK/
<!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");
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var isDown=false;
var startX;
var startY;
var imgX=50;
var imgY=50;
var imgWidth,imgHeight;
var img=new Image();img.onload=start;img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house32x32transparent.png";
function start(){
imgWidth=img.width;
imgHeight=img.height;
ctx.drawImage(img,imgX,imgY);
}
function handleMouseDown(e){
e.preventDefault();
startX=parseInt(e.clientX-offsetX);
startY=parseInt(e.clientY-offsetY);
// Put your mousedown stuff here
if(startX>=imgX && startX<=imgX+imgWidth && startY>=imgY && startY<=imgY+imgHeight){
isDown=true;
}
}
function handleMouseUp(e){
e.preventDefault();
isDown=false;
}
function handleMouseOut(e){
e.preventDefault();
isDown=false;
}
function handleMouseMove(e){
if(!isDown){return;}
e.preventDefault();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousemove stuff here
if(!isDown){return;}
imgX+=mouseX-startX;
imgY+=mouseY-startY;
startX=mouseX;
startY=mouseY;
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.drawImage(img,imgX,imgY);
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
$("#canvas").mouseout(function(e){handleMouseOut(e);});
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

Canvas Drag and Drop

I want to drag and drop images into a canvas, and make them draggable. so far this is all i can find but once the text has been dropped into the canvas it is no longer draggable.
enter code herehttp://jsfiddle.net/ranganadh/6WpKf/
Please someone help me :D
As #Zack Argyle says, any drawing on html canvas is just paint on a canvas--it can't be dragged.
How to drag text on html canvas:
Use jquery draggable to drag a listitem onto the canvas (as you've already done)
Put info about that text into an object (text, x & y position, text width & height)
Add that text object to an array that holds all text on the canvas
When the user starts a drag, find which text is under the mouse (the selected text)
As the user drags, move the selected text by the distance the user has dragged
You must repaint all text on the canvas every time the user drags any text to a new location.
Here's code and a Demo: http://jsfiddle.net/m1erickson/hQTLa/
<!doctype html>
<html lang="en">
<head>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<script>
$(function() {
// get reference to the canvas and its context
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
ctx.font = "16px helvetica";
// variables
// some text objects defining text on the canvas
var texts=[];
// variables used to get mouse position on the canvas
var $canvas=$("#canvas");
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var scrollX=$canvas.scrollLeft();
var scrollY=$canvas.scrollTop();
// variables to save last mouse position
// used to see how far the user dragged the mouse
// and then move the text by that distance
var startX;
var startY;
// this var will hold the index of the selected text
var selectedText=-1;
// make the <li> draggable
$("li").draggable({
helper: 'clone'
});
// drop on canvas
$("#canvas").droppable({
accept: "li",
drop: function(event,ui){
ctx.fillText($(ui.draggable).clone().text(),ui.position.left - event.target.offsetLeft,ui.position.top - event.target.offsetTop);
var text=$(ui.draggable).clone().text();
var x=ui.position.left - event.target.offsetLeft;
var y=ui.position.top - event.target.offsetTop;
var width=ctx.measureText(text).width;
var height=16;
// save this text info in an object in texts[]
texts.push({text:text,x:x,y:y,width:width,height:height});
// draw all texts to the canvas
draw();
}
});
// clear the canvas draw all texts
function draw(){
ctx.clearRect(0,0,canvas.width,canvas.height);
for(var i=0;i<texts.length;i++){
var text=texts[i];
ctx.fillText(text.text,text.x,text.y);
}
}
// test if x,y is inside the bounding box of texts[textIndex]
function textHittest(x,y,textIndex){
var text=texts[textIndex];
return(x>=text.x &&
x<=text.x+text.width &&
y>=text.y-text.height &&
y<=text.y);
}
// handle mousedown events
// iterate through texts[] and see if the user
// mousedown'ed on one of them
// If yes, set the selectedText to the index of that text
function handleMouseDown(e){
e.preventDefault();
startX=parseInt(e.clientX-offsetX);
startY=parseInt(e.clientY-offsetY);
// Put your mousedown stuff here
for(var i=0;i<texts.length;i++){
if(textHittest(startX,startY,i)){
selectedText=i;
}
}
}
// done dragging
function handleMouseUp(e){
e.preventDefault();
selectedText=-1;
}
// also done dragging
function handleMouseOut(e){
e.preventDefault();
selectedText=-1;
}
// handle mousemove events
// calc how far the mouse has been dragged since
// the last mousemove event and move the selected text
// by that distance
function handleMouseMove(e){
if(selectedText<0){return;}
e.preventDefault();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousemove stuff here
var dx=mouseX-startX;
var dy=mouseY-startY;
startX=mouseX;
startY=mouseY;
var text=texts[selectedText];
text.x+=dx;
text.y+=dy;
draw();
}
// listen for mouse events
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
$("#canvas").mouseout(function(e){handleMouseOut(e);});
}); // end $(function(){});
</script>
</head>
<body>
<ul id="drag">
<li class="new-item">Drag me down1</li>
<li class="new-item">Drag me down2</li>
<li class="new-item">Drag me down3</li>
</ul>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

Clipping images into different shapes like triangle, pentagon in html5 canvas?

I am developing a game in html 5 canvas where I have to clip images into many shapes. I also want to join these clipped images using mouse events. Can I only clip a square shape? Also, is it necessary to save x and y co-ordinates of each clipped image to know its position or is there any alternate way?
Here is an example to illustrate how to:
clip an image into 4 triangle pieces,
hit-test the pieces,
move the pieces using your mouse
Here's code and a Fiddle: http://jsfiddle.net/m1erickson/r59ch/
<!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");
var $canvas=$("#canvas");
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var scrollX=$canvas.scrollLeft();
var scrollY=$canvas.scrollTop();
var isDown=false;
var startX;
var startY;
var parts=[];
var selectedPart=-1;
var img=new Image();
img.onload=function(){
var cx=img.width/2;
var cy=img.height/2;
var w=img.width;
var h=img.height;
parts.push({x:25,y:25,points:[{x:0,y:0},{x:cx,y:cy},{x:0,y:h}]});
parts.push({x:25,y:25,points:[{x:0,y:0},{x:cx,y:cy},{x:w,y:0}]});
parts.push({x:125,y:25,points:[{x:w,y:0},{x:cx,y:cy},{x:w,y:h}]});
parts.push({x:25,y:25,points:[{x:0,y:h},{x:cx,y:cy},{x:w,y:h}]});
drawAll();
}
img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house100x100.png";
function drawAll(){
ctx.clearRect(0,0,canvas.width,canvas.height);
for(var i=0;i<parts.length;i++){
draw(parts[i]);
}
}
function draw(part){
ctx.save();
define(part);
ctx.clip();
ctx.drawImage(img,part.x,part.y);
ctx.stroke();
ctx.restore();
}
function hit(part,x,y){
define(part);
return(ctx.isPointInPath(x,y))
}
function move(part,x,y){
part.x+=x;
part.y+=y;
draw(part);
}
function define(part){
ctx.save();
ctx.translate(part.x,part.y);
ctx.beginPath();
var point=part.points[0];
ctx.moveTo(point.x,point.y);
for(var i=0;i<part.points.length;i++){
var point=part.points[i];
ctx.lineTo(point.x,point.y);
}
ctx.closePath();
ctx.restore();
}
function handleMouseDown(e){
e.preventDefault();
startX=parseInt(e.clientX-offsetX);
startY=parseInt(e.clientY-offsetY);
// Put your mousedown stuff here
for(var i=0;i<parts.length;i++){
if(hit(parts[i],startX,startY)){
isDown=true;
selectedPart=i;
return;
}
}
selectedPart=-1;
}
function handleMouseUp(e){
e.preventDefault();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mouseup stuff here
isDown=false;
}
function handleMouseOut(e){
e.preventDefault();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mouseOut stuff here
isDown=false;
}
function handleMouseMove(e){
if(!isDown){return;}
e.preventDefault();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousemove stuff here
var dx=mouseX-startX;
var dy=mouseY-startY;
startX=mouseX;
startY=mouseY;
//
var part=parts[selectedPart];
move(part,dx,dy);
drawAll();
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
$("#canvas").mouseout(function(e){handleMouseOut(e);});
}); // end $(function(){});
</script>
</head>
<body>
<h4>Drag the right triangle-image into place</h4>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
You can define a path and use that for clipping:
ctx.save(); /// store current state of canvas incl. default clip mask
ctx.beginPath();
ctx.moveTo(0, 10);
ctx.lineTo(200, 10);
ctx.lineTo(100, 110);
ctx.clip(); /// will close the path implicit
/// draw graphics here
ctx.restore(); /// restore default infinite clipping mask
This will create a triangle. If you now draw on top the graphics will be clipped to this shape. Coordinates given here are of course just for example.
A small note: the different browsers may or may not anti-alias the clipping mask. If not the result may turn out "hard-edged".
(I recommend to use save()/restore() in connection with clip(). There is suppose to be a resetClip() method but this is rarely implemented in the browsers and is currently considered for removal from the specs.)
An alternative to using clip() is to use image pattern. Define a pattern with the image you want to clip, then create the path as above and use fill() with the pattern set as fillStyle. For this to work properly you need to translate() the canvas before filling to place the image pattern in the desired position.

Categories