How to make background animation wave with JavaScript? - javascript

I want to make a background animation wave like this website hero section. https://raze.network/
Could anyone help me to make this animation background wave?
Thank you :)

There is a great example on codepen that you can use to get a general idea on how to animate this wave using JavaScript. The author allows commenting on CodePen so I would get in touch with him.
let noise = new SimplexNoise();
function draw(e) {
let xCount = 35;
let yCount = 80;
let iXCount = 1 / (xCount - 1);
let iYCount = 1 / (yCount - 1);
let time = e * 0.001;
let timeStep = 0.01;
let grad = ctx.createLinearGradient(-width, 0, width, height);
let t = time % 1;
let tSide = floor(time % 2) === 0;
let hueA = tSide ? 340 : 210;
let hueB = !tSide ? 340 : 210;
let colorA = hsl(hueA, 100, 50);
let colorB = hsl(hueB, 100, 50);
grad.addColorStop(map(t, 0, 1, THIRD, ZERO), colorA);
grad.addColorStop(map(t, 0, 1, TWO_THIRDS, THIRD), colorB);
grad.addColorStop(map(t, 0, 1, ONE, TWO_THIRDS), colorA);
ctx.globalAlpha = map(cos(time), -1, 1, 0.15, 0.3);
background(grad);
ctx.globalAlpha = 1;
beginPath();
for(let j = 0; j < yCount; j++) {
let tj = j * iYCount;
let c = cos(tj * TAU + time) * 0.1;
for(let i = 0; i < xCount; i++) {
let t = i * iXCount;
let n = noise.noise3D(t, time, c);
let y = n * height_half;
let x = t * (width + 20) - width_half - 10;
(i ? lineTo : moveTo)(x, y);
}
time += timeStep;
}
compositeOperation(compOper.lighter);
ctx.filter = 'blur(10px)';
stroke(grad, 5);
ctx.filter = 'blur(5px)';
stroke(hsl(0, 0, 100, 0.8), 2);
}
https://codepen.io/Alca/pen/gzxXLq

Related

P5.js curveVertex function is closing at a point

I've created a noise function that pairs with a circle function to create a random noise circle thing that looks pretty cool. My problem is the curveVertex function in P5.js works correctly except for the connection of the first and last vertex. My code is:
let start = Array(50).fill(0); // dont change
let amount = 1; // amount of shapes
let gap = 30; // between shapes
let amplify = 50; // 0 -->
let colorSpeed = 1; // 1 - 9
let colorSeparation = 3; // 0 - 80 recomended 0 - 10
function setup() {
createCanvas(windowWidth, windowHeight);
for(let i = 0 ; i < start.length; i++){
start[i] = random(i);
}
}
function draw() {
background(0);
for(let dnc = (amount + 1) * gap; dnc > gap; dnc -= gap){
drawNoiseCircle(dnc, getNoise(start.length));
}
start = start.map( c => c + 0.01 );
}
function getNoise(amount){
let lengths = [];
for(let i = 1; i < amount + 1; i++){
let n1 = noise(start[i - 1]);
let noise1 = map(n1, 0, 1, -amplify, amplify);
lengths.push(abs(-noise1));
}
return lengths;
}
function drawNoiseCircle(radius, lengths){
colorMode(HSB);
fill(((frameCount + radius) * colorSeparation)/-map(colorSpeed, 1, 10, -10, -1) % 360, 100, 50);
noStroke()
let x;
let y;
beginShape();
for(let l = 0; l < lengths.length; l++){
x = Math.cos(radians(l * 360 / lengths.length)) * (radius + lengths[l]) + width/2;
y = Math.sin(radians(l * 360 / lengths.length)) * (radius + lengths[l]) + height/2;
curveVertex(x, y);
}
endShape(CLOSE);
stroke("black");
line(width/2, height/2, width, height/2);
line(width/2, height/2 + 9, width, height/2 + 9);
}
<script src="https://cdn.jsdelivr.net/npm/p5#1.4.1/lib/p5.js"></script>
I understand the endShape(CLOSED) closes the shape with a straight line, but I'm not sure any other way to close the shape.
You can see the pointed edge on the right side, directly in the middle of the shape.
!EDIT!
I've added lines to the shape to show the line segment that isn't affected by the curve vertex. Also, I understand it may not be a very significant problem, but if the amount of vertexes shrink, it becomes a much bigger problem (eg. a square or a triangle).
Unfortunately I won't have time to dive deep and debug the actual issue with curveVertex (or it's math) at the time, but it seems there's something interesting with curveVertex() in particular.
#Ouoborus point makes sense and the function "should" behave that way (and it was with vertex(), but not curveVertex()). For some reason curveVertex() requires looping over the not just the first point again, but the second and third.
Here's basic example:
function setup() {
createCanvas(300, 300);
background(220);
let numPoints = 6;
let angleIncrement = TWO_PI / numPoints;
let radius = 120;
beginShape();
for(let i = 0 ; i < numPoints + 3; i++){
let angle = angleIncrement * i;
let x = 150 + cos(angle) * radius;
let y = 150 + sin(angle) * radius;
curveVertex(x, y);
}
endShape();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.min.js"></script>
Try decreasing numPoints + 3 to numPoints + 2 or notice the behaviour you're describing.
(I could speculate it might have something to do with how curveVertex() (Catmull-Rom splines) are implemented in p5 and how many coordinates/points it requires, but this isn't accurate without reading the source code and debugging a bit)
Here's a version of your code using the above notes:
let start = Array(30).fill(0);
let colorSpeed = 1; // 1 - 9
let colorSeparation = 3; // 0 - 80 recomended 0 - 10
function setup() {
createCanvas(600, 600);
colorMode(HSB);
noStroke();
// init noise seeds
for(let i = 0 ; i < start.length; i++){
start[i] = random(i);
}
}
function getNoise(seeds, amplify = 50){
let amount = seeds.length;
let lengths = [];
for(let i = 1; i < amount + 1; i++){
let n1 = noise(seeds[i - 1]);
let noise1 = map(n1, 0, 1, -amplify, amplify);
lengths.push(abs(-noise1));
}
return lengths;
}
function drawNoiseCircle(radius, lengths){
let sides = lengths.length;
let ai = TWO_PI / sides;
let cx = width * 0.5;
let cy = height * 0.5;
fill(((frameCount + radius) * colorSeparation)/-map(colorSpeed, 1, 10, -10, -1) % 360, 100, 50);
beginShape();
for(let i = 0 ; i < sides + 3; i++){
let noiseRadius = radius + lengths[i % sides];
let a = ai * i;
let x = cx + cos(a) * noiseRadius;
let y = cy + sin(a) * noiseRadius;
curveVertex(x, y);
}
endShape();
}
function draw() {
background(0);
// draw with updated perlin noise values
drawNoiseCircle(120, getNoise(start));
// increment noise seed
start = start.map( c => c + 0.01 );
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.min.js"></script>

HTML Canvas - color transition between shapes ( shapes not overlapping)

The image is what I am looking forward to achieve using html canvas, without using blur or shadow.
Question :
Is there way to achieve right section of the image from left section of the image?
The fiddle for the problem is (basic drawing) here
var canvas = document.createElement('canvas'),
d = canvas.width = canvas.height = 400,
sq_size = d / 10,
ctx = canvas.getContext('2d');
document.body.appendChild(canvas);
var color=["rgb(10,110,10)", "rgb(81,169,255)","rgb(81,239,255)",
"rgb(81,255,202)",
"rgb(81,255,132)","rgb(99,255,81)","rgb(169,255,81)",
"rgb(239,255,81)", "rgb(255,202,81)","rgb(255,132,81)"];
var x=0, len=color.length;
for(var i=0; i < d; i++){
while(x < d) {
var c = Math.floor(Math.random() * len);
ctx.fillStyle = color[c];
ctx.fillRect(x,i,sq_size,sq_size);
x = x + sq_size;
}
x = 0;
i = i+sq_size;
}
The closest you can get without implementing a blur.
You can use image smoothing ctx.imageSmoothingEnabled to blur an image that is very low resolution. Then mix the blurred and unblurred images using ctx.globalAlpha
Example
pixelSize controls the amount of blurring. A value of 1 is the max amount and gets less as this value gets bigger. Must be an integer value eg 1, 2, 3, 4, ...
Note results will vary depending on the device and browser / version used.
requestAnimationFrame(animationLoop);
const size = canvas.width;
const ctx = canvas.getContext('2d');
var mix = 123; // amount to transition
const transitionTime = 2; // seconds per transition
const swatches = [0,1,2];
const pixelSize = 2;
// eCurve p = 1 linear curve [default p = 2] is quadratic curve p = 3 cubic curve and so on.
const eCurve = (v, p = 2) => v < 0 ? 0 : v > 1 ? 1 : v ** p / (v ** p + (1 - v) ** p);
const cols = [
[10, 110, 10], [81, 169, 255], [81, 239, 255], [81, 255, 202], [81, 255, 132],
[99, 255, 81], [169, 255, 81], [239, 255, 81], [255,202, 81], [255,132,81]
];
const img = document.createElement("canvas");
img.height = img.width = swatches.length * pixelSize;
const imgCtx = img.getContext('2d');
function randomSwatch() {
swatches.forEach(y => { swatches.forEach(x => {
imgCtx.fillStyle = "rgb("+cols[Math.random() * cols.length | 0].join(",")+")";
imgCtx.fillRect(x * pixelSize, y * pixelSize, pixelSize, pixelSize);
}); });
}
function animationLoop() {
mix = (mix >= 4 ? (randomSwatch(), 0) : mix) + 1 / (transitionTime * 60);
ctx.globalAlpha = 1;
ctx.imageSmoothingEnabled = false;
ctx.drawImage(img, 0, 0, size, size);
ctx.imageSmoothingEnabled = true;
const a = mix % 2;
ctx.globalAlpha = eCurve(a > 1 ? 2 - a : a, 3);
ctx.drawImage(img, 0, 0, size, size);
requestAnimationFrame(animationLoop);
}
<canvas id="canvas" height="300" width="300"></canvas>
This solution works best for me. Complies with my large dataset.
Not O(1) and I cannot possibly think it can be, or even O(n) (Minor banter).
P.s: Code can be optimised further.
Fiddle here
var canvas = document.createElement('canvas'),
d = canvas.width = canvas.height = 250,
sq_size = d / 5,
ctx = canvas.getContext('2d');
document.body.appendChild(canvas);
canvas.setAttribute('id','cav');
var color=["rgb(10,110,10)", "rgb(81,169,255)","rgb(81,239,255)", "rgb(81,255,202)", "rgb(81,255,132)","rgb(99,255,81)","rgb(169,255,81)", "rgb(239,255,81)", "rgb(255,202,81)","rgb(255,132,81)"];
var x=0, len=color.length;
var prevcolorh;
var colorobj = {};
for(var i=0; i < d;){
colorobj[i] = {};
while(x < d) {
var c = Math.floor(Math.random() * len);
colorobj[i][x] = color[c];
var gradient = ctx.createLinearGradient(x, 0, x+sq_size, 0);
var a = (prevcolorh !== undefined) ? prevcolorh : colorobj[i][x];
gradient.addColorStop(0, a);
gradient.addColorStop(1, colorobj[i][x]);
prevcolorh = colorobj[i][x];
ctx.fillStyle = gradient;
ctx.fillRect(x, i, d, d);
x = x + sq_size;
}
x = 0;
i = i+sq_size;
}
var rgbs = {};
for(var i=0; i<d; i+=sq_size) {
var imgd = ctx.getImageData(0, i+(sq_size/2), d, sq_size);
rgbs[i] = {};
var arr = [];
for (var j = 0, c = 0, n = imgd.data.length; j < n; j += 4, c++) {
if(j > 0 && j < d*4) {
arr.push([imgd.data[j],imgd.data[j+1],imgd.data[j+2],imgd.data[+3]]);
}
}
rgbs[i] = arr;
}
for(var k in rgbs) {
for(var i=0; i<rgbs[k].length; i++) {
if(rgbs[parseInt(k)+sq_size] !== undefined) {
var gradient2 = ctx.createLinearGradient(0, parseInt(k)+(sq_size/2), 0, parseInt(k)+(sq_size/2) + sq_size);
gradient2.addColorStop(0, 'rgba('+rgbs[k][i].join(',')+')');
gradient2.addColorStop(1, 'rgba('+rgbs[parseInt(k)+sq_size][i].join(',')+')');
ctx.fillStyle = gradient2;
ctx.fillRect(i, parseInt(k)+(3*sq_size/4), 1, sq_size/2);
}
}
}

Using Set Interval Function to Animate

<html>
canvas {
background-color: lightgreen
}
<script>
var ctx = canvas.getContext("2d");
var n = 5;
const PI = 3.14;
var randomWalk = function (n) {
var list = [0, 1];
var l = list.length;
start = Math.round(n / 2);
count = 0;
while (start > 0 && start < n + 1) {
rand = list[Math.floor(Math.random() * l)];
if (rand == 1) { start = start + 1 }
else { start = start - 1 };
count = count + 1;
};
console.log(count);
};
var drawSquares = function (n) {
for (i = 50; i <= n * 50; i = i + 50) {
ctx.beginPath();
ctx.rect(i, 50, 50, 50);
ctx.stroke();
};
};
var drawDot = function (n) {
x = ((50 * n) / 2) + 50;
ctx.beginPath();
ctx.arc(x, 75, 5, 0, 2 * PI);
ctx.stroke();
ctx.fill();
};
var resetCanvas = function () {
ctx.clearRect(0, 0, canvas.width, canvas.height);
};
var moveDot = function (n) {
drawSquares(n);
drawDot(n);
var list = [0, 1];
var l = list.length;
start = ((50 * n) / 2) + 50;
count = 0;
while (start > 50 && start < ((n * 50) + 50)) {
rand = list[Math.floor(Math.random() * l)];
if (rand == 1) { start = start + 50 }
else { start = start - 50 };
count = count + 1;
//console.log(start);
resetCanvas();
drawSquares(n);
ctx.beginPath();
ctx.arc(start, 75, 5, 0, 2 * PI);
ctx.stroke();
ctx.fill();
};
console.log(count);
};
//moveDot(n);
setInterval(moveDot(n), 1500);
</script>
The function below is the function that isn't working properly within the set interval function. This function takes the number of boxes as the input and based on a random choice of 0 or 1, it moves the dot to the left or to the right however it's not being shown.
I created the function titled moveDot to move the dot, however when placed in the set interval function the dot does not move. Any ideas as to why the function is not working properly would be greatly appreciated! Thanks in advance for your help!

How to add text to P5.js visual? (to appear/disappear at specific moments)

I am looking to add text (appears in the begging, within the black part of the rectangle and disappears as the white slides in to then reappear as the black overtakes the pink again)
Centred, 2 lines of text, 3 words in total (as below for example)
Project One
Diary
I have no previous experience of working with text in P5 but looking through tutorials online, I am unable to find an example where it appears at the beginning of the sequence then disappears shortly after.
Any inclusion of fonts would also be helpful as I will be trying a few out!
var rectWidth = 1000;
var rectHeight = 600;
var colourlapse;
var rx = 60;
var ry = 60;
var inc = 0.005;
let colors = [[0, 0, 0], [255, 255, 255], [255, 9, 236]]
let cur_col1 = 1;
let cur_col2 = 0;
function setup() {
frameRate(49);
createCanvas(1100, 1100);
colourlapse = 0.0;
}
function draw() {
var w = colourlapse * rectWidth;
var sx1 = (inc > 0) ? rx : rx + rectWidth - w;
var sx2 = (inc > 0) ? rx + w : rx;
background(255);
stroke(255);
fill(0);
fill(...colors[cur_col1 % colors.length]);
rect(sx1, ry, w, rectHeight);
fill(...colors[cur_col2 % colors.length]);
rect(sx2, ry, rectWidth-w, rectHeight);
colourlapse += inc;
if (colourlapse >= 1) {
colourlapse = 1;
inc *= -1;
cur_col2 += 2;
} else if (colourlapse <= 0) {
colourlapse = 0;
inc *= -1;
cur_col1 += 2;
}
}
You can have a look at the text() function to which simply enough you pass the text string of characters you want to display and the x,y coordinates where you want the text to appear.
It's up to you how you change the fill colour and text coordinates for the effect you're trying to achieve.
Here's a very crude example based on your code:
var rectWidth = 1000;
var rectHeight = 600;
var colourlapse;
var rx = 60;
var ry = 60;
var inc = 0.005;
let colors = [[0, 0, 0], [255, 255, 255], [255, 9, 236]]
let cur_col1 = 1;
let cur_col2 = 0;
let textContents = ["text number one","text number two","text number three"];
function setup() {
frameRate(49);
createCanvas(1100, 1100);
colourlapse = 0.0;
}
function draw() {
var w = colourlapse * rectWidth;
var sx1 = (inc > 0) ? rx : rx + rectWidth - w;
var sx2 = (inc > 0) ? rx + w : rx;
background(255);
stroke(255);
let index1 = cur_col1 % colors.length;
let index2 = cur_col2 % colors.length;
fill(colors[index1]);
rect(sx1, ry, w, rectHeight);
// text
fill(127);
text(textContents[index1],sx2,ry);
fill(colors[cur_col2 % colors.length]);
rect(sx2, ry, rectWidth-w, rectHeight);
colourlapse += inc;
if (colourlapse >= 1) {
colourlapse = 1;
inc *= -1;
cur_col2 += 2;
} else if (colourlapse <= 0) {
colourlapse = 0;
inc *= -1;
cur_col1 += 2;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.min.js"></script>

p5.js - Low FPS for some basic animations

I'm having really bad performance on a project i wrote in Javascript (with the p5.js library)
Here is the code:
const fps = 60;
const _width = 400;
const _height = 300;
const firePixelChance = 1;
const coolingRate = 1;
const heatSourceSize = 10;
const noiseIncrement = 0.02;
const fireColor = [255, 100, 0, 255];
const bufferWidth = _width;
const bufferHeight = _height;
let buffer1;
let buffer2;
let coolingBuffer;
let ystart = 0.0;
function setup() {
createCanvas(_width, _height);
frameRate(fps);
buffer1 = createGraphics(bufferWidth, bufferHeight);
buffer2 = createGraphics(bufferWidth, bufferHeight);
coolingBuffer = createGraphics(bufferWidth, bufferHeight);
}
// Draw a line at the bottom
function heatSource(buffer, rows, _color) {
const start = bufferHeight - rows;
for (let x = 0; x < bufferWidth; x++) {
for (let y = start; y < bufferHeight; y++) {
if(Math.random() >= firePixelChance)
continue;
buffer.pixels[(x + (y * bufferWidth)) * 4] = _color[0]; // Red
buffer.pixels[(x + (y * bufferWidth)) * 4 +1] = _color[1]; // Green
buffer.pixels[(x + (y * bufferWidth)) * 4 +2] = _color[2]; // Blue
buffer.pixels[(x + (y * bufferWidth)) * 4 +3] = 255; // Alpha
}
}
}
// Produces the 'smoke'
function coolingMap(buffer){
let xoff = 0.0;
for(x = 0; x < bufferWidth; x++){
xoff += noiseIncrement;
yoff = ystart;
for(y = 0; y < bufferHeight; y++){
yoff += noiseIncrement;
n = noise(xoff, yoff);
bright = pow(n, 3) * 20;
buffer.pixels[(x + (y * bufferWidth)) * 4] = bright;
buffer.pixels[(x + (y * bufferWidth)) * 4 +1] = bright;
buffer.pixels[(x + (y * bufferWidth)) * 4 +2] = bright;
buffer.pixels[(x + (y * bufferWidth)) * 4 +3] = bright;
}
}
ystart += noiseIncrement;
}
// Change color of a pixel so it looks like its smooth
function smoothing(buffer, _buffer2, _coolingBuffer) {
for (let x = 0; x < bufferWidth; x++) {
for (let y = 0; y < bufferHeight; y++) {
// Get all 4 neighbouring pixels
const left = getColorFromPixelPosition(x+1,y,buffer.pixels);
const right = getColorFromPixelPosition(x-1,y,buffer.pixels);
const bottom = getColorFromPixelPosition(x,y+1,buffer.pixels);
const top = getColorFromPixelPosition(x,y-1,buffer.pixels);
// Set this pixel to the average of those neighbours
let sumRed = left[0] + right[0] + bottom[0] + top[0];
let sumGreen = left[1] + right[1] + bottom[1] + top[1];
let sumBlue = left[2] + right[2] + bottom[2] + top[2];
let sumAlpha = left[3] + right[3] + bottom[3] + top[3];
// "Cool down" color
const coolingMapColor = getColorFromPixelPosition(x,y,_coolingBuffer.pixels)
sumRed = (sumRed / 4) - (Math.random() * coolingRate) - coolingMapColor[0];
sumGreen = (sumGreen / 4) - (Math.random() * coolingRate) - coolingMapColor[1];
sumBlue = (sumBlue / 4) - (Math.random() * coolingRate) - coolingMapColor[2];
sumAlpha = (sumAlpha / 4) - (Math.random() * coolingRate) - coolingMapColor[3];
// Make sure we dont get negative numbers
sumRed = sumRed > 0 ? sumRed : 0;
sumGreen = sumGreen > 0 ? sumGreen : 0;
sumBlue = sumBlue > 0 ? sumBlue : 0;
sumAlpha = sumAlpha > 0 ? sumAlpha : 0;
// Update this pixel
_buffer2.pixels[(x + ((y-1) * bufferWidth)) * 4] = sumRed; // Red
_buffer2.pixels[(x + ((y-1) * bufferWidth)) * 4 +1] = sumGreen; // Green
_buffer2.pixels[(x + ((y-1) * bufferWidth)) * 4 +2] = sumBlue; // Blue
_buffer2.pixels[(x + ((y-1) * bufferWidth)) * 4 +3] = sumAlpha; // Alpha
}
}
}
function draw() {
background(0);
text("FPS: "+Math.floor(frameRate()), 10, 20);
fill(0,255,0,255);
buffer1.loadPixels();
buffer2.loadPixels();
coolingBuffer.loadPixels();
heatSource(buffer1, heatSourceSize, fireColor);
coolingMap(coolingBuffer);
smoothing(buffer1, buffer2, coolingBuffer);
buffer1.updatePixels();
buffer2.updatePixels();
coolingBuffer.updatePixels();
let temp = buffer1;
buffer1 = buffer2;
buffer2 = temp;
image(buffer2, 0, 0); // Draw buffer to screen
// image(coolingBuffer, 0, bufferHeight); // Draw buffer to screen
}
function mousePressed() {
buffer1.fill(fireColor);
buffer1.noStroke();
buffer1.ellipse(mouseX, mouseY, 100, 100);
}
function getColorFromPixelPosition(x, y, pixels) {
let _color = [];
for (let i = 0; i < 4; i++)
_color[i] = pixels[(x + (y * bufferWidth)) * 4 + i];
return _color;
}
function getRandomColorValue() {
return Math.floor(Math.random() * 255);
}
I'm getting ~12 FPS on chrome and ~1 FPS on any other browser and i cant figure out why..
Resizing my canvas to make it bigger also impacts the fps negatively...
In the devtools performance tab i noticed that both my smoothing and coolingMap functions are the things slowing it down, but i cant figure out what part of them are so heavy..
You've pretty much answered this for yourself already:
i'm starting to think this is normal and i should work on caching stuff and maybe use pixel groups instead of single pixels
Like you're discovering, doing some calculation for every single pixel is pretty slow. Computers only have finite resources, and there's going to be a limit to what you can throw at them.
In your case, you might consider drawing the whole thing to a canvas once at startup, and then moving the canvas up over the life of the program.

Categories

Resources