Resize canvas size as window is being resized (JavaScript) - javascript

What I want to do
I want to keep the canvas size full to the window.
What the problem is
I set the canvas size as stated below.
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
It worked.
But when I resized the window, the canvas size didn't change but instead kept its initial size.
What should I do to keep the canvas size full to the window without changing the balls' size?
Here is my code
const canvas = document.querySelector('#sandBox');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const ctx = canvas.getContext('2d');
class Circle {
constructor(x, y, r, c) {
this.x = x;
this.y = y;
this.r = r;
this.c = c;
}
draw() {
ctx.beginPath();
ctx.fillStyle = this.c;
ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2);
ctx.fill();
ctx.closePath();
}
}
const balls = [];
for (let i = 0; i < 20; i++) {
let r = Math.floor(Math.random() * 30) + 15;
let x = Math.random() * (canvas.width - r * 2) + r;
let y = Math.random() * (canvas.height - r * 2) + r;
let c = 'rgba(255,255,255,0.2)';
balls.push(new Circle(x, y, r, c));
}
balls.forEach(ball => ball.draw());
body {
position: relative;
}
canvas {
/* width: 100vw;
height: 100vh; */
background-color: #393939;
position: absolute;
top: 0;
left: 0;
z-index: -1;
}
<canvas id="sandBox"></canvas>

You can have a callback onresize and use that to recreate the canvas:
Each time you resize the window you'll have to redraw the canvas, unless you save it somewhere.
function init() {
const canvas = document.querySelector("#sandBox");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const ctx = canvas.getContext("2d");
class Circle {
constructor(x, y, r, c) {
this.x = x;
this.y = y;
this.r = r;
this.c = c;
}
draw() {
ctx.beginPath();
ctx.fillStyle = this.c;
ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2);
ctx.fill();
ctx.closePath();
}
}
const balls = [];
for (let i = 0; i < 20; i++) {
let r = Math.floor(Math.random() * 30) + 15;
let x = Math.random() * (canvas.width - r * 2) + r;
let y = Math.random() * (canvas.height - r * 2) + r;
let c = "rgba(255,255,255,0.2)";
balls.push(new Circle(x, y, r, c));
}
balls.forEach((ball) => ball.draw());
}
window.onload = function() {
init();
};
body {
position: relative;
}
canvas {
width: 100vw;
height: 100vh;
background-color: #393939;
position: absolute;
top: 0;
left: 0;
z-index: -1;
}
<body onresize="init()">
<canvas id="sandBox"></canvas>
</body>

Related

Pixels between rects instead of drawn lines in HTML5 Canvas

Basically I want background to be seen between rects. Right now I'm trying to leave a distance which is dependable on rect size between them, can I make that size to be exact number of pixels?
Because right now these empty spaces merge, sometimes are not seen at all, etc.
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
var canvas = document.getElementById("posHourCanvas");
var context = canvas.getContext('2d');
var boxes = [];
function init() {
context.clearRect(0, 0, canvas.width, canvas.height);
boxes.length = 0;
const strokeWidth = 0.2;
canvas.width = $('#two')[0].clientWidth;
var cellSize = canvas.width / 27;
canvas.height = 7 / 27 * canvas.width;
var x = y = 0;
draw(x, y, canvas.width, canvas.height, cellSize, strokeWidth);
}
function Box(x, y, day, hour) {
this.x = x;
this.y = y;
this.day = day;
this.hour = hour;
}
function draw(x, y, w, h, cellSize, strokeWidth) {
let onePixel = cellSize * strokeWidth;
cellSize = cellSize * (1 - strokeWidth);
context.beginPath();
context.lineWidth = 0.01;
context.strokeStyle = 'rgba(255, 255, 255, 0)';
for (let i = 0; i < 7; i++) {
context.beginPath();
dayRect(context, cellSize, i, onePixel);
let startX = 3 * cellSize + onePixel;
for (let j = 0; j < 25; j++) {
context.rect(startX, i * cellSize + i * onePixel, cellSize, cellSize);
context.fillStyle = "white";
context.fill();
startX += cellSize + onePixel;
}
}
}
function dayRect(context, cellSize, day, onePixel) {
var offSet = day * onePixel;
context.rect(0, day * cellSize + offSet, 3 * cellSize, cellSize);
context.fillStyle = "white";
context.fill();
}
init();
window.addEventListener("resize", init, false);
body {
margin: auto;
color: white;
background-color: black;
}
div#two {
margin-left: 5%;
width: 10%;
height: 30%;
}
<script src="https://code.jquery.com/jquery-3.3.1.js" integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60=" crossorigin="anonymous"></script>
<div id="parent">
<div>text above</div>
<div id="two">
<canvas id="posHourCanvas" width="600" height="300"></canvas>
</div>
<div>text under</div>
</div>
JSFIDDLE: http://jsfiddle.net/kgbh9352/

How to resize Canvas Width on Viewport

I have a canvas demo that spawns some circles. I can't seem to figure out how to have it be responsive in setting either canvas.width or canvas.style.width (what's the difference here?) on a windows resize using window.innerWidth.
Code works fine but it rerenders strangely on smaller viewports. I tried adding this snippet of code at the bottom of my javascript file, but it broke animation.
// ADDING THESE LINES PREVENTS ANIMATION FROM RUNNING
if (window.innerWidth < 1000) {
canvas.width = window.innerWidth;
} else {
canvas.width = 1000;
}
var canvas = document.querySelector("canvas");
canvas.width = 1000;
canvas.height = 100;
var c = canvas.getContext("2d");
// Constructor Function (object blueprint)
function Circle(x, y, dx, dy, radius, counter) {
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
this.radius = radius;
this.counter = counter;
this.draw = function() {
c.beginPath();
c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
c.strokeStyle = "white";
c.stroke();
c.fillStyle = "white";
c.fill();
};
this.update = function() {
if (this.y + this.radius > canvas.height) {
this.y = 0;
}
this.x += this.dx;
this.y += this.dy;
this.draw();
};
}
// Initialize array to store snow objects
var circleArray = [];
// Initialize objects with constructor
for (var i = 0; i < 50; i++) {
var radius = 1 + Math.random() * 5;
var x = Math.random() * canvas.width;
var y = 0 - Math.random() * 50; // start at top, render some circles off screen
var dx = (Math.random() - 0.5) * 2;
var dy = 0.5 + Math.random() * 0.5; // use gravity
circleArray.push(new Circle(x, y, dx, dy, radius, 0));
}
function animate() {
requestAnimationFrame(animate); // recurisvely run
c.clearRect(0, 0, innerWidth, innerHeight); // erases previously drawn content
for (var i = 0; i < circleArray.length; i++) {
circleArray[i].update();
}
// ADDING THESE LINES PREVENTS ANIMATION FROM RUNNING
//if (window.innerWidth < 1000) {
// canvas.width = window.innerWidth;
// } else {
// canvas.width = 1000;
// }
}
animate();
body {
background-color: grey;
display: flex;
justify-content: center;
}
.wrapper {
position: relative;
width: 1000px;
height: 110px;
min-height: 110px;
margin-top: 50vh;
}
.wrapper > * {
width: 1000px;
position: absolute;
}
canvas {
position: absolute;
}
img {
width: 100%;
height: 110px;
}
<div class="wrapper">
<img class="stars" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/867725/stars.png
" alt="" />
<img class="tress" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/867725/trees.png
" alt="" />
<img class="clouds" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/867725/clouds.png" alt="" />
<canvas></canvas>
</div>
The difference between canvas.width and canvas.style.width is that canvas.width specifies the actual size of the canvas in pixels, while canvas.style.width stretches or compresses the canvas to the width you specify. This will set the canvas width to 300px:
canvas.width = 300;
This will also set the canvas width to 300px, but will stretch it until it reaches 600px:
canvas.width = 300;
canvas.style.width = "600px";
Using canvas.width is better practice.
For the animation to run you must first fix the canvas width. Putting the code that resizes the canvas at the beginning of the animate() function solves the problem:
var canvas = document.querySelector("canvas");
canvas.width = 1000;
canvas.height = 100;
var c = canvas.getContext("2d");
// Constructor Function (object blueprint)
function Circle(x, y, dx, dy, radius, counter) {
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
this.radius = radius;
this.counter = counter;
this.draw = function() {
c.beginPath();
c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
c.strokeStyle = "white";
c.stroke();
c.fillStyle = "white";
c.fill();
};
this.update = function() {
if (this.y + this.radius > canvas.height) {
this.y = 0;
}
this.x += this.dx;
this.y += this.dy;
this.draw();
};
}
// Initialize array to store snow objects
var circleArray = [];
// Initialize objects with constructor
for (var i = 0; i < 50; i++) {
var radius = 1 + Math.random() * 5;
var x = Math.random() * canvas.width;
var y = 0 - Math.random() * 50; // start at top, render some circles off screen
var dx = (Math.random() - 0.5) * 2;
var dy = 0.5 + Math.random() * 0.5; // use gravity
circleArray.push(new Circle(x, y, dx, dy, radius, 0));
}
function animate() {
if (window.innerWidth < 1000) {
canvas.width = window.innerWidth;
} else {
canvas.width = 1000;
}
requestAnimationFrame(animate); // recurisvely run
c.clearRect(0, 0, innerWidth, innerHeight); // erases previously drawn content
for (var i = 0; i < circleArray.length; i++) {
circleArray[i].update();
}
}
animate();
body {
background-color: grey;
display: flex;
justify-content: center;
}
.wrapper {
position: relative;
width: 1000px;
height: 110px;
min-height: 110px;
margin-top: 50vh;
}
.wrapper>* {
width: 1000px;
position: absolute;
}
canvas {
position: absolute;
}
img {
width: 100%;
height: 110px;
}
<div class="wrapper">
<img class="stars" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/867725/stars.png
" alt="" />
<img class="tress" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/867725/trees.png
" alt="" />
<img class="clouds" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/867725/clouds.png" alt="" />
<canvas></canvas>
</div>

Canvas spark lines

I would like to create a spark lines with the various lengths and animate them by moving them from center to end of the canvas and the process has to loop on a canvas. To achieve this i started with a particle system.
Please check the below code and here is the codepen link https://codepen.io/yesvin/pen/XPKNYW
window.onload = function() {
var canvas = document.getElementById("canvas"),
context = canvas.getContext("2d"),
w = canvas.width = window.innerWidth,
h = canvas.height = window.innerHeight,
centerX = w / 2,
centerY = h / 2,
speed = 0,
time = 0,
numObjects = 5,
x, y, vx, vy, life, maxLife;
var lines = {},
lineIndex = 0;
function Line() {
this.x = centerX;
this.y = centerY;
this.vx = Math.random() * 16 - 8;
this.vy = Math.random() * 16 - 8;
this.life = 0;
this.maxLife = Math.random() * 10 + 20;
lineIndex++;
lines[lineIndex] = this;
this.id = lineIndex;
}
Line.prototype.draw = function() {
this.x += this.vx;
this.y += this.vy;
this.life++;
if (this.life >= this.maxLife) {
delete lines[this.id];
}
context.fillStyle = "#000";
context.fillRect(this.x, this.y, 3, 3)
}
setInterval(function() {
context.fillStyle = 'rgba(255,255,255,.05)';
context.fillRect(0, 0, w, h);
new Line();
for (var i in lines) {
lines[i].draw();
}
}, 30)
};
body {
overflow: hidden;
margin: 0;
padding: 0;
}
canvas {
display: block;
}
<canvas id="canvas"></canvas>
So, How do we create this same effect using the lineTo(), and moveTo() methods? I tried with the following code (which is commented in a codepen)
context.beginPath();
context.moveTo(centerX, centerY);
context.lineTo(this.x * Math.random() * w, this.y * Math.random() * h);
context.lineWidth = 1;
context.stroke();
context.strokeStyle = "#000";
Sample GIF
Thanks in advance.
Here is one approach...
With lines you will get a more continuous effect:
The change I'm making to your code is to keep track of the start and end points.
window.onload = function() {
var canvas = document.getElementById("canvas"),
context = canvas.getContext("2d"),
w = canvas.width = window.innerWidth,
h = canvas.height = window.innerHeight,
centerX = w / 2,
centerY = h / 2;
var lines = {},
lineIndex = 0;
function Line() {
this.start = { x: centerX, y: centerY };
this.end = { x: centerX, y: centerY };
this.vx = Math.random() * 16 - 8;
this.vy = Math.random() * 16 - 8;
this.life = 0;
this.maxLife = Math.random() * 10 + 20;
lineIndex++;
lines[lineIndex] = this;
this.id = lineIndex;
}
Line.prototype.draw = function() {
this.end.x += this.vx;
this.end.y += this.vy;
this.life++;
if (this.life >= this.maxLife) {
delete lines[this.id];
}
//context.fillStyle = "#000";
//context.fillRect(this.x, this.y, 1, 1)
context.beginPath();
context.moveTo(this.start.x, this.start.y);
context.lineTo(this.end.x, this.end.y);
context.lineWidth = 1;
context.stroke();
context.strokeStyle = "#000";
}
setInterval(function() {
context.fillStyle = 'rgba(255,255,255,.05)';
context.fillRect(0, 0, w, h);
new Line();
for (var i in lines) {
lines[i].draw();
}
}, 30)
};
body {
overflow: hidden;
margin: 0;
padding: 0;
}
canvas {
display: block;
}
<canvas id="canvas"></canvas>

Remove objects in the canvas in certain coordinates

I would like to remove the balls already generated in the canvas on the click and decrease the counter on the bottom, but my function does not work. Here is my code concerning the part of the ball removal.
Is it possible to use a div to get the same result and to facilitate the removal of the balls? thank you
ball.onclick = function removeBalls(event) {
var x = event.clientX;
var y = event.clientY;
ctx.clearRect(x, y, 100, 50);
ctx.fillStyle = "#000000";
ctx.font = "20px Arial";
ctx.fillText("Balls Counter: " + balls.length - 1, 10, canvas.height - 10);
}
below I enclose my complete code
// GLOBAL VARIBLES
var gravity = 4;
var forceFactor = 0.3; //0.3 0.5
var mouseDown = false;
var balls = []; //hold all the balls
var mousePos = []; //hold the positions of the mouse
var ctx = canvas.getContext('2d');
var heightBrw = canvas.height = window.innerHeight;
var widthBrw = canvas.width = window.innerWidth;
var bounciness = 1; //0.9
window.onload = function gameCore() {
function onMouseDown(event) {
mouseDown = true;
mousePos["downX"] = event.pageX;
mousePos["downY"] = event.pageY;
}
canvas.onclick = function onMouseUp(event) {
mouseDown = false;
balls.push(new ball(mousePos["downX"], mousePos["downY"], (event.pageX - mousePos["downX"]) * forceFactor,
(event.pageY - mousePos["downY"]) * forceFactor, 5 + (Math.random() * 10), bounciness, random_color()));
ball
}
function onMouseMove(event) {
mousePos['currentX'] = event.pageX;
mousePos['currentY'] = event.pageY;
}
function resizeWindow(event) {
canvas.height = window.innerHeight;
canvas.width = window.innerWidth;
}
function reduceBounciness(event) {
if (bounciness == 1) {
for (var i = 0; i < balls.length; i++) {
balls[i].b = bounciness = 0.9;
document.getElementById("btn-bounciness").value = "⤽ Bounciness";
}
} else {
for (var i = 0; i < balls.length; i++) {
balls[i].b = bounciness = 1;
document.getElementById("btn-bounciness").value = " ⤼ Bounciness";
}
}
return bounciness;
}
function reduceSpeed(event) {
for (var i = 0; i < balls.length; i++) {
balls[i].vx = velocityX = 20 + c;
balls[i].vy = velocityY = 20 + c;
}
}
function speedUp(event) {
for (var i = 0; i < balls.length; i++) {
balls[i].vx = velocityX = 120 + c;
balls[i].vy = velocityY = 120 + c;
}
}
function stopGravity(event) {
if (gravity == 4) {
for (var i = 0; i < balls.length; i++) {
balls[i].g = gravity = 0;
balls[i].vx = velocityX = 0;
balls[i].vy = velocityY = 0;
document.getElementById("btn-gravity").value = "►";
}
} else {
for (var i = 0; i < balls.length; i++) {
balls[i].g = gravity = 4;
balls[i].vx = velocityX = 100;
balls[i].vy = velocityY = 100;
document.getElementById("btn-gravity").value = "◾";
}
}
}
ball.onclick = function removeBalls(event) {
var x = event.clientX;
var y = event.clientY;
ctx.clearRect(x, y, 100, 50);
ctx.fillStyle = "#000000";
ctx.font = "20px Arial";
ctx.fillText("Balls Counter: " + balls.length - 1, 10, canvas.height - 10);
}
document.getElementById("btn-gravity").addEventListener("click", stopGravity);
document.getElementById("btn-speed-up").addEventListener("click", speedUp);
document.getElementById("btn-speed-down").addEventListener("click", reduceSpeed);
document.getElementById("btn-bounciness").addEventListener("click", reduceBounciness);
document.addEventListener("mousedown", onMouseDown);
document.addEventListener("mousemove", onMouseMove);
window.addEventListener('resize', resizeWindow);
}
// GRAPHICS CODE
function circle(x, y, r, c) { // x position, y position, r radius, c color
//draw a circle
ctx.beginPath(); //approfondire
ctx.arc(x, y, r, 0, Math.PI * 2, true);
ctx.closePath();
//fill
ctx.fillStyle = c;
ctx.fill();
//stroke
ctx.lineWidth = r * 0.1; //border of the ball radius * 0.1
ctx.strokeStyle = "#000000"; //color of the border
ctx.stroke();
}
function random_color() {
var letter = "0123456789ABCDEF".split(""); //exadecimal value for the colors
var color = "#"; //all the exadecimal colors starts with #
for (var i = 0; i < 6; i++) {
color = color + letter[Math.round(Math.random() * 15)];
}
return color;
}
function selectDirection(fromx, fromy, tox, toy) {
ctx.beginPath();
ctx.moveTo(fromx, fromy);
ctx.lineTo(tox, toy);
ctx.moveTo(tox, toy);
}
//per velocità invariata rimuovere bounciness
function draw_ball() {
this.vy = this.vy + gravity * 0.1; // v = a * t
this.x = this.x + this.vx * 0.1; // s = v * t
this.y = this.y + this.vy * 0.1;
if (this.x + this.r > canvas.width) {
this.x = canvas.width - this.r;
this.vx = this.vx * -1 * this.b;
}
if (this.x - this.r < 0) {
this.x = this.r;
this.vx = this.vx * -1 * this.b;
}
if (this.y + this.r > canvas.height) {
this.y = canvas.height - this.r;
this.vy = this.vy * -1 * this.b;
}
if (this.y - this.r < 0) {
this.y = this.r;
this.vy = this.vy * 1 * this.b;
}
circle(this.x, this.y, this.r, this.c);
}
// OBJECTS
function ball(positionX, positionY, velosityX, velosityY, radius, bounciness, color, gravity) {
this.x = positionX;
this.y = positionY;
this.vx = velosityX;
this.vy = velosityY;
this.r = radius;
this.b = bounciness;
this.c = color;
this.g = gravity;
this.draw = draw_ball;
}
// GAME LOOP
function game_loop() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (mouseDown == true) {
selectDirection(mousePos['downX'], mousePos['downY'], mousePos['currentX'], mousePos['currentY']);
}
for (var i = 0; i < balls.length; i++) {
balls[i].draw();
}
ctx.fillStyle = "#000000";
ctx.font = "20px Arial";
ctx.fillText("Balls Counter: " + balls.length, 10, canvas.height - 10);
}
setInterval(game_loop, 10);
* {
margin: 0px; padding: 0px;
}
html, body {
width: 100%; height: 100%;
}
#canvas {
display: block;
height: 95%;
border: 2px solid black;
width: 98%;
margin-left: 1%;
}
#btn-speed-up, #btn-speed-down, #btn-bounciness, #btn-gravity{
padding: 0.4%;
background-color: beige;
text-align: center;
font-size: 20px;
font-weight: 700;
float: right;
margin-right: 1%;
margin-top:0.5%;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Power Balls</title>
<link rel="stylesheet" type="text/css" href="css/style.css">
</head>
<body>
<canvas id="canvas"></canvas>
<input type="button" value="⤼ Bounciness" id="btn-bounciness"></input>
<input type="button" onclick="c+=10" value="+ Speed" id="btn-speed-up"></input>
<input type="button" value="◾" id="btn-gravity"></input>
<input type="button" onclick="c+= -10" value=" - Speed" id="btn-speed-down"></input>
<script src="js/main.js"></script>
</body>
</html>
I see two problems:
ball.onclick will not get triggered, as ball it is not a DOM object. Instead, you need to work with canvas.onclick. Check whether the user clicked on a ball or on empty space to decide whether to delete or create a ball.
To delete the ball, ctx.clearRect is not sufficient. This will clear the ball from the currently drawn frame, but the object still remains in the array balls and will therefore be drawn again in the next frame via balls[i].draw();. Instead, you need to remove the clicked ball entirely from the array, e. g. by using splice.
Otherwise, nice demo! :)
This cannot be done because the canvas is an immediate mode API. All you can do is draw over the top but this is not reliable.
https://en.wikipedia.org/wiki/Immediate_mode_(computer_graphics)
You will have to store each item in a separate data structure, then re-draw whenever a change occurs. In your case there is an array of balls, so you should remove the one that was clicked, before redrawing the entire array.
Each time you remove something, clear the canvas then re-draw each ball.
There are optimisations you can make if this is too slow.

How to stop canvas jumping animation

I have a canvas animation which you can see here.
I've noticed that once you have watched the animation after a while (approximately 25 seconds) the animation starts to jump around. I'm struggling to figure out how to make it so that it is one constant fluid motion?
Code below:
<canvas id="canvas"></canvas>
var canvas = document.querySelector("#canvas");
var ctx = canvas.getContext("2d");
canvas.width = parseInt(getComputedStyle(canvas).width);
canvas.height = parseInt(getComputedStyle(canvas).height);
var P = 4;
var A = 4;
function draw(shift) {
var w = canvas.width;
var h = canvas.height;
shift = shift >= 500*Math.PI ? shift - 100*Math.PI : shift;
ctx.clearRect(0, 0, w, h);
var grd = ctx.createLinearGradient(0, 0, w, h);
grd.addColorStop(0, "#4a8bf5");
grd.addColorStop(1, "#f16b55");
ctx.strokeStyle = grd;
ctx.lineCap = "round";
for (var i = 0; i < w; ) {
var _A = Math.abs(A*Math.cos(2*i));
ctx.beginPath();
var pos = Math.exp(-_A * i / w) * Math.sin(P * Math.PI * (i + shift) / w);
pos *= h / 2;
var lw = Math.exp(-_A * i / w) * Math.sin(3 * Math.PI * (i - shift) / w) * 2;
ctx.lineWidth = (lw)+1;
ctx.lineTo(i, h / 2 - pos);
ctx.closePath();
ctx.stroke();
i += 1;
}
window.requestAnimationFrame(function(){
draw(shift + 1);
});
}
draw(0);
The solution is to make sure that the change in shift results in the sin() argument changing by a multiple of 2π.
Given
Math.sin((i + shift) / (w / P))
this can be done using something like
if (shift > 500) shift -= 2 * Math.PI * (w / P);
There will still be a jump in the 2nd sin() argument here, the line width. To avoid this, shift has to be reduced by a number that causes both arguments to change by multiples of 2π, the LCM if you will.
var canvas = document.querySelector("#canvas");
var ctx = canvas.getContext("2d");
canvas.width = parseInt(getComputedStyle(canvas).width);
canvas.height = parseInt(getComputedStyle(canvas).height);
var P = 10;
var A = 4;
var shift = 0;
function draw() {
var w = canvas.width;
var h = canvas.height;
shift += 1;
if (shift > 500) shift -= 2 * Math.PI * (w / P);
shift_el.innerHTML = shift;
ctx.clearRect(0, 0, w, h);
var grd = ctx.createLinearGradient(0, 0, w, h);
grd.addColorStop(0, "#4a8bf5");
grd.addColorStop(1, "#f16b55");
ctx.strokeStyle = grd;
ctx.lineCap = "round";
for (var i = 0; i < w;) {
var _A = Math.abs(A * Math.cos(2 * i));
ctx.beginPath();
var pos = Math.exp(-_A * i / w) * Math.sin((i + shift) / (w / P));
pos *= h / 2;
var lw = Math.exp(-_A * i / w) * Math.sin(3 * Math.PI * (i - shift) / w) * 2;
ctx.lineWidth = (lw) + 1;
ctx.lineTo(i, h / 2 - pos);
ctx.closePath();
ctx.stroke();
i += 1;
}
window.requestAnimationFrame(draw);
}
draw();
body {
background: #ffffff;
padding: 0;
margin: 0;
}
canvas {
height: 200px;
width: 100%;
}
#shift_el {
position: absolute;
top: 0
}
<canvas id="canvas"></canvas>
<div id="shift_el"></div>

Categories