After unsucessfull thread I'm asking for help again. How do I let the user add some text on the canvas by dragging text to their desired position? Let's say, they enter the text somewhere somehow, it appears on a canvas and then user can drag that text to desired position. Which technique I should use? Is there any way for someone to write a quick code?
Here's an outline of how to drag text on html canvas:
Create a text object that holds info about this word (text, x,y,width,height).
Create an array to hold all text objects
On mousedown, hit-test each text object in the array to see if the user mousedown'ed on a text
On mousemove, move the selected text by the distance that the user dragged the mouse
Demo: http://jsfiddle.net/m1erickson/tLvMK/
Here's commented 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;}
</style>
<script>
$(function(){
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;
// some text objects
var texts=[];
// some test texts
texts.push({text:"Hello",x:20,y:20});
texts.push({text:"World",x:20,y:70});
// calculate width of each text for hit-testing purposes
ctx.font="16px verdana";
for(var i=0;i<texts.length;i++){
var text=texts[i];
text.width=ctx.measureText(text.text).width;
text.height=16;
}
// this var will hold the index of the selected text
var selectedText=-1;
// START: 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>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
Related
I'm generating a grid of hexagons by using a for loop and I'm having some issues
for (var i=0; i <= rows; i++) {
for (var j=0; j <= cols; j++) {
ctx.save();
ctx.translate(0+i*distX, 0+j*distY);
drawHexagon(ctx);
ctx.fill();
ctx.restore();
}
}
My end goal is to create a grid of hexagons that move away from the mouse cursor when it's moving around the page, with an area of influence. I can't work out how to draw a path between each of the hexagons and I'm also having an issue with trying to animate the hexagons.
I'm still a canvas newbie, I went through the tutorials on Mozilla's developer network and all of the animations were on singular objects, not objects generated in a grid.
I was thinking that I should try and store the grid and affect it later but I'm not sure how I would go about that, I also don't think canvas works like that.
I found this which is pretty much what I want to do but I can't understand how it works:
http://codepen.io/soulwire/pen/Ffvlo
I'm fine combing through it now, if anyone could walk me through it that would be great :)
Edit: I've since gotten a grid drawn behind the dots, I'd like to manipulate this too. I still don't understand the codepen linked above, it's a little over my head.
Your link applies 2 forces:
Particles near the mouse are repelled. More specifically, if the particles centerpoint is near the mouse centerpoint, then the particle is repelled along the line between the two centerpoints.
Particles not near the mouse are attracted back to their original positions. More specifically, the particles move toward their original centerpoint along the line between their current centerpoint and their original centerpoint.
The math works like this:
// Given the mouse centerpoint (mx,my) & particle's centerpoint (px,py)
// calculate the difference between x's & y's
var dx=px-mx;
var dy=py-my;
// You can repel the particle by increasing the
// particle's position by a fraction of dx & dy
px+=dx/100;
py+=dy/100;
// And you can attract the particle by decreasing the
// particle's position by a fraction of dx & dy
px-=dx/100;
py-=dy/100;
Here's annotated code and a Demo (easing removed for ease of understanding):
// canvas related variables
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(); }
ctx.fillStyle='skyblue';
// mouse related variables
var PI2=Math.PI*2;
var mouseRadius=75; // this is the mouse's radius of influence
var mouseRadiusSquared=mouseRadius*mouseRadius;
var mouseIsDown=false;
var mx,my;
// define a bunch of hex objects stored in an array
var hexRadius=5;
var hexPadding=5;
var hexes=[];
for(var y=hexRadius;y<ch;y+=hexRadius*2+hexPadding){
for(var x=hexRadius;x<cw;x+=hexRadius*2+hexPadding){
hexes.push({startingX:x,startingY:y,x:x,y:y});
}}
// start a continuously running ticker loop
requestAnimationFrame(tick);
// listen for mouse events
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
// draw every hex in its current position
function draw(){
ctx.clearRect(0,0,cw,ch);
ctx.beginPath();
for(var i=0;i<hexes.length;i++){
var h=hexes[i];
ctx.moveTo(h.x,h.y);
ctx.arc(h.x,h.y,hexRadius,0,PI2);
ctx.closePath();
}
ctx.fill();
}
// create a continuously running ticker
function tick(time){
// update each hex position based on its
// position relative to the mouse
for(var i=0;i<hexes.length;i++){
var h=hexes[i];
// calculate if this hex is inside the mouse radius
var dx=h.x-mx;
var dy=h.y-my;
if(mouseIsDown && dx*dx+dy*dy<mouseRadiusSquared){
// hex is inside mouseRadius
// so mouseDown repels hex
h.x+=dx/120;
h.y+=dy/120;
}else if(h.x==h.startingX && h.y==h.startingY){
// hex is at startingX/Y & is not being repelled
// so do nothing
}else{
// hex has moved off startingX/Y
// but is no longer being repelled
// so gravity attracts hex back to its startingX/Y
dx=h.x-h.startingX;
dy=h.y-h.startingY;
h.x-=dx/60;
h.y-=dy/60;
}
}
// redraw the hexes in their new positions
draw();
// request another tick
requestAnimationFrame(tick);
}
// listen for mousedown events
function handleMouseDown(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// calculate the mouse position
mx=parseInt(e.clientX-offsetX);
my=parseInt(e.clientY-offsetY);
// set the mousedown flag
mouseIsDown=true;
}
// listen for mouseup events
function handleMouseUp(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// clear the mousedown flag
mouseIsDown=false;
}
body{ background-color: ivory; padding:10px; }
#canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Press the mouse down to repel the particles.<br>Release to return particles to starting point.</h4>
<canvas id="canvas" width=300 height=300></canvas>
I have a contract text which is stored into MS SQL VARMAX field. When loaded into a canvas I need to have the user signed in different places. Then need to save the signatures as svg format. But how do I grab the relative positions of each signature? So when I load back the text I can show the signatures in the right positions.
Thanks,
Doron
When the person initially signs the contract, presumably you will have a separate canvas positioned directly over your contract text. The signatory will move the mouse/pen over the canvas to create their signature. The signature will be the only opaque pixels on the canvas.
You can use getImageData to fetch the pixel data for the canvas. Then you can loop through each pixel and save the leftmost, topmost, rightmost and bottommost opaque pixel position. That gives your desired bounding box for the signature.
Here's how to get the bounding box of a signature on the canvas.
function findBoundary(){
var data=ctx.getImageData(0,0,cw,ch).data;
var top=1000000;
var left=1000000;
var right=-10;
var bottom=-10;
for(var y=0;y<ch;y++){
for(var x=0;x<cw;x++){
var n=(y*cw+x)*4+3;
if(data[n]>200){
if(x<left){left=x;}
if(x>right){right=x;}
if(y<top){top=y;}
if(y>bottom){bottom=y;}
}
}}
return({x:left,y:top,width:right-left+1,height:bottom-top+1});
}
Example code and a Demo:
Note: This simple demo isn't meant to be a signature capture app--I assume you already have a full signature app. It just draws a stoke as you drag the mouse and shows you the bounding box of the stroke when you release the mouse.
var $results=$('#results');
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
ctx.lineCap = "round";
ctx.lineWidth=2;
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;
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUpOut(e);});
$("#canvas").mouseout(function(e){handleMouseUpOut(e);});
function findBoundary(){
var data=ctx.getImageData(0,0,cw,ch).data;
var top=1000000;
var left=1000000;
var right=-10;
var bottom=-10;
for(var y=0;y<ch;y++){
for(var x=0;x<cw;x++){
var n=(y*cw+x)*4+3;
if(data[n]>200){
if(x<left){left=x;}
if(x>right){right=x;}
if(y<top){top=y;}
if(y>bottom){bottom=y;}
}
}}
return({x:left,y:top,width:right-left+1,height:bottom-top+1});
}
function handleMouseDown(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
startX=parseInt(e.clientX-offsetX);
startY=parseInt(e.clientY-offsetY);
// Put your mousedown stuff here
ctx.clearRect(0,0,cw,ch);
ctx.lineWidth=3;
ctx.strokeStyle='black';
isDown=true;
}
function handleMouseUpOut(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
isDown=false;
var pos=findBoundary();
ctx.strokeStyle='red';
ctx.lineWidth=1;
ctx.globalAlpha=0.50;
ctx.strokeRect(pos.x,pos.y,pos.width,pos.height);
ctx.globalAlpha=1.00;
$results.text(
'Signature boundary x/y: '
+parseInt(pos.x)+'/'
+parseInt(pos.y)+', width/height: '
+parseInt(pos.width)+'/'
+parseInt(pos.height)
);
}
function handleMouseOut(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mouseOut stuff here
isDown=false;
}
function handleMouseMove(e){
if(!isDown){return;}
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousemove stuff here
ctx.beginPath();
ctx.moveTo(startX,startY);
ctx.lineTo(mouseX,mouseY);
ctx.stroke();
startX=mouseX;
startY=mouseY;
}
body{ background-color: white; }
#canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4 id='results'>Sign by dragging</h4>
<canvas id="canvas" width=300 height=300></canvas>
[ Addition based on additional question ]
In addition to the signature there could be 2 initials some where on
the contract...How would you hand that?
That involves set recognition through establishing a bounding box.
Find the row containing the topmost opaque pixel,
Move downward by row until you have sufficient rows with no opaque pixels (== until you're sure the signature is vertically complete).
Find the column containing the leftmost opaque pixel,
Move rightward by column until you have sufficient rows with no opaque pixels (== until you're sure the signature is horizontally complete).
The bounding box of the signature is the left/right and top/bottom pixels determined in #1-4.
Erase the pixels in the bounding box.
At this point you've successfully captured the first signature (or initials).
Repeat steps #1-6 until you find no pixels (== until there are no more signatures or initials).
Good luck with your project!
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I have created:
an HTML5 canvas 100% width and height of screen with taphold and tapmove event listeners.
I would like to create:
a vertically curved canvas line (Bezier) that is the height of the canvas,
And moves downward on taphold until touch ends while
the actual point(s) on the line being touched change color as you trace the line
As the line is moving downward, the line is continually generating from the top of the page
id like this vertically curvy line to be neverending if touchhold persists
If your touch lands outside the line:
//alert something
A Demo: http://jsfiddle.net/m1erickson/k5KsC/
OK, here is code to draw a curvey line down the canvas and turn that line a different color as the user drags across the line (I use mouse instead of drag, but you can substitute touch).
The concepts involved in making this work are fairly complex so your "homework" is to (1) Google these concepts and (2) learn how they work and (3) see how they are applied in the code.
mouse and touch events
drawing quadratic and Bezier curves in canvas
creating a spline in canvas (your curvey vertical line is actually a spline)
globalCompositeOperation in canvas (this is used to change the line color as the user drags)
Here is example 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;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
ctx.lineCap = "round";
ctx.lineWidth=5;
ctx.fillStyle="maroon";
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 $alert=$("#alert");
var curves;
var maxY=0;
drawCurveyLine();
function drawCurveyLine(){
var points=[];
for(var i=0;i<10;i++){
var x=Math.random()*20+10;
var y=i*canvas.height/9;
points.push(x);
points.push(y);
}
curves=calculateSplineCurves(points,.25);
drawSpline(curves,"skyblue")
}
function calculateSplineCurves(pts,t){
var cp=[]; // array of control points, as x0,y0,x1,y1,...
var n=pts.length;
var curves=[];
// Draw an open spline
for(var i=0;i<n-4;i+=2){
cp=cp.concat(getControlPoints(pts[i],pts[i+1],pts[i+2],pts[i+3],pts[i+4],pts[i+5],t));
}
// Q-start
curves.push({x0:pts[0],y0:pts[1],x1:cp[0],y1:cp[1],x2:pts[2],y2:pts[3]});
// B-curves
for(var i=2;i<pts.length-5;i+=2){
ctx.beginPath();
curves.push({x0:pts[i],y0:pts[i+1],x1:cp[2*i-2],y1:cp[2*i-1],x2:cp[2*i],y2:cp[2*i+1],x3:pts[i+2],y3:pts[i+3]});
}
// Q-end
curves.push({x0:pts[n-4],y0:pts[n-3],x1:cp[2*n-10],y1:cp[2*n-9],x2:pts[n-2],y2:pts[n-1]});
return(curves);
}
//
function drawSpline(curves,linecolor){
// Q-starting
var q=curves[0];
ctx.beginPath();
ctx.moveTo(q.x0,q.y0);
ctx.quadraticCurveTo(q.x1,q.y1,q.x2,q.y2);
// B's
for(var i=1;i<curves.length-1;i++){
var b=curves[i];
ctx.bezierCurveTo(b.x1,b.y1,b.x2,b.y2,b.x3,b.y3);
}
// Q-ending
var q=curves[curves.length-1];
ctx.quadraticCurveTo(q.x1,q.y1,q.x2,q.y2);
ctx.strokeStyle=linecolor;
ctx.stroke();
};
//
function getControlPoints(x0,y0,x1,y1,x2,y2,t){
var d01=Math.sqrt(Math.pow(x1-x0,2)+Math.pow(y1-y0,2));
var d12=Math.sqrt(Math.pow(x2-x1,2)+Math.pow(y2-y1,2));
var fa=t*d01/(d01+d12);
var fb=t-fa;
var p1x=x1+fa*(x0-x2);
var p1y=y1+fa*(y0-y2);
var p2x=x1-fb*(x0-x2);
var p2y=y1-fb*(y0-y2);
return [p1x,p1y,p2x,p2y];
}
function handleMouseDown(e){
e.preventDefault();
e.stopPropagation();
startX=parseInt(e.clientX-offsetX);
startY=parseInt(e.clientY-offsetY);
// Put your mousedown stuff here
isDown=true;
}
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();
e.stopPropagation();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
if(mouseX>60){
$alert.text("You are outside the line!");
}else{
if(mouseY>maxY){
maxY=mouseY;
$alert.text("OK");
ctx.save();
ctx.globalCompositeOperation="source-atop"
ctx.fillRect(0,0,300,maxY);
ctx.restore();
}
}
}
$("#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 id="alert">Drag down the curvey line.</h4>
<canvas id="canvas" width=300 height=500></canvas>
</body>
</html>
was wondering if it was possible to add/remove a circle on a canvas with a mouse event, such as mousedown. The main point being able to move a checker piece that is drawn on the canvas. Here my code that draws the pieces, I added the event listener, but i don't know how to draw another piece but clicking somewhere on the canvas.
<script type="text/javascript">
var canvas=document.getElementById("checkerboard");
var context2d=canvas.getContext("2d");
canvas.addEventListener("mousedown", moveP, false);
function play(){
context2d.fillStyle="red";
for(var x=0; x<8; x++){
for(var y=0; y<3; y++){
if(((x+y)%2)==1){
context2d.beginPath();
context2d.moveTo(x*80+5, y*80+40);
context2d.arc(x*80+40, y*80+40, 30, 0, 2*Math.PI);
context2d.lineWidth=15;
context2d.strokeStyle="#9F000F";
context2d.stroke();
context2d.fill();
}
}
}
context2d.fillStyle="grey";
for(var x=0; x<8; x++){
for(var y=5; y<8; y++){
if(((x+y)%2)==1){
context2d.beginPath();
context2d.moveTo(x*80+5, y*80+40);
context2d.arc(x*80+40, y*80+40, 30, 0, 2*Math.PI);
context2d.lineWidth=15;
context2d.strokeStyle="#B6B6B4";
context2d.stroke();
context2d.fill();
}
}
}
}
</script>
thanks for any help
You can listen for mousedown and mouseup events on the canvas like this:
// get references to the canvas and its context
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
// get the bounding box of the canvas
// (needed when calculating the mouse position)
var BB=canvas.getBoundingClientRect();
var offsetX=BB.left;
var offsetY=BB.top;
// tell the browser to trigger handleMousedown & handleMouseup
// in response to mouse events
canvas.onmousedown=handleMousedown;
canvas.onmouseup=handleMouseup;
And you can respond to mouse events like this:
function handleMousedown(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// calculate the mouse position
var mouseX=e.clientX-offsetX;
var mouseY=e.clientY-offsetY;
//now do your mouse down stuff
}
function handleMouseup(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// calculate the mouse position
var mouseX=e.clientX-offsetX;
var mouseY=e.clientY-offsetY;
//now do your mouse up stuff
}
Here's a Demo: http://jsfiddle.net/m1erickson/tP3m4/
I have a canvas drawing implemented on my project. I would like to show speech-bubbles with information related to specific mouse clicks on the canvas. Say a click on a particular region of my canvas allows for a popup that gives text information about that region on the canvas.
<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.0.min.js"></script>
<ajaxToolkit:BalloonPopupExtender ID="BalloonPopupExtender1"
runat="server"
TargetControlID="myCanvas"
BalloonPopupControlID="Panel1"
Position="TopLeft"
BalloonStyle="Cloud"
BalloonSize="Small"
CustomCssUrl="CustomStyle/BalloonPopupOvalStyle.css"
CustomClassName="oval"
UseShadow="true"
ScrollBars="Auto"
DisplayOnMouseOver="true"
DisplayOnFocus="false"
DisplayOnClick="true" />
<canvas id="myCanvas" width="915" height="850" style="border: 2px double #000000;"></canvas>
<script type="text/javascript">
However this doesn't work, I believe this is because myCanvas is not a asp.net/server side element, hence runat ="server" isn't correct methodology.
I am currently following these blogs:-
http://www.c-sharpcorner.com/UploadFile/364074/balloonpopupextendercontrol-in-ajax/
http://www.asp.net/ajaxLibrary/AjaxControlToolkitSampleSite/BalloonPopup/BalloonPopupExtender.aspx
Any idea how to implement the popup on the canvas, upon a click?
Given that you want to respond to clicks on specific canvas coordinates, you might have to work on the client side. Here's code to do an info popup on the client side.
This is code that will draw an info balloon inside a separate canvas element. The canvas is moved off-screen until it's needed. You can of course, style this popup balloon in any way you want because it's a canvas element!
<canvas id="balloon" width=105 height=105></canvas>
function drawBalloon(X,Y,theInfo){
popCtx.save();
popCtx.fillStyle="#FD0";
popCtx.strokeStyle="#000";
// draw the balloon
popCtx.beginPath();
popCtx.moveTo(52,02);
popCtx.quadraticCurveTo(02,02,02,42);
popCtx.quadraticCurveTo(02,77,27,77);
popCtx.quadraticCurveTo(27,102,07,102);
popCtx.quadraticCurveTo(37,102,42,77);
popCtx.quadraticCurveTo(102,77,102,42);
popCtx.quadraticCurveTo(102,02,52,02);
popCtx.lineWidth=3;
popCtx.stroke();
popCtx.fill();
// draw theInfo
popCtx.font="10pt arial";
popCtx.fillStyle="black";
popCtx.fillText(theInfo,10,50);
popCtx.restore();
// move the balloon canvas to the target
$("#balloon").css({left:offsetX+X, top:offsetY+Y});
}
If you're not used to client-side javascript, here's how to get the position of the target-filled canvas relative to the window
<canvas id="canvas" width=300 height=300></canvas>
// get the position of canvas relative to window
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
And here's how to listen for clicks on the target-filled canvas.
// listen for clicks on the canvas
$("#canvas").click(function(e){
// get the mouseclick position
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// see if we clicked on any targets, show the balloon
for(var i=0;i<circles.length;i++){
var circle=circles[i];
var dx=circle.x-mouseX;
var dy=circle.x-mouseY;
var radius=circle.radius;
// true if we clicked in the target circle
if(dx*dx+dy*dy<=radius*radius){
drawBalloon(circles[i].x+radius,circles[i].y-100,circles[i].info);
}
}
});
To test if any target location on the canvas was clicked, we can test a circular area around the target like this:
var dx=targetCircle.x-mouseX;
var dy=targetCircle.x-mouseY;
var radius=targetCircle.radius;
// true if we clicked in the target circle
if(dx*dx+dy*dy<=radius*radius){
// we hit a target, display the balloon
}
Here is working example code and a Fiddle: http://jsfiddle.net/m1erickson/AJvkN/
<!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:10px;padding-top:100px; }
#canvas{border:1px solid red;}
#balloon{ position:absolute; left:-200px; }
</style>
<script>
$(function(){
// get reference to our drawing canvas
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
// get reference to our balloon canvas
var balloon=document.getElementById("balloon");
var popCtx=balloon.getContext("2d");
// get the position of canvas relative to window
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
// define some targets and their basic info
var circles=[];
circles.push({x:40, y:30, radius:15,color:"red", info:"I'm red."});
circles.push({x:150, y:150,radius:25,color:"green",info:"I'm centered."});
circles.push({x:110, y:85, radius:40,color:"blue", info:"I'm big."});
// draw the target circles on the canvas
for(var i=0;i<circles.length;i++){
drawCircle(circles[i]);
}
// listen for clicks on the canvas and show the balloon
$("#canvas").click(function(e){
// get the mouseclick position
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// see if we clicked on any targets
for(var i=0;i<circles.length;i++){
var circle=circles[i];
var dx=circle.x-mouseX;
var dy=circle.x-mouseY;
var radius=circle.radius;
// true if we clicked in the target circle
if(dx*dx+dy*dy<=radius*radius){
drawBalloon(circles[i].x+radius,circles[i].y-100,circles[i].info);
}
}
});
// listen for clicks on the balloon and then hide the balloon
$("#balloon").click(function hideBalloon(e){ $("#balloon").css({left:-200}); });
function drawCircle(circle){
ctx.save();
ctx.beginPath();
ctx.fillStyle=circle.color;
ctx.strokeStyle="black";
ctx.lineWidth=3;
ctx.arc(circle.x,circle.y,circle.radius,0,Math.PI*2,false);
ctx.closePath();
ctx.fill();
ctx.stroke();
ctx.restore();
}
function drawBalloon(X,Y,theInfo){
popCtx.save();
popCtx.fillStyle="#FD0";
popCtx.strokeStyle="#000";
// draw the balloon
popCtx.beginPath();
popCtx.moveTo(52,02);
popCtx.quadraticCurveTo(02,02,02,42);
popCtx.quadraticCurveTo(02,77,27,77);
popCtx.quadraticCurveTo(27,102,07,102);
popCtx.quadraticCurveTo(37,102,42,77);
popCtx.quadraticCurveTo(102,77,102,42);
popCtx.quadraticCurveTo(102,02,52,02);
popCtx.lineWidth=3;
popCtx.stroke();
popCtx.fill();
// draw theInfo
popCtx.font="10pt arial";
popCtx.fillStyle="black";
popCtx.fillText(theInfo,10,50);
popCtx.restore();
// move the balloon canvas to the target
$("#balloon").css({left:offsetX+X, top:offsetY+Y});
}
}); // end $(function(){});
</script>
</head>
<body>
<p>Click circles to popup an info balloon</p>
<p>When info balloon appears, click it do dismiss it</p>
<canvas id="canvas" width=300 height=300></canvas>
<canvas id="balloon" width=105 height=105></canvas>
</body>
</html>