Skip to content

Instantly share code, notes, and snippets.

@shamansir
Last active August 31, 2017 17:09
Show Gist options
  • Save shamansir/cd7f4b42377e18c74415fda65845c03c to your computer and use it in GitHub Desktop.
Save shamansir/cd7f4b42377e18c74415fda65845c03c to your computer and use it in GitHub Desktop.
A Star Warp with Canvas
<canvas width="1400" height="1000">
</canvas>
<button>Restart</button>
const WIDTH = 1400;
const HEIGHT = 1000;
const STARS_COUNT = 100;
const STAR_MAX_RADIUS = 5;
const START_AT = 500; // in ms
const ANIMATION_DURATION = 2000; // in ms
const FADE_DURATION = 4000; // in ms
const TRAVEL_LENGTH = 200; // in px
const cvs = document.getElementsByTagName('canvas')[0];
const ctx = cvs.getContext('2d');
const pxRatio = window.devicePixelRatio || 1;
//ctx.scale(pxRatio, pxRatio);
const vectorLength = (x1, y1, x2, y2) => Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
const createStars = () =>
Array.from(
new Array(STARS_COUNT),
() => {
const x = Math.random() * WIDTH,
y = Math.random() * HEIGHT,
radius = Math.random() * STAR_MAX_RADIUS,
circRadius = vectorLength(x, y, WIDTH / 2, HEIGHT / 2),
angle = Math.atan2(y - HEIGHT / 2, x - WIDTH / 2);
return { x, y, radius, circRadius, angle };
}
);
let stars = createStars();
let startTime = new Date().getTime();
let lastTime = startTime, dt;
let animationPos;
const restartButton = document.getElementsByTagName('button')[0];
restartButton.addEventListener('click', () => {
stars = createStars();
startTime = new Date().getTime();
lastTime = startTime;
});
const animate = () => {
dt = new Date().getTime() - lastTime;
lastTime += dt;
animationPos = (lastTime - startTime - START_AT) / ANIMATION_DURATION;
ctx.fillStyle = 'midnightblue';
ctx.fillRect(0, 0, WIDTH, HEIGHT);
for (const star of stars) {
if (animationPos < 0) {
ctx.fillStyle = 'white';
ctx.beginPath();
ctx.arc(star.x, star.y, star.radius, 0, 2 * Math.PI, false);
ctx.fill();
// ctx.lineWidth = 1;
// ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)';
// ctx.beginPath();
// ctx.arc(WIDTH / 2, HEIGHT / 2, star.circRadius, 0, 2 * Math.PI, false);
// ctx.stroke();
}
if ((animationPos >= 0) && (animationPos <= 1)) {
const nextCircRadius = star.circRadius + (animationPos * TRAVEL_LENGTH);
const newX = WIDTH / 2 + nextCircRadius * Math.cos(star.angle);
const newY = HEIGHT / 2 + nextCircRadius * Math.sin(star.angle);
ctx.strokeStyle = 'white';
ctx.fillStyle = 'white';
ctx.lineWidth = star.radius * 1.5;
ctx.beginPath();
ctx.moveTo(star.x, star.y);
ctx.lineTo(newX, newY);
ctx.closePath();
ctx.stroke();
ctx.arc(newX, newY, star.radius, 0, 2 * Math.PI, false);
ctx.fill();
// ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)';
// ctx.beginPath();
// ctx.arc(WIDTH / 2, HEIGHT / 2, star.circRadius + (animationPos * TRAVEL_LENGTH), 0, 2 * Math.PI, false);
// ctx.stroke();
}
if ((animationPos > 1)/* && ((animationPos - 1.0) * ANIMATION_DURATION <= FADE_DURATION)*/) {
const opacity = (animationPos - 1.0) * ANIMATION_DURATION / FADE_DURATION;
if (opacity <= 1) {
ctx.fillStyle = 'rgba(255, 255, 255, ' + (opacity < 1 ? 1.0 - opacity : 0) + ')';
const nextCircRadius = star.circRadius + (animationPos * TRAVEL_LENGTH);
const newX = WIDTH / 2 + nextCircRadius * Math.cos(star.angle);
const newY = HEIGHT / 2 + nextCircRadius * Math.sin(star.angle);
ctx.beginPath();
ctx.arc(newX, newY, star.radius, 0, 2 * Math.PI, false);
ctx.fill();
}
ctx.fillStyle = 'rgba(255, 255, 255, ' + (opacity < 1 ? opacity : 1) + ')';
ctx.beginPath();
ctx.arc(star.x, star.y, star.radius, 0, 2 * Math.PI, false);
ctx.fill();
}
};
requestAnimationFrame(animate);
};
requestAnimationFrame(animate);
canvas {
width: 700px;
height: 500px;
}
button {
position: absolute;
top: 10px;
left: 720px;
font-size: 20px;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment