Move cursor and display it in another place - javascript

I am learning JavaScript. And I have this task - to draw two rectangles, in one of them, I should move the cursor, and it should appear in the second rectangle. It is not that hard to track the cursor, bu I have no idea how to display it somewhere else. Do I need to create separate canvas? How to display cursor image?
I would be very grateful for any tips!
Here is a simple code that I have for now:
<html>
<body>
<canvas id="myCanvas" width="800" height="600" ></canvas>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.rect(20, 20, 300, 200);
ctx.stroke();
ctx.rect(350, 20, 300, 200);
ctx.stroke();
var cursorX;
var cursorY;
document.onmousemove = function(e){
cursorX = e.pageX;
cursorY = e.pageY;
}
</script>
</body>

You should create an IMG with a cursor in it. Then, when you are moussing over one rectangle, use the img's (or containing DIV's) css to display it over the second rectangle correctly. It is similar to how you might display a tooltip
function (event) {
var x = event.pageX;
var y = event.pageY;
var mouseImg = document.getElementById('mouseImg');
if (mouseImg ) {
$(mouseImg ).css('left',(x + rectangleOffset.x) + 'px');
$(mouseImg ).css('top',y + rectangleOffset.y + 'px');
$(mouseImg ).show();
}
}

Related

How to add mouse event in drawn canvas compoent

I want to draw 200 or more(highly fluid) object in canvas.
and add mouse over, mouse click event each of them.
source code like this...
(valiable k is increase)
'
....
....
for( k = 0 ; k < 200; k++){
start = start[k];
end = end[k];
x1 = centerX-radius*Math.sin(-arg*start)*0.9;
y1 = centerY-radius*Math.cos(-arg*start)*0.9;
x2 = centerX-radius*Math.sin(-arg*start)*0.95;
y2 = centerY-radius*Math.cos(-arg*start)*0.95;
x3 = centerX-radius*Math.sin(-arg*end)*0.95;
y3 = centerY-radius*Math.cos(-arg*end)*0.95;
x4 = centerX-radius*Math.sin(-arg*end)*0.9;
y4 = centerY-radius*Math.cos(-arg*end)*0.9;
Shape(ctx, x1,y1,x2,y2,x3,y3,x4,y4,k);
}
function Shape(ctx, x1,y1,x2,y2,x3,y3,x4,y4, k){
ctx.strokeStyle = "black";
ctx.fillStyle = "red";
ctx.globalAlpha = 1.0;
ctx.moveTo(x1,y1);
ctx.lineTo(x2,y2);
ctx.lineTo(x3,y3);
ctx.lineTo(x4,y4);
ctx.lineTo(x1,y1);
ctx.lineWidth = 0.5;
ctx.fill();
ctx.stroke();
ctx.fillText(k,(x2+x3)/2,(y2+y3)/2);
}
....
....
my hope is..
if mouse over on shape, display valiable k
if mouse click on shape, go other url with valiable k parameter
but, I did not want to use image.
please help me.
thanks.
If you keep the shape's coordinates in an array, you can loop trough them and check for collision with the mouse's coordinates.
Canvas are drawn like bitmap. All the changes are made to the pixels, and no trace of line or path would be kept. If you want to see whether a click is on or inside certain path, you need to implement you own hit test. If the shapes you draw can overlap each other, you will need to handle the order by yourself. It's doable, but you are on your own.
The other way out is to use SVG instead. Because SVG are objects, browser will keep track of them for you. You can just add onclick to an SVG element like you do to an HTML element.
The easiest solution would be just use library like d3: http://d3js.org/
Since your shapes are irregular, it would be difficult to do hit-testing mathematically.
Fortunately, the context has the isPointInPath method that will test if the supplied mouseX / mouseY is inside the last defined path.
To hit-test your irregular shapes:
Keep enough information to redefine each path in an object.
Add each shape object to an array.
In the mousemove event handler...
Iterate through the array
Redefine each shape (1 at a time). Note: redefining is drawing without stroke/fill.
Use context.isPointInPath(mouseX,mouseY) to hit-test if the mouse is inside the last defined shape.
Here is example code and a Demo: http://jsfiddle.net/m1erickson/o5xp21t2/
<!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;
ctx.strokeStyle = "black";
ctx.fillStyle = "red";
ctx.globalAlpha = 1.0;
ctx.lineWidth = 0.5;
ctx.font="14px verdana";
var centerX=150;
var centerY=150;
var radius=120;
var arg=1;
var start=0;
var end=Math.PI/8;
var shapes=[];
for(var k=0;k<10;k++){
start+=Math.PI/8;
end+=Math.PI/8;
x1 = centerX-radius*Math.sin(-arg*start)*0.9;
y1 = centerY-radius*Math.cos(-arg*start)*0.9;
x2 = centerX-radius*Math.sin(-arg*start)*0.95;
y2 = centerY-radius*Math.cos(-arg*start)*0.95;
x3 = centerX-radius*Math.sin(-arg*end)*0.95;
y3 = centerY-radius*Math.cos(-arg*end)*0.95;
x4 = centerX-radius*Math.sin(-arg*end)*0.9;
y4 = centerY-radius*Math.cos(-arg*end)*0.9;
var s={x1:x1,y1:y1,x2:x2,y2:y2,x3:x3,y3:y3,x4:x4,y4:y4,k:k};
shapes.push(s);
Shape(s,k,true);
}
$results=$("#results");
$("#canvas").mousemove(function(e){handleMouseMove(e);});
function handleMouseMove(e){
e.preventDefault();
e.stopPropagation();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
for(var k=0;k<shapes.length;k++){
Shape(shapes[k],k,false);
if(ctx.isPointInPath(mouseX,mouseY)){
$results.text("Last mouseover: "+k);
}
}
}
function Shape(s, k, draw){
ctx.fillStyle="red";
ctx.beginPath();
ctx.moveTo(s.x1,s.y1);
ctx.lineTo(s.x2,s.y2);
ctx.lineTo(s.x3,s.y3);
ctx.lineTo(s.x4,s.y4);
ctx.lineTo(s.x1,s.y1);
if(draw){
ctx.fill();
ctx.stroke();
ctx.fillStyle="blue";
ctx.fillText(k,(s.x2+s.x3)/2,(s.y2+s.y3)/2);
}
}
}); // end $(function(){});
</script>
</head>
<body>
<p id=results>Hover mouse over shapes.</p>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

increase performance on html canvas mousemove image mask

I have a canvas that is drawing an image and clipping to create the effect that the image is being revealed. I have the code working properly I have tried using a debouce method and also rAF to increase the canvas rendering performance but I only saw small gains if any.
I suspect the way I am iterating through my array of x and y coordinates could be the issue.
It seems to lag quite a bit when it is out putting the array in console about the same rate as the circle appear on the screen.
Here is the redraw function:
function redraw(mouse) {
m.push(mouse);
m.forEach(function (a) {
ctx.drawImage(img, 0, 0);
ctx.beginPath();
ctx.rect(0, 0, 500, 500);
ctx.arc(a.x, a.y, 70, 0, Math.PI * 2, true);
ctx.clip();
ctx.fillRect(0, 0, 500, 500)
})
}
I guess what I am looking for is some advice to speed up my code so the rendering of the circles seems more like drawing.
Here is the working demo -> http://jsfiddle.net/naeluh/4h7GR/
There are several issues here :
• Your mouse code is a nightmare, traversing the DOM on every move.
• You are redrawing everything on each move.
So i suggest a way more efficient solution :
• stack two canvases, the one below is your image, the one on top is the mask.
• Deal efficiently with the mouse.
• Only clear part of the mask canvas on mouse move : just one circle drawn on the mask canvas for each move.
(for that i used a globalCompositeOperation = 'destination-out' )
Result is perfectly smooth either on Firefox, Chrome, or Safari .
(tested on mac OS).
the fiddle :
(you have to click to clear)
http://jsfiddle.net/gamealchemist/4h7GR/22/
html
<canvas style='position: absolute; top: 0;left: 0;' id="canvas1" width="500" height="500"></canvas>
<canvas style='position: absolute;top: 0;left: 0;' id="canvas2" width="500" height="500"></canvas>
js
var can = document.getElementById("canvas1");
var ctx = can.getContext("2d");
var can2 = document.getElementById("canvas2");
var ctx2 = can2.getContext("2d");
var img = new Image();
img.onload = function () { ctx.drawImage(img,0,0); };
img.src = "http://placekitten.com/500/500";
ctx2.fillStyle='#000';
ctx2.fillRect(0,0,500,500);
ctx2.globalCompositeOperation = 'destination-out';
function clearThis(x,y) {
console.log('toto');
ctx2.fillStyle='#F00000';
ctx2.beginPath();
ctx2.arc(x, y, 70, 0, Math.PI * 2, true);
ctx2.fill();
}
var mouse = {
x: 0,
y: 0,
down: false
};
function setupMouse(canvas, onMouseMove, preventDefault) {
var rectLeft, rectTop;
var hook = canvas.addEventListener.bind(canvas);
var mouseDown = updateMouseStatus.bind(null, true);
var mouseUp = updateMouseStatus.bind(null, false);
hook('mousedown', mouseDown);
hook('mouseup', mouseUp);
hook('mousemove', updateCoordinates);
hook('scroll', updateRect);
// var mouseOut = function() { mouse.down=false ; } ;
// hook('mouseout', mouseOut);
function updateMouseStatus(b, e) {
mouse.down = b;
updateCoordinates(e);
if (preventDefault) {
e.stopPropagation();
e.preventDefault();
}
}
function updateCoordinates(e) {
mouse.x = (e.clientX - rectLeft);
mouse.y = (e.clientY - rectTop);
onMouseMove(mouse.x, mouse.y);
}
function updateRect() {
var rect = canvas.getBoundingClientRect();
rectLeft = rect.left;
rectTop = rect.top;
}
updateRect();
};
setupMouse(can2, clearThis, true);
The Above Code will do Fine .. But nEed some Editing
I have Edited the Code in Fiddle ..and i beleive there Is some Improvement in perforamnce
So I looked a little more and found a bug as expected.
The main problem is the accumulation of the drawing path.
Why Need to add clip and fillRect at every go ..Do it at last... the Major issue solved,Like
can.addEventListener("mousemove", function (e) {
var mouse = getMouse(e, can);
requestAnimationFrame(function () {
redraw(mouse);
ctx.clip();
ctx.fillRect(0, 0, 500, 500);
console.log(mouse);
});
}, false);
2.The Updated JSFiidle is
UpdatedFiddle

HTML5 Canvas Coordinates Chnged in chrome

I have a Sharepoint page in which i want to show a hierarchical diagram with boxes.According to my requirement those boxes should work as links to other sharepoint pages in the same site.
Since sharepoint's default designer tools doesn't support designing such diagrams, I created a page with html5 canvas and the element i wanted inside that.
Inside the canvas i created few boxes and lines to connect them.And i added texts inside the boxes.Then i used a mouse listener to check whether the mouse pointer hovers over a box and if so changed the pointer icon and the link to be redirected to.
I added the canvas tag inside the sharepoint page by "Edit Source" and i added the javascript part using 'Embed Code'
Now the code works perfectly in IE and Firefox.
In chrome although the boxes,lines and text are drawn according to the coordinates i gave in the code but But when i hover the mouse over them it gives different coordinates for mouse listener in different browser sizes.So the mouse pointer doesn't change at correct locations ie: over the boxes.
This doesn't happen in firefox or IE. They changes the mouse pointer when it comes over the boxes and links to the pages perfectly.
Why does it change when i use chrome?
And why does it only affect to the mouse listener coordinates.
This is the code i used.(I have removed the repetitive parts which draws other boxes)
Same in jsfiddle
​<canvas id="myCanvas" height="500" width="960" style="border: 1px solid;">​<img src="" alt=""/> </canvas>​
<script>
var canvas = document.getElementById("myCanvas");
var ctx;
var rNBDX = 50; var rNBDY = 150;
var rectWidth = 200;
var rectHeight = 100;
var cornerRadius = 20;
var linkNBD="https://google.com";
var textNBD1 ="Google";
var linkHeight=20;
var linkNum = 0;
function draw(){
canvas = document.getElementById("myCanvas");
if(canvas.getContext){
ctx=canvas.getContext("2d");
//Drawing Lines
ctx.lineWidth = 3;
ctx.strokeStyle = '#000000';
ctx.moveTo(380, 100);
ctx.lineTo(380, 125);
ctx.stroke();
//Drawing Rectangles
ctx.fillStyle="#0b61d0";
ctx.strokeStyle="#0b61d0";
ctx.lineJoin = "round";
ctx.lineWidth = cornerRadius;
ctx.strokeRect(rNBDX+(cornerRadius/2), rNBDY+(cornerRadius/2), rectWidth-cornerRadius, rectHeight-cornerRadius);
ctx.fillRect(rNBDX+(cornerRadius/2), rNBDY+(cornerRadius/2), rectWidth-cornerRadius, rectHeight-cornerRadius);
//Drawing the Texts
ctx.font='24px Segoe UI Light';
ctx.fillStyle = "#FFFFFF";
ctx.fillText(textNBD1,(rNBDX+rectWidth/2)-(ctx.measureText(textNBD1).width)/2,rNBDY+rectHeight/2);
//Add mouse listeners
canvas.addEventListener("mousemove", on_mousemove, false);
canvas.addEventListener("click", on_click, false);
}
}
function on_mousemove (ev) {
var x, y;
if (ev.layerX || ev.layerX == 0) {
x = ev.layerX;
y = ev.layerY;
}
x-=canvas.offsetLeft;
y-=canvas.offsetTop;
if(x>=rNBDX && x <= (rNBDX + rectWidth) && y>=rNBDY && y<= (rNBDY+rectHeight)){
document.body.style.cursor = "pointer";
linkNum=1;
}
else{
document.body.style.cursor = "";
}
}
function on_click(e) {
switch (linkNum)
{
case 1:
window.location = linkNBD;
break;
}
}
draw();
</script>
Try adjusting the mouse coordinates like this:
function on_mousemove (ev) {
var x, y,
rect = canvas.getBoundingClientRect();
x = ev.clientX - rect.left + 1;
y = ev.clientY - rect.top + 1;
...
You will have to add (as in the example) the width of the left/top border though as getBoundingClientRect does not include those (you can calculate this dynamically using getComputedStyle and getPropertyValue of that for the borders).

Line is not being drawn correctly on canvas

I am a newbie in HTML5 but have good experience of HTML. I was learning about canvas and thought of making a program. In this I was handling the user's mousedown and mouseup and was setting up the values of my variables according to the coordinates of the mouse. Then with the help of those I was stroking the line on the canvas which is not being drawn properly.
The work I have done to achieve this:
HTML
<script type="text/javascript" src="jquery.min.js"></script>
<script src="bhaiya.js"></script>
<canvas id="myCanvas" style="height: 100%; width: 100%;">
</canvas>
JS
$(document).ready(function() {
var $x1 = 0;
var $x2 = 0;
var $y1 = 0;
var $y2 = 0;
$(this).mousedown(function(e){
$x1 = e.pageX;
$y1 = e.pageY;
});
$(this).mouseup(function(e){
$x2 = e.pageX;
$y2 = e.pageY;
var c = document.getElementById("myCanvas");
var context = c.getContext("2d");
context.moveTo($x1, $y1);
context.lineTo($x2, $y2);
context.stroke();
});
});
What is the problem? Any help would be appreciated! :)
1) If you're bothered by the fact the drawing is fuzzy and doesn't seem to follow the x and y you give, then you can fix it like this :
var c = document.getElementById("myCanvas");
c.width = c.clientWidth;
c.height = c.clientHeight;
2) you must take into account the offset due to the canvas position when it's not exactly in the top-left corner of the document :
$x1 = e.pageX-c.offsetLeft;
$y1 = e.pageY-c.offsetTop;
Demonstration
Note that in a real application you shouldn't recreate the context each time. In this case, you would also begin a new path when needed (probably at each click).
Use .beginPath():
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.beginPath();
context.moveTo(100, 150);
context.lineTo(450, 50);
context.stroke();
http://jsfiddle.net/j4XY8/
http://dev.opera.com/articles/view/html5-canvas-painting/ (might be helpful)

How can I alter the colour of a html5 canvas element using jquery?

Basically I have several canvas drawings on my page what I want to happen is when a the jquery function is activated the canvas drawings change to the colour of my choosing. I assume it involves some way of accessing context.fillStyle which defines the original colour but I am unsure how to alter it. In addition, would it be possible to instead give the canvas drawing a css style in the first instance and then change that style when the jquery is processed?
HTML
<canvas class="canvaslink" id="canvasId" width="50" height="50"></canvas>
<canvas class="canvaslink" id="canvasId2" width="50" height="50"></canvas>
Canvas script
<script>
function drawSomething(canvas) {
var context = canvas.getContext("2d");
var width = 125; // Triangle Width
var height = 45; // Triangle Height
var padding = 5;
// Draw a path
context.beginPath();
context.moveTo(padding + width-125, height + padding); // Top Corner
context.lineTo(padding + width-90,height-17 + padding); // point
context.lineTo(padding, height-35 + padding); // Bottom Left
context.closePath();
// Fill the path
context.fillStyle = "#9ea7b8";
context.fill();
}
drawSomething(document.getElementById("canvasId"));
drawSomething(document.getElementById("canvasId2"));
</script>
Jquery Script
<script>
var counter = $('#counter div strong');
var counterH2 = $('h2 strong');
$('#box').click(function(){
$("#counter").css("display", "block");
var counterValue = counter.text();
counterValue = ++counterValue;
counter.text(counterValue);
counterH2.text(counterValue);
if (counterValue == 3){
alert("Thanks for visiting!");
$('body').css({"background-color":"#9ea7b8"});
$('body').css({"color":"#11112c"});
**//I'd like to change the canvas colour here!**
}
});
</script>
Many thanks
It's as simple as this:
document.getElementById("ID").style.background = 'color';
You can do that :
var context = canvas.getContext('2d');
context.fillStyle = "#000000";
context.fill();
// Other properties ...
You can see an HTML5 canvas tutorial (very simple) here.
In case this is of any use, here is the solution I ended up with:
First the HTML:
<canvas class="canvaslink" id="canvasId" width="50" height="50"></canvas>
<canvas class="canvaslink" id="canvasIda" width="50" height="50"></canvas>
<canvas class="canvaslink" id="canvasId2" width="50" height="50"></canvas>
<canvas class="canvaslink" id="canvasId2a" width="50" height="50"></canvas>
I created duplicate canvas elements which I used CSS to hide with:
CSS:
#canvasIda, canvasId2a {
display:none;
}
Then I made the following changes to the original Jquery script:
<script>
var counter = $('#counter div strong');
var counterH2 = $('h2 strong');
$('#box').click(function(){
$("#counter").css("display", "block");
var counterValue = counter.text();
counterValue = ++counterValue;
counter.text(counterValue);
counterH2.text(counterValue);
if (counterValue == 3){
$('body').css({"background-color":"#9ea7b8"});
$('body').css({"color":"#11112c"});
$('a').css({"color":"#11112c"});
//remove the previous canvas elements
element = document.getElementById("canvasId");
element2 = document.getElementById("canvasId2");
element.parentNode.removeChild(element);
element2.parentNode.removeChild(element2);
//function to draw new canvas elements with new desired colour
function drawSomething2(canvas) {
var context = canvas.getContext("2d");
var width = 125; // Triangle Width
var height = 45; // Triangle Height
var padding = 5;
// Draw a path
context.beginPath();
context.moveTo(padding + width-125, height + padding); // Top Corner
context.lineTo(padding + width-90,height-17 + padding); // point
context.lineTo(padding, height-35 + padding); // Bottom Left
context.closePath();
// Fill the path
context.fillStyle = "#11112c";
context.fill();
}
//draw the canvas elements
drawSomething2(document.getElementById("canvasIda"));
drawSomething2(document.getElementById("canvasId2a"));
//display the previously hidden elements containing the new canvas drawings
$('#canvasIda').css({"display":"block"});
$('#canvasId2a').css({"display":"block"});
}
});
I'm sure many can come up with a more efficient solution but this worked and I'm not complaining.

Categories