How to fillRect canvas grid cell depending on mouse position? - javascript

I've pretty code about grid parameters depending on mouse coords.
CANVAS GRID DEMO HERE
I want to clear filled, selected(imoX/imoY) cell while mouse is outside the selected(imoX/imoY) cell.
It should be like:
onmouseover[CellNumberX] = fillRect()
onmouseout[CellNumberX] = strokeRect()
Any solutions ?
Thanks.

You can use this hit test to see if the mouse is over a rectangle:
// mx,my == mouse coordinates, r.x,r.y,r.width,r.height == rect definition
var mouseIsInside= mx>r.x && mx<r.x+r.width && my>r.y && my<r.y+r.height;
Or use this hit test to see if the mouse is over a grid cell:
// the offsets are the top left coordinates where the grid begins
var cellX = parseInt((mx-gridLeftOffset)/cellWidth);
var cellY = parseInt((my-gridTopOffset)/cellHeight);
Example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
ctx.lineWidth=3;
function reOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
// define each rectangle
var rects=[];
rects.push({x:20,y:20,width:50,height:35,fill:'red'});
rects.push({x:100,y:20,width:75,height:100,fill:'blue'});
rects.push({x:200,y:50,width:75,height:50,fill:'green'});
// listen for mousemove events on the canvas
canvas.addEventListener('mousemove',function(e){handleMouseMove(e);});
draw(0,0);
function draw(mx,my){
// clear the canvas in preparation to redraw all rects
// in their new hovered or not-hovered state
ctx.clearRect(0,0,cw,ch);
// redraw each rect in the rects array
for(var i=0;i<rects.length;i++){
var r=rects[i];
// is the mouse inside this rect?
if(mx>r.x && mx<r.x+r.width && my>r.y && my<r.y+r.height){
// it's outside so fill the rect
ctx.strokeRect(r.x,r.y,r.width,r.height);
}else{
// it's inside so stroke the rect
ctx.fillStyle=r.fill;
ctx.fillRect(r.x,r.y,r.width,r.height);
ctx.strokeRect(r.x,r.y,r.width,r.height);
}
}
}
function handleMouseMove(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// get the mouse position
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// redraw all the rects
draw(mouseX,mouseY);
}
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>Hover mouse over rects to remove fill</h4>
<canvas id="canvas" width=300 height=300></canvas>

Related

JQuery tooltip in base of canvas coordinates

i'm trying to draw a graph in a canvas, every vertex has its own coordinates (in center of the circle - 6px radius - that represent it).
I want to show a tooltip when i am over a vertex with mouse...and hide this tooltip when i am not on a vertex.
Now the tooltip is showing (only after the second pass on canvas with mouse) with right data, but when i am no more on vertex, tooltip is still here.
Here is the code of canvas.addEventListener (only here is tooltip)
canvas.addEventListener('mousemove', function(evt) {
var mX = evt.clientX;
var mY = evt.clientY;
mX -= canvas.offsetLeft;
mY -= canvas.offsetTop;
$("canvas").tooltip();
for (i=0; i<points.length; i++) {
if (mX<points[i].x+6 && mX>points[i].x-6) {
if (mY<points[i].y+6 && mY>points[i].y-6) {
var str = getNodeRelations(evt);
x1 = points[i].x-6;
x2 = points[i].x+6;
y1 = points[i].y-6;
y2 = points[i].y+6;
/*if ($("canvas").tooltip("instance") != undefined && $("canvas").tooltip("option", "disabled") == true) {
$("canvas").tooltip("option", "disabled", false);
}*/
$("canvas").tooltip({
content: str,
effect: "fade",
track: true
});
}
}
}
/*if ($("canvas").tooltip("instance") != undefined && ((mX<x1 || mX>x2) && (mY<y1 || mY>y2))) {
$("canvas").tooltip("option", "disabled", true);
}*/
}, false);
}
In comment block are not working codelines
Thank you for help in advance!
The jQueryUI Tooltip appears when the mouse is over any part of the target element. That's why the tooltip won't fade -- because the mouse is still over your canvas element.
Therefore, jqueryUI Tooltip is not very useful to show tips on individual canvas drawings like your vertices. Yes, you can force it to show/hide in ways unintended by its API, but that risks unintended failures too.
A simple alternative might be:
Show/hide a div element containing your tip text.
Use CSS to position the tip-div.
Hit-test each vertex in mousemove to show/hide the tip-div.
Example starting code:
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 rects=[];
rects.push({x:50,y:50,w:40,h:25,fill:'red',tip:'I am the red box'});
rects.push({x:50,y:150,w:50,h:75,fill:'blue',tip:'I am the blue box'});
for(var i=0;i<rects.length;i++){
var r=rects[i];
ctx.fillStyle=r.fill;
ctx.fillRect(r.x,r.y,r.w,r.h);
ctx.stroke();
}
$tip=$('#tip');
$tip.hide();
$("#canvas").mousemove(function(e){handleMouseMove(e);});
function handleMouseMove(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
$tip.hide();
for(var i=0;i<rects.length;i++){
var r=rects[i];
ctx.beginPath();
ctx.moveTo(r.x,r.y);
ctx.lineTo(r.x+r.w,r.y);
ctx.lineTo(r.x+r.w,r.y+r.h);
ctx.lineTo(r.x,r.y+r.h);
ctx.closePath();
if(ctx.isPointInPath(mouseX,mouseY)){
$tip.text(r.tip);
$tip.css({left:e.clientX+3,top:e.clientY-18}).show();
}
}
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
#tip{position:absolute;background:white;border:1px solid blue;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Hover over rectangle to show tooltip.</h4>
<canvas id="canvas" width=300 height=300></canvas>
<div id=tip>Tooltip</div>

faster method of copying image data

i have the following script
// copy image data to secondary canvas
var pixelData = contextSource.getImageData(x - (lineWidth/2), y - (lineWidth/2), lineWidth, lineWidth);
var tmpCanvas = document.createElement('canvas');
tmpCanvas.width = tmpCanvas.height = lineWidth;
var tmpContext = tmpCanvas.getContext('2d');
tmpContext.putImageData(pixelData, 0, 0);
contextDest.save();
contextDest.arc(x, y, (lineWidth/2), 0, 2*Math.PI);
contextDest.clip();
contextDest.drawImage(tmpCanvas, x - (lineWidth/2), y - (lineWidth/2));
contextDest.restore();
the script is sampling image data from canvas source when mouse is moving over the source, then copy it to destination. the script is working good, but a bit slow. here is the result when i move the mouse pointer a bit faster.
is there any faster method than mine? please help
#Banana has a good point.
Instead of drawing just the mouse positions, try connecting the positions into a single continuous line..
If you want the rounded effect in your illustration, you can set:
context.lineCap='round';
context.lineJoin='round';
As to masking faster...
A much faster way of masking your image is to:
draw your single line on the second canvas.
Use compositing to make all new draws be visible only where existing pixels are opaque. This compositing is 'source-in' and is set using: context.globalCompositeOperation='source-in'
Draw your image onto the second canvas. The image will show only where the line was.
Using compositing is much faster because compositing is hardware accelerated and is optimized by the browser.
That compositing code might look like this:
function draw(){
// clear the second canvas
ctx1.clearRect(0,0,cw,ch);
// draw your continuous line
ctx1.beginPath();
ctx1.moveTo(points[0].x,points[0].y);
for(var i=1;i<points.length;i++){
p=points[i];
ctx1.lineTo(p.x,p.y);
}
ctx1.stroke();
// set compositing so new draws only appear in
// existing opaque pixels
ctx1.globalCompositeOperation='source-in';
// draw the image
// the image will only be visible in the exising line
ctx1.drawImage(img,0,0);
// be tidy! return compositing to its default mode
ctx1.globalCompositeOperation='source-over';
}
Here's an example and Demo:
var canvas1=document.getElementById("canvas1");
var ctx1=canvas1.getContext("2d");
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 points=[];
var cw,ch;
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/tempHouse%201.jpg";
function start(){
cw=canvas.width=canvas1.width=img.width;
ch=canvas.height=canvas1.height=img.height;
ctx1.lineCap = "round";
ctx1.lineJoin = "round";
ctx1.lineWidth=20;
ctx.drawImage(img,0,0);
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
$("#canvas").mouseout(function(e){handleMouseOut(e);});
}
function draw(){
// clear the second canvas
ctx1.clearRect(0,0,cw,ch);
// draw your continuous line
ctx1.beginPath();
ctx1.moveTo(points[0].x,points[0].y);
for(var i=1;i<points.length;i++){
p=points[i];
ctx1.lineTo(p.x,p.y);
}
ctx1.stroke();
// set compositing so new draws only appear in
// existing opaque pixels
ctx1.globalCompositeOperation='source-in';
// draw the image
// the image will only be visible in the exising line
ctx1.drawImage(img,0,0);
// be tidy! return compositing to its default mode
ctx1.globalCompositeOperation='source-over';
}
function handleMouseDown(e){
e.preventDefault();
e.stopPropagation();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
points.length=0;
points.push({x:mouseX,y:mouseY});
isDown=true;
}
function handleMouseUp(e){
e.preventDefault();
e.stopPropagation();
isDown=false;
draw();
}
function handleMouseOut(e){
e.preventDefault();
e.stopPropagation();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
points.push({x:mouseX,y:mouseY});
isDown=false;
draw();
}
function handleMouseMove(e){
if(!isDown){return;}
e.preventDefault();
e.stopPropagation();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
points.push({x:mouseX,y:mouseY});
draw();
}
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>
<canvas id="canvas" width=300 height=300></canvas><br>
<canvas id="canvas1" width=300 height=300></canvas>

How can I drag a piece of user generated text around the HTML5 canvas?

Basically what I have coded is the ability to type a word into a text box. When a button is pressed to submit it that word is then posted to the HTML5 canvas so people can see it. What I want to do now is to have the ability to drag that word around the HTML5 canvas. I'm having slightly difficulty in achieving this and was wondering if someone could help me with this please? Here's my code what I've done so far:
var fname;
var canvas;
var ctx;
var canvasX;
var canvasY;
var mouseIsDown;
function addTitle2() {
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
canvas.addEventListener("mousedown", mouseDown, false);
canvas.addEventListener("mousemove", mouseXY, false);
document.body.addEventListener("mouseup", mouseUp, false);
var fname = document.forms[0].fname.value;
ctx.fillStyle = "black";
ctx.strokeStyle = "black";
ctx.font = "35px Arial";
ctx.fillText(fname, Math.random() * 500, Math.random() * 400);
ctx.stroke();
}
function mouseUp() {
mouseIsDown = 0;
mouseXY();
}
function mouseDown() {
mouseIsDown = 1;
mouseXY();
}
function mouseXY(e) {
e.preventDefault();
canvasX = e.pageX - canvas.offsetLeft;
canvasY = e.pageY - canvas.offsetTop;
ShowPos();
}
function ShowPos() {
if(mouseIsDown) {
ctx.fillText(fname, canvasX, canvasY);
}
}
Dragging text is largely responding to mouse events.
A Demo: http://jsfiddle.net/m1erickson/9xAGa/
First create text objects to refer to
// some text objects
var texts=[];
// some test texts
texts.push({text:"Hello",x:20,y:20});
texts.push({text:"World",x:20,y:70});
In mousedown
Iterate through each text object and see if the mouse is inside.
// 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;
}
}
}
// 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);
}
In mousemove
Change the selected text's x,y by the distance the mouse has been dragged:
// 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();
}
In mouseup
The drag is over:
// done dragging
function handleMouseUp(e){
e.preventDefault();
selectedText=-1;
}
Annotated Code:
<!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;}
#theText{width:10em;}
</style>
<script>
$(function(){
// canvas related variables
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
// 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;
// an array to hold text objects
var texts=[];
// this var will hold the index of the hit-selected text
var selectedText=-1;
// clear the canvas & redraw 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);});
$("#submit").click(function(){
// calc the y coordinate for this text on the canvas
var y=texts.length*20+20;
// get the text from the input element
var text={text:$("#theText").val(),x:20,y:y};
// calc the size of this text for hit-testing purposes
ctx.font="16px verdana";
text.width=ctx.measureText(text.text).width;
text.height=16;
// put this new text in the texts array
texts.push(text);
// redraw everything
draw();
});
}); // end $(function(){});
</script>
</head>
<body>
<input id="theText" type="text">
<button id="submit">Draw text on canvas</button><br>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
Create a transparent div over canvas and position it such a way that it cover only area you filled with text. Make this div draggable. On div position change clear canvas and redraw text on canvas based on new position of div.
You should repeat all fillText stuff when mouse is down, also clear the screen before every draw
function drawText() {
ctx.clearRect(0, 0, 500, 400);
ctx.fillStyle = "black";
ctx.strokeStyle = "black";
ctx.font = "35px Arial";
ctx.fillText(fname, canvasX, canvasY);
ctx.stroke();
}
Here's a jsfiddle
Okay so I just want to point out one problem in the following jsfiddle solution by markE
Dragging text is largely responding to mouse events
the problem is that if your page doesn't fit the window and is scrollable if you have scrolled your page and now you are dragging the text, it won't work because the mouse event will return clientY that couldn't calculate the saved coordinates.
Reproduce by giving height as
<canvas id="canvas" width=300 height=3000></canvas>
and drag text after scrolling.

How to draw a rectangle on canvas like we do on paint?

Say i want to draw a rectangle on canvas. I want to be able to get the co-ordinates from user's mouse. Ideal scenario is user clicks at a point and drags down to another end like those rectangles we draw using paint. How can i draw a rectangle like we do in paint by dragging mouse? (how to get the co-ordinates of the mouse when he clicks mouse and leaves at?)
Here's a outline of how to drag-draw a rectangle on canvas:
In mousedown:
save the starting mouse position
set a flag indicating the drag has begun
In mousemove:
clear the canvas of the previous rectangle
calculate the rectangle width/height based on the starting vs current mouse position
draw a rectangle from the starting XY to the current mouse position
In mouseup:
clear the dragging flag because the drag is over
Here's example code and a Demo: http://jsfiddle.net/m1erickson/6E2yd/
<!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(){
// get references to the canvas and context
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
// style the context
ctx.strokeStyle = "blue";
ctx.lineWidth=3;
// calculate where the canvas is on the window
// (used to help calculate mouseX/mouseY)
var $canvas=$("#canvas");
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var scrollX=$canvas.scrollLeft();
var scrollY=$canvas.scrollTop();
// this flage is true when the user is dragging the mouse
var isDown=false;
// these vars will hold the starting mouse position
var startX;
var startY;
function handleMouseDown(e){
e.preventDefault();
e.stopPropagation();
// save the starting x/y of the rectangle
startX=parseInt(e.clientX-offsetX);
startY=parseInt(e.clientY-offsetY);
// set a flag indicating the drag has begun
isDown=true;
}
function handleMouseUp(e){
e.preventDefault();
e.stopPropagation();
// the drag is over, clear the dragging flag
isDown=false;
}
function handleMouseOut(e){
e.preventDefault();
e.stopPropagation();
// the drag is over, clear the dragging flag
isDown=false;
}
function handleMouseMove(e){
e.preventDefault();
e.stopPropagation();
// if we're not dragging, just return
if(!isDown){return;}
// get the current mouse position
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousemove stuff here
// clear the canvas
ctx.clearRect(0,0,canvas.width,canvas.height);
// calculate the rectangle width/height based
// on starting vs current mouse position
var width=mouseX-startX;
var height=mouseY-startY;
// draw a new rect from the start position
// to the current mouse position
ctx.strokeRect(startX,startY,width,height);
}
// 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>
<h4>Drag the mouse to create a rectangle</h4>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
clear the
See this, move you mouse over the square, and witness the awesomeness of Process.js
http://processingjs.org/learning/topic/pattern/
Using this function you can get the mousecoordinates
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
this function takes in the canvas object and the event.
Now you just have to add an eventHandler on mousedown and mouseup and you can get both the locations.
var canvas = document.getElementById('canvasId');
var ctx = canvas.getContext('2d');
var locA, locB;
document.addEventListener('mousedown', function(e) {
e.preventDefault();
locA = getMousePos(canvas, e);
});
document.addEventListener('mouseup', function(e) {
e.preventDefault();
locB = getMousePos(canvas, e);
ctx.fillStyle = '#000000';
ctx.fillRect(locA.x, locA.y, (locB.x - locA.x), (locB.y - locA.y));
});
function source: http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/
There are still some problems surrounding canvas coordinates vs document coordinates, but I'm sure you'll be able to fix that.

Moving canvas shapes with mouse

After pressing a button, I'd like to draw a circle at the tip of the mouse pointer on a canvas and then place it when the user clicks again. Here's what I've got so far:
$("#button").click(function(e){
var canvas = document.getElementById('MyCanvas');
var context = canvas.getContext('2d');
canvas.addEventListener('mousemove', function(evt) {
var mousePos = getMousePos(canvas, evt);
var message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y;
console.log(message);
var nodehandle = document.getElementById('circle');
if(mousePos.x && mousePos.y) {
nodehandle.x = mousePos.x;
nodehandle.y = mousePos.y;
flag = 1;
}
}, false);
});
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
My problem is that when I draw a circle like this:
function drawCircle(mouseX, mouseY){
var c = document.getElementById("grid");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.arc(95,50,5,0,2*Math.PI);
ctx.stroke();
}
I don't know how to select that circle (the getElementById('circle') returns null even if I add ctx.id='circle' to the drawCircle function). I'm also going to need to erase and redraw the circle each time the mouse moves, and I'm sure there's a nice way to do that but I'm not aware of it.
Anything you draw on the canvas--like circles, are just like dried paint on the canvas.
Your circles cannot be selected or moved like html elements.
To move a circle you must clear the canvas and redraw the circle at a different location.
It's convenient to store info about the circle in an object.
var circle1 = { centerX:100, centerY=100, radius=20 }
And you can draw circle1 using that info:
ctx.beginPath();
ctx.arc(circle1.centerX, circle1.centerY, circle1.radius, 0,Math.PI*2);
ctx.closePath();
ctx.fill();
For more than 1 circle you can create a circles array and put each circle object into that array
var circles=[];
circles.push(circle1);
Then to "move" a circle, just change the object's centerX/centerY to the mouse position and redraw all the circles on the canvas.
circle1.centerX=mouseX;
circle1.centerY=mouseY;
// Clear the canvas and redraw all circles
// The "moved" circle will be redrawn at its new position
function drawAll(){
ctx.clearRect(0,0,canvas.width,canvas.height);
for(var i=0;i<circles.length;i++){
var c=circles[i];
ctx.beginPath();
ctx.arc(c.centerX,c.centerY,c.radius,0,Math.PI*2);
ctx.closePath();
ctx.fillStyle=c.color;
ctx.fill();
}
}
You can use Html radio buttons to determine which action a mouse-click will do:
Create a new circle at the mouse position, or
Select the circle under the mouse position, or
"Move" the currently selected circle
Here's example code and a Demo: http://jsfiddle.net/m1erickson/CEB7T/
<!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(){
// get references to the canvas and its context
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var $canvas=$("#canvas");
// get the canvas position on the page
// used to get mouse position
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var scrollX=$canvas.scrollLeft();
var scrollY=$canvas.scrollTop();
ctx.lineWidth=3;
// save info about each circle in an object
var circles=[];
var selectedCircle=-1;
// the html radio buttons indicating what action to do upon mousedown
var $create=$("#rCreate")[0];
var $select=$("#rSelect")[0];
var $move=$("#rMove")[0];
// draw all circles[]
function drawAll(){
ctx.clearRect(0,0,canvas.width,canvas.height);
for(var i=0;i<circles.length;i++){
var c=circles[i];
ctx.beginPath();
ctx.arc(c.cx,c.cy,c.radius,0,Math.PI*2);
ctx.closePath();
ctx.fillStyle=c.color;
ctx.fill();
// if this is the selected circle, highlight it
if(selectedCircle==i){
ctx.strokeStyle="red";
ctx.stroke();
}
}
}
function handleMouseDown(e){
e.preventDefault();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
if($create.checked){
// create a new circle a the mouse position and select it
circles.push({cx:mouseX,cy:mouseY,radius:10,color:randomColor()});
selectedCircle=circles.length-1;
}
if($select.checked){
// unselect any selected circle
selectedCircle=-1;
// iterate circles[] and select a circle under the mouse
for(var i=0;i<circles.length;i++){
var c=circles[i];
var dx=mouseX-c.cx;
var dy=mouseY-c.cy;
var rr=c.radius*c.radius;
if(dx*dx+dy*dy<rr){ selectedCircle=i; }
}
}
if($move.checked && selectedCircle>=0){
// move the selected circle to the mouse position
var c=circles[selectedCircle];
c.cx=mouseX;
c.cy=mouseY;
}
// redraw all circles
drawAll();
}
// return a random color
function randomColor(){
return('#'+Math.floor(Math.random()*16777215).toString(16));
}
// handle mousedown events
$("#canvas").mousedown(function(e){handleMouseDown(e);});
}); // end $(function(){});
</script>
</head>
<body>
<input type="radio" name="grp1" id="rCreate" checked>Click will create a new circle.<br>
<input type="radio" name="grp1" id="rSelect">Click will select an existing circle.<br>
<input type="radio" name="grp1" id="rMove">Click will move selected circle.<br>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

Categories

Resources