简单介绍
类似电影里的魔法效果
轨迹次数速度都可以自己改改
效果图
源代码
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