How to draw a curve that could move to left with canvas? - javascript

I'm writing a program that will draw the sine curve with canvas.
HTML:
<canvas id="mycanvas" width="1000" height="100">
Your browser is not supported.
</canvas>
JavaScript:
var canvas = document.getElementById("mycanvas");
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
ctx.lineWidth = 3;
var x = 0,
y = 0;
var timeout = setInterval(function() {
ctx.beginPath();
ctx.moveTo(x, y);
x += 1;
y = 50 * Math.sin(0.1 * x) + 50;
ctx.lineTo(x, y);
ctx.stroke();
if (x > 1000) {
clearInterval(timeout);
}
}, 10);
}
This works really nice: http://jsfiddle.net/HhGnb/
However, now I can only offer say 100px for the canvas width, so only the leftest 100px of the curve could be seen. http://jsfiddle.net/veEyM/1/
I want to archive this effect: when the right point of the curve is bigger than the width of canvas, the whole curve could move left, so I can see the rightest point of the curve, it's a bit like the curve is flowing to left. Can I do that?

One of the basic ideas of the <canvas> element is that the computer 'forgets' the drawing commands and only saves the pixels, like a bitmap. So to move everything to the left, you need to clear the canvas and draw everything again.
There is also one thing I'd like to advise you - you always start with x = 0 and y = 0, but obviously at x = 0 then y is not necessarily equal to 0 as well. EDIT: implemented this.
Anyway, I ended up with this code: http://jsfiddle.net/veEyM/5/
var canvas = document.getElementById("mycanvas");
var points = {}; // Keep track of the points in an object with key = x, value = y
var counter = 0; // Keep track when the moving code should start
function f(x) {
return 50 * Math.sin(0.1 * x) + 50;
}
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
ctx.lineWidth = 3;
var x = 0,
y = f(0);
var timeout = setInterval(function() {
if(counter < 100) { // If it doesn't need to move, draw like you already do
ctx.beginPath();
ctx.moveTo(x, y);
points[x] = y;
x += 1;
y = f(x);
ctx.lineTo(x, y);
ctx.stroke();
if (x > 1000) {
clearInterval(timeout);
}
} else { // The moving part...
ctx.clearRect(0, 0, 100, 100); // Clear the canvas
ctx.beginPath();
points[x] = y;
x += 1;
y = f(x);
for(var i = 0; i < 100; i++) {
// Draw all lines through points, starting at x = i + ( counter - 100 )
// to x = counter. Note that the x in the canvas is just i here, ranging
// from 0 to 100
ctx.lineTo(i, points[i + counter - 100]);
}
ctx.stroke();
}
counter++;
}, 10);
}

Related

How to make an object blink once in js?

I'm not proficient in js to say the very least.
I have a bouncy ball in a container in js. When the ball hits a certain part of its container, I want a box to light up briefly. I want to control the duration of the blink. I want the blink to happen once.
So far this works but the blink is incredibly brief:
I have a canvas object
<Canvas id="button1" width="100px" height="50px"></canvas>
And this code in place. Let's assume for simplicity's sake that the ball being in the right place sets ball_is_in_area to T for a very short duration.
var button1;
var button1ctx;
var ball_is_in_area = F;
button1 = document.getElementById("button1");
button1ctx = button1.getContext("2d");
button1ctx.fillStyle = "white";
button1ctx.fillRect(0, 0, canvas.width, canvas.height);
if( ball_is_in_area == T){
snd.play();
button1ctx.fillStyle = "red";
button1ctx.fillRect(0, 0, canvas.width, canvas.height);
}
"Don't use a canvas object use X" type answers are also appreciated!
Using requestAnimationFrame and based on this sample, you can use the timestamp parameter provided and, whenever you hit a wall, extend the timer for when the blink will end. Then use this timer to determine the color of the background.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var x = canvas.width / 2, y = canvas.height / 2;
var ballRadius = 10, dx = 2, dy = -2;
var blinkDuration = 60; // Duration in milliseconds
var endBlink = 0;
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
function draw(timeStamp) {
if (x + dx > canvas.width - ballRadius || x + dx < ballRadius) {
endBlink = timeStamp + blinkDuration; // Hit a wall
dx = -dx;
}
if (y + dy > canvas.height - ballRadius || y + dy < ballRadius) {
endBlink = timeStamp + blinkDuration;
dy = -dy;
}
// If endBlink > timeStamp, change the color
ctx.fillStyle = (endBlink > timeStamp ? "#338" : "#114");
ctx.fillRect(0, 0, canvas.width, canvas.height);
drawBall();
x += dx;
y += dy;
requestAnimationFrame(draw);
}
requestAnimationFrame(draw);
body { margin: 0 }
<canvas id="canvas" width="630" height="190"></canvas>

Loop Background Image Animation in Canvas

I am new to Canvas and want to loop background Image in the below smoke effect. On searching, I have found an example that how we can loop background Image in canvas Link to looping animation so I tried integrating the looping code with the smoke effect but no success. Any help will be appreciated.
// Create an array to store our particles
var particles = [];
// The amount of particles to render
var particleCount = 60;
// The maximum velocity in each direction
var maxVelocity = 2;
// The target frames per second (how often do we want to update / redraw the scene)
var targetFPS = 33;
// Set the dimensions of the canvas as variables so they can be used.
var canvasWidth = window.innerWidth;
var canvasHeight = window.innerHeight;
// borders for particles on top and bottom
var borderTop = 0.01 * canvasHeight;
var borderBottom = 0.99 * canvasHeight;
// Create an image object (only need one instance)
var imageObj = new Image();
var looping = false;
var totalSeconds = 0;
// Once the image has been downloaded then set the image on all of the particles
imageObj.onload = function() {
particles.forEach(function(particle) {
particle.setImage(imageObj);
});
};
// Once the callback is arranged then set the source of the image
imageObj.src = "https://image.ibb.co/fdpeJF/Smoke.png";
// A function to create a particle object.
function Particle(context) {
// Set the initial x and y positions
this.x = 0;
this.y = 0;
// Set the initial velocity
this.xVelocity = 0;
this.yVelocity = 0;
// Set the radius
this.radius = 5;
// Store the context which will be used to draw the particle
this.context = context;
// The function to draw the particle on the canvas.
this.draw = function() {
// If an image is set draw it
if (this.image) {
this.context.drawImage(this.image, this.x - 128, this.y - 128);
// If the image is being rendered do not draw the circle so break out of the draw function
return;
}
// Draw the circle as before, with the addition of using the position and the radius from this object.
this.context.beginPath();
this.context.arc(this.x, this.y, this.radius, 0, 2 * Math.PI, false);
this.context.fillStyle = "rgba(0, 255, 255, 1)";
this.context.fill();
this.context.closePath();
};
// Update the particle.
this.update = function() {
// Update the position of the particle with the addition of the velocity.
this.x += this.xVelocity;
this.y += this.yVelocity;
// Check if has crossed the right edge
if (this.x >= canvasWidth) {
this.xVelocity = -this.xVelocity;
this.x = canvasWidth;
}
// Check if has crossed the left edge
else if (this.x <= 0) {
this.xVelocity = -this.xVelocity;
this.x = 0;
}
// Check if has crossed the bottom edge
if (this.y >= borderBottom) {
this.yVelocity = -this.yVelocity;
this.y = borderBottom;
}
// Check if has crossed the top edge
else if (this.y <= borderTop) {
this.yVelocity = -this.yVelocity;
this.y = borderTop;
}
};
// A function to set the position of the particle.
this.setPosition = function(x, y) {
this.x = x;
this.y = y;
};
// Function to set the velocity.
this.setVelocity = function(x, y) {
this.xVelocity = x;
this.yVelocity = y;
};
this.setImage = function(image) {
this.image = image;
};
}
// A function to generate a random number between 2 values
function generateRandom(min, max) {
return Math.random() * (max - min) + min;
}
// The canvas context if it is defined.
var context;
// Initialise the scene and set the context if possible
function init() {
var canvas = document.getElementById('myCanvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
if (canvas.getContext) {
// Set the context variable so it can be re-used
context = canvas.getContext('2d');
// Create the particles and set their initial positions and velocities
for (var i = 0; i < particleCount; ++i) {
var particle = new Particle(context);
// Set the position to be inside the canvas bounds
particle.setPosition(generateRandom(0, canvasWidth), generateRandom(borderTop, borderBottom));
// Set the initial velocity to be either random and either negative or positive
particle.setVelocity(generateRandom(-maxVelocity, maxVelocity), generateRandom(-maxVelocity, maxVelocity));
particles.push(particle);
context.clearRect(0, 0, canvas.width, canvas.height);
}
} else {
alert("Please use a modern browser");
}
}
// The function to draw the scene
function draw() {
// background image
context.globalAlpha = 1;
context.globalCompositeOperation = 'source-over';
context.drawImage(backImg, 0, 0, canvasWidth, canvasHeight);
context.fillStyle = "rgba(255,255,255, .5)";
context.fillRect(0, 0, canvasWidth, canvasHeight);
context.globalAlpha = 0.75;
context.globalCompositeOperation = 'soft-lights';
// Fog layer
// Go through all of the particles and draw them.
particles.forEach(function(particle) {
particle.draw();
});
}
// Update the scene
function update() {
particles.forEach(function(particle) {
particle.update();
});
}
// Initialize the scene
init();
backImg = new Image();
backImg.src = 'https://image.ibb.co/cTOOdF/e2VZQY.jpg';
// If the context is set then we can draw the scene (if not then the browser does not support canvas)
if (context) {
setInterval(function() {
// Update the scene befoe drawing
update();
// Draw the scene
draw();
}, 1000 / targetFPS);
}
<canvas id="myCanvas" ></canvas>
I just added a few lines. Hopefully you can spot them. I commented everything I added.
// Create an array to store our particles
var particles = [];
// The amount of particles to render
var particleCount = 60;
// The maximum velocity in each direction
var maxVelocity = 2;
// The target frames per second (how often do we want to update / redraw the scene)
var targetFPS = 33;
// Set the dimensions of the canvas as variables so they can be used.
var canvasWidth = window.innerWidth;
var canvasHeight = window.innerHeight;
// borders for particles on top and bottom
var borderTop = 0.01 * canvasHeight;
var borderBottom = 0.99 * canvasHeight;
// Create an image object (only need one instance)
var imageObj = new Image();
// x position of scrolling image
var imageX = 0;
var looping = false;
var totalSeconds = 0;
// Once the image has been downloaded then set the image on all of the particles
imageObj.onload = function() {
particles.forEach(function(particle) {
particle.setImage(imageObj);
});
};
// Once the callback is arranged then set the source of the image
imageObj.src = "https://image.ibb.co/fdpeJF/Smoke.png";
// A function to create a particle object.
function Particle(context) {
// Set the initial x and y positions
this.x = 0;
this.y = 0;
// Set the initial velocity
this.xVelocity = 0;
this.yVelocity = 0;
// Set the radius
this.radius = 5;
// Store the context which will be used to draw the particle
this.context = context;
// The function to draw the particle on the canvas.
this.draw = function() {
// If an image is set draw it
if (this.image) {
this.context.drawImage(this.image, this.x - 128, this.y - 128);
// If the image is being rendered do not draw the circle so break out of the draw function
return;
}
// Draw the circle as before, with the addition of using the position and the radius from this object.
this.context.beginPath();
this.context.arc(this.x, this.y, this.radius, 0, 2 * Math.PI, false);
this.context.fillStyle = "rgba(0, 255, 255, 1)";
this.context.fill();
this.context.closePath();
};
// Update the particle.
this.update = function() {
// Update the position of the particle with the addition of the velocity.
this.x += this.xVelocity;
this.y += this.yVelocity;
// Check if has crossed the right edge
if (this.x >= canvasWidth) {
this.xVelocity = -this.xVelocity;
this.x = canvasWidth;
}
// Check if has crossed the left edge
else if (this.x <= 0) {
this.xVelocity = -this.xVelocity;
this.x = 0;
}
// Check if has crossed the bottom edge
if (this.y >= borderBottom) {
this.yVelocity = -this.yVelocity;
this.y = borderBottom;
}
// Check if has crossed the top edge
else if (this.y <= borderTop) {
this.yVelocity = -this.yVelocity;
this.y = borderTop;
}
};
// A function to set the position of the particle.
this.setPosition = function(x, y) {
this.x = x;
this.y = y;
};
// Function to set the velocity.
this.setVelocity = function(x, y) {
this.xVelocity = x;
this.yVelocity = y;
};
this.setImage = function(image) {
this.image = image;
};
}
// A function to generate a random number between 2 values
function generateRandom(min, max) {
return Math.random() * (max - min) + min;
}
// The canvas context if it is defined.
var context;
// Initialise the scene and set the context if possible
function init() {
var canvas = document.getElementById('myCanvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
if (canvas.getContext) {
// Set the context variable so it can be re-used
context = canvas.getContext('2d');
// Create the particles and set their initial positions and velocities
for (var i = 0; i < particleCount; ++i) {
var particle = new Particle(context);
// Set the position to be inside the canvas bounds
particle.setPosition(generateRandom(0, canvasWidth), generateRandom(borderTop, borderBottom));
// Set the initial velocity to be either random and either negative or positive
particle.setVelocity(generateRandom(-maxVelocity, maxVelocity), generateRandom(-maxVelocity, maxVelocity));
particles.push(particle);
context.clearRect(0, 0, canvas.width, canvas.height);
}
} else {
alert("Please use a modern browser");
}
}
// The function to draw the scene
function draw() {
// background image
context.globalAlpha = 1;
context.globalCompositeOperation = 'source-over';
// draw twice to cover wrap around
context.drawImage(backImg, imageX, 0, canvasWidth, canvasHeight);
context.drawImage(backImg, imageX + canvasWidth, 0, canvasWidth, canvasHeight);
context.fillStyle = "rgba(255,255,255, .5)";
context.fillRect(0, 0, canvasWidth, canvasHeight);
context.globalAlpha = 0.75;
context.globalCompositeOperation = 'soft-light';
// Fog layer
// Go through all of the particles and draw them.
particles.forEach(function(particle) {
particle.draw();
});
}
// Update the scene
function update() {
// incrementally change image position of background to scroll left
imageX -= maxVelocity;
if (imageX < -canvasWidth) {
imageX += canvasWidth;
}
particles.forEach(function(particle) {
particle.update();
});
}
// Initialize the scene
init();
backImg = new Image();
backImg.src = 'https://image.ibb.co/cTOOdF/e2VZQY.jpg';
// If the context is set then we can draw the scene (if not then the browser does not support canvas)
if (context) {
setInterval(function() {
// Update the scene befoe drawing
update();
// Draw the scene
draw();
}, 1000 / targetFPS);
}
<canvas id="myCanvas"></canvas>
Just to add to the answer given some additional improvements to the code structure.
Use requestAnimationFrame to call render calls.
Don't expose properties of objects if not needed.
Don't use forEach iteration in time critical code. Use for loops.
Use constants where ever possible.
Comments that state the obvious are just noise in the source code making it harder to read. Limit comment to abstracts that may not be obvious to another programmer reading the code.
eg
// If an image is set draw it
if (this.image) {
Really is that comment of any use to anyone. Comments should help not degrade the readability of code.
Also the original code tried to set the global composite operations to soft-lights this is not a know operation. I corrected it to soft-light which can on some machines, be a very slow render operation. It may pay to selected another operation for machines that are slow. This can be done by simply monitoring the render time of particles and switching operation type is too slow.
A quick rewrite of the OP's code.
const particles = [];
const particleCount = 60;
const maxVelocity = 2;
var canvasWidth = innerWidth;
var canvasHeight = innerHeight;
var borderTop = 0.01 * canvasHeight;
var borderBottom = 0.99 * canvasHeight;
var ctx;
const backgroundColor = "rgba(255,255,255, .5)";
const backgroundSpeed = -0.1;
var looping = false;
var totalSeconds = 0;
var lastTime = 0;
var frameTime = (1000 / 30) - (1000 / 120); // one quater frame short to
// allow for timing error
var imageCount = 0;
const backImg = new Image();
const imageObj = new Image();
backImg.src = 'https://image.ibb.co/cTOOdF/e2VZQY.jpg';
imageObj.src = "https://image.ibb.co/fdpeJF/Smoke.png";
backImg.onload = imageObj.onload = imageLoad;
function imageLoad(){
imageCount += 1;
if(imageCount === 2){
init();
}
}
function init() {
var canvas = myCanvas;
canvas.width = innerWidth;
canvas.height = innerHeight;
ctx = canvas.getContext('2d');
for (var i = 0; i < particleCount; i += 1) {
particles.push(new Particle(ctx));
}
lastTime = performance.now();
requestAnimationFrame(mainLoop);
}
function mainLoop(time){
if(time-lastTime > frameTime){
lastTime = time;
update();
draw(time);
}
requestAnimationFrame(mainLoop);
}
const rand = (min, max) => Math.random() * (max - min) + min; // names are best short (short only without ambiguity)
function Particle(ctx) {
var x, y, xVel, yVel, radius, image;
const color = "rgba(0, 255, 255, 1)";
x = rand(0, canvasWidth),
y = rand(borderTop, borderBottom);
xVel = rand(-maxVelocity, maxVelocity);
yVel = rand(-maxVelocity, maxVelocity);
radius = 5;
image = imageObj;
this.draw = function () { ctx.drawImage(image, x - 128, y - 128) }
this.update = function () {
x += xVel;
y += yVel;
if (x >= canvasWidth) {
xVel = -xVel;
x = canvasWidth;
}
else if (x <= 0) {
xVel = -xVel;
x = 0;
}
if (y >= borderBottom) {
yVel = -yVel;
y = borderBottom;
}
else if (y <= borderTop) {
yVel = -yVel;
y = borderTop;
}
}
}
function draw(time) {
var i,x;
ctx.globalAlpha = 1;
ctx.globalCompositeOperation = 'source-over';
x = time * backgroundSpeed;
x = ((x % canvasWidth) + canvasWidth) % canvasWidth;
ctx.drawImage(backImg, x, 0, canvasWidth, canvasHeight);
ctx.drawImage(backImg, x - canvasWidth, 0, canvasWidth, canvasHeight);
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
ctx.globalAlpha = 0.75;
ctx.globalCompositeOperation = 'soft-light';
for(i = 0; i < particles.length; i += 1){
particles[i].draw();
}
}
function update() {
for(i = 0; i < particles.length; i += 1){
particles[i].update();
}
}
canvas {
position : absolute;
top : 0px;
left : 0px;
}
<canvas id=myCanvas></canvas>

Removing lines when drawing multiple arcs in a row in javascript

So I'm trying to draw 8 random circles (Or bubbles as I call them in this case) on the screen for a simple project I'm making. I want to make it so that I can show the bubbles, but there are lines connecting each bubble at its startAngle.
<!DOCTYPE html>
<html>
<head>
<title>Image</title>
</head>
<body>
<script src="https://code.jquery.com/jquery-2.1.0.js"></script>
<canvas id="canvas" width="400" height="400"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var height = canvas.height;
var width = canvas.width;
ctx.strokeRect(0, 0, width, height);
var bubbles = [];
var Bubble = function () {
this.x = Math.floor(Math.random() * width);
this.y = Math.floor(Math.random() * height);
this.xspeed = 5;
this.yspeed = 5;
};
for (var i = 0; i < 8; i++) {
bubbles[i] = new Bubble();
};
Bubble.prototype.draw = function () {
for (var i = 0; i < 8; i++) {
ctx.fillStyle = "Black";
ctx.arc(bubbles[i].x, bubbles[i].y, 10, 0, Math.PI * 2, false);
}
};
setInterval(function () {
for (var i = 0; i < bubbles.length; i++) {
ctx.strokeStyle = "Black";
bubbles[i].draw();
ctx.stroke();
}
}, 30);
</script>
</body>
</html>
Basically, I've made 8 Bubble objects, then I've drawn an arc at their x and y (random) position, but it shows lines connecting them like so:
Output of code
When you run the code, it randomly generates 8 different locations and draws 8 arcs at their location, but it shows the lines that connect them. Is there a way to hide or get rid of these lines? I've tried to clear the canvas after each draw, but that hides the entire thing including the circle. I've been searching for most of the day and I couldn't find an answer to my specific problem. The answer is probably obvious, but I couldn't seem to find the solution due to my inexperience.
Call ctx.beginPath() before arc() to draw separate entities?
ctx.arc() creates an ctx.lineTo() between the last coordinates of the current path, and the first position of the arc.
So to avoid it, you can simply manually call moveTo() to lift the drawing pen to the first position of the arc.
This way, you can draw multiple arcs in the same Path and in the same stroke call (which becomes interesting when you draw a lot of arcs)
const ctx = c.getContext('2d'),
w = c.width,
h = c.height;
ctx.beginPath(); // call it once
for(let i = 0; i<100; i++){
let rad = Math.random()*20 + 5
let posX = rad + Math.random() * (w - rad *2);
let posY = rad + Math.random() * (h - rad *2);
// our arc will start at 3 o'clock
ctx.moveTo(posX + rad, posY); // so simply add 'rad' to the centerX
ctx.arc(posX, posY, rad, 0, Math.PI*2);
}
ctx.stroke(); // call it once
<canvas id="c" width="500"></canvas>

is it possible to draw a big number of simple geometric figures in HTML5.canvas?

I have this awesome piece of code.
The idea, as you can imagine,is to draw a grid of rectangles. I want a big grid, let's say 100 X 100 or more.
However, when i run the awesome piece of code for the desired size (100X 100), my browser crashes.
How can i achieve that?
* please note: when i say 100X100 i mean the final number of rectangles (10k) not the size of the canvas.
thank u
function init() {
var cnv = get('cnv');
var ctx = cnv.getContext('2d');
var ancho = 12; // ancho means width
var alto = 12; // alto means height
ctx.fillStyle = randomRGB();
for (var i = 0; i < cnv.width; i+= ancho) {
for (var j = 0; j < cnv.height; j+= alto) {
//dibujar means to draw, rectangulo means rectangle
dibujarRectangulo(i+ 1, j+1, ancho, alto, ctx);
}
}
}
function dibujarRectangulo(x, y, ancho, alto, ctx) {
ctx.rect(x, y, ancho, alto);
ctx.fill();
ctx.closePath();
}
The dibujarRectanglo() function calls rect() function which adds a closed rectanglar subpath to the current path. Then calls fill() function to fill the current path. Then calls closePath() function to close the subpath, which does nothing since the subpath is already closed.
In other words, the first dibujarRectanglo() function call is painting a path that contains 1 rectangle subpath. The second call is painting a path that contains 2 rectangle subpaths. The third call is painting a path that contains 3 rectangle subpaths. And so on. If the loop calls dibujarRectanglo() function 10000 times then a total of 1+2+3+...+10000 = 50005000 (i.e. over 50 million) rectangle subpaths will be painted.
The dibujarRectangle() function should be starting a new path each time. For example...
function dibujarRectangulo(x, y, ancho, alto, ctx) {
ctx.beginPath();
ctx.rect(x, y, ancho, alto);
ctx.fill();
}
Then 10000 calls will only paint 10000 rectangle subpaths which is a lot faster that painting 50 million rectangle subpaths.
16,384 boxes on the wall
As I said in the comment its easy to draw a lot of boxes, it is not easy to have them all behave uniquely. Anyways using render to self to duplicate boxes exponential there are 128 * 128 boxes so that's 16K, one more iteration and it would be 64K boxes.
Its a cheat, I could have just drawn random pixels and called each pixel a box.
Using canvas you will get upto 4000 sprites per frame on a top end machine using FireFox with each sprite having a location, center point, rotation, x and y scale, and an alpha value. But that is the machine going flat out.
Using WebGL you can get much higher but the code complexity goes up.
I use a general rule of thumb, if a canva 2D project has more than 1000 sprites then it is in need of redesign.
var canvas = document.getElementById("can");
var ctx = canvas.getContext("2d");
/** CreateImage.js begin **/
var createImage = function (w, h) {
var image = document.createElement("canvas");
image.width = w;
image.height = h;
image.ctx = image.getContext("2d");
return image;
}
/** CreateImage.js end **/
/** FrameUpdate.js begin **/
var w = canvas.width;
var h = canvas.height;
var cw = w / 2;
var ch = h / 2;
var boxSize = 10;
var boxSizeH = 5;
var timeDiv = 1.2;
var bBSize = boxSize * 128; // back buffer ssize
var buff = createImage(bBSize, bBSize);
var rec = createImage(boxSize, boxSize);
var drawRec = function (ctx, time) {
var size, x, y;
size = (Math.sin(time / 200) + 1) * boxSizeH;
ctx.fillStyle = "hsl(" + Math.floor((Math.sin(time / 500) + 1) * 180) + ",100%,50%)";
ctx.strokeStyle = "Black";
ctx.setTransform(1, 0, 0, 1, 0, 0)
ctx.clearRect(0, 0, boxSize, boxSize);
x = Math.cos(time / 400);
y = Math.sin(time / 400);
ctx.setTransform(x, y, -y, x, boxSizeH, boxSizeH)
ctx.fillRect(-boxSizeH + size, -boxSizeH + size, boxSize - 2 * size, boxSize - 2 * size);
ctx.strokeRect(-boxSizeH + size, -boxSizeH + size, boxSize - 2 * size, boxSize - 2 * size);
}
function update(time) {
var fw, fh, px, py, i;
time /= 7;
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, w, h);
drawRec(rec.ctx, time);
time /= timeDiv;
buff.ctx.clearRect(0, 0, bBSize, bBSize)
buff.ctx.drawImage(rec, 0, 0);
buff.ctx.drawImage(rec, boxSize, 0);
fw = boxSize + boxSize; // curent copy area width
fh = boxSize; // curent copy area height
px = 0; // current copy to x pos
py = boxSize; // current copy to y pos
buff.ctx.drawImage(buff, 0, 0, fw, fh, px, py, fw, fh); // make square
for (i = 0; i < 6; i++) {
drawRec(rec.ctx, time);
time /= timeDiv;
buff.ctx.drawImage(rec, 0, 0);
fh += fh; // double size across
px = fw;
py = 0;
buff.ctx.drawImage(buff, 0, 0, fw, fh, px, py, fw, fh); // make rec
drawRec(rec.ctx, time);
time /= timeDiv;
buff.ctx.drawImage(rec, 0, 0);
fw += fw; // double size down
px = 0;
py = fh;
buff.ctx.drawImage(buff, 0, 0, fw, fh, px, py, fw, fh);
}
// draw the boxes onto the canvas,
ctx.drawImage(buff, 0, 0, 1024, 1024);
requestAnimationFrame(update);
}
update();
.canv {
width:1024px;
height:1024px;
}
<canvas id="can" class = "canv" width=1024 height=1024></canvas>

How to make a scrolling starfield

I want to write a simple scrolling right to left starfield. I have printed out the stars randomly. Now, how do I target each star and randomly give it a speed (say 1-10) and begin moving it? I also need to put each star back on the right edge after it reaches the left edge.
Following is my code written so far:
<!DOCTYPE html>
<html>
<head>
<script>
function stars()
{
canvas = document.getElementById("can");
if(canvas.getContext)
{
ctx = canvas.getContext("2d");
ctx.fillStyle = "black";
ctx.rect (0, 0, 400, 400);
ctx.fill();
starfield();
}
}
//print random stars
function starfield()
{
for (i=0; i<10; i++)
{
var x = Math.floor(Math.random()*399);
var y = Math.floor(Math.random()*399);
var tempx = x;
ctx.fillStyle = "white";
ctx.beginPath();
ctx.arc(x, y, 3, 0, Math.PI*2, true);
ctx.closePath();
ctx.fill();
}
}
</script>
</head>
<body onload="stars()">
<h1>Stars</h1>
<canvas id="can" width="400" height="400"style="border:2px solid #000100" ></canvas>
</body >
</html>
Here's a quick demo on Codepen. After saving the stars in an array, I'm using requestAnimationFrame to run the drawing code and update the position on every frame.
function stars() {
canvas = document.getElementById("can");
console.log(canvas);
if (canvas.getContext) {
ctx = canvas.getContext("2d");
ctx.fillStyle = "black";
ctx.rect(0, 0, 400, 400);
ctx.fill();
starfield();
}
}
// Create random stars with random velocity.
var starList = []
function starfield() {
for (i = 0; i < 20; i++) {
var star = {
x: Math.floor(Math.random() * 399),
y: Math.floor(Math.random() * 399),
vx: Math.ceil(Math.random() * 10)
};
starList.push(star);
}
}
function run() {
// Register for the next frame
window.requestAnimationFrame(run);
// Reset the canvas
ctx.fillStyle = "black";
ctx.rect(0, 0, 400, 400);
ctx.fill();
// Update position and draw each star.
var star;
for(var i=0, j=starList.length; i<j; i++) {
star = starList[i];
star.x = (star.x - star.vx + 400) % 400;
ctx.fillStyle = "white";
ctx.beginPath();
ctx.arc(star.x, star.y, 3, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
}
}
stars();
run();
Put your x,y coordinates in an array, and then make a function that draws the array.
var stars = [
{x:110, y:80},
{x:120, y:20},
{x:130, y:60},
{x:140, y:40}
]
Then make a function to alter the x,y coordinates (for example increment y=y+1) each time before using the draw function.
Bonus:
This array solution allows you to have each star move at its own speed, you could store a delta (say 1 upto 3) in that array, and do y=y+delta instead. This looks 3D.
You could even go further and have a seperate x and y delta, and have stars fly out from the middle, which is even more 3D!
Or even simpler/faster could be to have the render function accept an x,y offset. It could then even wrap around, so that what falls off the screen on one side comes back on the other. It looks like you are rotating in space.
I simple way to imitate star movement towards a point(like a center) is simply divide both X and Y by Z coordinate.
nx = x / z
ny = y / z
And simply decrease z value as you iterate. As z is big, your points will be around a point and as z decreases the result will be bigger and bigger which imitates "moving" of a stars.
Just providing a solution which uses jQuery because using it you can get the output with lesser lines of code compared to complete canvas solution.It uses two canvas divs to get the desired output:
Check this fiddle
Little updated code from the code posted in the question
<script>
function stars(){
canvas = document.getElementById("can1");
canvasCopy = document.getElementById("can2");
if(canvas.getContext){
ctx = canvas.getContext("2d");
ctx.fillStyle = "black";
ctx.rect (0, 0, 400, 400);
ctx.fill();
starfield();
var destCtx = canvasCopy.getContext('2d');
destCtx.drawImage(canvas, 0, 0);
}
}
//print random stars
function starfield(){
for (i=0;i<10;i++){
var x = Math.floor(Math.random()*399);
var y = Math.floor(Math.random()*399);
var tempx = x;
ctx.fillStyle = "white";
ctx.beginPath();
ctx.arc(x, y, 3, 0, Math.PI*2, true);
ctx.closePath();
ctx.fill();
}
}
</script>
<body onload="stars()">
<h1>Stars</h1>
<div id="starBlocks">
<canvas id="can1" width="400" height="400"style="border:2px solid #000100" ></canvas>
<canvas id="can2" width="400" height="400"style="border:2px solid #000100" ></canvas>
</div>
</body >
jQuery
function playStars()
{
$('#starBlocks').animate({
scrollLeft : 400
},10000,'linear',function(){
$('#starBlocks').scrollLeft(0);
playStars();
});
}
playStars();
CSS
#starBlocks{
white-space:nowrap;
font-size:0px;
width:400px;
overflow:hidden;
}

Categories

Resources