Making a portion of the canvas link to another webpage - javascript

I currently have a code that simply draws circles onto a canvas. However, I want those circles to be able to direct the user to a given link if he or she chooses to click on the circle again. I'm not entirely sure how to implement this though. Simply put, can drawn objects be used as a click event to direct user to another webpage?
http://jsfiddle.net/PTDy9/
<head>
<script src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
</head>
<body>
<img id="graph" style=display:none src="http://i47.tinypic.com/29zr14o.jpg" alt="graph" >
<canvas id="myCanvas" width="700" height="400" style="border:1px solid #FFFFF;">
<script>
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
var img=document.getElementById("graph");
ctx.drawImage(img,0,0);
var color_list = ["#FFC0CB", "#00ffff", "#DA70D6", "#90EE90", "#FF8C00", "#CD853F"];
var color_iter = 0;
var bullet_y = 450;
var width = img.naturalWidth;
var height = img.naturalHeight;
jQuery(document).ready(function(){
$("#myCanvas").click(function(e){
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
if (x < width && y < height) {
var ctx= this.getContext("2d");
ctx.beginPath();
ctx.arc(x, y, 10,0, 2*Math.PI);
color = color_list[color_iter];
ctx.strokeStyle = color;
ctx.fillStyle = color;
if (color_iter == color_list.length-1) {
color_iter = 0;
}
else {color_iter = color_iter + 1;}
ctx.fillStyle = color;
ctx.globalAlpha = .4;
ctx.fill();
ctx.stroke();
var a = document.createElement('a');
}
});
})
</script>
</body>

Here's one way let the user click on a circle to open a specified url in a new browser tab.
First create 1+ link objects specifying the click area on the canvas and the desired url:
var links=[];
addLink(75,75,30,"Google","http://www.google.com");
addLink(150,150,30,"CNN","http://www.cnn.com");
function addLink(x,y,radius,label,url){
links.push({
cx:x,
cy:y,
radius:radius,
label:label,
link:url
});
}
Then listen for mouse clicks and test if any link area was clicked.
If any specific link area was clicked, then open up the corresponding url in a new browser tab:
$("#canvas").mousedown(function(e){handleMouseDown(e);});
function handleMouseDown(e){
e.preventDefault();
e.stopPropagation();
mx=parseInt(e.clientX-offsetX);
my=parseInt(e.clientY-offsetY);
for(var i=0;i<links.length;i++){
var link=links[i];
var dx=link.cx-mx;
var dy=link.cy-my;
if(dx*dx+dy*dy<link.radius*link.radius){
window.open(link.link,'_blank');
}
}
}
Full 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");
var $canvas=$("#canvas");
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var scrollX=$canvas.scrollLeft();
var scrollY=$canvas.scrollTop();
var links=[];
addLink(75,75,30,"Google","http://www.google.com");
addLink(150,150,30,"CNN","http://www.cnn.com");
drawLinks();
$("#canvas").mousedown(function(e){handleMouseDown(e);});
function addLink(x,y,radius,label,url){
links.push({
cx:x,
cy:y,
radius:radius,
label:label,
link:url
});
}
function drawLinks(){
ctx.save();
ctx.fillStyle="green";
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.font="14px verdana";
ctx.textAlign="center";
ctx.textBaseline="middle";
for(var i=0;i<links.length;i++){
var link=links[i];
ctx.beginPath();
ctx.arc(link.cx,link.cy,link.radius,0,Math.PI*2);
ctx.closePath();
ctx.fillStyle="blue";
ctx.fill();
ctx.fillStyle="white";
ctx.fillText(link.label,link.cx,link.cy);
}
ctx.restore();
}
function handleMouseDown(e){
e.preventDefault();
e.stopPropagation();
mx=parseInt(e.clientX-offsetX);
my=parseInt(e.clientY-offsetY);
for(var i=0;i<links.length;i++){
var link=links[i];
var dx=link.cx-mx;
var dy=link.cy-my;
if(dx*dx+dy*dy<link.radius*link.radius){
window.open(link.link,'_blank');
}
}
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

Related

Javascript Canvas one item flickering

I am trying to make to objects move towards each other in Canvas, when they meet and overlap one should then disappear and the other should fall down. Now I got the animation to do that, but one of the items is flickering.
<!DOCTYPE html>
<html>
<head>
<style>
canvas{border:#666 3px solid;}
</style>
</head>
<body onload="draw(530,15); draw1(1,15);">
<canvas id="canvas" width="600" height="400"></canvas>
<script>
function draw(x,y){
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.save();
ctx.clearRect(x, y, 600, 400);
ctx.fillStyle = "rgba(0,200,0,1)";
ctx.fillRect (x, y, 70, 50);
ctx.restore();
x -= 0.5;
if(x==300)
{
return;
};
var loopTimer = setTimeout('draw('+x+','+y+')',5);
};
function draw1(w,e){
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.save();
ctx.clearRect(w-1,e-2,600,400);
ctx.fillStyle = "rgba(0,200,0,1)";
ctx.fillRect (w, e, 70, 50);
ctx.restore();
w += 1;
if(w==265)
{
w -= 1;
e +=2;
};
var loopTimer = setTimeout('draw1('+w+','+e+')',10);
};
</script>
</body>
</html>
Been trying for two days, but can't seem to fix it properly. Thanks in advance.
You are rendering too many frames per second forcing the browser to present frames. Each time a draw function returns the browser presumes you want to present the frame to the page.
Animations need to be synced to the display refresh rate which for most devices is 60FPS. To do this you have one render loop that handles all the animation. You call this function via requestAnimationFrame (RAF) which ensures that the animation stays in sync with the display hardware and browser rendering.
<!DOCTYPE html>
<html>
<head>
<style>
canvas{border:#666 3px solid;}
</style>
</head>
<!-- dont need this <body onload="draw(530,15); draw1(1,15);">-->
<body>
<canvas id="canvas" width="600" height="400"></canvas>
<script>
var canvas,ctx,x,y,w,e;
var canvas,ctx,x,y,w,e;
function draw() {
ctx.fillStyle = "rgba(0,200,0,1)";
ctx.fillRect(x, y, 70, 50);
};
function draw1(w, e) {
ctx.fillStyle = "rgba(0,200,0,1)";
ctx.fillRect(w, e, 70, 50);
};
function update(time){ // high precision time passed by RAF when it calls this function
ctx.clearRect(0,0,canvas.width,canvas.height); // clear all of the canvas
if(w + 70 >= x){
e += 2;
}else{
x -= 0.75;
w += 1;
};
draw(x,y);
draw1(w,e);
requestAnimationFrame(update)
// at this point the function exits and the browser presents
// the canvas bitmap for display
}
function start(){ // set up
x = 530;
y = 15;
w = 1;
e = 15;
canvas = document.getElementById('canvas');
ctx = canvas.getContext('2d');
requestAnimationFrame(update)
}
window.addEventListener("load",start);
</script>
</body>
</html>
You're method of animation is very outdated (ie, the use of setTimeout). Instead you should be using requestAnimationFrame as demonstrated below. This will give smooth, flicker free animation.
<!DOCTYPE html>
<html>
<head>
<style>
canvas{border:#666 3px solid;}
</style>
</head>
<body onload="requestAnimationFrame(animate);">
<canvas id="canvas" width="600" height="400"></canvas>
<script>
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var x = 530, y = 15;
function animate(){
requestID = requestAnimationFrame(animate);
ctx.clearRect(x, y, 600, 400);
ctx.fillStyle = "rgba(0,200,0,1)";
ctx.fillRect (x, y, 70, 50);
x -= 0.5;
if(x==300)
{
cancelAnimationFrame(requestID)
};
}
</script>
</body>
</html>
the first 2 parameters of ctx.clearReact in both draw functions should be 0:
ctx.clearRect(0, 0, 600, 400);
This means you clear all canvas.

HTML Canvas draw a circle on mouse click and drag it untill the required radius is obtained

Im new to canvas and i was playing around with it.
I wanted to draw a circle on mouse click and radius of circle should be decided by mouse drag (similar to drawing circle in Paint in windows )
i have tried creating a circle but struck doing this
my code
<html>
<head>
</head>
<body style="margin:0">
<canvas id="canvas" width="500" height="500" style="border:1px solid"></canvas>
<script>
var canvas=document.getElementById('canvas');
var context=canvas.getContext('2d');
var radius=50;
var putPoint = function(e){
context.beginPath();
context.arc(e.clientX, e.clientY, radius, 0, Math.PI*2);
context.fill();
}
canvas.addEventListener('mousedown',putPoint);
</script>
</body>
</html>
my code in plunker
http://plnkr.co/edit/DPa9km1hHAAsCBCbnGvB?p=preview
I would be happy if someone help me out
Thanks in advance
the general ideia is that you have to take 2 points, the one there circle center will be (this is where the user presses the mouse), and the current point, where the mouse is moving
the distance between the 2 points will be the radius, and is given by the Pythagorean theorem h^2 = c^2 + c^2 so:
onmousedown save that point as center
omousemove calculate the distance to center and use as radius
omouseup stop the operation/animation
here is some sample code, modify to your needs
<html>
<head>
</head>
<body style="margin:0">
<canvas id="canvas" width="500" height="500" style="border:1px solid"></canvas>
<script>
var canvas=document.getElementById('canvas');
var context=canvas.getContext('2d');
var radius=50;
var nStartX = 0;
var nStartY = 0;
var bIsDrawing = false;
var putPoint = function(e){
nStartX = e.clientX;nStartY = e.clientY;
bIsDrawing = true;
radius = 0;
}
var drawPoint = function(e){
if(!bIsDrawing)
return;
var nDeltaX = nStartX - e.clientX;
var nDeltaY = nStartY - e.clientY;
radius = Math.sqrt(nDeltaX * nDeltaX + nDeltaY * nDeltaY)
context.clearRect(0, 0, canvas.width, canvas.height);
context.beginPath();
context.arc(nStartX, nStartY, radius, 0, Math.PI*2);
context.fill();
}
var stopPoint = function(e){
bIsDrawing = false;
}
canvas.addEventListener('mousedown',putPoint);
canvas.addEventListener('mousemove',drawPoint);
canvas.addEventListener('mouseup',stopPoint);
</script>
</body>
</html>

How would I align circles horizontally using loops?

I have managed to get the circles on top of each other but I have no clue how to make a line of circles that do not overlap.
This is what I have gotten so far.
HTML
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<canvas id="myCanvas" width="800" height="600"></canvas>
<script src="js/main.js"></script>
</body>
</html>
JavaScript
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext('2d');
for(var i = 0; i < 10; i++) {
ctx.fillStyle="rgba(0,0,0,0.5)";
fillCircle(200,200,i*20)
}
var width = window.innerWidth;
var height = 100;
function fillCircle(x, y, radius) {
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
}
The x-value of any next circle must be at least be the sum of the current and next circle radii beyond the current circle's x-value.
So if:
var currentCircleX=20
var currentCircleRadius=15
var nextCircleRadius=25
Then:
var nextCircleX = currentCircleX + currentCircleRadius + nextCircleRadius
But if you are also stroking the circles:
Since a context stroke will extend half-outside the defined path, you must also add half the lineWidth for each circle to avoid the circles touching:
// account for the lineWidth that extends beyond the arc's path
var nextCircleX =
currentCircleX + currentCircleRadius + nextCircleRadius + context.lineWidth
Example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
ctx.fillStyle="rgba(0,0,0,0.5)";
var currentCircleX=0;
var currentCircleRadius=0;
for(var i = 0; i < 10; i++) {
var nextCircleRadius=i*20;
var nextCircleX=currentCircleX+currentCircleRadius+nextCircleRadius;
fillCircle(nextCircleX,200,nextCircleRadius);
currentCircleX=nextCircleX;
currentCircleRadius=nextCircleRadius;
}
function fillCircle(x, y, radius) {
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
}
body{ background-color: ivory; padding:10px; }
#canvas{border:1px solid red;}
<canvas id="canvas" width=300 height=300></canvas>

javascript console in the browser went unresponsive when running my script

I wrote a simple script to draw a path on HTML5 canvas, however when running the javascript in chrome:
The longer the path grows (as I draw it), the less responsive the page is, and eventually the javascript console is totally stuck, and I noticed the CPU is almost 100% busy. Could you please give me some hints?
Here is my code:
<!DOCTYPE html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script>
var clickX = new Array();
var clickY = new Array();
var clickDrag = new Array();
var paint;
var context;
window.onload =function(){init();};
function init(){
context = document.getElementById("surface").getContext("2d");
$('#surface').mousedown(function(e){
var touchX = e.pageX - this.offsetLeft;
var touchY = e.pageY - this.offsetTop;
paint = true;
addClick(touchX, touchY);
redraw();
});
$('#surface').mousemove(function(e){
if(paint){
addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop);
redraw();
}
});
$('#surface').mouseup(function(e){
paint = false;
});
$('#surface').mouseleave(function(e){
paint = false;
});
};
function addClick(x, y){
clickX.push(x);
clickY.push(y);
}
function redraw(){
context.strokeStype = "#df4b26";
context.lineJoin = "round";
context.lineWidth = 5;
console.log(clickX.length);
context.beginPath();
for(var i=0; i<clickX.length;i++){
context.lineTo(clickX[i], clickY[i]);
console.log(clickX[i]+", "+clickY[i]);
context.stroke();
}
context.closePath();
}
</script>
</head>
<body>
<canvas id="surface" style="border:1px solid #000000;" width="800" height ="600"></canvas>
</body>
Here are some issues I noticed:
A Demo after refactoring some of your code: http://jsfiddle.net/m1erickson/LStXc/
You have a typo in redraw (strokeStype s/b strokeStyle)
If your project doesn't require saving/reusing the user's polyline then you don't need to save the mouse positions in an array. You can just continuously draw the line by adding a .lineTo with each mousemove event.
Some performance issues:
Calling external functions (as your addClick) are slower than inline commands so consider moving the addClick code into the mousemove handler.
If your canvas is not being repositioned, you can calculate the offsets once before sketching begins.
Setting context state (.strokeStyle, .lineJoin, .lineWidth) are relative expensive when repeated in a very active function like a mouse handler. If your state does not change during the sketch then set these once before sketching begins
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("surface");
var context=canvas.getContext("2d");
var canvasOffset=$("#surface").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
context.strokeStyle = "#df4b26";
context.lineJoin = "round";
context.lineWidth = 5;
var clickX = new Array();
var clickY = new Array();
var clickDrag = new Array();
var paint;
var context;
$('#surface').mousedown(function(e){
var touchX = e.clientX - offsetX;
var touchY = e.clientY - offsetY;
paint = true;
clickX.push(e.clientX-offsetX);
clickY.push(e.clientY-offsetY);
lastX=touchX;
lastY=touchY;
});
$('#surface').mousemove(function(e){
if(paint){
var x=e.clientX-offsetX;
var y=e.clientY-offsetY;
clickX.push(x);
clickY.push(y);
context.beginPath();
context.moveTo(lastX,lastY)
context.lineTo(x,y);
context.stroke();
context.closePath();
lastX=x;
lastY=y;
}
});
$('#surface').mouseup(function(e){
paint = false;
});
$('#surface').mouseleave(function(e){
paint = false;
});
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="surface" width=300 height=300></canvas>
</body>
</html>
You can try with this redraw function:
var actClick = 0;
function redraw(){
context.strokeStype = "#df4b26";
context.lineJoin = "round";
context.lineWidth = 5;
console.log(clickX.length);
context.beginPath();
actClick = actClick - 2;
for( ; actClick < clickX.length ; actClick++ ){
context.lineTo(clickX[actClick], clickY[actClick]);
context.stroke();
}
context.closePath();
}
You can find the jsFiddle
The problem is that you redraw the wole image every new point, so every new point it will become slower.
Try the below code. Hope this will work for you
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script>
var paint;
var context;
window.onload =function(){init();};
function init(){
context = document.getElementById("surface").getContext("2d");
$('#surface').mousedown(function(e){
var touchX = e.pageX; //e.pageX - this.offsetLeft;
var touchY = e.pageY; //e.pageY - this.offsetTop;
paint = true;
context.beginPath();
redraw(touchX, touchY);
});
$('#surface').mousemove(function(e){
if(paint){
var touchX = e.pageX; //e.pageX - this.offsetLeft;
var touchY = e.pageY; //e.pageY - this.offsetTop;
redraw(touchX, touchY);
}
});
$('#surface').mouseup(function(e){
paint = false;
});
$('#surface').mouseleave(function(e){
paint = false;
});
};
function redraw(nextX,nextY){
context.strokeStype = "#df4b26";
context.lineJoin = "round";
context.lineWidth = 5;
console.log(clickX.length);
context.lineTo(nextX, nextY);
console.log(nextX+", "+nextY);
context.stroke();
//context.closePath();
}
</script>
</head>
<body>
<canvas id="surface" style="border:1px solid #000000;" width="800" height ="600"></canvas>
</body>

Javascript line around a circle

I want to programm this cool visualization with javascrip:
http://imgur.com/ZCUW7js
I have this: http://test.wikunia.de/pi/ but unfortunately I have no idea how to draw the lines that there is a black circle in the middle. Any idea?
I am using quadraticCurveTo now, but maybe bezier curve is a better option...
My full code:
var canvas = document.getElementById('myCanvas');
var color_arr = new Array("yellow","orange","OrangeRed","red","violetred","MediumSlateBlue","blue","aquamarine","green","greenyellow");
var sA = (Math.PI / 180) * 270;
var pA = (Math.PI / 180) * 36;
if (canvas && canvas.getContext) {
var ctx = canvas.getContext("2d");
if (ctx) {
ctx.fillStyle = "black";
ctx.fillRect(0,0,ctx.canvas.width, ctx.canvas.height);
for (var i=0; i <= 9; i++) {
ctx.strokeStyle = color_arr[i];
ctx.lineWidth = 5;
ctx.beginPath();
ctx.arc (350, 350, 250, sA+(i)*pA, sA+(i+1)*pA, false);
ctx.stroke();
ctx.closePath();
ctx.fillStyle = "white";
ctx.strokeStyle = "white";
ctx.font = "italic 30pt Arial";
if (i > 4 && i < 8) {
ctx.fillText(i.toString(), 350+290*Math.cos(sA+(i+0.5)*pA),350+290*Math.sin(sA+(i+0.5)*pA));
} else {
if (i == 3 || i == 4 || i == 8) {
ctx.fillText(i.toString(), 350+275*Math.cos(sA+(i+0.5)*pA),350+275*Math.sin(sA+(i+0.5)*pA));
} else {
ctx.fillText(i.toString(), 350+260*Math.cos(sA+(i+0.5)*pA),350+260*Math.sin(sA+(i+0.5)*pA));
}
}
}
var pi = '31415...';
for (i = 0; i <= 250; i++) {
line(parseInt(pi.substr(i,1)),parseInt(pi.substr(i+1,1)));
}
}
}
function line(no_1,no_2) {
var rand_1 = Math.random();
var rand_2 = Math.random();
var grad= ctx.createLinearGradient(350+250*Math.cos(sA+(no_1+rand_1)*pA), 350+250*Math.sin(sA+(no_1+rand_1)*pA), 350+250*Math.cos(sA+(no_2+rand_2)*pA), 350+250*Math.sin(sA+(no_2+rand_2)*pA));
grad.addColorStop(0, color_arr[no_1]);
grad.addColorStop(1, color_arr[no_2]);
ctx.lineWidth = 1;
ctx.strokeStyle = grad;
ctx.beginPath();
ctx.moveTo(350+250*Math.cos(sA+(no_1+rand_1)*pA), 350+250*Math.sin(sA+(no_1+rand_1)*pA));
ctx.quadraticCurveTo(350,350,350+250*Math.cos(sA+(no_2+rand_2)*pA),350+250*Math.sin(sA+(no_2+rand_2)*pA));
ctx.stroke();
}
Interesting!
The black circle in the middle is just an absence of curves.
The "lines" are cubic Bezier curves.
The beziers appear to be anchored on both ends to the circle circumference at intervals.
Here's my try at a simplified version of that PI: http://jsfiddle.net/m1erickson/Ju6E8/
This could be addictive so I'm leaving my attempt simple!
<!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:50px; }
#canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var PI2=Math.PI*2;
var cx=150;
var cy=150;
var r=100;
ctx.arc(cx,cy,r,0,Math.PI*2);
ctx.closePath();
ctx.stroke();
for(var a=0;a<PI2;a+=PI2/20){
ctx.strokeStyle="blue";
curve(a,PI2/2.5,25);
ctx.strokeStyle="green";
curve(a,PI2/5,50);
ctx.strokeStyle="red";
curve(a,PI2/10,75);
}
function curve(rotation,offset,innerRadius){
var x1=cx+r*Math.cos(rotation);
var y1=cy+r*Math.sin(rotation);
var x2=cx+innerRadius*Math.cos(rotation+offset/3.5);
var y2=cy+innerRadius*Math.sin(rotation+offset/3.5);
var x3=cx+innerRadius*Math.cos(rotation+offset/1.5);
var y3=cy+innerRadius*Math.sin(rotation+offset/1.5);
var x4=cx+r*Math.cos(rotation+offset);
var y4=cy+r*Math.sin(rotation+offset);
ctx.beginPath();
ctx.moveTo(x1,y1);
ctx.bezierCurveTo(x2,y2,x3,y3,x4,y4);
ctx.stroke();
}
$("#stop").click(function(){});
}); // end $(function(){});
</script>
</head>
<body>
<button id="stop">Stop</button><br>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

Categories

Resources