I have a top to bottom falling canvas animation, but I want to reverse it (go from bottom to top). I can't figure out how to change the direction
I have my code here
http://js.do/code/176399
sample:
function Ember(x, y, s /*radius*/ , p /*num points*/ ) {
this.x = x;
this.y = y;
this.s = s;
this.p = p;
this.img = document.createElement('canvas');
var context = this.img.getContext('2d'),
len = this.s / 1.45;
this.img.height = this.img.width = this.s * 2;
context.translate(this.s, this.s);
context.rotate((Math.PI * 1 / 10));
context.beginPath();
for (var i = 0; i < p; i++) {
context.lineTo(0, -s);
context.rotate((Math.PI * 2 / (p * 2)));
context.lineTo(0, s);
context.rotate((Math.PI * 2 / (p * 2)));
}
context.closePath();
context.shadowBlur = this.s / 3;
context.shadowColor = 'rgba(174, 12, 1, 0.9)';
context.fillStyle = 'rgba(133,80,33,.45)';
context.fill();
}
Just need to reverse the "fall" to bottom to top.
Update:
following off of Jared's suggestion
Changed:
embers[i].y += embers[i].vy;
to:
embers[i].y -= embers[i].vy;
However, I only get one animation cycle would like to have it continually animate new embers on the screen
Take a look at this line where you update the ember's Y position:
embers[i].y = -embers[i].s;
Try changing this to something like this:
embers[i].y = embers[i].s;
<canvas id="canvas"></canvas>
<script>
function Ember(x, y, s /*radius*/ , p /*num points*/ ) {
this.x = x;
this.y = y;
this.s = s;
this.p = p;
this.img = document.createElement('canvas');
var context = this.img.getContext('2d'),
len = this.s / 1.45;
this.img.height = this.img.width = this.s * 2;
context.translate(this.s, this.s);
context.rotate((Math.PI * 1 / 10));
context.beginPath();
for (var i = 0; i < p; i++) {
context.lineTo(0, -s);
context.rotate((Math.PI * 2 / (p * 2)));
context.lineTo(0, s);
context.rotate((Math.PI * 2 / (p * 2)));
}
context.closePath();
context.shadowBlur = this.s / 3;
context.shadowColor = 'rgba(174, 12, 1, 0.9)';
context.fillStyle = 'rgba(133,80,33,.45)';
context.fill();
}
window.requestAnimationFrame = (function () {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
var canvas, context, height, width, embers;
setTimeout(init, 10);
function init() {
canvas = document.getElementById('canvas');
context = canvas.getContext('2d');
height = canvas.height = document.body.offsetHeight;
width = canvas.width = document.body.offsetWidth;
embers = [];
for (var i = 0; i < 150; i++) {
var x = Math.random() * width,
y = Math.random() * height,
s = Math.random() * 5 + 5,
p = Math.random() * 8 + 8;
var s = new Ember(x, y, s, p);
s.vx = Math.random() * 2 - 1;
s.vy = Math.random() * 2 + 1;
s.r = Math.random() * 360;
embers.push(s);
}
update();
render();
}
function update() {
for (var i = 0, l = embers.length; i < l; i++) {
embers[i].r += embers[i].vx / 10;
embers[i].x += embers[i].vx;
embers[i].y -= embers[i].vy;
if (embers[i].y < 0) {
embers[i].y = Math.random()*height;
embers[i].vx = Math.random() * 2 - 1;
embers[i].vy = Math.random() * 2 + 1;
}
}
setTimeout(update, 1000 / 30);
}
function render() {
context.clearRect(0, 0, width, height);
for (var i = 0, l = embers.length; i < l; i++) {
context.save();
context.translate(embers[i].x, embers[i].y);
context.rotate(embers[i].r);
context.drawImage(embers[i].img, 0, 0);
context.restore();
}
requestAnimationFrame(render);
}
</script>
Wrong if condition in update function, change it to check if v(embers[i].y < 0), ans set appropriate new y position
if (embers[i].y < 0) {
embers[i].y = Math.random()*height;
Related
Edit
Here is a JSFiddle with the code for the "tail" function commenting out.Solar System JSFiddle
I have this object I am working on that has an object orbiting a center mass. That works perfectly.
I am now trying to add a trailing line or "tail" that follows behind the planet.
My tail object looks like this:
function Tail(maxLength){
this.points = [];
this.maxLength = maxLength;
this.addPoint = function(point){
for(var i = Math.min(maxLength, this.points.length); i < maxLength; i++){
this.points[i] = this.points[i - 1];
}
this.points[0] = point;
}
this.draw = function(ctx){
for(var i = 1; Math.min(maxLength, this.points.length); i++){
if(i < maxLength - 20){
ctx.globalAlpha = 1;
} else {
ctx.globalAlpha = (this.maxLength - i) / 20;
}
ctx.beginPath();
ctx.moveTo(this.points[i - 1].x, this.points[i - 1].y);
ctx.lineTo(this.points[i].x, this.points[i].y);
ctx.stroke();
}
ctx.globalAlpha = 1;
}
}
The addPoint function takes an object that looks like '{x: currentX, y: currentY}
currentX and currentY are the x and y point of the object when ever it gets called.
I am lost on how I need to add the point to the points array and then draw based on those coordinates.
I modified your version to working condition
var canvas, width, height, ctx;
var bodies = [];
function init(){
canvas = document.getElementById("space-time");
width = window.innerWidth;
height = window.innerHeight;
canvas.width = width;
canvas.height = height;
ctx = canvas.getContext('2d');
createBodies();
setInterval(function(){
updateSystem();
updateBodies(0.01);
ctx.clearRect(0, 0, width, height);
drawBodies();
}, 10);
}
function createBodies(){
bodies.push(new Body((this.width / 2) - 250, (this.height / 2) - 300, 200, 0, 1, 10, "#14c71d", true));
bodies.push(new Body((this.width / 2) + 100, (this.height / 2) + 100, 350, 0, 1, 5, "#de2d16", true));
bodies.push(new Body(this.width / 2, this.height / 2, 0, 0, 1000000, 30, "#FF8501", false)); //sun
}
function drawBodies(){
for(var i = 0; i < bodies.length; i++){
bodies[i].draw(ctx);
}
}
function updateBodies(dt){
for(var i = 0; i < bodies.length; i++){
bodies[i].update(dt);
}
}
function updateSystem(){
var G = 10;
for(var i = 0; i < bodies.length; i++){
for(var j = 0; j < bodies.length; j++){
if(i === j) continue;
var b1 = bodies[i];
var b2 = bodies[j];
var dist = Math.sqrt((b1.x - b2.x) * (b1.x - b2.x) + (b1.y - b2.y) * (b1.y - b2.y));
var force = G * (b1.m * b2.m) / dist / dist;
var nx = (b2.x - b1.x) / dist;
var ny = (b2.y - b1.y) / dist;
b1.ax += nx * force / b1.m;
b1.ay += ny * force / b1.m;
b2.ax -= nx * force / b2.m;
b2.ay -= ny * force / b2.m;
}
}
}
function Body(x, y, v, angle, mass, radius, color, hasTail){
this.x = x;
this.y = y;
this.vx = v * Math.cos(angle);
this.vy = v * Math.sin(angle);
this.m = mass;
this.radius = radius;
this.color = color;
this.ax = 0;
this.ay = 0;
if (hasTail) {
this.tail = new Tail(50);
}
this.update = function(dt){
this.vx += this.ax * dt;
this.vy += this.ay * dt;
this.x += this.vx * dt;
this.y += this.vy * dt;
this.ax = 0;
this.ay = 0;
if(this.tail){
this.tail.addPoint({x: this.x, y: this.y});
}
}
this.draw = function(ctx){
ctx.strokeStyle = this.color;
ctx.fillStyle = this.color;
ctx.shadowColor = this.color;
ctx.shadowBlur = 5;
if(this.tail){
this.tail.draw(ctx);
}
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, 6.28);
ctx.fill();
}
}
function Tail(maxLength){
this.points = [];
this.maxLength = maxLength;
this.addPoint = point => {
this.points = [point].concat(this.points).slice(0, this.maxLength);
}
this.draw = function(ctx){
for(var i = 1; i < this.points.length; i++){
ctx.beginPath();
if(i < maxLength - 20){
ctx.globalAlpha = 1;
} else {
ctx.globalAlpha = (this.maxLength - i) / 20;
}
ctx.moveTo(this.points[i - 1].x, this.points[i - 1].y);
ctx.lineTo(this.points[i].x, this.points[i].y);
ctx.stroke();
}
ctx.globalAlpha = 1;
}
}
#space-time {
background-color: #1a1a1c;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Solar System AJ</title>
</head>
<body onload="init();">
<canvas id="space-time"></canvas>
</body>
</html>
You can visualisate the track of objects, if you fill frame with background with low opacity instead of clearing it:
var canvas, width, height, ctx;
var bodies = [];
function init(){
canvas = document.getElementById("space-time");
width = window.innerWidth;
height = window.innerHeight;
canvas.width = width;
canvas.height = height;
ctx = canvas.getContext('2d');
createBodies();
setInterval(function(){
updateSystem();
updateBodies(0.01);
// ctx.clearRect(0, 0, width, height);
// All magic here:
ctx.fillStyle = `rgba(0, 0, 0, .05)`;
ctx.shadowBlur = 0;
ctx.fillRect(0, 0, canvas.width, canvas.height);
drawBodies();
}, 10);
}
function createBodies(){
bodies.push(new Body((this.width / 2) - 250, (this.height / 2) - 300, 200, 0, 1, 10, "#14c71d", true));
bodies.push(new Body((this.width / 2) + 100, (this.height / 2) + 100, 350, 0, 1, 5, "#de2d16", true));
bodies.push(new Body(this.width / 2, this.height / 2, 0, 0, 1000000, 30, "#FF8501", false)); //sun
}
function drawBodies(){
for(var i = 0; i < bodies.length; i++){
bodies[i].draw(ctx);
}
}
function updateBodies(dt){
for(var i = 0; i < bodies.length; i++){
bodies[i].update(dt);
}
}
function updateSystem(){
var G = 10;
for(var i = 0; i < bodies.length; i++){
for(var j = 0; j < bodies.length; j++){
if(i === j) continue;
var b1 = bodies[i];
var b2 = bodies[j];
var dist = Math.sqrt((b1.x - b2.x) * (b1.x - b2.x) + (b1.y - b2.y) * (b1.y - b2.y));
var force = G * (b1.m * b2.m) / dist / dist;
var nx = (b2.x - b1.x) / dist;
var ny = (b2.y - b1.y) / dist;
b1.ax += nx * force / b1.m;
b1.ay += ny * force / b1.m;
b2.ax -= nx * force / b2.m;
b2.ay -= ny * force / b2.m;
}
}
}
function Body(x, y, v, angle, mass, radius, color, hasTail){
this.x = x;
this.y = y;
this.vx = v * Math.cos(angle);
this.vy = v * Math.sin(angle);
this.m = mass;
this.radius = radius;
this.color = color;
this.ax = 0;
this.ay = 0;
this.update = function(dt){
this.vx += this.ax * dt;
this.vy += this.ay * dt;
this.x += this.vx * dt;
this.y += this.vy * dt;
this.ax = 0;
this.ay = 0;
}
this.draw = function(ctx){
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, 6.28);
ctx.strokeStyle = this.color;
ctx.fillStyle = this.color;
ctx.shadowColor = this.color;
ctx.shadowBlur = 5;
ctx.fill();
}
}
#space-time {
background-color: #1a1a1c;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Solar System AJ</title>
</head>
<body onload="init();">
<canvas id="space-time"></canvas>
</body>
</html>
I've looked at a few different posts on StackOverflow, but didn't really find the one that solved my issue. The code below works, but it's flickering constantly.
Essentially, I'm just creating a starry background where random stars will fade in and out
var canvas = document.querySelector("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var c = canvas.getContext("2d");
function Star(x, y, a, z, size, b) {
this.x = x;
this.y = y;
this.z = z;
this.a = a;
this.size = size;
this.b = b;
this.draw = function () {
c.fillStyle = "rgba(155, 241, 052, 1)";
c.beginPath();
c.arc(this.x, this.y, this.z, 0, Math.PI * 2, false);
c.fill();
};
this.update = function () {
if (this.z > this.size) {
this.a = 0;
}
if (this.z < 0) {
this.a = 1;
}
if (this.a == 1) {
this.z += this.b;
} else {
this.z -= this.b;
}
this.draw();
};
}
var starArray = [];
for (var i = 0; i < 100; i++) {
var size = Math.random() * 3 + 2; //size range
var x = Math.random() * innerWidth; //x coordinate
var y = Math.random() * innerHeight; //y coordinate
var z = Math.random() * size; //star size
var a = 1; //on-off switch for the star to fade in or fade out
var b = Math.random() / 20; //fade-in/fade-out rate (random for each star)
starArray.push(new Star(x, y, a, z, size, b));
}
function animate() {
requestAnimationFrame(animate);
c.clearRect(0, 0, innerWidth, innerHeight);
for (var i = 0; i < starArray.length; i++) {
starArray[i].update();
}
}
animate();
You are providing a negative radius to CanvasRenderingContext2D.arc(). You may need to rethink your logic or use Math.abs to make sure the radius provided is always non-negative.
c.arc(this.x, this.y, Math.abs(this.z), 0, Math.PI * 2, false);
var canvas = document.querySelector("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var c = canvas.getContext("2d");
function Star(x, y, a, z, size, b) {
this.x = x;
this.y = y;
this.z = z;
this.a = a;
this.size = size;
this.b = b;
this.draw = function () {
c.fillStyle = "rgba(155, 241, 052, 1)";
c.beginPath();
c.arc(this.x, this.y, Math.abs(this.z), 0, Math.PI * 2, false);
c.fill();
};
this.update = function () {
if (this.z > this.size) {
this.a = 0;
}
if (this.z < 0) {
this.a = 1;
}
if (this.a == 1) {
this.z += this.b;
} else {
this.z -= this.b;
}
this.draw();
};
}
var starArray = [];
for (var i = 0; i < 100; i++) {
var size = Math.random() * 3 + 2; //size range
var x = Math.random() * innerWidth; //x coordinate
var y = Math.random() * innerHeight; //y coordinate
var z = Math.random() * size; //star size
var a = 1; //on-off switch for the star to fade in or fade out
var b = Math.random() / 20; //fade-in/fade-out rate (random for each star)
starArray.push(new Star(x, y, a, z, size, b));
}
function animate() {
requestAnimationFrame(animate);
c.clearRect(0, 0, innerWidth, innerHeight);
for (var i = 0; i < starArray.length; i++) {
starArray[i].update();
}
}
animate();
<canvas></canvas>
You are getting negative radius on the arc call, just do:
c.arc(this.x, this.y, Math.max(this.z, 0), 0, Math.PI * 2, false);
I have the following canvas. I'm trying to make it smaller using the width and height attributes, but it doesn't work. This is my code:
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="canvas" width="200" height="50"></canvas>
<script>
//set the variables
var a = document.getElementById('canvas'),
c = a.getContext('2d'),
w = a.width = window.innerWidth,
h = a.height = window.innerHeight,
area = w * h,
particleNum = 300,
ANIMATION;
var particles = [];
//create the particles
function Particle(i) {
this.id = i;
this.hue = rand(50, 0, 1);
this.active = false;
}
Particle.prototype.build = function() {
this.x = w / 2;
this.y = h / 2;
this.r = rand(7, 2, 1);
this.vx = Math.random() * 10 - 5;
this.vy = Math.random() * 10 - 5;
this.gravity = .01;
this.opacity = Math.random() + .5;
this.active = true;
c.beginPath();
c.arc(this.x, this.y, this.r, 0, 2 * Math.PI, false);
c.fillStyle = "hsla(" + this.hue + ",100%,50%,1)";
c.fill();
};
Particle.prototype.draw = function() {
this.active = true;
this.x += this.vx;
this.y += this.vy;
this.vy += this.gravity;
this.hue -= 0.5;
this.r = Math.abs(this.r - .05);
c.beginPath();
c.arc(this.x, this.y, this.r, 0, 2 * Math.PI, false);
c.fillStyle = "hsla(" + this.hue + ",100%,50%,1)";
c.fill();
// reset particle
if(this.r <= .05) {
this.active = false;
}
};
//functionality
function drawScene() {
c.fillStyle = "black";
c.fillRect(0,0,w,h);
for(var i = 0; i < particles.length; i++) {
if(particles[i].active === true) {
particles[i].draw();
} else {
particles[i].build();
}
}
ANIMATION = requestAnimationFrame(drawScene);
}
function initCanvas() {
var s = getComputedStyle(a);
if(particles.length) {
particles = [];
cancelAnimationFrame(ANIMATION);
ANIMATION;
console.log(ANIMATION);
}
w = a.width = window.innerWidth;
h = a.height = window.innerHeight;
for(var i = 0; i < particleNum; i++) {
particles.push(new Particle(i));
}
drawScene();
console.log(ANIMATION);
}
//init
(function() {
initCanvas();
addEventListener('resize', initCanvas, false);
})();
//helper functions
function rand(max, min, _int) {
var max = (max === 0 || max)?max:1,
min = min || 0,
gen = min + (max - min) * Math.random();
return (_int) ? Math.round(gen) : gen;
};
</script>
</body>
</html>
Pay more attention here:
var a = document.getElementById('canvas'),
c = a.getContext('2d'),
w = a.width = window.innerWidth,
h = a.height = window.innerHeight,
area = w * h,
As you can see, w is the width of the window and h is the height of the window. Try to edit w and h variable with custom values and tell me if it worked ;)
EDIT:
Simply replace h and w with this in your script tag:
a.style.width = '500px'; //random value, insert custom here
a.style.height = '500px';
I have the following canvas animation for random 'rain' like gravity elements:
$(document).ready(function() {
var canvas = $('#canvas')[0];
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
if(canvas.getContext) {
var ctx = canvas.getContext('2d');
var w = canvas.width;
var h = canvas.height;
ctx.strokeStyle = "rgba("+Math.round(Math.random())*255+", "+Math.round(Math.random())*255+", "+Math.round(Math.random())*255+", 0.5)";
ctx.lineWidth = 1;
ctx.lineCap = 'round';
var init = [];
var maxParts = 1000;
for(var a = 0; a < maxParts; a++) {
init.push({
x: Math.random() * w,
y: Math.random() * h,
l: Math.random() * 1,
xs: -4 + Math.random() * 4 + 2,
ys: Math.random() * 10 + 10
})
}
var particles = [];
for(var b = 0; b < maxParts; b++) {
particles[b] = init[b];
}
function draw() {
ctx.clearRect(0, 0, w, h);
for(var c = 0; c < particles.length; c++) {
var p = particles[c];
ctx.beginPath();
ctx.moveTo(p.x, p.y);
ctx.lineTo(p.x + p.l * p.xs, p.y + p.l * p.ys);
ctx.stroke();
}
move();
}
function move() {
for(var b = 0; b < particles.length; b++) {
var p = particles[b];
p.x += p.xs;
p.y += p.ys;
if(p.x > w || p.y > h) {
p.x = Math.random() * w;
p.y = -20;
}
}
}
setInterval(draw, 30);
}
});
https://codepen.io/chriscamplin/pen/OXyeVP
How could I extend this to collect the elements in a funnel shape and narrow them down, almost like a hourglass timer.
I want to make the particles follow the mouse and I am not sure on how to do that.
I figured I can replace the x and y with the mouses position but I can figure that out either.
I would appreciate an almost exact answer and not examples please.
window.onload = function() {
var canvas = document.createElement("canvas"),
c = canvas.getContext("2d"),
particles = {}
particleIndex = 0,
particleNum = Math.random() * 2;
canvas.width = 400;
canvas.height = 400;
document.body.appendChild(canvas);
c.fillStyle = "black";
c.fillRect(0, 0, canvas.width, canvas.height);
function Particle() {
this.x = canvas.width / 10;
this.y = canvas.height / 2;
this.vx = Math.random() * 10 - 5;
this.vy = Math.random() * 10 - 5;
this.gravity = .2;
particleIndex++;
particles[particleIndex] = this;
this.id = particleIndex;
this.life = 0;
this.maxLife = Math.random() * 30 + 10;
this.color = "rgb(" + parseInt(Math.random() * 255, 10) + ",0,0)";
this.color2 = "hsl(" + parseInt(Math.random() * 255, 10) + ",50%,50%)";
}
Particle.prototype.draw = function() {
this.x += this.vx;
this.y += this.vy;
if (Math.random() < 0.1) {
this.vx = Math.random() * 10 - 5;
this.vy = Math.random() * 10 - 5;
}
this.vy += this.gravity;
this.life++;
if (this.Life >= this.maxLife) {
delete particles[this.id];
}
c.fillStyle = this.color2;
c.fillRect(this.x, this.y, 10, 10);
};
//var p = new Particle();
setInterval(function() {
c.fillStyle = "rgba(0,0,0,0.5)";
c.fillRect(0, 0, canvas.width, canvas.height);
for (var i in particles) {
particles[i].draw();
}
for (var i = 0; i < particleNum; i++) {
new Particle();
}
}, 30);
};