canvas实现彩色线条绘制屏保动画效果代码

代码语言:html

所属分类:动画

代码描述:canvas实现彩色线条绘制屏保动画效果代码

代码标签: canvas 彩色 线条 绘制 屏保 动画

下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开

<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  

  
  
<style>
:root {
  background: black;
  color: white;
}
</style>

  
</head>

<body translate="no">
  
  
      <script  >
const particles = 4;

const minD = 0.05; // min/max distance
const maxD = 1;
const maxV = 20; // max velocity
const maxF = 10; // max force
const F = 0.0186125; // attraction force
const G = 0.003; // gravity

const canvas = document.createElement("canvas");
canvas.style.position = "absolute";
canvas.style.top = canvas.style.left = 0;
document.body.appendChild(canvas);

const buffer = document.createElement("canvas");
const bufferCtx = buffer.getContext("2d");

const ctx = canvas.getContext("2d");

let w, h, hw, hh;

const PI2 = Math.PI * 2;

const random = (min = -1, max = 1) => Math.random() * (max - min) + min;

const resize = () => {
  w = Math.max(innerWidth, 1) - innerWidth % 2;
  h = Math.max(innerHeight, 1) - innerHeight % 2;
  hw = w / 2;
  hh = h / 2;
  canvas.width = buffer.width = w;
  canvas.height = buffer.height = h;
  initContext();
};

const initContext = () => {
  ctx.translate(hw, hh);
  ctx.fillStyle = "white";
  ctx.strokeStyle = "white";
  ctx.lineWidth = 1.3;
  ctx.fillRect(-hw, -hh, w, h);
  bufferCtx.fillStyle = "black";
  bufferCtx.fillRect(0, 0, w, h);
};

resize(false);

const debounce = (fn, delay) => {
  let timeout;
  return () => {
    if (timeout) clearTimeout(timeout);
    timeout = setTimeout(() => fn(), delay);
  };
};

const debouncedResize = debounce(resize, 100);

addEventListener("resize", () => debouncedResize());

const createPoints = (count, source, phase = Math.random() * PI2) =>
Array.from({ length: count }, (_, i) => {
  const x = source?.x ?? Math.sin(phase + i / count * PI2) * .9;
  const y = source?.y ?? Math.cos(phase + i / count * PI2) * .9;
  const dx = source?.dx ?? -x / 4;
  const dy = source?.dy ?? -y / 4;
  return { x, y, dx, dy, closest: null };
});

const project2d = ({ x, y }) => {
  return {
    x: Math.round(x * hw),
    y: Math.round(y * hh) };

};

const distance = (p1, p2) =>
Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));

const map = (value, min = 0, max = 1, targetMin = 0, targetMax = 1) =>
targetMin + (value - min) * (targetMax - targetMin) / (max - min);

let firstHit = false;

const updatePoint = dt => (p, i, points) => {
  p.dy += G * dt;
  p.closest = getClosestPoints(points, p);

  const [cdx, cdy] = p.closest.reduce((sum, cp) => {
    const dx = cp.x - p.x;
    const dy = cp.y - p.y;
    const d = distance(cp, p);
    if (d > maxD) return sum;
    if (d < minD) {
      const rStr = .5 * (1 - d / minD);
      sum[0] -= dx / d * rStr;
      sum[1] -= dy / d * rStr;
      return sum;
    }
    const mag = Math.min(maxF, (1 - d / maxD) / (d * d));
    const force = mag; // p.closest.length;
    sum[0] += dx / d * force;
    sum[1] += dy / d * force;
    return sum;
  }, [0, 0]);

  const dtF = Math.min(maxF * dt, F * dt);
  p.dx += Math.max(-dtF, Math.min(dtF, cdx * F * dt));
  p.dy += Math.max(-dtF, Math.min(dtF, cdy * F * dt));

  const dtV = maxV * dt;
  p.dx = Math.max(-dtV, Math.min(dtV, p.dx));
  p.dy = Math.max(-dtV, Math.min(dtV, p.dy));

  if (msP) {
    const mdx = i % 2 ? msX - p.x : p.x - msX;
    const mdy = i % 2 ? msY - p.y : p.y - msY;
    const mdd = distance(p, { x: msX, y: msY });
    if (mdd < .7) {
      p.dx = (p.dx * 19 + mdx * (.7 - mdd)) / 20;
      p.dy = (p.dy * 19 + mdy * (.7 - mdd)) / 20;
    }
  }

  let collide = false;
  if (p.x <= -1 || p.x >= 1) {
    p.x = Math.min(1 - 1 / w, Math.max(-1 + 1 / w, p.x));
    p.dx *= -1;
    collide = true;
  }
  if (p.y < -1 || p.y > 1) {
    p.y = Math.min(1 - 1 / h, Math.max(-1 + 1 / h, p.y));
    p.dy *= -1;
    collide = true;
  }

  p.x += p.dx * dt;
  p.y += p.dy * dt;

  const shatter = collide && (random(0, 100) > 81.6 || !firstHit);
  if (shatter) {
    firstHit = true;
    const newPoints = createPoints(Math.round(random(1, 2)), p);

    const normX = p.x <= -1 ? 1 : p.x >= 1 ? -1 : 0;
    const normY = p.y <= -1 ? 1 : p.y >= 1 ? -1 : 0;
    const speed = Math.sqrt(p.dx * p.dx + p.dy * p.dy);
    const dot = p.dx * normX + p.dy * normY;
    const refX = p.dx - 2 * dot * normX;
    const refY = p.dy - 2 * dot * normY;

    const spreadA = Math.PI / 4;
    const loss = .5;

    newPoints.forEach((np, i, a) => {
      np.x += random(-.01, .01);
      np.y += random(-.01, .01);
      np.x = Math.max(-1, Math.min(1, np.........完整代码请登录后点击上方下载按钮下载查看

网友评论0