HTML
Don’t need too many elements, simple is true
<div class="debut">
<! -- Background -->
<canvas class="music-cover-background" id="background">your brower does not support canvas</canvas>
<! -- Foreground section -->
<div class="music-cover">
<img src="images/1753378458.jpg" class="music-cover-image"></img>
</div>
</div>
Copy the code
CSS
Find an opening and draw a circle
.debut {
position: absolute;
width: 100%;
height: 100%;
display: inline-flex;
align-items: center;
justify-content: center;
}
.music-cover {
width: 23.75 rem; /* 380px */
height: 23.75 rem; /* 380px */
box-sizing: border-box;
border:.125rem solid #B3B3B3; /* 2px solid #B3B3B3 */
border-radius: 50%;
display: inline-flex;
align-items: center;
justify-content: center;
}
Copy the code
Center the layout using Flex
Put a picture in the circle and make it go around
.music-cover-image {
width: 21.25 rem; /* 340px */
height: 21.25 rem; /* 340px */
border: none;
border-radius: 50%;
animation: rotate infinite linear 25s;
}
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }}Copy the code
Animation time 25s was measured by me with a stopwatch
Draw a shadow behind the picture and choose a simple color
.music-cover::before {
content: ""; position: absolute; Width: 21.25 rem; /* 340px */ height: 21.25rem; /* 340px */ border-radius: 50%; The filter: the blur (1.875 rem); /* 30px */ background-image: radial-gradient(white, silver); }Copy the code
Pseudo-elements are enough
canvas
Let’s place the canvas
.music-cover-background {
position: absolute;
}
Copy the code
Position: Absolute centered because the parent element. Debut uses flex layout
Right after the size
const canvas = document.getElementById('background');
canvas.width = canvas.height = Math.ceil(canvas.parentNode.firstElementChild.offsetWidth * 1.68421);
Copy the code
Defining a triangle
const PI2 = 2 * Math.PI;
class Triangle {
constructor(context, speed, pole, range) {
this.ctx = context;
this.pole = pole;
this.range = range;
this.speed = speed;
this.points = [[0.0], [0.0], [0.0]].this.__restart();
}
__restart() {
this.angle = Math.random() * PI2; // Generate a random movement direction
this.speedX = Math.cos(this.angle) * this.speed;
this.speedY = Math.sin(this.angle) * this.speed;
this.opacity = 1;
const dist = Math.random() * 150; // In order to generate a well-proportioned triangle, let the triangle start at a random distance dist from the pole
const distX = Math.cos(this.angle) * dist;
const distY = Math.sin(this.angle) * dist;
constTheta equalsMath.random() * PI2; // Rotate the triangle by a random θ degree
const x2 = Math.random() * 10;
const y2 = 20 + Math.random() * 20;
const x3 = 10 + Math.random() * 15;
const y3 = 12 + Math.random() * 6;
this.points[0] [0] = Math.floor(this.pole[0] + distX);
this.points[0] [1] = Math.floor(this.pole[1] + distY);
this.points[1] [0] = Math.floor(this.pole[0] + distX + (x2 * MathCos (theta) - y2 *MathSin (theta)));this.points[1] [1] = Math.floor(this.pole[1] + distY + (y2 * MathCos (theta) + x2 *MathSin (theta)));this.points[2] [0] = Math.floor(this.pole[0] + distX + (x3 * MathCos (theta) - y3 *MathSin (theta)));this.points[2] [1] = Math.floor(this.pole[1] + distY + (y3 * MathCos (theta) + x3 *MathSin (theta))); } __distance() {const dx = this.points[0] [0] - this.pole[0];
const dy = this.points[0] [1] - this.pole[1];
return Math.floor(Math.sqrt(dx * dx + dy * dy));
}
__lerp(src, dst, coeff) {
return src + (dst - src) * coeff;
}
__update() {
const dist = this.__distance();
if (dist - this.range > 0.0001)
this.__restart();
else {
this.points.forEach((point, index) = > {
this.points[index][0] = point[0] + this.speedX;
this.points[index][1] = point[1] + this.speedY;
});
this.opacity = this.__lerp(1.0, dist / this.range);
}
}
render() {
this.__update();
this.ctx.lineWidth = 2;
this.ctx.lineJoin = "miter";
this.ctx.strokeStyle = `rgba(179, 179, 179, The ${this.opacity}) `;
this.ctx.beginPath();
this.ctx.moveTo(this.points[0] [0].this.points[0] [1]);
this.ctx.lineTo(this.points[1] [0].this.points[1] [1]);
this.ctx.lineTo(this.points[2] [0].this.points[2] [1]);
this.ctx.closePath();
this.ctx.stroke();
this.ctx.fillStyle = 'rgba(67, 67, 67, .2)';
this.ctx.fill(); }}Copy the code
Define a “scene”
class Scene {
constructor(canvas) {
this.cvs = canvas;
this.ctx = canvas.getContext('2d');
this.triangleSet = [];
this.triangleNum = 25; // Number of triangles
const realm = this.cvs.width / 2; // Canvas center
for (let i = 0; i < this.triangleNum; ++i)
this.triangleSet[i] = new Triangle(this.ctx, 1.5, [realm, realm], realm);
}
render() {
this.ctx.clearRect(0.0.this.cvs.width, this.cvs.height); // Clear the canvas in time
this.triangleSet.forEach(triangle= > triangle.render());
}
run() {
if (!this.timer) {
this.timer = setInterval(this.render.bind(this), 25);
}
}
stop() {
if (this.timer) {
clearInterval(this.timer);
this.timer = 0; }}}Copy the code
Finally, “Run scene”
const canvas = document.getElementById('background');
canvas.width = canvas.height = Math.ceil(canvas.parentNode.lastElementChild.offsetWidth * 1.68421);
const scene = new Scene(canvas);
scene.run();
Copy the code