javascript
复制代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.p {
/* 设置一个描边的颜色 */
stroke: #000;
/* 线宽度 */
stroke-width: 2;
/* 虚线的空心部分和实心部分是200 */
/* stroke-dasharray: 200; */
/* 值不能写死,需要动态获取到路径的长度*/
stroke-dasharray: var(--l);
/* 虚线的偏移量,正数是往起始点方向偏移,负数往相反方向偏移 */
/* stroke-dashoffset:200; */
stroke-dashoffset: var(--l);
/* 一个圆头的线 */
/* stroke-linecap: round; */
animation: stroke 2s forwards;
}
@keyframes stroke {
to {
stroke-dashoffset: 0
}
}
</style>
</head>
<body>
<svg class="icon" width="200" height="200">
<!-- 描绘一个线,从坐标0到100% -->
<!-- 线 -->
<line class="p" x1="0" y1="50%" x2="100%" y2="50%"></line>
<!-- 圆 圆心在中点-->
<circle class="p" cx="50%" cy="50%" r="40" fill="none"></circle>
<path class="p" d="M3.8,6.6h16.4"></path>
<path class="p" d="M20.2,12.1H3.8"></path>
<path class="p" d="M3.8,17.5h16.4"></path>
</svg>
</body>
<script>
// 获取到路径的真实长度,调用js的方法getTotalLength()
const paths = document.querySelectorAll('.p');
paths.forEach(p => {
const l = p.getTotalLength() + 1;
p.style.setProperty('--l', l)
})
</script>
</html>
javascript
复制代码
// 绘制上下文
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d', {
willReadFrequently: true //提升渲染效率
});
// 设置画布宽高
function initCanvasSize() {
canvas.width = window.innerWidth * devicePixelRatio;
canvas.height = window.innerHeight * devicePixelRatio; //提高清晰度
}
initCanvasSize()
// 获取范围内的随机数
function getRandom(min, max) {
return Math.floor(Math.random() * (max + 1 - min) + min)
}
// 创造粒子,每一个粒子在程序里面可以表达为一个对象
class Particle {
constructor() {
// 圆圈尺寸随机数
this.size = getRandom(2 * devicePixelRatio, 7 * devicePixelRatio);
const r = Math.min(canvas.width, canvas.height) / 2
const rad = getRandom(0, 360) * Math.PI / 180
const cx = canvas.width / 2
const cy = canvas.height / 2
this.x = cx + r * Math.cos(rad)
this.y = cy + r * Math.sin(rad)
}
draw() {
ctx.beginPath()
ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI)
ctx.fillStyle = '#5445544d'
ctx.fill()
}
moveTo(tx, ty) {
// 定义运动时间
const duration = 500
// 设置一下其实坐标
const sx = this.x,
sy = this.y
const xSpeed = (tx - sx) / duration
const ySpeed = (ty - sy) / duration
const startTime = Date.now()
// 写一个函数,每次调用时运动一小点
const _move = () => {
const t = Date.now() - startTime //当前运动了多长时间
const x = sx + xSpeed * t //初始位置+速度*时间
const y = sy + ySpeed * t
this.x = x
this.y = y
if (t >= duration) {
this.x = tx
this.y = ty
return;
}
requestAnimationFrame(_move) //注册下一次移动
}
_move()
}
}
// 多个粒子实现
const particles = []
// 清空画布
function clear() {
ctx.clearRect(0, 0, canvas.width, canvas.height)
}
let text = null
// 更新坐标,粒子信息
function update() {
// 1.首先先把要渲染的文字画出来
const curText = getText() //避免频繁更新
if (text === curText) {
return;
}
text = curText
const {
width,
height
} = canvas
ctx.fillStyle = "#000"
ctx.textBaseline = "middle"
ctx.font = `${140*devicePixelRatio}px 'DS-Digital',sans-serif`;
ctx.textAlign = "center"
ctx.fillText(text, width / 2, height / 2)
// 根据文字拿到相应像素
const points = getPoints()
clear()
for (let i = 0; i < points.length; i++) {
const [x, y] = points[i]
const p = particles[i]
if (!p) {
p = new Particle()
particles.push(p)
}
p.moveTo(x,y)
}
}
function getPoints() {
const points = []
const {
data
} = ctx.getImageData(0, 0, canvas.width, canvas.height) //data为像素点每个像素的rgba值
const gap = 6
for (let i = 0; i < canvas.width; i += gap) {
for (let j = 0; j < canvas.height; j++) {
const index = (i + j * canvas.width) * 4
const r = data[index]
const g = data[index + 1]
const b = data[index + 2]
const a = data[index + 3]
if (r === 0 && g === 0 && b === 0 && a === 255) {
points.push([i, j])
}
}
}
return points
}
function getText() {
return new Date().toTimeString().substring(0, 8)
}
function draw() {
clear()
update()
for (const p of particles) {
p.draw()
}
// requestAnimationFrame(draw) //下一次又重新画
}
draw()