drag image after dropping it in canvas element - javascript

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>

Related

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>

To drag shapes drawn on canvas same as paint

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();

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.

One pixel fill, with canvas

This might be a somewhat stupid question, but...is it possible to fill an HTML canvas element, pixel by pixel, depending on where a user clicks?
I want to have a blank canvas, that users will click one pixel at a time, which will fill a color, and enter that user/pixel into a database.
How would this be done?
How can I know what pixel, what user clicked?
Thanks
Yes, you can set each canvas pixel individually based on mouse-clicks.
Here's how you set an individual pixel using context.getImageData and context.putImageData:
function setPixel(x, y, red, green, blue) {
pixPos=( (~~x) + (~~y)) * 4;
var pxData = ctx.getImageData(x,y,1,1);
pxData.data[0]=red;
pxData.data[1]=green;
pxData.data[2]=blue;
pxData.data[3]=255;
ctx.putImageData(pxData,x,y);
}
And you get the X/Y position of the mouse click by adding an event listener like this:
// get the position of the canvas relative to the web page
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
// tell the browser to send you mouse down events
// Here I use jquery -- be sure to add jquery or just do addEventListener instead
$("#canvas").mousedown(function(e){handleMouseDown(e);});
// handle the mousedown events that the browser sends you
function handleMouseDown(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousedown stuff here
setPixel(mouseX,mouseY,red,green,blue);
}
Here's code and a fiddle: http://jsfiddle.net/m1erickson/wtStf/
<!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 red=255;
var green=0;
var blue=0;
function setPixel(x, y, red, green, blue) {
pixPos=( (~~x) + (~~y)) * 4;
var pxData = ctx.getImageData(x,y,1,1);
pxData.data[0]=red;
pxData.data[1]=green;
pxData.data[2]=blue;
pxData.data[3]=255;
ctx.putImageData(pxData,x,y);
}
function handleMouseDown(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousedown stuff here
setPixel(mouseX,mouseY,red,green,blue);
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
[Edited for additional question]
You can easily modify the code to set blocks of pixels like this:
var blockWidth=25;
var blockHeight=25;
function setPixel(x, y, red, green, blue) {
pixPos=( (~~x) + (~~y)) * 4;
var pxData = ctx.getImageData(x,y,blockWidth,blockHeight);
for(var n=0;n<blockWidth*blockHeight;n++){
pxData.data[n*4+0]=red;
pxData.data[n*4+1]=green;
pxData.data[n*4+2]=blue;
pxData.data[n*4+3]=255;
}
ctx.putImageData(pxData,x,y);
}

Categories