所以我有以下使用形状的HTML / JS Canvas Wave动画:
https://codepen.io/baidoc/pen/yLBgppw
我正在尝试通过二进制代码替换圆形。最后,它看起来像是一堆二进制代码(01010101),而不是一堆形状。
实现此目标的最佳方法是什么?绘制自定义SVG还是通过CTX FillText?
function drawParticle(particle, canvas, ctx) {
canvas = document.getElementById('binary-canvas');
const vh = canvas.height / 100;
ctx.fillStyle = particle.colour;
ctx.beginPath();
ctx.ellipse(
particle.x * canvas.width,
particle.y * vh + (canvas.height / 2),
particle.diameter * vh,
particle.diameter * vh,
0,
0,
2 * Math.PI
);
ctx.fill();
}
答案 0 :(得分:1)
最好的方法是使用drawImage()
渲染文本。
您当然可以使用fillText
,但这是一种非常缓慢的方法,因此,您调用它的次数越少,性能就越好,并且对于粒子系统而言,性能很重要。
因此,首先准备两个画布,一个画布上画有“ 0”,另一个画布上画有“ 1”。
然后,在初始化粒子时,只需存储它们将引用的画布中的哪些。
最后,只需使用粒子的存储画布,其坐标和大小调用ctx.drawImage
:
// returns a new <canvas> with given character drawn on it
// can be used directly with drawImage
function makeCharacterCanvas( txt ) {
const canvas = document.createElement('canvas');
canvas.width = canvas.height = 50;
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'white';
ctx.font = "50px monospace";
ctx.textAlign = "center";
ctx.textBaseLine = "bottom";
ctx.fillText(txt, canvas.width / 2, canvas.height);
return canvas;
}
const chars = [makeCharacterCanvas('0'), makeCharacterCanvas('1')];
// OP's code below
// modified version of random-normal
function normalPool(o){var r=0;do{var a=Math.round(normal({mean:o.mean,dev:o.dev}));if(a<o.pool.length&&a>=0)return o.pool[a];r++}while(r<100)}function randomNormal(o){if(o=Object.assign({mean:0,dev:1,pool:[]},o),Array.isArray(o.pool)&&o.pool.length>0)return normalPool(o);var r,a,n,e,l=o.mean,t=o.dev;do{r=(a=2*Math.random()-1)*a+(n=2*Math.random()-1)*n}while(r>=1);return e=a*Math.sqrt(-2*Math.log(r)/r),t*e+l}
const NUM_PARTICLES = 500;
const PARTICLE_SIZE = 1.5; // View heights
const SPEED = 30000; // Milliseconds
let particles = [];
function rand(low, high) {
return Math.random() * (high - low) + low;
}
function createParticle(canvas) {
return {
x: -2,
y: -2,
diameter: Math.max(0, randomNormal({ mean: PARTICLE_SIZE, dev: PARTICLE_SIZE / 2 })),
duration: randomNormal({ mean: SPEED, dev: SPEED * 0.1 }),
amplitude: randomNormal({ mean: 16, dev: 2 }),
offsetY: randomNormal({ mean: 0, dev: 10 }),
arc: Math.PI * 2,
startTime: performance.now() - rand(0, SPEED),
// [edit]
// store which character this particle will hold
char: chars[+(Math.random() > .5)],
// We lost colour, but still have opacity
opacity: rand(0, 1)
}
}
function moveParticle(particle, canvas, time) {
const progress = ((time - particle.startTime) % particle.duration) / particle.duration;
return {
...particle,
x: progress,
y: ((Math.sin(progress * particle.arc) * particle.amplitude) + particle.offsetY),
};
}
function drawParticle(particle, canvas, ctx) {
canvas = document.getElementById('binary-canvas');
const vh = canvas.height / 100;
// [edit]
// set opacity
ctx.globalAlpha = particle.opacity;
// draw the corresponding <canvas>
ctx.drawImage(
particle.char,
particle.x * canvas.width,
particle.y * vh + (canvas.height / 2),
particle.diameter * vh * 2,
particle.diameter * vh * 2
)
}
function draw(time, canvas, ctx) {
// Move particles
particles.forEach((particle, index) => {
particles[index] = moveParticle(particle, canvas, time);
})
// Clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw the particles
particles.forEach((particle) => {
drawParticle(particle, canvas, ctx);
})
// Schedule next frame
requestAnimationFrame((time) => draw(time, canvas, ctx));
}
function initializeCanvas() {
let canvas = document.getElementById('binary-canvas');
canvas.width = canvas.offsetWidth * window.devicePixelRatio;
canvas.height = canvas.offsetHeight * window.devicePixelRatio;
let ctx = canvas.getContext("2d");
window.addEventListener('resize', () => {
canvas.width = canvas.offsetWidth * window.devicePixelRatio;
canvas.height = canvas.offsetHeight * window.devicePixelRatio;
ctx = canvas.getContext("2d");
})
return [canvas, ctx];
}
function startAnimation() {
const [canvas, ctx] = initializeCanvas();
// Create a bunch of particles
for (let i = 0; i < NUM_PARTICLES; i++) {
particles.push(createParticle(canvas));
}
requestAnimationFrame((time) => draw(time, canvas, ctx));
};
// Start animation when document is loaded
(function () {
if (document.readystate !== 'loading') {
startAnimation();
} else {
document.addEventListener('DOMContentLoaded', () => {
startAnimation();
})
}
}());
html, body {
background:#111830;
background-image: url("https://cl.profi-homepage.de/wp-content/uploads/2019/07/bg_nur_highlight-1.png");
background-repeat: no-repeat;
background-position: center center;
background-attachment: scroll;
background-size: contain;
margin: 0;
}
#binary-canvas {
width: 100%;
height: 100vh;
vertical-align: middle;
}
<canvas id="binary-canvas"></canvas>
一个缺点是,您松散了一些颜色上的随机性,但是考虑到原始片段中的颜色,我将假定不透明度就足够了。