I have used JavaScript to draw circles at specific points onto the canvas after set times using SetTimeout after I have pressed a button.
How do i make the circles then disappear after a set time or before the next one appears?
JavaScript
//button
function MButton() {
drawOnCanvas();
Circle();
Circle2();
}
function drawOnCanvas() {
var canvas = document.getElementById("canvas_1");
if (canvas.getContext) {
canvas_context = canvas.getContext("2d");
//alert("alert draw");
setTimeout();
}
}
function Circle() {
setTimeout(function () {
canvas_context.fillStyle = "red";
canvas_context.beginPath();
canvas_context.arc(195, 180, 10, 0, Math.PI * 2, true);
canvas_context.closePath();
canvas_context.fill();
}, 300);
}
function Circle2() {
setTimeout(function () {
canvas_context.fillStyle = "red";
canvas_context.beginPath();
canvas_context.arc(285, 180, 10, 0, Math.PI * 2, true);
canvas_context.closePath();
canvas_context.fill();
}, 1500);
}
HTML
<CANVAS WIDTH="360" HEIGHT="300" ID="canvas_1">
Canvas tag not supported
</CANVAS>
<INPUT TYPE ="Button" VALUE=" Play " onClick="MButton()">
I am new to this and I would really appreciate the help!
Here are the general steps to creating canvas circles that disappear after a specified time
Create javascript objects for each circle containing info about that circle.
The object holds info on how to draw the circle: x,y,radius,color
The object also holds info on how long the object will appear after being drawn. That's visibleDuration in the example below. visibleDuration:750 indicates this circle should remain visible for 750ms and then disappear
The object also hold info on how much longer it should display before it disappears. That's visibleCountdown in the example below. When the user clicks the "Display Red Circle" button, visibleCountdown will be set to 750. visibleCountdown is decremented in the animation frame.
circles.red=({
x:100,
y:100,
radius:25,
color:"red",
visibleDuration:750, // this circle disappears after 750ms
visibleCountdown:0 // this is used as a display countdown timer for this circle
});
Create an animation loop with the efficient requestAnimationFrame method.
requestAnimationFrame is preferred to setTimeout for performance reasons (check out why on Google!)
// begin the animation loop
animate();
// This is an animation loop using the highly-efficient requestAnimationFrame method
// It will run about 60 x per second
function animate(){
requestAnimationFrame(animate);
}
Inside the animation loop, draw each circle if their visibleCountdown has not expired
// reduce visibleCountdown by the elapsed time
visibleCountdown -= elapsedTimeSinceLastTimeInLoop
if(visibleCountdown>0){
// draw this circle since it's countdown is still above zero
}
Here is example code and a Demo: http://jsfiddle.net/m1erickson/utdG8/
<!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 circles={};
circles.red=({
x:100,
y:100,
radius:25,
color:"red",
visibleDuration:750,
visibleCountdown:0
});
circles.blue=({
x:175,
y:150,
radius:20,
color:"blue",
visibleDuration:1500,
visibleCountdown:0
});
var startTime=lastTime=performance.now();
animate();
function animate(currentTime){
requestAnimationFrame(animate);
ctx.clearRect(0,0,canvas.width,canvas.height);
var elapsed=currentTime-lastTime;
lastTime=currentTime;
for(var i in circles){
var circle=circles[i];
circle.visibleCountdown-=elapsed;
if(circle.visibleCountdown>0){
drawCircle(circle);
}
}
}
function drawCircle(circle){
ctx.globalAlpha=circle.visibleCountdown/circle.visibleDuration;
ctx.beginPath();
ctx.arc(circle.x,circle.y,circle.radius,0,Math.PI*2);
ctx.closePath();
ctx.fillStyle=circle.color;
ctx.fill();
ctx.globalAlpha=1.00;
}
function showCircle(circle){
circle.visibleCountdown=circle.visibleDuration
}
$("#red").click(function(){
showCircle(circles["red"]);
});
$("#blue").click(function(){
showCircle(circles["blue"]);
});
}); // end $(function(){});
</script>
</head>
<body>
<button id="red">Show Red for 0.75 seconds</button><br>
<button id="blue">Show Blue for 1.50 seconds</button><br>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
You have to use the clearRect command
context.clearRect ( x , y , w , h );
This will wipe out the area for you!
Related
I want to make a spaceship shoot in a game I am making, but I dont seem to be able to get the positions of the shots to load properly.
I have an array called shots[] and I want to push Shot() objects into it every N ticks when the player is holding down the mouse button.
So basically I want Shot() have x property equal to my ship.x property and y=ship.y.
Then I want it to have a Shot.dx property, which changes, depending on wether the cursor is above the middle of canvas or bellow (+3/-3) or left or right of the center (dy=+3/-3).
// Shooting
var shots = [] //Bullet array
//Object, which should be the position of the bullet.
function Shot() {
this.x=350
this.y=250;
this.dx=Shoot.x
this.dy=Shoot.y
}
//This keeps track of the cursor position in relation to the center of canvas.
function Shoot() {
started = false;
this.mousedown = function (ev) {
started = true;
};
this.mousemove = function (ev) {
if (started) {
if (ev.clientX>=350) this.x=3;
else this.x=-3;
if (ev.clientY>=250) this.y=3;
else this.y=-3;
}
};
this.mouseup = function (ev) {
started = false;
};
}
//The problem is, that when I set this.x in Shot() to be =ship.x the values
//dont get updated and it stays undefined after I push it into the array.
//Now I have it set to the center of canvas, but that it useless because it needs
//to move with the ship, but even now I am getting weird numbers and not the numbers
//that I actually put in. dx and dy dont get updated at all.
// Ship Model
var ship = {
x: 350,
y: 250,
lives: 3,
invulnerable: 0,
}
//Main function- pushes the objects into the array
function mainLoop() {
tick++
count()
interval()
chase()
console.log(started)
if (started && tick%20==0)
shots.push(new Shot());
keyboard()
display()
check()
requestAnimationFrame(mainLoop);
}
// Initialization
window.onload = function() {
// Setting variables
button = document.getElementById("button")
text = document.getElementById("text")
canvas = document.getElementById("canvas")
ctx = canvas.getContext("2d")
weapon = new Shoot();
canvas.onmousedown = weapon.mousedown;
canvas.onmousemove = weapon.mousemove;
canvas.onmouseup = weapon.mouseup;
requestAnimationFrame(mainLoop);
}
//I know this is a lot of code, but its all relevant. I am new to Javascript
//so I expect this to be some sort of a trivial error.
Here is a JSfiddle, but I dont know how that works so I cant get it to draw canvas, sorry: http://jsfiddle.net/JH3M6/
Here's an outline of how to fire your shots:
create an array to hold your shot objects
on mousedown: set the started flag (starts firing)
on mousedown: set the firing position for any new shot(s) to the current mouse position
on mousemove: reset the firing position for any new shot(s) to the current mouse position
on mouseup: clear the started flag (stops firing)
In the animation loop:
add a shot at the current firing position if the mouse is still down
move all shots by their dx,dy
remove any shots from the shots[] array if the shot has moved off-canvas
clear the screen and draw the shots in their new positions
A Demo: http://jsfiddle.net/m1erickson/2f9sf/
Here's 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(){
// canvas related vars
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var bb=canvas.getBoundingClientRect();
var offsetX=bb.left;
var offsetY=bb.top;
ctx.fillStyle="blue";
// vars related to firing position and Shot(s)
var shotColor=ctx.fillStyle;
var started,mouseX,mouseY,dx,dy;
// Shots fired
var shots = [] //Bullet array
//Object, which should be the position of the bullet.
function Shot(x,y,dx,dy) {
this.x=x;
this.y=y;
this.dx=dx;
this.dy=dy;
}
Shot.prototype.display=function(){
// make fillstyle blue if it's not already blue
if(!ctx.fillStyle==shotColor){ctx.fillStyle=shotColor;}
// draw the shot on the canvas
ctx.fillRect(this.x,this.y,5,5);
}
// listen for mouse events
canvas.onmousedown=function(e){ started=true; setFirePosition(e); }
canvas.onmouseup=function(e){ started=false; }
canvas.onmousemove=function(e){
if(started){setFirePosition(e);}
}
// start the animation loop
requestAnimationFrame(animate);
// set the firing position of the next shot
function setFirePosition(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
dx=(mouseX>=canvas.width/2)?-3:3;
dy=(mouseY>=canvas.height/2)?-3:3;
}
// animation loop
// add shots if the mouse is down
// move shots until they move off-canvas
function animate(){
// request another frame
requestAnimationFrame(animate);
// if the mouse is down, add a shot
if(started){
shots.push(new Shot(mouseX,mouseY,dx,dy));
}
// if no work to do, return
if(shots.length==0){return;}
// new array of active shots
// "active" == shot has not moved off-canvas
var a=[];
// clear the canvas for this frame
ctx.clearRect(0,0,cw,ch);
for(var i=0;i<shots.length;i++){
// get a shot to process
var shot=shots[i];
// move this shot
shot.x+=shot.dx;
shot.y+=shot.dy;
// if the shot hasn't moved offscreen
// add the shot to "a" (the replacement shots array);
// draw this shot
if(shot.x>=0 && shot.x<=cw && shot.y>0 && shot.y<=ch){
a.push(shot);
shot.display();
}
}
// if shots went off-canvas, remove them from shots[]
if(a.length<shots.length){
shots.length=0;
Array.prototype.push.apply(shots,a);
}
}
}); // end $(function(){});
</script>
</head>
<body>
<h4>Mousedown to fire shots</h4>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
I am trying to translate and save my canvas each time I press right key, so that it moves horizontally each time I press right key. This is the function I am using to move the canvas horizontally each time which is working for the first time and but not later.
function clearRight(){
var canvas1=document.getElementById('plot');
ctx=canvas1.getContext("2d");
ctx.restore();
ctx.translate(-1000,0);
ctx.save();
ctx.clearRect(0,0,canvas1.width,canvas1.height);
}
rightKey(){
clearRight();
draw();
}
Can anyone please point where am I going wrong in trying to move the canvas?
UPDATE
I have solved the issue I was facing.
To move the canvas horizontally
var translated=0;
function clear()
{
var canvas1=document.getElementById('plot');
var ctx=canvas1.getContext("2d");
ctx.restore();
ctx.save();
ctx.clearRect(0,0,canvas1.width,canvas1.height);
}
function rightKey()
{
clear();
ctx.clearRect(0,0,canvas1.width,canvas1.height);
translated += 10;
ctx.translate(-translated,300);
draw(ctx);
}
I'm assuming there's a reason why you're not just drawing an oversized canvas contained in a smaller div-wrapper with scrollbars enabled...so here's an alternative.
You could draw your entire plotted graph to a separate canvas.
Then to pan left/right you can draw that temporary canvas to your main canvas with an offset.
A Demo: http://jsfiddle.net/m1erickson/GfRLq/
Before panning right:
After panning right:
About dynamically changing plots:
If your plots are dynamic, then you can still use this panning technique.
Just update the tempCanvas with each new plot.
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 offset=0;
// create some test data
var points=[];
for(var i=0;i<50;i++){
points.push({x:i*40,y:100+Math.random()*100-50});
}
// create a temporary canvas
var tempCanvas=document.createElement("canvas");
var tempCtx=tempCanvas.getContext("2d");
tempCanvas.width=40*points.length;
tempCanvas.height=300;
// draw your complete plot on the tempCanvas
// draw the line
tempCtx.beginPath();
tempCtx.moveTo(points[0].x,points[0].y);
for(var i=0;i<points.length;i++){
var point=points[i];
tempCtx.lineTo(point.x,point.y);
}
tempCtx.lineWidth=5;
tempCtx.strokeStyle="blue";
tempCtx.stroke();
// draw the markers
for(var i=0;i<points.length;i++){
var point=points[i];
tempCtx.beginPath();
tempCtx.arc(point.x,point.y,10,0,Math.PI*2);
tempCtx.closePath();
tempCtx.fillStyle="black";
tempCtx.fill();
tempCtx.fillStyle="white";
tempCtx.fillText(i,point.x-3,point.y+3);
}
ctx.drawImage(tempCanvas,0,0)
// function to draw the canvas with your specified offset
function drawPlotWithOffset(offset){
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.drawImage(tempCanvas,offset,0,canvas.width,canvas.height,0,0,canvas.width,canvas.height)
}
$("#left").click(function(){
offset-=20;
if(offset<0){offset=0;}
drawPlotWithOffset(offset);
});
$("#right").click(function(){
offset+=20;
if(offset>tempCanvas.width-canvas.width){
offset=tempCanvas.width-canvas.width;
}
drawPlotWithOffset(offset);
});
}); // end $(function(){});
</script>
</head>
<body>
<button id="left">Pan Left</button><br>
<button id="right">Pan Right</button><br>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
I am failing at getting a DOM Image onclick event to work.
var context = document.getElementById('canvas').getContext('2d');
var image = new Image();
image.src = "foo.png"
image.onclick = function(e) { console.log("clicked"); }
setInterval(function() {
context.drawImage(image, 100, 100, 50, 50);
};
Why do I not get the log message when i click on the image. In developer tools i can see the onclick function is not null for the image.
Yes, what Musa said...and a few other things.
Some changes to your code
Image.src=”foo.png” should come after the image.onclick function
Context.drawImage should be inside the image.onclick function
setInterval is not needed as far as I can see
Try this:
<!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 context=document.getElementById("canvas").getContext("2d");
var image=new Image();
image.onload=function(){
context.drawImage(image,0,0);
}
image.src="http://i.imgur.com/nJiIJIJ.png";
document.getElementById("canvas").addEventListener("click", function(){console.log("clicked");}, false);
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
You cannot set onclick for a particular image added in canvas . You can set onclick for the whole canvas alone so you have to use any third party js or else you should do some calculations which finds that you clicked on the image of the canvas ..
Other users are right.
The image you draw on the canvas is a DOM element but it is rendered in a position which is not stored in the DOM.
This doesn't mean you can access it's position and compare it with the mouse position.
I'm using an external library here, but it does what you need: http://jsfiddle.net/Saturnix/cygUH/
this is the library used.
Since I can't post link to jsfiddles without posting the code, here's the script I've wrote for you.
function demo(g) {
g.ctx.font = "bold 16px Arial";
g.draw = function () {
g.ctx.clearRect(0, 0, g.width, g.height)
var posX = 0;
var posY = 0;
g.ctx.drawImage(image, posX, posY);
if (g.mouseX > posX && g.mouseX < image.width &&
g.mouseY > posY && g.mouseY < image.height &&
g.mousePressed)
g.ctx.fillText("You're clicking the image!", g.mouseX, g.mouseY);
}
}
You can cast a ray (with an onclick on the canvas) into the canvas and manually test your images for intersection with the ray. You should write a
objectsUnderPoint( x, y );
function that returns an array of all the images that intersect with the ray at x, y.
This is the way it is usually done in 3D engines as well. You ofcourse need to keep the image position as a property of the image for intersection testing.
I would like to achieve jQuery Knob-like effect using HTML5 Canvas, but with a circle knob/cursor, instead of the stroke cursor effect that jQuery Knob does.
Based on jQuery Knob code, I was managed to connect the onMouseMove event with my circle knob/cursor so the circle knob moves according to the X and Y coordinates of where the mouse is. However I cannot "restrict" the knob to move only on/along the circle path just like this example, so if I click/mousedown inside the circle path, the circle knob moves to inside the path.
Is there any way to achieve this only using Canavas and jQuery, not Raphael like the example above?
One of my thoughts was to move the circle knob back on track (on the path) whenever mousemove event occurs outside the path (like this). However no luck in succeeding the calculation for this. Is there any math/geometry formula I can use to achieve this?
Just a little bit of trigonometry will answer your question!
This code will find the point on a circle closest to a mouseclick.
var rads = Math.atan2(mouseY - knobCenterY, mouseX - knobCenterX);
var indicatorX=knobRadius*Math.cos(rads)+knobCenterX;
var indicatorY=knobRadius*Math.sin(rads)+knobCenterY;
This code will put an indicator on the knob closest to where the user clicks
And here is a Fiddle --- http://jsfiddle.net/m1erickson/pL5jP/
<!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>
<!--[if lt IE 9]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<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 circleArc=Math.PI*2;
// drawing design properties
var knobCenterX=100;
var knobCenterY=100;
var knobRadius=50;
var knobColor="green";
var indicatorRadius=5;
var indicatorColor="yellow";
Draw(canvas.width/2,1); // just to get started
function Draw(mouseX,mouseY){
// given mousePosition, what is the nearest point on the knob
var rads = Math.atan2(mouseY - knobCenterY, mouseX - knobCenterX);
var indicatorX=knobRadius*Math.cos(rads)+knobCenterX;
var indicatorY=knobRadius*Math.sin(rads)+knobCenterY;
// start drawing
ctx.clearRect(0,0,canvas.width,canvas.height);
// draw knob
ctx.beginPath();
ctx.arc(knobCenterX,knobCenterY,knobRadius,0,circleArc,false);
ctx.fillStyle="ivory";
ctx.fill();
ctx.lineWidth=2;
ctx.strokeStyle=knobColor;
ctx.stroke();
// draw indicator
ctx.beginPath();
ctx.arc(indicatorX, indicatorY, indicatorRadius, 0, circleArc, false);
ctx.fillStyle = indicatorColor;
ctx.fill();
ctx.lineWidth = 2;
ctx.strokeStyle = 'black';
ctx.stroke();
}
function handleMouseDown(e){
MouseX=parseInt(e.clientX-offsetX);
MouseY=parseInt(e.clientY-offsetY);
Draw(MouseX,MouseY);
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
}); // end $(function(){});
</script>
</head>
<body>
<br/><p>Click anywhere in the canvas to set the knob indicator</p><br/>
<canvas id="canvas" width=200 height=200></canvas>
</body>
</html>
I have a background, let's say it's green grass. On top of the background I have a black overlay. What I want now is to make a movable hole in the overlay so that you can see the background like in the image below.
I am pretty new to canvas so I'm not sure what I'm supposed to look for. Alpha mask?
So my question is how can I achieve the effect demonstrated in the image above?
If it were HTML I would have two images of the grass, one as the background and one above the overlay in a div with a border radius that can move and just calculate positions.
Thanks.
Are you looking for a moving "flashlight" kind of effect?
If so, you can do that by drawing a circular path and then using it as a clipping region with: context.clip();
Anything drawn after the .clip() will be viewed through the clipping path.
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/pRzxt/
<!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");
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
var radius=50;
var x=100;
var dx=10;
var y=100;
var dy=10;
var delay=10;
var img=new Image();
img.onload=function(){
var canvas1=document.getElementById("image");
var ctxImg=canvas1.getContext("2d");
ctxImg.drawImage(img,0,0,img.width,img.height,0,0,canvas.width,canvas.height);
animate();
}
img.src="http://lh3.ggpht.com/_Z-i7eF_ACGI/TRxpFywLCxI/AAAAAAAAAD8/ACsxiuO_C1g/house%20vector.png";
function animate() {
if(--delay<0){
// update
x+=dx;
if(x-radius<0 || x+radius>=canvas.width){dx=-dx;}
y+=dy;
if(y-radius<0 || y+radius>=canvas.height){dy=-dy;}
delay=10;
// draw stuff
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.beginPath();
ctx.arc(x,y, radius, 0, 2 * Math.PI, false);
ctx.clip();
ctx.drawImage(img,0,0,img.width,img.height,0,0,canvas.width,canvas.height);
ctx.restore();
}
// request new frame
requestAnimFrame(function() {
animate();
});
}
}); // end $(function(){});
</script>
</head>
<body>
<p>Image clipped by moving circle</p>
<canvas id="canvas" width=300 height=200></canvas>
<br/><p>Unclipped image</p>
<canvas id="image" width=300 height=200></canvas>
</body>
</html>
I did something similar for a little canvas test I was working on a while back. What you can do is create a div with a canvas element on top of the bottom layer and draw a radial gradient with transparency on that top layer canvas. I have a fiddle here: http://jsfiddle.net/CnEBQ/14/
In particular look at this bit of code for the radial gradient. The context is attached to the top div canvas:
var gradient = tCTX.createRadialGradient(CANVAS_SIZE.x/2, CANVAS_SIZE.y/2, 250, CANVAS_SIZE.x/2, CANVAS_SIZE.y/2, 0);
gradient.addColorStop(0, "#000");
gradient.addColorStop(1, "transparent");
tCTX.fillStyle = gradient;
tCTX.fillRect(0, 0, CANVAS_SIZE.x, CANVAS_SIZE.y);
There may be a little bad code in there, but it should give you an idea of whether this is where you want to go. You could redraw the top layer "hole" as needed on a timer or some event to get it moving. And you can play with the gradient setting to get more or less "darkness".
I'm having quite a time trying to find a good reference to the functions I'm using here, but a decent place to look for more explanation of these functions is
the Mozilla Canvas API
where the parameters to the gradient functions are explained. Especially useful since they're not immediately obvious.