粒子组成文字动画效果

代码语言:html

所属分类:粒子

代码描述:粒子组成文字动画效果

代码标签: 动画 效果

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

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">

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

body, html{
	width: 100%;
	height: 100%;
	position: relative;
}


#text-container{
	font-family: 'Rock Salt';
	position: relative;
	display: block;
	width: 100%;
	height: 100%;
}
</style>

</head>
<body translate="no">
<div id="text-container"></div>

<script>
function _defineProperty(obj, key, value) {if (key in obj) {Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true });} else {obj[key] = value;}return obj;}window.onload = function () {

  const PI2 = Math.PI * 2;
  const SIN = Math.sin;
  const COS = Math.cos;
  const SMALL = 650;


  /*		/$$$$$$                                      /$$$$$$$                                      /$$$$$$$$ /$$           /$$
                     		/$$__  $$                                    | $$__  $$                                    | $$_____/| $$          | $$
                     		| $$  \__/ /$$   /$$  /$$$$$$   /$$$$$$       | $$  \ $$ /$$   /$$  /$$$$$$   /$$$$$$       | $$      | $$ /$$   /$$| $$
                     		|  $$$$$$ | $$  | $$ /$$__  $$ |____  $$      | $$  | $$| $$  | $$ /$$__  $$ |____  $$      | $$$$$   | $$| $$  | $$| $$
                     		\____  $$| $$  | $$| $$  \ $$  /$$$$$$$      | $$  | $$| $$  | $$| $$  \ $$  /$$$$$$$      | $$__/   | $$| $$  | $$|__/
                     		/$$  \ $$| $$  | $$| $$  | $$ /$$__  $$      | $$  | $$| $$  | $$| $$  | $$ /$$__  $$      | $$      | $$| $$  | $$
                     		|  $$$$$$/|  $$$$$$/| $$$$$$$/|  $$$$$$$      | $$$$$$$/|  $$$$$$/| $$$$$$$/|  $$$$$$$      | $$      | $$|  $$$$$$$ /$$
                     		\______/  \______/ | $$____/  \_______/      |_______/  \______/ | $$____/  \_______/      |__/      |__/ \____  $$|__/
                     									| $$                                          | $$                                     /$$  | $$
                     									| $$                                          | $$                                    |  $$$$$$/
                     									|__/                                          |__/                                     \______/     */


  ///////////////////////
  // UTILITY FUNCTIONS //
  ///////////////////////

  //some utility functions
  function randomInRange(min, max) {return Math.random() * (max - min) + min;}

  //I'll leave this here just in case anyone wants to play with the particles rgb channels
  //(P-P-PROTIP: setting the blue and red channels with this function makes for a cool palette)
  function randomIntInRange(min, max) {return ~~(Math.random() * (max - min) + min);}


  function mergeObjects(target, object, deep = false) {

    for (let prop in object) {
      if (target.hasOwnProperty(prop)) {
        if (typeof object[prop] === 'object' && deep) {
          target[prop] = mergeObjects(target[prop], object[prop], true);
        } else {
          target[prop] = object[prop];
        }
      } else {
        target[prop] = object[prop];
      }
    }

    return target;

  }


  function chooseRandomFrom(array) {return array[~~(Math.random() * array.length)];}


  function createSupaDupaGradient(context) {

    const canvas = context.canvas,gradient = context.createRadialGradient(canvas.width / 2, canvas.height / 2, canvas.width / 5, canvas.width / 2, canvas.height / 2, canvas.width * 0.7);

    gradient.addColorStop(0, '#550e8f');
    gradient.addColorStop(1, '#101010');

    return gradient;

  }


  //create a canvas with the same size of a given one and return its context
  function createCanvasFrom(canvas) {

    const referenceCanvas = document.createElement('canvas');

    const $referenceCanvas = referenceCanvas.getContext('2d');

    $referenceCanvas.canvas.width = referenceCanvas.width = canvas.width;
    $referenceCanvas.canvas.height = referenceCanvas.height = canvas.height;

    return $referenceCanvas;

  }


  //create a new canvas fitting it inside a parent container specified by the user
  function createFitCanvas(element) {

    const canvas = document.createElement('canvas');
    const $canvas = canvas.getContext('2d');

    $canvas.canvas.width = canvas.width = element.offsetWidth;
    $canvas.canvas.height = canvas.height = element.offsetHeight;

    canvas.style.position = 'absolute'; //so it fits snuggly in its container

    element.append(canvas);

    return canvas;

  }


  //get active pixels from the canvas we are rendering the text to
  function getAlphaPixelsFromImage(imageData, step = 2) {

    const alphaPixels = [];

    for (let i = 0, counter = 0; i < imageData.data.length; i++) {

      if (imageData.data[i]) {

        counter++;

        if ((i - 3) % 4 === 0 && counter % step === 0 && Math.random() > 0.5) {

          alphaPixels.push({
            r: imageData.data[i - 3],
            g: imageData.data[i - 2],
            b: imageData.data[i - 1],
            alpha: imageData.data[i],
            pixelIndex: (i - 3) / 4 });


        }

      }

    }

    return alphaPixels;

  }


  //get an array of Floats containing the particle data we are etracting from our render text
  function getParticlesFromImage(imageData, { particleProps, particleMaxRadius, pointSpacing, palette }) {

    const alphaPixels = getAlphaPixelsFromImage(imageData, pointSpacing);

    const particlesArray = new Float32Array(alphaPixels.length * particleProps);

    for (let i = 0, particlePointer = 0, x = undefined, y = undefined, color = undefined; i < alphaPixels.length; i++) {

      if (palette) {color = chooseRandomFrom(palette);}

      x = alphaPixels[i].pixelIndex % imageData.width;
      y = alphaPixels[i].pixelIndex / imageData.width;

      particlePointer = i * particleProps;

      particlesArray[particlePointer++] = x; //position.x ========= +0 (aka particlePointer's current value, aka a particle's address in memory)
      particlesArray[particlePointer++] = y; //position.y ========= +1
      particlesArray[particlePointer++] = x; //targetPosition.x === +2
      particlesArray[particlePointer++] = y; //targetPosition.y === +3
      particlesArray[particlePointer++] = randomInRange(0, 1000); //particle.rotationProgress.x ====== +4
      particlesArray[particlePointer++] = randomInRange(0, 1000); //particle.rotationProgress.y ====== +5
      particlesArray[particlePointer++] = randomInRange(-1, 1); //particle.direction.x ============= +6
      particlesArray[particlePointer++] = randomInRange(-1, 1); //particle.direction.y ============= +7
      particlesArray[particlePointer++] = randomInRange(0.5, particleMaxRadius); //particle.radius === +8

      //colorRGBA values for each particle
      particlesArray[particlePointer++] = palette ? color["r"] : alphaPixels[i].r; //particles's color's "red" channel ===== +9
      particlesArray[particlePointer++] = palette ? color["g"] : alphaPixels[i].g; //particles's color's "green" channel === +10
      particlesArray[particlePointer++] = palette ? color["b"] : alphaPixels[i].b; //particles's color's "blue" channel ==== +11
      particlesArray[particlePointer] = alphaPixels[i].alpha; //particles's color's "alpha" channel ====================== +12

    }

    return particlesArray;

  }


  /////////////
  // CLASSES //
  /////////////

  class ParticleText {

    constructor(string, element, options = {}) {_defineProperty(this, "animate",
      () => {
        this.renderParticles(this.settings.particles);
        this.frameID = window.requestAnimationFrame(this.animate);
      });const _particleProps = 13; //<----- you shouldn't touch this guy right here, but I ain't your dad, so if you really want to, go ahead and change it
      //setting up the canvases needed for ParticleText
      const canvas = createFitCanvas(element);const $referenceCanvas = createCanvasFrom(canvas);const _defaults = { particles: { //canvas background color
          background: undefined, //particle shape
          pointSpacing: 5, particleMaxRadius: 2, palette: [], //particle motion
          revolutionRadius: 2, revolutionSlowness: 5, //only update half of the particles each cycle, repaint every other cycle
          enhancedRendering: true }, //text default settings
        text: { fontSize: 150, fontFamily: 'serif', padding: 50, lineHeight: undefined } }; //deep merge user supplied arguments and the defaults
      this.settings = mergeObjects(_defaults, options, true); //I am adding this property later simply because I don't want the user to change it easily
      //(If you are a professional reading this, how would you go about doing this in a cleaner way?? Comment below to let me know, it would be greatly appreciated!)
      this.settings.particles.particleProps = _particleProps; //reference to the parent element of the rendering canvas
      this.parent = element; //the a.........完整代码请登录后点击上方下载按钮下载查看

网友评论0