JQuery tooltip in base of canvas coordinates - javascript

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>

Related

How to fillRect canvas grid cell depending on mouse position?

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>

Making different figures on canvas html5

I have a canvas but I don't know how to create other figure in the same canvas which overlay it, I have 2 buttons, one to puts images and then link it and make a figure and other to puts another image but in a different figure.
For example you have the button "a" and button "b". The button "a" puts images and make the figure linking the images. Now you want to start a new figure, you use the button "b", puts a image, and when you back to button "a" it must link the new image that buttons "b" has put before. I don't know If I'm explaining well.
I'll try to pass a variable to compare if you are using one button or another to use the same function to draw. the variable is nF, if nF=0 => button "a" if nF=1=>button "b"
Here is my code
function position(year, mon) { //that function puts the images in the html
$('#' + year + ' .' + mon).prepend('<img class="black_point" src="./images/circle.png"/>');
}
function draw(nF) {
var fN = nF;
var table = document.getElementById("table");
var images = table.getElementsByTagName("img");
var canvas = document.getElementById("miCanvas");
var ctx = canvas.getContext("2d");
var x, y; // Remember coordinates
canvas.width = table.offsetWidth;
canvas.height = table.offsetHeight;
function connect(image, index) { //this function link the images
var tabBcr = table.getBoundingClientRect();
var imgBcr = image.getBoundingClientRect();
x = imgBcr.left + (imgBcr.width / 2) - tabBcr.left;
y = imgBcr.top + (imgBcr.height / 2) - tabBcr.top;
index === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y);
ctx.save(); //save the state I think
}
// new path here
ctx.beginPath();
for (var i = 0; i < images.length; i++) {
connect(images[i], i); // provide index so we can sep. move/line
}
if (fN == 1) {//This doesn't work :(
ctx.fillStyle = "orange";
ctx.globalCompositeOperation = "source-over";
ctx.fill();
cxt.restore();
} else {
// then at the end:
ctx.fill();
cxt.restore();
}
}
Since the original description in your question differs greatly from your newly added images, I offer this code as a learning starting point without explanation:
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.lineWidth=2;
var colors=['green','blue','gold','cyan'];
var figures=[];
var selectedFigure=-1;
var circles=[];
var selectedCircle=-1;
var connectors=[];
addFigure();
$('#new').attr('disabled',true);
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$('#new').click(function(){
addFigure();
});
///// functions
function addFigure(){
figures.push({
circleCount:0,
color:randomColor(),
lastCX:0,
lastCY:0
});
selectedFigure=figures.length-1;
}
function addCircle(mx,my){
var figure=figures[selectedFigure];
var circle={
id:circles.length,
cx:mx,
cy:my,
radius:15,
figure:selectedFigure,
color:figure.color,
};
circles.push(circle);
if(figure.circleCount>0){
var connector={
figure:selectedFigure,
x0:figure.lastCX,
y0:figure.lastCY,
x1:mx,
y1:my,
}
connectors.push(connector);
}
figure.lastCX=mx;
figure.lastCY=my;
figure.circleCount++;
selectedCircle=circle.id;
$('#new').attr('disabled',false);
}
function drawAll(){
ctx.clearRect(0,0,cw,ch);
for(var i=0;i<connectors.length;i++){
drawConnector(connectors[i]);
}
for(var i=0;i<circles.length;i++){
drawCircle(circles[i]);
}
}
function drawCircle(circle){
var highlighted=(circle.figure==selectedFigure);
ctx.strokeStyle=(highlighted)?'red':'black';
ctx.lineWidth=(circle.id==selectedCircle)?6:2;
ctx.beginPath();
ctx.arc(circle.cx,circle.cy,circle.radius,0,Math.PI*2);
ctx.closePath();
ctx.fillStyle=circle.color;
ctx.fill();
ctx.stroke();
ctx.lineWidth=2;
}
function drawConnector(connector){
var highlighted=(connector.figure==selectedFigure);
ctx.strokeStyle=(highlighted)?'red':'lightgray';
ctx.beginPath();
ctx.moveTo(connector.x0,connector.y0);
ctx.lineTo(connector.x1,connector.y1);
ctx.stroke();
}
function handleMouseDown(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
if(selectedFigure<0){return;}
var mouseX=parseInt(e.clientX-offsetX);
var mouseY=parseInt(e.clientY-offsetY);
var wasCircleClicked=false;;
for(var i=0;i<circles.length;i++){
var c=circles[i];
var dx=mouseX-c.cx;
var dy=mouseY-c.cy;
if(dx*dx+dy*dy<=c.radius*c.radius){
selectedFigure=c.figure;
selectedCircle=i;
var figure=figures[selectedFigure];
figure.lastCX=c.cx;
figure.lastCY=c.cy;
wasCircleClicked=true;
break;
}
}
if(!wasCircleClicked){
addCircle(mouseX,mouseY);
}
drawAll();
}
function randomColor(){
if(colors.length>0){
var color=colors[0];
colors.splice(0,1);
return(color);
}else{
return('#'+Math.floor(Math.random()*16777215).toString(16));
}
}
body{ background-color: white; }
#canvas{border:1px solid red; margin:0 auto; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Click on empty area to add a circle to the currently selected figure.<br><br>Click on a circle to select its figure.<br>Selected figures have a red stroke.<br>New circles will be connected to the last-clicked circle.</h4>
<button id=new>Add new figure</button><br>
<canvas id="canvas" width=400 height=300></canvas>
Here's a framework for displaying the people of different families.
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(); }
// vars
var selectedFamily=0;
var nextFamily=0;
var families=[];
// set listeners
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$(document).on('change','.fam',function(){
selectedFamily=this.value;
$('#focusFamily').text('Click canvas to add person to family#'+selectedFamily);
draw();
});
$('#addfamily').click(function(){ addFamily(); });
// add a first family
addFamily();
// functions
function addFamily(){
families.push({id:nextFamily,people:[]});
var id=nextFamily;
var input=$('<input type=radio />');
input.prop({
'value':nextFamily,
'id':'fam'+nextFamily,
'name':'fams',
'class':'fam',
'checked':'checked',
});
var label=$('<label>',{
'for':'fam'+nextFamily,
'html':'Work on Family#'+nextFamily,
});
$('#family').append('<br>').append(input).append(label);
selectedFamily=nextFamily;
nextFamily++;
draw();
}
function handleMouseDown(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
mx=parseInt(e.clientX-offsetX);
my=parseInt(e.clientY-offsetY);
families[selectedFamily].people.push({x:mx,y:my});
draw();
}
function draw(){
ctx.clearRect(0,0,cw,ch);
var people=families[selectedFamily].people;
for(var i=0;i<people.length;i++){
var person=people[i];
ctx.beginPath();
ctx.arc(person.x,person.y,15,0,Math.PI*2);
ctx.closePath();
ctx.fill();
ctx.stroke()
}
}
body{ background-color: ivory; }
#container{
display:inline-block;
vertical-align:top;
border:1px solid blue;
padding:10px;
}
#canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<br>
<h4 id=focusFamily>Click canvas to add person to family#0</h4>
<canvas id="canvas" width=300 height=300></canvas>
<div id=container>
<button id=addfamily>Add Family</button>
<div id=family></div>
</div>

How to differentiate click and mousedown event in JavaScript?

I have a canvas, I want to draw dots when user clicked and draw a line when clicked and dragged.
In order to identify whether I should generate a line when mouse is moving on the canvas, I set a variable 'isDrawing' to tell if the user has clicked on the canvas before moving on it. I bind 'mousedown' event to the canvas and set 'isDrawing' to true when the event is triggered. If it is true I will start drawing a line, otherwise I will do nothing to this behavior. But the problem is when user clicked to draw dots, the 'isDrawing' is also set to true because the 'mousedown' event is triggered by the click. My question is how to differentiate the click and mousedown event so that when user just clicked somewhere the 'mousedown' event will not be triggered? thanks.
#Aaron has the start of a good idea...Add your dot in mouseup instead of mousedown.
In mouseup if the mouse has been dragged less than 5 total pixels then treat the mouseup as a click rather than a drag. (5 pixels is an example--adjust for your desired tolerances).
In mousemove, delay drawing your line until the mouse has been dragged at least 5 pixels.
Here's example code and a Demo: http://jsfiddle.net/m1erickson/ZTuKP/
<!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 lastX,lastY;
var dragHash;
function handleMouseDown(e){
e.preventDefault();
e.stopPropagation();
lastX=parseInt(e.clientX-offsetX);
lastY=parseInt(e.clientY-offsetY);
// Put your mousedown stuff here
dragHash=0;
isDown=true;
}
function handleMouseUp(e){
e.preventDefault();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
if(dragHash<5){
alert("It's a click...add a dot");
}else{
alert("You've been dragging");
}
// Put your mouseup 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-lastX;
var dy=mouseY-lastY;
lastX=mouseX;
lastY=mouseY;
// accumulate the drag distance
// (used in mouseup to see if this is a drag or click)
dragHash+=Math.abs(dx)+Math.abs(dy);
if(dragHash>4){
// it's a drag operation, draw the line
}
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
Here's an example using pure javascript small and compact: http://jsfiddle.net/kychan/2t97S/
function e(id) { return document.getElementById(id); }
var box = e('box'),
ctx = box.getContext('2d'),
w = box.width,
h = box.height,
mx = 0,
my = 0
;
ctx.fillStyle = '#333';
ctx.fillRect(0,0,w,h);
ctx.fillStyle = '#FF0000';
ctx.strokeStyle= '#FF0000';
box.addEventListener('mousedown', function(e) {
mx = e.pageX - box.offsetLeft,
my = e.pageY - box.offsetTop;
}, false);
// reduces dender.
function d(i,c) {
return (c-10<i && c+10>i);
}
box.addEventListener('mouseup', function(e) {
var nx = e.pageX - box.offsetLeft,
ny = e.pageY - box.offsetTop;
ctx.beginPath();
if (d(mx,nx) && d(my,ny)) {
ctx.arc(mx,my,1, 0, Math.PI*2, false);
}else{
ctx.moveTo(mx, my);
ctx.lineTo(nx, ny);
}
ctx.closePath();
ctx.stroke();
mx=nx, my=ny;
}, false);

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.

canvas drag and drop with multiple items

I am creating a multiple item drag and drop for a project and have a reached a wall.
At present I have 5 square items I have added to the canvas and also stored there x, y, width, height, bgcolour into an array called items. I have detected when the mouse selects one of these squares and can drag an item around. However my issue is that the item I am dragging around is always the same item, the first one added to the canvas. If anybody could help me work out how to detect which item specifically I have selected that would be great.
There is a'lot of code so I will try and post only the required bits.
//Items are added to canvas and values added to items[];
//a click event runs when the canvas is clicked, the following code is then run
var mouseCheck = function(e) {
var length = items.length;
var pos = $('#scalesPlatform').offset(),
top = pos.top,
left = pos.left,
mx = e.pageX - left,
my = e.pageY - top;
var imagedata = ctx.getImageData(mx, my, 1, 1);
if (imagedata.data[3] > 0) {
for (var i = length - 1; i >= 0; i--) {
var hit = items[i];
offsetX = mx - items[i].x;
offsetY = my - items[i].y;
hit.x = mx - offsetX;
hit.y = my - offsetY;
canvas.addEventListener('mousemove', function() {
move(hit, drag, items, event);
});
canvas.addEventListener('mouseup', function() {
drag = false;
move(hit, drag, event);
});
}
}
}
The issue is I need the variable hit to equal the item I have selected.
Any help would be greatly apprecaited.
Here’s how to drag/drop with multiple items
You have your squares defined in objects:
var items=[]
items.push({x:0,y:10,width:50,height:50,color:"red",isDragging:false});
items.push({x:70,y:10,width:50,height:50,color:"green",isDragging:false});
items.push({x:140,y:10,width:50,height:50,color:"blue",isDragging:false});
So you can hit test like this to detect which item(s) will be dragged:
function setDragging(x,y){
for(var i=0;i<items.length;i++){
var item=items[i];
// if x/y hit this item, set it’s isDragging flag
if(x>=item.x && x<=item.x+item.width && y>=item.y && y<=item.y+item.height){
item.isDragging=true;
}
}
}
Your mousemove handler calculates the distance of the drag.
dragX=mouseX-startX;
dragY=mouseY-startY;
Then in your draw() function you can handle both dragging and non-dragging items.
Items being dragged will be drawn at their original position plus dragX/dragY.
if(item.isDragging){
ctx.rect(item.x+dragX,item.y+dragY,item.width,item.height);
}else{
ctx.rect(item.x,item.y,item.width,item.height);
}
Here is example code and a Fiddle: http://jsfiddle.net/m1erickson/62L9q/
<!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 isMouseDown=false;
var startX;
var startY;
var dragX;
var dragY;
var items=[]
items.push({x:0,y:10,width:50,height:50,color:"red",isDragging:false});
items.push({x:70,y:10,width:50,height:50,color:"green",isDragging:false});
items.push({x:140,y:10,width:50,height:50,color:"blue",isDragging:false});
draw();
function draw(){
ctx.clearRect(0,0,canvas.width,canvas.height);
for(var i=0;i<items.length;i++){
var item=items[i];
if(isMouseDown){
}
ctx.beginPath();
if(item.isDragging){
ctx.rect(item.x+dragX,item.y+dragY,item.width,item.height);
}else{
ctx.rect(item.x,item.y,item.width,item.height);
}
ctx.fillStyle=item.color
ctx.fill();
}
}
function setDragging(x,y){
for(var i=0;i<items.length;i++){
var item=items[i];
if(x>=item.x && x<=item.x+item.width && y>=item.y && y<=item.y+item.height){
item.isDragging=true;
}
}
}
function clearDragging(x,y){
for(var i=0;i<items.length;i++){
var item=items[i];
if(item.isDragging){
items[i].isDragging=false;
item.x+=dragX;
item.y+=dragY;
}
}
}
function handleMouseDown(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousedown stuff here
startX=mouseX;
startY=mouseY;
setDragging(startX,startY);
isMouseDown=true;
}
function handleMouseUp(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mouseup stuff here
isMouseDown=false;
clearDragging();
}
function handleMouseOut(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mouseOut stuff here
isMouseDown=false;
clearDragging();
}
function handleMouseMove(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousemove stuff here
if(isMouseDown){
dragX=mouseX-startX;
dragY=mouseY-startY;
draw(mouseX,mouseY);
}
}
$("#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>

Categories

Resources