Question:
I have a StackOverflow word:
<h1>StackOverflow</h1>
How to create an animation effect for this word, for example, in the form of a wave and at the same time pouring one color into another?
I'm imagining the following animation script:
- Sequential from left to right change of color of letters
- Sequential increase from original font size for each letter
- Change font size to original size in reverse order
- Change the color of the letters back to the original color
- Animation looping
How to implement similar scenario of such animation using any technology mentioned in question tags?
Answer:
I don’t like frames, I don’t pretend to anything, just here’s a cool effect for you:
let s = 620;
document.body.innerHTML += `<canvas id="canvas"
width="${s}" height="${s/4}" ></canvas>`;
let ctx = canvas.getContext('2d');
let dots = [];
let mouse = {x:0, y:0}
let startedAt = Date.now();
ctx.font = 'bold '+(s/7.5)+'px Arial';
ctx.fillStyle = 'red';
ctx.textBaseline = "middle";
ctx.textAlign = "center";
ctx.fillText('Стековерфлоу', s/2, s/8);
let mask = ctx.getImageData(0,0,s,s/4);
for (let i = 0; dots.length < 3000; i++){
let x = s*Math.random();
let y1 = s*Math.random();
let y2 = -s*Math.random();
let offset = parseInt(y1)*s*4 + parseInt(x)*4;
if (mask.data[offset])
dots.push({x, y1, y2, speed: {x:0, y:0}, i})
}
ctx.fillStyle = 'black';
requestAnimationFrame(function draw(){
let t = Date.now() - startedAt;
ctx.clearRect(0,0,s,s);
dots.forEach(dot => {
let t1 = Math.min(1,(t-dot.x*4)/(500+2000*Math.abs(Math.sin(dot.i*4))));
t1 = t1*t1*t1
let x = dot.x;
let y = dot.y2 + (dot.y1-dot.y2) * t1;
let dx = mouse.x-x;
let dy = mouse.y-y;
let lenSq = dx*dx + dy*dy;
if (lenSq < 900) {
let d = 30-Math.sqrt(lenSq);
dot.speed.x += dx/30*d;
dot.speed.y += dy/30*d;
}
x += dot.speed.x;
y += dot.speed.y;
dot.speed.x *= 0.92;
dot.speed.y *= 0.92;
ctx.fillRect(x-0.75, y-0.75, 1.5, 1.5);
});
requestAnimationFrame(draw);
});
addEventListener('mousemove', e => {
let bb = canvas.getBoundingClientRect();
mouse.x = e.x - bb.x;
mouse.y = e.y - bb.y;
});
['click','touchstart'].forEach(type =>
addEventListener(type, () => startedAt = Date.now()));
To arrange the points in the form of letters, a canvas is used, the desired text is drawn on it.
The first step is to generate a lot of points, and check each one for hitting the text mask, you can do this by checking the color value of the pixel by the coordinates of the point, let it be the red channel:
let mask = ctx.getImageData(0,0,s,s/4);
let red = mask.data[y*width*4 + x*4];
After the points are placed, you can animate them, for this we initially raise each point to the area of \u200b\u200bnegative y values and move it down at a random speed until it reaches its location, we also add a delay proportional to the x coordinate, to animate from left to right.
The final touch is the reaction to the pointer: everything is relatively simple here, we calculate the distance from the pointer to the point, and if it is less than a certain threshold, we change the point coordinate to a value that depends on this distance.