siriwave
Version:
The Siri wave replicated in a JS library.
16 lines (13 loc) • 9.37 kB
JavaScript
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
class t{constructor(t,i){this.ATT_FACTOR=4,this.GRAPH_X=2,this.AMPLITUDE_FACTOR=.6,this.ctrl=t,this.definition=i}globalAttFn(t){return Math.pow(this.ATT_FACTOR/(this.ATT_FACTOR+Math.pow(t,this.ATT_FACTOR)),this.ATT_FACTOR)}xPos(t){return this.ctrl.width*((t+this.GRAPH_X)/(2*this.GRAPH_X))}yPos(t){return this.AMPLITUDE_FACTOR*(this.globalAttFn(t)*(this.ctrl.heightMax*this.ctrl.amplitude)*(1/this.definition.attenuation)*Math.sin(this.ctrl.opt.frequency*t-this.ctrl.phase))}draw(){const{ctx:t}=this.ctrl;t.moveTo(0,0),t.beginPath();const i=(this.definition.color||this.ctrl.color).replace(/rgb\(/g,"").replace(/\)/g,"");t.strokeStyle=`rgba(${i},${this.definition.opacity})`,t.lineWidth=this.definition.lineWidth;for(let i=-this.GRAPH_X;i<=this.GRAPH_X;i+=this.ctrl.opt.pixelDepth)t.lineTo(this.xPos(i),this.ctrl.heightMax+this.yPos(i));t.stroke()}static getDefinition(){return[{attenuation:-2,lineWidth:1,opacity:.1},{attenuation:-6,lineWidth:1,opacity:.2},{attenuation:4,lineWidth:1,opacity:.4},{attenuation:2,lineWidth:1,opacity:.6},{attenuation:1,lineWidth:1.5,opacity:1}]}}class i{constructor(t,i){this.GRAPH_X=25,this.AMPLITUDE_FACTOR=.8,this.SPEED_FACTOR=1,this.DEAD_PX=2,this.ATT_FACTOR=4,this.DESPAWN_FACTOR=.02,this.DEFAULT_NOOFCURVES_RANGES=[2,5],this.DEFAULT_AMPLITUDE_RANGES=[.3,1],this.DEFAULT_OFFSET_RANGES=[-3,3],this.DEFAULT_WIDTH_RANGES=[1,3],this.DEFAULT_SPEED_RANGES=[.5,1],this.DEFAULT_DESPAWN_TIMEOUT_RANGES=[500,2e3],this.ctrl=t,this.definition=i,this.noOfCurves=0,this.spawnAt=0,this.prevMaxY=0,this.phases=[],this.offsets=[],this.speeds=[],this.finalAmplitudes=[],this.widths=[],this.amplitudes=[],this.despawnTimeouts=[],this.verses=[]}getRandomRange(t){return t[0]+Math.random()*(t[1]-t[0])}spawnSingle(t){var i,s,e,h,o,a,r,n,l,p;this.phases[t]=0,this.amplitudes[t]=0,this.despawnTimeouts[t]=this.getRandomRange(null!==(s=null===(i=this.ctrl.opt.ranges)||void 0===i?void 0:i.despawnTimeout)&&void 0!==s?s:this.DEFAULT_DESPAWN_TIMEOUT_RANGES),this.offsets[t]=this.getRandomRange(null!==(h=null===(e=this.ctrl.opt.ranges)||void 0===e?void 0:e.offset)&&void 0!==h?h:this.DEFAULT_OFFSET_RANGES),this.speeds[t]=this.getRandomRange(null!==(a=null===(o=this.ctrl.opt.ranges)||void 0===o?void 0:o.speed)&&void 0!==a?a:this.DEFAULT_SPEED_RANGES),this.finalAmplitudes[t]=this.getRandomRange(null!==(n=null===(r=this.ctrl.opt.ranges)||void 0===r?void 0:r.amplitude)&&void 0!==n?n:this.DEFAULT_AMPLITUDE_RANGES),this.widths[t]=this.getRandomRange(null!==(p=null===(l=this.ctrl.opt.ranges)||void 0===l?void 0:l.width)&&void 0!==p?p:this.DEFAULT_WIDTH_RANGES),this.verses[t]=this.getRandomRange([-1,1])}getEmptyArray(t){return new Array(t)}spawn(){var t,i;this.spawnAt=Date.now(),this.noOfCurves=Math.floor(this.getRandomRange(null!==(i=null===(t=this.ctrl.opt.ranges)||void 0===t?void 0:t.noOfCurves)&&void 0!==i?i:this.DEFAULT_NOOFCURVES_RANGES)),this.phases=this.getEmptyArray(this.noOfCurves),this.offsets=this.getEmptyArray(this.noOfCurves),this.speeds=this.getEmptyArray(this.noOfCurves),this.finalAmplitudes=this.getEmptyArray(this.noOfCurves),this.widths=this.getEmptyArray(this.noOfCurves),this.amplitudes=this.getEmptyArray(this.noOfCurves),this.despawnTimeouts=this.getEmptyArray(this.noOfCurves),this.verses=this.getEmptyArray(this.noOfCurves);for(let t=0;t<this.noOfCurves;t++)this.spawnSingle(t)}globalAttFn(t){return Math.pow(this.ATT_FACTOR/(this.ATT_FACTOR+Math.pow(t,2)),this.ATT_FACTOR)}sin(t,i){return Math.sin(t-i)}yRelativePos(t){let i=0;for(let s=0;s<this.noOfCurves;s++){let e=4*(s/(this.noOfCurves-1)*2-1);e+=this.offsets[s];const h=t*(1/this.widths[s])-e;i+=Math.abs(this.amplitudes[s]*this.sin(this.verses[s]*h,this.phases[s])*this.globalAttFn(h))}return i/this.noOfCurves}yPos(t){return this.AMPLITUDE_FACTOR*this.ctrl.heightMax*this.ctrl.amplitude*this.yRelativePos(t)*this.globalAttFn(t/this.GRAPH_X*2)}xPos(t){return this.ctrl.width*((t+this.GRAPH_X)/(2*this.GRAPH_X))}drawSupportLine(){const{ctx:t}=this.ctrl,i=[0,this.ctrl.heightMax,this.ctrl.width,1],s=t.createLinearGradient.apply(t,i);s.addColorStop(0,"transparent"),s.addColorStop(.1,"rgba(255,255,255,.5)"),s.addColorStop(.8,"rgba(255,255,255,.5)"),s.addColorStop(1,"transparent"),t.fillStyle=s,t.fillRect.apply(t,i)}draw(){const{ctx:t}=this.ctrl;if(t.globalAlpha=.7,t.globalCompositeOperation=this.ctrl.opt.globalCompositeOperation,0===this.spawnAt&&this.spawn(),this.definition.supportLine)return this.drawSupportLine();for(let t=0;t<this.noOfCurves;t++)this.spawnAt+this.despawnTimeouts[t]<=Date.now()?this.amplitudes[t]-=this.DESPAWN_FACTOR:this.amplitudes[t]+=this.DESPAWN_FACTOR,this.amplitudes[t]=Math.min(Math.max(this.amplitudes[t],0),this.finalAmplitudes[t]),this.phases[t]=(this.phases[t]+this.ctrl.speed*this.speeds[t]*this.SPEED_FACTOR)%(2*Math.PI);let i=-1/0;for(const s of[1,-1]){t.beginPath();for(let e=-this.GRAPH_X;e<=this.GRAPH_X;e+=this.ctrl.opt.pixelDepth){const h=this.xPos(e),o=this.yPos(e);t.lineTo(h,this.ctrl.heightMax-s*o),i=Math.max(i,o)}t.closePath(),t.fillStyle=`rgba(${this.definition.color}, 1)`,t.strokeStyle=`rgba(${this.definition.color}, 1)`,t.fill()}return i<this.DEAD_PX&&this.prevMaxY>i&&(this.spawnAt=0),this.prevMaxY=i,null}static getDefinition(){return[{color:"255,255,255",supportLine:!0},{color:"15, 82, 169"},{color:"173, 57, 76"},{color:"48, 220, 155"}]}}class s{constructor(s){var{container:e}=s,h=function(t,i){var s={};for(var e in t)Object.prototype.hasOwnProperty.call(t,e)&&i.indexOf(e)<0&&(s[e]=t[e]);if(null!=t&&"function"==typeof Object.getOwnPropertySymbols){var h=0;for(e=Object.getOwnPropertySymbols(t);h<e.length;h++)i.indexOf(e[h])<0&&Object.prototype.propertyIsEnumerable.call(t,e[h])&&(s[e[h]]=t[e[h]])}return s}(s,["container"]);this.phase=0,this.run=!1,this.curves=[];const o=window.getComputedStyle(e);this.opt=Object.assign({container:e,style:"ios",ratio:window.devicePixelRatio||1,speed:.2,amplitude:1,frequency:6,color:"#fff",cover:!1,width:parseInt(o.width.replace("px",""),10),height:parseInt(o.height.replace("px",""),10),autostart:!0,pixelDepth:.02,lerpSpeed:.1,globalCompositeOperation:"lighter"},h),this.speed=Number(this.opt.speed),this.amplitude=Number(this.opt.amplitude),this.width=Number(this.opt.ratio*this.opt.width),this.height=Number(this.opt.ratio*this.opt.height),this.heightMax=Number(this.height/2)-6,this.color=`rgb(${this.hex2rgb(this.opt.color)})`,this.interpolation={speed:this.speed,amplitude:this.amplitude},this.canvas=document.createElement("canvas");const a=this.canvas.getContext("2d");if(null===a)throw new Error("Unable to create 2D Context");if(this.ctx=a,this.canvas.width=this.width,this.canvas.height=this.height,!0===this.opt.cover?this.canvas.style.width=this.canvas.style.height="100%":(this.canvas.style.width=this.width/this.opt.ratio+"px",this.canvas.style.height=this.height/this.opt.ratio+"px"),"ios9"===this.opt.style)this.curves=(this.opt.curveDefinition||i.getDefinition()).map((t=>new i(this,t)));else this.curves=(this.opt.curveDefinition||t.getDefinition()).map((i=>new t(this,i)));this.opt.container.appendChild(this.canvas),this.opt.autostart&&this.start()}hex2rgb(t){t=t.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i,((t,i,s,e)=>i+i+s+s+e+e));const i=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(t);return i?`${parseInt(i[1],16).toString()},${parseInt(i[2],16).toString()},${parseInt(i[3],16).toString()}`:null}intLerp(t,i,s){return t*(1-s)+i*s}lerp(t){const i=this.interpolation[t];return null!==i&&(this[t]=this.intLerp(this[t],i,this.opt.lerpSpeed),this[t]-i==0&&(this.interpolation[t]=null)),this[t]}clear(){this.ctx.globalCompositeOperation="destination-out",this.ctx.fillRect(0,0,this.width,this.height),this.ctx.globalCompositeOperation="source-over"}draw(){this.curves.forEach((t=>t.draw()))}startDrawCycle(){this.clear(),this.lerp("amplitude"),this.lerp("speed"),this.draw(),this.phase=(this.phase+Math.PI/2*this.speed)%(2*Math.PI),window.requestAnimationFrame?this.animationFrameId=window.requestAnimationFrame(this.startDrawCycle.bind(this)):this.timeoutId=setTimeout(this.startDrawCycle.bind(this),20)}start(){if(!this.canvas)throw new Error("This instance of SiriWave has been disposed, please create a new instance");this.phase=0,this.run||(this.run=!0,this.startDrawCycle())}stop(){this.phase=0,this.run=!1,this.animationFrameId&&window.cancelAnimationFrame(this.animationFrameId),this.timeoutId&&clearTimeout(this.timeoutId)}dispose(){this.stop(),this.canvas&&(this.canvas.remove(),this.canvas=null)}set(t,i){this.interpolation[t]=i}setSpeed(t){this.set("speed",t)}setAmplitude(t){this.set("amplitude",t)}}export{s as default};