Adding Image to an Object with Javascript Canvas [duplicate] - javascript

I am trying to move an image from the right to the center and I am not sure if this is the best way.
var imgTag = null;
var x = 0;
var y = 0;
var id;
function doCanvas()
{
var canvas = document.getElementById('icanvas');
var ctx = canvas.getContext("2d");
var imgBkg = document.getElementById('imgBkg');
imgTag = document.getElementById('imgTag');
ctx.drawImage(imgBkg, 0, 0);
x = canvas.width;
y = 40;
id = setInterval(moveImg, 0.25);
}
function moveImg()
{
if(x <= 250)
clearInterval(id);
var canvas = document.getElementById('icanvas');
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
var imgBkg = document.getElementById('imgBkg');
ctx.drawImage(imgBkg, 0, 0);
ctx.drawImage(imgTag, x, y);
x = x - 1;
}
Any advice?

This question is 5 years old, but since we now have requestAnimationFrame() method, here's an approach for that using vanilla JavaScript:
var imgTag = new Image(),
canvas = document.getElementById('icanvas'),
ctx = canvas.getContext("2d"),
x = canvas.width,
y = 0;
imgTag.onload = animate;
imgTag.src = "http://i.stack.imgur.com/Rk0DW.png"; // load image
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height); // clear canvas
ctx.drawImage(imgTag, x, y); // draw image at current position
x -= 4;
if (x > 250) requestAnimationFrame(animate) // loop
}
<canvas id="icanvas" width=640 height=180></canvas>

drawImage() enables to define which part of the source image to draw on target canvas. I would suggest for each moveImg() calculate the previous image position, overwrite the previous image with that part of imgBkg, then draw the new image. Supposedly this will save some computing power.

Here's my answer.
var canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
var myImg = new Image();
var myImgPos = {
x: 250,
y: 125,
width: 50,
height: 25
}
function draw() {
myImg.onload = function() {
ctx.drawImage(myImg, myImgPos.x, myImgPos.y, myImgPos.width, myImgPos.height);
}
myImg.src = "https://mario.wiki.gallery/images/thumb/c/cc/NSMBUD_Mariojump.png/1200px-NSMBUD_Mariojump.png";
}
function moveMyImg() {
ctx.clearRect(myImgPos.x, myImgPos.y, myImgPos.x + myImgPos.width, myImgPos.y +
myImgPos.height);
myImgPos.x -= 5;
}
setInterval(draw, 50);
setInterval(moveMyImg, 50);
<canvas id="canvas" class="canvas" width="250" height="150"></canvas>

For lag free animations,i generally use kinetic.js.
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 200
});
var layer = new Kinetic.Layer();
var hexagon = new Kinetic.RegularPolygon({
x: stage.width()/2,
y: stage.height()/2,
sides: 6,
radius: 70,
fill: 'red',
stroke: 'black',
strokeWidth: 4
});
layer.add(hexagon);
stage.add(layer);
var amplitude = 150;
var period = 2000;
// in ms
var centerX = stage.width()/2;
var anim = new Kinetic.Animation(function(frame) {
hexagon.setX(amplitude * Math.sin(frame.time * 2 * Math.PI / period) + centerX);
}, layer);
anim.start();
Here's the example,if you wanna take a look.
http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-animate-position-tutorial/
Why i suggest this is because,setInterval or setTimeout a particular function causes issues when large amount of simultaneous animations take place,but kinetic.Animation deals with framerates more intelligently.

Explaining window.requestAnimationFrame() with an example
In the following snippet I'm using an image for the piece that is going to be animated.
I'll be honest... window.requestAnimationFrame() wasn't easy for me to understand, that is why I coded it as clear and intuitive as possible. So that you may struggle less than I did to get my head around it.
const
canvas = document.getElementById('root'),
btn = document.getElementById('btn'),
ctx = canvas.getContext('2d'),
brickImage = new Image(),
piece = {image: brickImage, x:400, y:70, width:70};
brickImage.src = "https://i.stack.imgur.com/YreH6.png";
// When btn is clicked execute start()
btn.addEventListener('click', start)
function start(){
btn.value = 'animation started'
// Start gameLoop()
brickImage.onload = window.requestAnimationFrame(gameLoop)
}
function gameLoop(){
// Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height)
// Draw at coordinates x and y
ctx.drawImage(piece.image, piece.x, piece.y)
let pieceLeftSidePos = piece.x;
let middlePos = canvas.width/2 - piece.width/2;
// Brick stops when it gets to the middle of the canvas
if(pieceLeftSidePos > middlePos) piece.x -= 2;
window.requestAnimationFrame(gameLoop) // Needed to keep looping
}
<input id="btn" type="button" value="start" />
<p>
<canvas id="root" width="400" style="border:1px solid grey">
A key point
Inside the start() function we have:
brickImage.onload = window.requestAnimationFrame(gameLoop);
This could also be written like: window.requestAnimationFrame(gameLoop);
and it would probably work, but I'm adding the brickImage.onload to make sure that the image has loaded first. If not it could cause some issues.
Note: window.requestAnimationFrame() usually loops at 60 times per second.

Related

Canvas Javascript Looping

I'm trying to loop my animation, but no matter what I do, it won't loop. I'm pretty new to canvas, javascript and code in general.
var canvas = document.getElementById("fabrication");
var ctx = canvas.getContext("2d");
var background = new Image();
background.src =
"C:/Users/dylan/Desktop/ProjectTwo/Images/fabricationbackground.jpg";
background.onload = function(){
}
//Loading all of my canvas
var posi =[];
posi[1] = 20;
posi[2] = 20;
var dx=10;
var dy=10;
var ballRadius = 4;
//Variables for drawing a ball and it's movement
function drawballleft(){
posi =xy(posi[1],posi[2])
}
function xy(x,y){
ctx.drawImage(background,0,0);
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI*2);
ctx.fillStyle = "#FFFFFFF";
ctx.fill();
ctx.closePath();
var newpos=[];
newpos[1]= x +dx;
newpos[2]= y +dy;
return newpos;
//Drawing the ball, making it move off canvas.
if (newpos[1] > canvas.width) {
newpos[1] = 20;
}
if (newpos[2] > canvas.height) {
newpos[2] = 20;
}
//If statement to detect if the ball moves off the canvas, to make it return to original spot
}
setInterval(drawballleft, 20);
//Looping the function
Please let me know if I've done something wrong, I really want to learn what I'm doing here. The ball is supposed to go off the canvas, and loop back onto itself, but it goes off the canvas and ends.
Thanks in advance!
I have made a few changes to your code.
First I am using requestAnimationFrame instead of setInterval. http://www.javascriptkit.com/javatutors/requestanimationframe.shtml
Second I am not using an image because I didn't want to run into a CORS issue. But you can put your background image back.
I simplified your posi array to use indexes 0 and 1 instead of 1 and 2 to clean up how you create your array.
I moved your return from before the two ifs to after so the ball will move back to the left or top when it goes off the side. I think that was the real problem you were seeing
var canvas = document.getElementById("fabrication");
var ctx = canvas.getContext("2d");
//Loading all of my canvas
var posi =[20,20];
var dx=10;
var dy=10;
var ballRadius = 4;
//Variables for drawing a ball and it's movement
function drawballleft(){
posi = xy(posi[0],posi[1])
requestAnimationFrame(drawballleft);
}
function xy(x,y){
ctx.fillStyle = '#FFF';
ctx.fillRect(0,0,400,300);
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI*2);
ctx.fillStyle = "#000";
ctx.fill();
ctx.closePath();
var newpos=[x+dx,y+dy];
//Drawing the ball, making it move off canvas.
if (newpos[0] > canvas.width) {
newpos[0] = 20;
}
if (newpos[1] > canvas.height) {
newpos[1] = 20;
}
//If statement to detect if the ball moves off the canvas, to make it return to original spot
return newpos;
}
requestAnimationFrame(drawballleft);
canvas {
outline: 1px solid red;
}
<canvas width="400" height="300" id="fabrication"></canvas>
To make it all even simpler...
Use an external script for handling the canvas.
A really good one ;) :
https://github.com/GustavGenberg/handy-front-end#canvasjs
Include it with
<script type="text/javascript" src="https://gustavgenberg.github.io/handy-front-end/Canvas.js"></script>
Then it's this simple:
// Setup canvas
const canvas = new Canvas('my-canvas', 400, 300).start(function (ctx, handyObject, now) {
// init
handyObject.Ball = {};
handyObject.Ball.position = { x: 20, y: 20 };
handyObject.Ball.dx = 10;
handyObject.Ball.dy = 10;
handyObject.Ball.ballRadius = 4;
});
// Update loop, runs before draw loop
canvas.on('update', function (handyObject, delta, now) {
handyObject.Ball.position.x += handyObject.Ball.dx;
handyObject.Ball.position.y += handyObject.Ball.dy;
if(handyObject.Ball.position.x > canvas.width)
handyObject.Ball.position.x = 20;
if(handyObject.Ball.position.y > canvas.height)
handyObject.Ball.position.y = 20;
});
// Draw loop
canvas.on('draw', function (ctx, handyObject, delta, now) {
ctx.clear();
ctx.beginPath();
ctx.arc(handyObject.Ball.position.x, handyObject.Ball.position.y, handyObject.Ball.ballRadius, 0, Math.PI * 2);
ctx.fillStyle = '#000';
ctx.fill();
ctx.closePath();
});
I restructured your code and used the external script, and now it looks much cleaner and easier to read and toubleshoot!
JSFiddle: https://jsfiddle.net/n7osvt7y/

Is there any way to draw a "streak" (fading "digital phosphor" effect) on HTML5 canvas?

I want to draw a moving dot on an HTML5 canvas that follows a complicated trajectory. This I know how to do; see, for example, the Lorenz attractor as implemented below. But with small dots it is hard to follow. Is there a way to add a blurry trail behind a dot? I can keep past history of drawn points, I just don't know how to make them fade.
In technical terms, I suppose this would be a polyline/curve where the opacity/width/color changes smoothly along the curve. I know how to draw polylines (and can figure out the Bezier curve stuff if I need to), but I don't know how to apply a smooth gradient along a path.
(Digital oscilloscopes solved this "problem" by having a Digital Phosphor Oscilloscope effect where the scope emulated the old analog "phosphor" effect: areas hit by the scope's "beam" would take a while to fade.)
<!DOCTYPE html>
<html>
<head><script type="text/javascript">
document.addEventListener("DOMContentLoaded", function(event) {
var x = 1, y = 0, z = 0, t=0;
function onTick(timestamp)
{
var ctx = document.getElementById('canvas').getContext('2d');
ctx.clearRect(0, 0, 300, 300);
ctx.fillStyle = 'black';
var cx = 150;
var cy = 150;
var r = 5;
var now = timestamp * 0.001;
var dt = now - t;
t = now;
if (dt > 0.1)
dt = 0.1;
// Lorenz attractor
var sigma = 10, rho=28, beta=8/3;
var dxdt = sigma*(y-x);
var dydt = x*(rho-z)-y;
var dzdt = x*y-beta*z;
x += dt*dxdt;
y += dt*dydt;
z += dt*dzdt;
var drawx = cx + r*x;
var drawy = cy + r*y;
var rdot = 2;
ctx.beginPath();
ctx.arc(drawx, drawy, rdot, 0, 2 * Math.PI, true);
ctx.fill();
requestAnimationFrame(onTick);
}
requestAnimationFrame(onTick);
});
</script></head>
<body>
<canvas id="canvas" width="300" height="300"/>
</body>
</html>
Instead of clearing the rectangle each frame, just paint it in an alpha channel to save those previous dots momentarily. I replaced your clearRect with fillRect the fillStyle is white see-through.
Keep in ming you can adjust the alpha channel, this will make the dot stay for longer/short duration. In my code this is the 0.04 in the ctx.fillStyle = "rgba(255, 255, 255, 0.04)";. I just adjusted it lower to make those traces stay for a longer time.
document.addEventListener("DOMContentLoaded", function(event) {
var x = 1, y = 0, z = 0, t=0;
function onTick(timestamp)
{
var ctx = document.getElementById('canvas').getContext('2d');
//ctx.clearRect(0, 0, 300, 300);
ctx.fillStyle = "rgba(255, 255, 255, 0.04)";
ctx.fillRect(0, 0, 300, 300);
ctx.fillStyle = 'black';
var cx = 150;
var cy = 150;
var r = 5;
var now = timestamp * 0.001;
var dt = now - t;
t = now;
if (dt > 0.1)
dt = 0.1;
// Lorenz attractor
var sigma = 10, rho=28, beta=8/3;
var dxdt = sigma*(y-x);
var dydt = x*(rho-z)-y;
var dzdt = x*y-beta*z;
x += dt*dxdt;
y += dt*dydt;
z += dt*dzdt;
var drawx = cx + r*x;
var drawy = cy + r*y;
var rdot = 2;
ctx.beginPath();
ctx.arc(drawx, drawy, rdot, 0, 2 * Math.PI, true);
ctx.fill();
requestAnimationFrame(onTick);
}
requestAnimationFrame(onTick);
});
canvas {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: -1;
}
<canvas id="canvas"></canvas>
Classic trick was to draw a polyline instead single dot, altering color and/or opacity per each vertice of polyline, the brightest would be the furthest along traectory

How do I add four rotating images to an animated background?

I am trying to add four rotating images to an animated background.
I can only get one image working correctly with my code below.
How can I add in the other three images?
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
var img = document.createElement('img');
img.onload = function(){
render();
}
img.src = 'nano3.png';
function drawImage(img,x,y,r,sx,sy){
sx=sx||0;
sy=sy||0;
r=(r*Math.PI/180)||0;
var cr = Math.cos(r);
var sr = Math.sin(r);
ctx.setTransform(cr,sr,-sr,cr,x-(cr*sx-sr*sy),y-(sr*sx+cr*sy));
ctx.drawImage(img,1,2);
}
var r = 1;
function render(){
requestAnimationFrame(render);
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0,0,800,800);
drawImage(img,50,50,r++,img.width/2,img.height/2);
}
This should help you out, I just created an object known as rotatingimage which stores a location, an image and its current rotation. We call the 'draw' method in a 'setInterval' function call which deals with rotating the canvas and then drawing the sprite correctly.
Just a note rotating many images can cause the canvas to lag also the CurrentRotation variable never gets reset to 0 when it reaches >359 so the CurrentRotation variable will keep going higher and higher, you may want to fix that in the RotatingImage.prototype.Draw function
jsFiddle:https://jsfiddle.net/xd8brfrk/
Javascript
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
function RotatingImage(x, y, spriteUrl, rotationSpeed) {
this.XPos = x;
this.YPos = y;
this.Sprite = new Image();
this.Sprite.src = spriteUrl;
this.RotationSpeed = rotationSpeed;
this.CurrentRotation = 0;
}
RotatingImage.prototype.Draw = function(ctx) {
ctx.save();
this.CurrentRotation += 0.1;
ctx.translate(this.XPos + this.Sprite.width/2, this.YPos + this.Sprite.height/2);
ctx.rotate(this.CurrentRotation);
ctx.translate(-this.XPos - this.Sprite.width/2, -this.YPos - this.Sprite.height/2);
ctx.drawImage(this.Sprite, this.XPos, this.YPos);
ctx.restore();
}
var RotatingImages = [];
RotatingImages.push(new RotatingImage(50, 75, "http://static.tumblr.com/105a5af01fc60eb94ead3c9b342ae8dc/rv2cznl/Yd9oe4j3x/tumblr_static_e9ww0ckmmuoso0g4wo4okosgk.png", 1));
RotatingImages.push(new RotatingImage(270, 25, "http://static.tumblr.com/105a5af01fc60eb94ead3c9b342ae8dc/rv2cznl/Yd9oe4j3x/tumblr_static_e9ww0ckmmuoso0g4wo4okosgk.png", 1));
RotatingImages.push(new RotatingImage(190, 180, "http://static.tumblr.com/105a5af01fc60eb94ead3c9b342ae8dc/rv2cznl/Yd9oe4j3x/tumblr_static_e9ww0ckmmuoso0g4wo4okosgk.png", 1));
RotatingImages.push(new RotatingImage(100, 270, "http://static.tumblr.com/105a5af01fc60eb94ead3c9b342ae8dc/rv2cznl/Yd9oe4j3x/tumblr_static_e9ww0ckmmuoso0g4wo4okosgk.png", 1));
setInterval(function() {
ctx.fillStyle = "#000"
ctx.fillRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < RotatingImage.length; i++) {
var rotatingImage = RotatingImages[i];
rotatingImage.Draw(ctx);
}
}, (1000 / 60));
you can use save and restore to apply different transform to your drawing
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/save
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/restore

Canvas+Javascript water overlay

I'm trying to make water waves in Javascript on a canvas but there is something wrong.
My idea was making 3 waves with different colors but they overdraw each other.
I was not able figure out where the problem is.
<!DOCTYPE HTML>
<html>
<style>
<!-- 100% area -->
body, html {
height: 100%;
width: 100%;
}
</style>
<body>
<canvas id="myCanvas" ></canvas>
<script>
//get window size
var canvas = document.getElementById( "myCanvas" );
canvas.width = window.innerWidth; /// equal to window dimension
canvas.height = window.innerHeight;
// get the context
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext('2d');
// VARIABLES
var frameCount=0;
var N = 30;
var positionXTeiler= Math.floor(canvas.width/(N-N/2));
var size = 50;
var xOffset = 200;
var colors = [];
var amplitude = 200;
var wavesCount = 3;
var init = function()
{
colors.push("rgba(0,0,128,1)");
colors.push("rgba(0,0,255,1)");
colors.push("rgba(47,86,233,1)");
}
var draw = function() {
context.clearRect (0, 0, canvas.width, canvas.height);
for (i=0; i<N; i++) {
for (n=0; n<wavesCount; n++) {
var x = amplitude*Math.sin (frameCount*0.02+n*Math.PI/2);
context.save();
context.fillStyle = colors[n];
context.beginPath();
context.arc(positionXTeiler*i+x-xOffset,canvas.height-n*20,size,0,Math.PI*2,true);
context.closePath();
context.fill();
context.restore();
}
}
// count the frame and loop the animation
frameCount = frameCount+1;
requestAnimationFrame(draw);
};
// start the loop
init();
draw();
</script>
</body>
</html>
My result should look like that + with moving
Loop the waves and, inside, loop the circles (i.e. invert the two loops).
The goal is to draw all circles of a wave before moving to the next. This way you are making sure that the circles of a wave are drawn on top of the circles of the previous one.
Also, you may want to consider using a time-based increment instead of a frame count. Animation frames are not guaranteed to be regular and their rate depends of the user's system.
//get window size
var canvas = document.getElementById( "myCanvas" );
canvas.width = window.innerWidth; /// equal to window dimension
canvas.height = window.innerHeight;
// get the context
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext('2d');
// VARIABLES
var frameCount=0;
var N = 30;
var positionXTeiler= Math.floor(canvas.width/(N-N/2));
var size = 50;
var xOffset = 200;
var colors = [];
var amplitude = 200;
var wavesCount = 3;
var init = function()
{
colors.push("rgba(0,0,128,1)");
colors.push("rgba(0,0,255,1)");
colors.push("rgba(47,86,233,1)");
}
var draw = function() {
context.clearRect (0, 0, canvas.width, canvas.height);
for (n=wavesCount-1; n>=0; n--) {
for (i=0; i<N; i++) {
var x = amplitude*Math.sin (frameCount*0.02+n*Math.PI/2);
context.save();
context.fillStyle = colors[n];
context.beginPath();
context.arc(positionXTeiler*i+x-xOffset,canvas.height-n*20,size,0,Math.PI*2,true);
context.closePath();
context.fill();
context.restore();
}
}
// count the frame and loop the animation
frameCount = frameCount+1;
requestAnimationFrame(draw);
};
// start the loop
init();
draw();
<!-- 100% area -->
body, html {
height: 100%;
width: 100%;
}
<!DOCTYPE HTML>
<html>
<body>
<canvas id="myCanvas" ></canvas>
</body>
</html>

creating a recurring animation that doesn't interrupt previous call

I'm trying to creating a recurring animation of vertical rows of circles. Each row begins at the bottom of the browser and goes to the top, occurring at random intervals between 0 and 2 seconds. The problem is that when the animations are too close together in timing, the new one discontinues the previous one, so sometimes the row of circles does not go all the way to the top of the browser. How can I prevent this and instead have multiple rows animating at once?
Here's the fiddle
var timer;
var newLine1 = function(){
clearInterval(timer);
var posX = Math.random() * canvas.width;
posY = canvas.height;
timer = setInterval(function() {
posY -= 20;
c.fillStyle = "rgba(23, 23, 23, 0.05)";
c.fillRect(0, 0, canvas.width, canvas.height);
c.fillStyle = "white";
c.beginPath();
c.arc(posX, posY, 10, 0, twoPi, false);
c.fill();
}, 30);
setTimeout(newLine1, Math.random() * 2000);
};
newLine1();
Here's one way using a rising image of your vertically fading circles and the preferred animation loop (requestAnimationFrame).
Annotated code and a Demo:
// canvas related variables
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
// cache PI*2 because it's used often
var PI2=Math.PI*2;
// variables related to the stream of circles
var radius=10;
var alpha=1.00;
var alphaFade=0.05;
// create an in-memory canvas containing
// a stream of vertical circles
// with alpha=1.00 at top and alpha=0.00 at bottom
// This canvas is drawImage'd on the on-screen canvas
// to simulate animating circles
var streamHeight=(1/alphaFade)*radius*2;
var columnCanvas=document.createElement('canvas');
var columnCtx=columnCanvas.getContext('2d');
columnCanvas.width=radius*2;
columnCanvas.height=streamHeight;
for(var y=radius;y<ch+radius*2;y+=radius*2){
columnCtx.fillStyle='rgba(255,255,255,'+alpha+')';
columnCtx.beginPath();
columnCtx.arc(radius,y,radius,0,PI2);
columnCtx.closePath();
columnCtx.fill();
alpha-=alphaFade;
}
// just testing, remove this
document.body.appendChild(columnCanvas);
// create an array of stream objects
// each stream-object is a column of circles
// at random X and with Y
// animating from bottom to top of canvas
var streams=[];
// add a new stream
function addStream(){
// reuse any existing stream that's already
// scrolled off the top of the canvas
var reuseStream=-1;
for(var i=0;i<streams.length;i++){
if(streams[i].y<-streamHeight){
reuseStream=i;
break;
}
}
// create a new stream object with random X
// and Y is off-the bottom of the canvas
var newStream={
x: Math.random()*(cw-radius),
y: ch+radius+1
}
if(reuseStream<0){
// add a new stream to the array if no stream was available
streams.push(newStream);
}else{
// otherwise reuse the stream object at streams[reuseStream]
streams[reuseStream]=newStream;
}
}
// move all streams upward if the
// elapsed time is greater than nextMoveTime
var nextMoveTime=0;
// move all streams every 16ms X 3 = 48ms
var moveInterval=16*3;
// add a new stream if the
// elapsed time is greater than nextAddStreamTime
var nextAddStreamTime=0;
// set the background color of the canvas to black
ctx.fillStyle='black';
// start the animation frame
requestAnimationFrame(animate);
// the animation frame
function animate(currentTime){
// request a new animate loop
requestAnimationFrame(animate);
// add a new stream if the
// current elapsed time is > nextAddStreamTime
if(currentTime>nextAddStreamTime){
nextAddStreamTime+=Math.random()*1000;
addStream();
}
// move all streams upward if the
// current elapsed time is > nextMoveTime
if(currentTime>nextMoveTime){
nextMoveTime+=moveInterval;
ctx.fillRect(0,0,cw,ch);
for(var i=0;i<streams.length;i++){
var s=streams[i];
if(s.y<-streamHeight){continue;}
ctx.drawImage(columnCanvas,s.x,s.y);
s.y-=radius*2;
}
}
}
body{ background-color: ivory; padding:10px; }
canvas{border:1px solid red;}
<canvas id="canvas" width=300 height=400></canvas>
How about like this. I've only re-worked the newLine1() function. At the end of the line drawing (when posY is < 0), then you trigger the timeout to start another line.
var newLine1 = function(){
var posX = Math.random() * canvas.width;
posY = canvas.height;
timer = setInterval(function() {
posY -= 20;
... drawing code ...
if(posY < 0) {
clearInterval(timer);
setTimeout(newLine1, Math.random() * 2000);
}
}, 30);
};
newLine1();
It also means you don't need the clearInterval at the top, but you clear the timer interval only when the drawing is done (in the posY<0 case).
UPDATE:
Here is take two. I've factored out the line rendering stuff into it's own little class. renderLine then just manages the line intervals and the restarting a line (with timeout) when the first render is done. Finally, we just kick off a bunch of lines.
window.onload = function() {
function LineAnimator(canvas, startX, startY) {
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
this.startX = startX;
this.startY = startY;
this.interval = null;
this.reset();
}
LineAnimator.prototype.reset = function() {
this.posX = 0 + this.startX;
this.posY = 0 + this.startY;
}
/** return false when there's no more to draw */
LineAnimator.prototype.render = function() {
this.posY -= 20;
this.ctx.fillStyle = 'rgba(23,23,23,0.1)';
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
this.ctx.fillStyle = 'white';
this.ctx.beginPath();
this.ctx.arc(this.posX, this.posY, 10, 0, twoPi, false);
this.ctx.fill();
if (this.posY < 0) {
return false; /* done rendering */
}
else {
return true;
}
};
var canvas = document.getElementById("paper"),
c = canvas.getContext("2d"),
twoPi = Math.PI * 2;
canvas.width = 500;
canvas.height = 700;
c.fillStyle = "#232323";
c.fillRect(0, 0, canvas.width, canvas.height);
c.save();
var renderLine = function() {
console.log('render line');
var posX = Math.random() * canvas.width;
posY = canvas.height;
var animator = new LineAnimator(canvas, posX, posY);
var timer = setInterval(function() {
if(!animator.render()) {
console.log('done rendering');
clearInterval(timer);
setTimeout(renderLine, Math.random() * 2000)
}
}, 30);
};
var ii = 0,
nConcurrentLines = 8;
for (; ii < nConcurrentLines; ++ii ) {
renderLine();
}
};
This definitely looks a bit different than what I think you're going for, but I kind of like the effect. Though, i would take a close look at #MarkE's answer below. I think his approach is much better. There are no timeouts or intervals and it's using the requestAnimationFrame method which seems much cleaner.

Categories

Resources