三郎前端特效学习源代码:魔法旋转粒子动态渐变特效

本文介绍了如何创建一个类似电影魔法效果的前端特效,包括粒子旋转和动态渐变。提供了HTML、JavaScript和CSS的源代码,并且强调用户可以自定义轨迹次数和速度。文章分为三个部分,分别展示了HTML、JavaScript的两个不同部分。
摘要由CSDN通过智能技术生成

三郎前端特效学习源代码:魔法旋转粒子动态渐变特效

简单介绍

类似电影里的魔法效果
轨迹次数速度都可以自己改改

效果图

在这里插入图片描述
在这里插入图片描述

源代码

html部分


<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <style type="text/css">
      * {
    
        margin: 0;
        padding: 0;
      }
      #canvas {
    
        background-color: #000000;
      }
    </style>
    <title>Document</title>
  </head>
  <body>
    <canvas id="canvas"></canvas>
    <script src="proton.min.js"></script>
    <script src="index.js"></script>
  </body>
</html>

js部分

// 获取canvs
const canvas = document.getElementById("canvas");

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

// 创建proton实例
const proton = new Proton();

// 创建主魔法线条
const emitter1 = createEmitter();
// 存活时间2秒
emitter1.totalTime = 2;

// 添加到proton中
proton.addEmitter(emitter1);

//创建canvas renderer
const renderer = new Proton.CanvasRenderer(canvas);
// 添加renderer
proton.addRenderer(renderer);

// 初始化主魔法线的变动函数
let changeEmitter1 = changePosition(emitter1, Math.PI / 3.4);

// 第二条魔法线出现的标志
let flag = true;
// 第三条魔法线出现的标志
let flag2 = true;

// 第二条魔法线
let emitter2 = null;
// 第三条魔法线
let emitter3 = null;
// 第二条魔法线变动函数
let changeEmitter2 = null;
// 第三条魔法线的变动函数
let changeEmitter3 = null;

// let theta = 0;
// let a = 1000;

// 初始化画布绘画循环
function draw() {
   
  window.requestAnimationFrame(draw);

  // 发动第一条魔法线
  changeEmitter1.moveClockWise();

  // 在第一条魔法线发动的0.35秒后发动第二条
  if (emitter1.emitTime > 0.35 && flag) {
   
    emitter2 = createEmitter();
    emitter2.totalTime = 0.3;
    changeEmitter2 = changePosition(
      emitter2,
      changeEmitter1.get().theta,
      0,
      emitter1.p.x,
      emitter1.p.y
    );
    proton.addEmitter(emitter2);
    flag = false;
  }

  // 如果第二条魔法线已经初始化完成
  if (emitter2 && changeEmitter2) {
   
    changeEmitter2.moveStyle1();
  }

  // 在第一条魔法线发动的0.8秒后发动第三条
  if (emitter1.emitTime > 0.8 && flag2) {
   
    emitter3 = createEmitter();
    emitter3.totalTime = 1.2;
    changeEmitter3 = changePosition(
      emitter3,
      -1.2,
      0,
      emitter1.p.x,
      emitter1.p.y
    );
    proton.addEmitter(emitter3);
    flag2 = false;
  }

  // 如果第三条魔法线已经初始化完成
  if (emitter3 && changeEmitter3) {
   
    changeEmitter3.moveStyle2();
  }

  // theta += 0.1;
  // a -= 1;

  // emitter.p.x = (a * Math.cos(theta)) / theta + canvas.width / 2;
  // emitter.p.y = (a * Math.sin(theta)) / theta + canvas.height / 2;

  proton.update();
}

draw();

/**
 * 定义魔法线变化函数
 * @param {*} emitter
 * @param {*} theta 角度
 * @param {*} a y轴变化参数
 * @param {*} x 起始x坐标
 * @param {*} y 起始y坐标
 */
function changePosition(emitter, theta = Math.PI / 2, a = 600, x, y) {
   
  return {
   
    // 第一条魔法线变化样式
    moveClockWise: () => {
   
      theta += 0.1;
      theta *= 1.001;
      a -= 4;
      emitter.p.x = (a * Math.cos(theta)) / theta + canvas.width / 2;
      emitter.p.y = (a * Math.sin(theta)) / theta + canvas.height / 2;
    },
    // 第二条魔法线变化样式
    moveStyle1: () => {
   
      theta -= 0.05;
      a -= 20;
      emitter.p.x = -(a * Math.cos(theta)) / theta + x;
      emitter.p.y = (a * Math.sin(theta)) / theta + y;
    },
    // 第三条魔法线变化样式
    moveStyle2: () => {
   
      theta -= 0.03;

      a -= 20;
      emitter.p.x = -(a * Math.cos(theta)) / theta + x;
      emitter.p.y = (a * Math.sin(theta)) / theta + y;
    },

    // 获取当前魔法线的角度和y轴变化参数,用于确定后边出现的魔法线的位置
    get: () => {
   
      return {
    theta, a };
    }
  };
}

/**
 * 创建emitter
 */
function createEmitter() {
   
  const emitter = new Proton.Emitter();
  // 每多少秒发射几颗粒子,particle
  emitter.rate = new Proton.Rate(new Proton.Span(2, 8), 0.01);

  // emitter.addInitialize(new Proton.Position(new Proton.CircleZone(0, 0, 1, 1)));
  // 质量
  emitter.addInitialize(new Proton.Mass(1));
  // 半径
  emitter.addInitialize(new Proton.Radius(1, 3));
  // 生命
  emitter.addInitialize(new Proton.Life(2));
  // 速度
  emitter.addInitialize(
    new Proton.Velocity(
      new Proton.Span(-0.2, 0.2),
      new Proton.Span(0, 180),
      "polar"
    )
  );

  // 每个particle的颜色行为
  emitter.addBehaviour(new Proton.Color("#ffffff"));
  // 透明度从1到0 变化
  emitter.addBehaviour(new Proton.Alpha(1, 0));
  // 大小从0.6倍到0.4倍
  emitter.addBehaviour(new Proton.Scale(0.6, 0.4));

  // 起始位置
  emitter.p.x = canvas.width / 2;
  emitter.p.y = canvas.height / 2;

  // 发射
  emitter.emit();
  return emitter;
}

第二个js部分

不需要自己写 ,复制一下就行

/*!
* Proton v4.1.0
* https://github.com/a-jie/Proton
*
* Copyright 2013-2019, A-JIE
* Licensed under the MIT license
* http://www.opensource.org/licenses/mit-license
*
*/
!function(t,e){
   "object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.Proton=e()}(this,function(){
   "use strict";function s(t,e){
   if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var e=3.1415926,h={
   PI:e,PIx2:2*e,PI_2:e/2,PI_180:e/180,N180_PI:180/e,Infinity:-999,isInfinity:function(t){
   return t===this.Infinity||t===1/0},randomAToB:function(t,e,i){
   return 2<arguments.length&&void 0!==i&&i?Math.floor(Math.random()*(e-t))+t:t+Math.random()*(e-t)},randomFloating:function(t,e,i){
   return this.randomAToB(t-e,t+e,i)},randomColor:function(){
   return"#"+("00000"+(16777216*Math.random()<<0).toString(16)).slice(-6)},randomZone:function(){
   },floor:function(t,e){
   var i=1<arguments.length&&void 0!==e?e:4,a=Math.pow(10,i);return Math.floor(t*a)/a},degreeTransform:function(t){
   return t*e/180},toColor16:function(t){
   return"#"+t.toString(16)}},i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){
   return typeof t}:function(t){
   return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},t=function(t,e,i){
   return e&&a(t.prototype,e),i&&a(t,i),t};function a(t,e){
   for(var i=0;i<e.length;i++){
   var a=e[i];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(t,a.key,a)}}function o(t,e,i){
   null===t&&(t=Function.prototype);var a=Object.getOwnPropertyDescriptor(t,e);if(void 0===a){
   var r=Object.getPrototypeOf(t);return null===r?void 0:o(r,e,i)}if("value"in a)return a.value;var n=a.get;return void 0!==n?n.call(i):void 0}function r(t,e){
   if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{
   constructor:{
   value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function l(t,e){
   if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}var n=(t(u,[{
   key:"getValue",value:function(t){
   var e=0<arguments.length&&void 0!==t&&t;return this.isArray?P.getRandFromArray(this.a):this.center?h.randomFloating(this.a,this.b,e):h.randomAToB(this.a,this.b,e)}}],[{
   key:"setSpanValue",value:function(t,e,i){
   return t instanceof u?t:void 0===e?new u(t):void 0===i?new u(t,e):new u(t,e,i)}},{
   key:"getSpanValue",value:function(t){
   return t instanceof u?t.getValue():t}}]),u);function u(t,e,i){
   s(this,u),P.isArray(t)?(this.isArray=!0,this.a=t):(this.isArray=!1,this.a=P.initValue(t,1),this.b=P.initValue(e,this.a),this.center=P.initValue(i,!1))}var c=function(t){
   --t;for(var e=1;e<32;e<<=1)t|=t>>e;return t+1},d=function(t,e){
   return[1,0,0,0,1,0,t,e,1]},y=function(t){
   var e=Math.cos(t),i=Math.sin(t);return[e,-i,0,i,e,0,0,0,1]},p=function(t,e){
   return[t,0,0,0,e,0,0,0,1]},f=function(t,e){
   var i=t[0],a=t[1],r=t[2],n=t[3],s=t[4],o=t[5],h=t[6],l=t[7],u=t[8],c=e[0],d=e[1],y=e[2],p=e[3],f=e[4],v=e[5],g=e[6],m=e[7],b=e[8];return[i*c+a*p+r*g,i*d+a*f+r*m,i*y+a*v+r*b,n*c+s*p+o*g,n*d+s*f+o*m,n*y+s*v+o*b,h*c+l*p+u*g,h*d+l*f+u*m,h*y+l*v+u*b]},v={
   createCanvas:function(t,e,i,a){
   var r=3<arguments.length&&void 0!==a?a:"absolute",n=document.createElement("canvas");return n.id=t,n.width=e,n.height=i,n.style.opacity=0,n.style.position=r,this.transform(n,-500,-500,0,0),n},createDiv:function(t,e,i){
   var a=document.createElement("div");return a.id=t,a.style.position="absolute",this.resize(a,e,i),a},resize:function(t,e,i){
   t.style.width=e+"px",t.style.height=i+"px",t.style.marginLeft=-e/2+"px",t.style.marginTop=-i/2+"px"},transform:function(t,e,i,a,r){
   t.style.willChange="transform";var n="translate("+e+"px, "+i+"px) scale("+a+") rotate("+r+"deg)";this.css3(t,"transform",n)},transform3d:function(t,e,i,a,r){
   t.style.willChange="transform";var n="translate3d("+e+"px, "+i+"px, 0) scale("+a+") rotate("+r+"deg)";this.css3(t,"backfaceVisibility","hidden"),this.css3(t,"transform",n)},css3:function(t,e,i){
   var a=e.charAt(0).toUpperCase()+e.substr(1);t.style["Webkit"+a]=i,t.style["Moz"+a]=i,t.style["O"+a]=i,t.style["ms"+a]=i,t.style[""+e]=i}},g={
   },m={
   },b=0,_=function(t,e,i){
   t.drawImage(e,i.x,i.y);var a=t.getImageData(i.x,i.y,i.width,i.height);return t.clearRect(i.x,i.y,i.width,i.height),a},x=function(t,e,i){
   var a="string"==typeof t?t:t.src;if(g[a])e(g[a],i);else{
   var r=new Image;r.onload=function(t){
   g[a]=t.target,e(g[a],i)},r.src=a}},k=function(t,e,i){
   var a=t.src;if(!m[a]){
   var r=c(t.width),n=c(t.height),s=v.createCanvas("proton_canvas_cache_"+ ++b,r,n);s.getContext("2d").drawImage(t,0,0,t.width,t.height),m[a]=s}return e&&e(m[a],i),m[a]},P={
   initValue:function(t,e){
   return t=null!=t?t:e},isArray:function(t){
   return"[object Array]"===Object.prototype.toString.call(t)},emptyArray:function(t){
   t&&(t.length=0)},toArray:function(t){
   return this.isArray(t)?t:[t]},getRandFromArray:function(t){
   return t?t[Math.floor(t.length*Math.random())]:null},emptyObject:function(t,e){
   var i=1<arguments.length&&void 0!==e?e:null;for(var a in t)i&&-1<i.indexOf(a)||delete t[a]},classApply:function(t,e){
   var i=1<arguments.length&&void 0!==e?e:null;return i?new(t.bind.apply(t,[null].concat(i))):new t},setVectorVal:function(t,e){
   var i=1<arguments.length&&void 0!==e?e:null;i&&(this.hasProp(i,"x")&&(t.p.x=i.x),this.hasProp(i,"y")&&(t.p.y=i.y),this.hasProp(i,"vx")&&(t.v.x=i.vx),this.hasProp(i,"vy")&&(t.v.y=i.vy),this.hasProp(i,"ax")&&(t.a.x=i.ax),this.hasProp(i,"ay")&&(t.a.y=i.ay),this.hasProp(i,"p")&&t.p.copy(i.p),this.hasProp(i,"v")&&t.v.copy(i.v),this.hasProp(i,"a")&&t.a.copy(i.a),this.hasProp(i,"position")&&t.p.copy(i.position),this.hasProp(i,"velocity")&&t.v.copy(i.velocity),this.hasProp(i,"accelerate")&&t.a.copy(i.accelerate))},hasProp:function(t,e){
   return!!t&&void 0!==t[e]},setProp:function(t,e){
   for(var i in e)t.hasOwnProperty(i)&&(t[i]=n.getSpanValue(e[i]));return t},getImageData:function(t,e,i){
   return _(t,e,i)},destroyAll:function(t,e){
   for(var i=1<arguments.length&&void 0!==e?e:null,a=t.length;a--;){
   try{
   t[a].destroy(i)}catch(t){
   }delete t[a]}t.length=0}},E={
   },A={
   _index:0,_cache:{
   },id:function(t){
   return void 0!==E[t]&&null!==E[t]||(E[t]=0),t+"_"+E[t]++},getId:function(t){
   var e=this.getIdFromCache(t);return e||(e="PUID_"+this._index++,this._cache[e]=t,e)},getIdFromCache:function(t){
   var e=void 0,i=void 0;for(i in this._cache){
   if((e=this._cache[i])===t)return i;if(this.isBody(e,t)&&e.src===t.src)return i}return null},isBody:function(t,e){
   return"object"===(void 0===t?"undefined":i(t))&&"object"===(void 0===e?"undefined":i(e))&&t.isInner&&e.isInner},getTarget:function(t){
   return this._cache[t]}},T=(t(R,[{
   key:"get",value:function(t,e,i){
   var a=void 0;return i=i||t.__puid||A.getId(t),(a=this.cache[i]&&0<this.cache[i].length?this.cache[i].pop():this.createOrClone(t,e)).__puid=t.__puid||i,a}},{
   key:"expire",value:function(t){
   return this.getCache(t.__puid).push(t)}},{
   key:"createOrClone",value:function(t,e){
   return this.total++,this.create?this.create(t,e):"function"==typeof t?P.classApply(t,e):t.clone()}},{
   key:"getCount",value:function(){
   var t=0;for(var e in this.cache)t+=this.cache[e].length;return t++}},{
   key:"destroy",value:function(){
   for(var t in this.cache)this.cache[t].length=0,delete this.cache[t]}},{
   key:"getCache",value:function(t){
   var e=0<arguments.length&&void 0!==t?t:"default";return this.cache[e]||(this.cache[e]=[]),this.cache[e]}}]),R);function R(t){
   s(this,R),this.total=0,this.cache={
   }}var O=(t(w,[{
   key:"update",value:function(t,e){
   this.add(t,e);var i=this.getEmitter(),a=this.getRenderer(),r="";switch(this.type){
   case 2:r+="emitter:"+this.proton.emitters.length+"<br>",i&&(r+="em speed:"+i.emitSpeed+"<br>"),i&&(r+="pos:"+this.getEmitterPos(i));break;case 3:i&&(r+="initializes:"+i.initializes.length+"<br>"),i&&(r+='<span style="display:inline-block;">'+this.concatArr(i.initializes)+"</span><br>"),i&&(r+="behaviours:"+i.behaviours.length+"<br>"),i&&(r+='<span style="display:inline-block;">'+this.concatArr(i.behaviours)+"</span><br>");break;case 4:a&&(r+=a.name+"<br>"),a&&(r+="body:"+this.getCreatedNumber(a)+"<br>");break;default:r+="particles:"+this.proton.getCount()+"<br>",r+="pool:"+this.proton.pool.getCount()+"<br>",r+="total:"+this.proton.pool.total}this.container.innerHTML=r}},{
   key:"add",value:function(t,e){
   var i=this;if(!this.container){
   this.type=1,this.container=document.createElement("div"),this.container.style.cssText=["position:absolute;bottom:0px;left:0;cursor:pointer;","opacity:0.9;z-index:10000;padding:10px;font-size:12px;font-family:Helvetica,Arial,sans-serif;","width:120px;height:50px;background-color:#002;color:#0ff;"].join(""),this.container.addEventListener("click",function(t){
   i.type++,4<i.type&&(i.type=1)},!1);var a=void 0,r=void 0;switch(t){
   case 2:a="#201",r="#f08";break;case 3:a="#020",r="#0f0";break;default:a="#002",r="#0ff"}this.container.style["background-color"]=a,this.container.style.color=r}this.container.parentNode||(e=e||this.body||document.body).appendChild(this.container)}},{
   key:"getEmitter",value:function(){
   return this.proton.emitters[this.emitterIndex]}},{
   key:"getRenderer",value:function(){
   return this.proton.renderers[this.rendererIndex]}},{
   key:"concatArr",value:function(t){
   var e="";if(!t||!t.length)return e;for(var i=0;i<t.length;i++)e+=(t[i].name||"").substr(0,1)+".";return e}},{
   key:"getCreatedNumber",value:function(t){
   return t.pool.total||t.cpool&&t.cpool.total||0}},{
   key:"getEmitterPos",value:function(t){
   return Math.round(t.p.x)+","+Math.round(t.p.y)}}]),w);function w(t){
   s(this,w),this.proton=t,this.container=null,this.type=1,this.emitterIndex=0,this.rendererIndex=0}var C=(t(S,[{
   key:"addEventListener",value:function(t,e){
   return this._listeners?this.removeEventListener(t,e):this._listeners={
   },this._listeners[t]||(this._listeners[t]=[]),this._listeners[t].push(e),e}},{
   key:"removeEventListener",value:function(t,e){
   if(this._listeners&&this._listeners[t])for(var i=this._listeners[t],a=i.length,r=0;r<a;r++)if(i[r]===e){
   1===a?delete this._listeners[t]:i.splice(r,1);break}}},{
   key:"removeAllEventListeners",value:function(t){
   t?this._listeners&&delete this._listeners[t]:this._listeners=null}},{
   key:"dispatchEvent",value:function(t,e){
   var i=!1,a=this._listeners;if(t&&a){
   var r=a[t];if(!r)return i;for(var n=void 0,s=r.length;s--;)n=r[s],i=i||n(e)}return!!i}},{
   key:"hasEventListener",value:function(t){
   var e=this._listeners;return!(!e||!e[t])}}],[{
   key:"bind",value:function(t){
   t.prototype.dispatchEvent=S.prototype.dispatchEvent,t.prototype.hasEventListener=S.prototype.hasEventListener,t.prototype.addEventListener=S.prototype.addEventListener,t.prototype.removeEventListener=S.prototype.removeEventListener,t.prototype.removeAllEventListeners=S.prototype.removeAllEventListeners}}]),S);function S(){
   s(this,S),this._listeners=null}var I=(t(D,[{
   key:"calculate",value:function(t,e,i){
   this.eulerIntegrate(t,e,i)}},{
   key:"eulerIntegrate",value:function(t,e,i){
   t.sleep||(t.old.p.copy(t.p),t.old.v.copy(t.v),t.a.multiplyScalar(1/t.mass),t.v.add(t.a.multiplyScalar(e)),t.p.add(t.old.v.multiplyScalar(e)),i&&t.v.multiplyScalar(i),t.a.clear())}}]),D);function D(t){
   s(this,D),this.type=t}var V=(t(M,[{
   key:"addRenderer",value:function(t){
   t.init(this),this.renderers.push(t)}},{
   key:"removeRenderer",value:function(t){
   var e=this.renderers.indexOf(t);this.renderers.splice(e,1),t.remove(this)}},{
   key:"addEmitter",value:function(t){
   this.emitters.push(t),(t.parent=this).dispatchEvent(M.EMITTER_ADDED,t)}},{
   key:"removeEmitter",value:function(t){
   var e=this.emitters.indexOf(t);this.emitters.splice(e,1),t.parent=null,this
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值