canvas鼠标交互粒子动画效果代码

代码语言:html

所属分类:粒子

代码描述:canvas鼠标交互粒子动画效果代码

代码标签: canvas 鼠标 交互 粒子 动画

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

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

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

    
  
  
<style>
/*
global
*/
@import url(//fonts.googleapis.com/css?family=Open+Sans);

*, *::before, *::after {
		margin: 0;
		padding: 0;
		border: 0;
		box-sizing: border-box;
}

*:focus {
		outline: none;
}

body {
		display: flex;
		align-items: center;
		justify-content: center;
		height: 100vh;
		background: radial-gradient(#202020, #000000);
		overflow: hidden;
}

canvas {
		touch-action: none;
}
</style>

  
  
</head>

<body translate="no">
  
  
      <script  >
//---

'use strict';

//---

console.clear();

//---

let w = 0;
let h = 0;
let initialWidth = w;
let initialHeight = h;

let animationFrame = null;
let isTouchDevice = false;

const canvas = document.createElement('canvas');
const context = canvas.getContext('2d', { willReadFrequently: true });

let imageData = null;
let data = null;

const center = { x: w / 2, y: h / 2 };
const border = { left: 1, top: 1, right: w, bottom: h };

let pointerPos = { x: center.x, y: center.y };
let pointerDown = false;
let pointerMoveTimeout;

const pointerMoveTimeoutTime = 2500;

//---

const text = [

{ text: '250', x: 0, y: 0, ox: 0, oy: 0, offsetX: 0, offsetY: -60, fontSizeFactor: 2.25, fontWeight: 'bold', fontSize: 0 },
{ text: 'FOLLOWERS', x: 0, y: 0, ox: 0, oy: 0, offsetX: 0, offsetY: 180, fontSizeFactor: 8.5, fontWeight: 'bold', fontSize: 0 }];



const dotsCountMax = 20164;
const dotsRadius = 3;
const dotsDistance = 0;
const dotsDiameter = dotsRadius * 2;
const dotsSpeed = 10;
const dotsWobbleFactor = 0.95;
const dotsWobbleSpeed = 0.05;
const dotsMaxEscapeRouteLengthBasis = 100;
let dotsMaxEscapeRouteLength = 100;
const dotsMouseDistanceSensitivitySpeed = 5;
const dotsMouseDistanceSensitivityMax = 250;
const dotsMouseDistanceSensitivityMinBasis = 100;
let dotsMouseDistanceSensitivityMin = 100;
let dotsMouseDistanceSensitivity = dotsMouseDistanceSensitivityMin;
let dotsHolder = [];
let dotsCount = dotsCountMax;

let introPath = [];
let introInterval = null;
let introIndex = 0;
let introPathCoordinatesCount = 256;
let introSpeedBasis = 10;
let introSpeed = introSpeedBasis;


//---

function init() {

  isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0;

  //---

  if (isTouchDevice === true) {

    canvas.addEventListener('touchmove', cursorMoveHandler, false);
    canvas.addEventListener('touchend', cursorLeaveHandler, false);
    canvas.addEventListener('touchcancel ', cursorLeaveHandler, false);

  } else {

    canvas.addEventListener('pointermove', cursorMoveHandler, false);
    canvas.addEventListener('pointerdown', cursorDownHandler, false);
    canvas.addEventListener('pointerup', cursorUpHandler, false);
    canvas.addEventListener('pointerleave', cursorLeaveHandler, false);

  }

  //---

  initialWidth = calculateDimensions(dotsCount, dotsDiameter, dotsDistance, dotsMouseDistanceSensitivityMax);
  initialHeight = initialWidth;

  //---

  document.body.appendChild(canvas);

  window.addEventListener('resize', onResize, false);

  restart();

}

function onResize(event) {

  restart();

}

function calculateDimensions(dotsCount, dotsDiameter, dotsDistance, dotsMouseDistanceSensitivityMax) {

  return Math.ceil(Math.sqrt(dotsCount)) * (dotsDiameter + dotsDistance) + dotsMouseDistanceSensitivityMax * 1;

}

function restart() {

  const innerWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
  const innerHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;

  //---

  const changeDimensions = c => {

    let dotsCountSQRT = Math.ceil(Math.sqrt(dotsCount));

    dotsCountSQRT += c;
    dotsCount = dotsCountSQRT * dotsCountSQRT;

    w = calculateDimensions(dotsCount, dotsDiameter, dotsDistance, dotsMouseDistanceSensitivityMax);
    h = w;

  };

  //---

  w = calculateDimensions(dotsCount, dotsDiameter, dotsDistance, dotsMouseDistanceSensitivityMax);
  h = w;

  if (w < innerWidth || h < innerHeight) {

    while ((w < innerWidth || h < innerHeight) && dotsCount < dotsCountMax) changeDimensions(2);

  }

  if (w > innerWidth || h > innerHeight) {

    while (w > innerWidth || h > innerHeight) changeDimensions(-2);

  }

  //---

  canvas.width = w;
  canvas.height = h;

  imageData = context.getImageData(0, 0, w, h);
  data = imageData.data;

  //---

  center.x = w / 2;
  center.y = h / 2;

  pointerPos.x = -10000;
  pointerPos.y = -10000;

  border.right = w;
  border.bottom = h;

  //---

  initTextCanvas();

  const scaleFactor = Math.min(w / initialWidth, h / initialHeight);
  const calculateFontSize = (w, baseFontSize, scaleFactor) => Math.round(w / baseFontSize * scaleFactor);
  const adjustOffset = (offset, scaleFactor) => offset * scaleFactor;

  text.forEach(t => {

    t.ox = adjustOffset(t.offsetX, scaleFactor);
    t.oy = adjustOffset(t.offsetY, scaleFactor);
    t.x = center.x + t.ox;
    t.y = center.y + t.oy;
    t.fontSize = calculateFontSize(w, t.fontSizeFactor, scaleFactor);

    drawTextToCanvas(t);

  });

  //---

  dotsMouseDistanceSensitivityMin = Math.round(dotsMouseDistanceSensitivityMinBasis * scaleFactor);
  dotsMaxEscapeRouteLength = Math.round(dotsMaxEscapeRouteLengthBasis * scaleFactor);

  //---

  removeDots();
  addDots();

  //---

  if (animationFrame != null) {

    cancelAnimFrame(animationFrame);

  }

  render();

  //---

  introSpeed = Math.round(introSpeedBasis / scaleFactor);

  initIntroPath(introPathCoordinatesCount);
  stopIntro();
  playIntro();

}

//---

function initTextCanvas() {

  context.fillStyle = 'white';
  context.fillRect(0, 0, w, h);
  context.fillStyle = 'black';

}

function drawTextToCanvas({ text, x, y, fontWeight, fontSize, color = 'black', align = 'center', baseline = 'middle' }) {

  context.font = `${fontWeight} ${fontSize}px 'Open Sans', sans-serif`;
  context.textAlign = align;
  context.textBaseline = baseline;
  context.fillText(text, x, y);

}

function isPixelBlack(x, y) {

  const imageData = context.getImageData(x, y, 1, 1).data;

  return imageData[0] === 0 && imageData[1] === 0 && imageData[2] === 0;

}

//---

function addDots() {

  const dotsPerRow = Math.ceil(Math.sqrt(dotsCount));

  const xs = Math.round(center.x - dotsPerRow * (dotsDiameter + dotsDistance) / 2) + dotsDiameter;
  const ys = Math.round(center.y - dotsPerRow * (dotsDiameter + dotsDistance) / 2) + dotsDiameter;

  for (let i = 0; i < dotsCount; i++) {

    const x = xs + i % dotsPerRow * (dotsDistance + dotsDiameter);
    const y = ys + Math.floor(i / dotsPerRow) * (dotsDistance + dotsDiameter);

    let dot = null;

    if (isPixelBlack(x, y) === true) {

      dot = addDot(x, y, dotsRadius, dotsDiameter, 255, Math.floor(Math.random() * 255), 155, 255);

    } else {

      dot = addDot(x, y, dotsRadius, dotsDiameter, Math.floor(Math.random() * 255), 0, 155, 255);

    }

    dotsHolder.push(dot);

  }

}

function addDot(x, y, radius, diameter, r, g, b, a) {

  const dot = {};

  dot.cx = x;
  dot.cy = y;
  dot.x = x;
  dot.y = y;
  dot.sx = 0;
  dot.sy = 0;
  dot.radius = radius;
  dot.minRadius = radius * 0.75;
  dot.maxRadius = radi.........完整代码请登录后点击上方下载按钮下载查看

网友评论0