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)
Related
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();
}
}
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>
here's my HTML
<html>
<head>
<meta charset="UTF-8" />
<script src="script.js"></script>
</head>
....
and here's the javascript. everything was fine when i had the script inline, but when i move it outside of the html file it breaks. just a simple html canvas drawing but not sure the issue. ideas?
// Canvas 1
var canvas = document.getElementById("canvas1");
var context = canvas.getContext("2d");
photo = document.getElementById("red");
function drawImage() {
context.drawImage(photo, 0, 0);
}
window.addEventListener("load", drawImage, false);
// Canvas 2
var canvas2 = document.getElementById("canvas2");
var context2 = canvas2.getContext("2d");
context2.fillStyle = "darkRed";
context2.fillRect(0, 2, 800, 500);
context2.moveTo(0, 0);
context2.lineTo(400, 300);
// Canvas 3
var canvas3 = document.getElementById("canvas3");
var context3 = canvas3.getContext("2d");
photo3 = document.getElementById("red2");
function drawImage() {
for (var x = 0; x < 6; x++) {
for (var y =0; y < 6; y++ ) {
context3.drawImage(photo3, x * 100, y * 75, 100, 75);
}
}
}
window.addEventListener("load", drawImage, false);
Since you're loading the script in the <head>, everything is running before the DOM is loaded, so all your getElementBuId() calls are failing. You either need to put the <script> tag at the end of the <body>, or put all the code into a window.onload function, e.g.
window.onload = function() {
var canvas = document.getElementById("canvas1");
var context = canvas.getContext("2d");
photo = document.getElementById("red");
function drawImage() {
context.drawImage(photo, 0, 0);
}
window.addEventListener("load", drawImage, false);
...
};
This has the added benefit of not polluting the global namespace.
I'll second what Barmar said. In general, I load my JavaScript at the end of the html for better performance, and so I'm sure I won't have this issue.
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).
I have a canvas that you can draw things with mouse.. When I click the button It has to capture the drawing and add it right under the canvas, and clear the previous one to draw something new..So first canvas has to be static and the other ones has to be created dynamically with the drawing that I draw .. What should I do can anybody help
here is jsfiddle
http://jsfiddle.net/dQppK/378/
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
painting = false,
lastX = 0,
lastY = 0;
You can create a new canvas the same way you’d create any element:
var newCanvas = document.createElement('canvas');
Then you can copy over your old canvas:
newCanvas.width = oldCanvas.width;
newCanvas.height = oldCanvas.height;
oldCanvas.parentNode.replaceChild(newCanvas, oldCanvas);
ctx = newCanvas.getContext('2d');
But if you’re just looking to clear your drawing surface, what’s wrong with clearRect?
ctx.clearRect(0, 0, canvas.width, canvas.height);
Or, in your case, another fillRect. Updated demo
here's the function i use for this, it is part of a library i made and use to ease a few things about canvas.
I just put it on github in case other function might be be of use, i'll have to make a readme later...
https://github.com/gamealchemist/CanvasLib
with namespaceing removed, the code is as follow to insert a canvas :
// insert a canvas on top of the current document.
// If width, height are not provided, use all document width / height
// width / height unit is Css pixel.
// returns the canvas.
insertMainCanvas = function insertMainCanvas (_w,_h) {
if (_w==undefined) { _w = document.documentElement.clientWidth & (~3) ; }
if (_h==undefined) { _h = document.documentElement.clientHeight & (~3) ; }
var mainCanvas = ga.CanvasLib.createCanvas(_w,_h);
if ( !document.body ) {
var aNewBodyElement = document.createElement("body");
document.body = aNewBodyElement;
};
document.body.appendChild(mainCanvas);
return mainCanvas;
}