@silkytone/danmu
Version:
弹幕的简单实现,实现普通弹幕或高级弹幕。
2 lines (1 loc) • 6.91 kB
JavaScript
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function v(i){return Object.prototype.toString.call(i).slice(8,-1)}function c(i,t){return v(i).toLowerCase()===t.toLowerCase()}function k(i){return c(i,"array")}function p(i){return S(i)?!1:c(i,"object")}function S(i){return c(i,"function")}function w(i){return c(i,"string")}function O(i){return c(i,"number")}function A(i){return c(i,"boolean")}function x(i){return["",null,void 0].includes(i)?!0:(k(i)?i:Object.keys(i)).length===0}function T(i,...t){return t.reduce((e,s)=>{if(x(s))return e;for(const[n,r]of Object.entries(s)){const o=e[n];p(r)&&p(o)?e[n]=T(o,r):e[n]=r}return e},{...i})}function P(i){return w(i)?i:Object.keys(i).reduce((t,e)=>(t.push(`${e}:${i[e]};`),t),[]).join("")}function _(i){return k(i)?i.filter(Boolean).join(" "):p(i)&&!w(i)?Object.keys(i).reduce((t,e)=>(i[e]&&t.push(e),t),[]).join(" "):i}function E(i,t){for(const[e,s]of Object.entries(t))i.addEventListener(e,s)}function g(i,t={},e=[]){const s=document.createElement(i);for(const[n,r]of Object.entries(t))n==="style"?s.style.cssText=P(r):n==="class"?s.className=_(r):n==="on"?E(s,r):s.setAttribute(n,r);if(e.length){const n=e.map(r=>w(r)?document.createTextNode(r):r);s.replaceChildren(...n)}return s}const h=()=>{var i;return((i=window.performance)==null?void 0:i.now())||Date.now()},M=Object.freeze(Object.defineProperty({__proto__:null,VNode:g,getTime:h,getType:v,isArray:k,isBoolean:A,isEmpty:x,isFunction:S,isNumber:O,isObject:p,isString:w,isType:c,mergeObject:T},Symbol.toStringTag,{value:"Module"}));class b{listener={};on(t,e){this.listener[t]||(this.listener[t]=[]),this.listener[t].push(e)}off(t,e){this.listener[t]&&(this.listener[t]=this.listener[t].filter(s=>s!==e))}emit(t,e){this.listener[t]&&this.listener[t].forEach(s=>{s(e)})}once(t,e){const s=n=>{this.off(t,s),e(n)};this.on(t,s)}clear(){this.listener={}}}const m=function(i){return window.requestAnimationFrame||i.webkitRequestAnimationFrame||i.mozRequestAnimationFrame||i.oRequestAnimationFrame||i.msRequestAnimationFrame||function(){let t=0;return function(e){i.setTimeout(()=>{e(h()-t)},1e3/6)}}()}(window);class j{count=0;__limit=0;status=!1;last={fps:0,records:0};listener=new b;get limit(){return this.__limit}set limit(t){if(isNaN(t))throw new Error("FPS must be a number");if([1/0,-1/0].includes(t))throw new Error("FPS cannot be Infinity, set it to 0 if you need to remove the restriction");this.__limit=t}constructor(t=0){this.limit=t,this.status=!1}getFps(){const t=h();this.last.fps?(this.count+=1,t-this.last.fps>1e3&&(this.listener.emit("FPS",this.count),this.last.fps=t,this.count=1)):(this.count=1,this.last.fps=t)}getRecords(){const t=h();if(this.last&&this.last.records!==t){const e=1e3/(t-this.last.records);this.listener.emit("RealTimeFPS",parseFloat(e.toFixed(1)))}this.last.records=t}on(t,e){if(!["FPS","RealTimeFPS"].includes(t))throw new Error("Invalid listener type");this.listener.on(t,e)}off(t,e){if(!["FPS","RealTimeFPS"].includes(t))throw new Error("Invalid listener type");this.listener.off(t,e)}run(t){this.status=!0;let e=h();const s=(n=0)=>{if(this.status)if(this.getFps(),this.getRecords(),this.limit){m(s);const r=1e3/this.limit;setTimeout(()=>t(n),r-(h()-e)%r)}else t(n),m(s)};m(s)}stop(){this.status=!1}}class F{gap;tracks;trackSize;size;occupied;constructor({width:t,height:e,trackSize:s=20,tracks:n=void 0,gap:r=0}){this.size={width:t,height:e},this.gap=r||0,n!==void 0?(this.tracks=n,this.trackSize=Math.round((e-(n-1)*r)/n)):(this.trackSize=s,this.tracks=Math.max(Math.floor((e+r)/(s+r)),1)),this.occupied=Array.from({length:this.tracks}).map(()=>[])}trackToPx(t){return t*(this.trackSize+this.gap)}prune(t){t=t||Date.now(),this.occupied.forEach((e,s)=>{this.occupied[s]=e.filter(({end:n})=>n>t)})}check(t,e,s){this.prune(e);const{tracks:n,trackSize:r,gap:o}=this,a=Math.ceil(t/(r+o));if(!(n<a))for(let l=0,u=n-a;l<u;l+=1){let f=0;for(let d=0;d<a;d+=1){const y=this.occupied[l+d];if(!y.length)f+=1;else{const{end:$,delay:z}=y[y.length-1];if($+z<s)f+=1;else{l+=d,f=0;break}}if(f>=a)return{index:l,count:a}}}}add(t,e,s,n){const r=Math.ceil(t/(this.size.width/s)),o=n||Date.now(),a=o+s,l=this.check(e,o,a);if(!l)return null;for(let u=0;u<l.count;u++)this.occupied[l.index+u].push({start:o,end:a,delay:r});return l}destroy(){this.occupied=Array.from({length:this.tracks}).map(()=>[])}}const B=Object.freeze(Object.defineProperty({__proto__:null,Animation:j,AnimationFrame:m,Listener:b,Tracks:F},Symbol.toStringTag,{value:"Module"}));class R{listener;get height(){return this.$el.offsetHeight}get width(){return this.$el.offsetWidth}$el;constructor(t){t.style.transform="translateX(0)",t.style.willChange="transform",t.style.position="absolute",t.style.left="100%",t.style.top="0",this.$el=t,this.listener=new b}destroy(){this.$el.remove()}on(t,e){this.listener.on(t,e)}off(t,e){this.listener.off(t,e)}once(t,e){this.listener.once(t,e)}}class L extends R{duration;constructor(t,e=3){super(g("div",{class:"var-barrage-item is-text",style:{display:"inline-block"}},[g("span",{},[t])])),this.duration=e,this.$el.style.whiteSpace="nowrap"}}class C{tracks;$el;animation;opt;size;moveTracks=[];waitTracks=[];status=!1;constructor(t,e){this.opt=T({limit:60},e||{}),this.$el=this.createElement(t),this.animation=new j(this.opt.limit),this.size={width:this.$el.clientWidth,height:this.$el.clientHeight},this.tracks=new F({...this.opt,...this.size})}createElement(t){const e=(()=>{if(typeof t=="string"){const s=document.querySelector(t);if(!s)throw new Error("element not found");return s}else return t})();return e.innerHTML="",e.style.width="100%",e.style.height="100%",e.style.overflow="hidden",e.style.userSelect="none",e.style.position="relative",e.style.pointerEvents="none",e}playAnimation(){if(this.status)return;this.status=!0;const t=this.size.width;this.animation.run(()=>{const e=Date.now();for(const[s,n]of Object.entries(this.moveTracks)){const r=(e-n.start)*n.step,o=t+n.value.width;r>o?(n.value.destroy(),this.moveTracks.splice(parseInt(s),1)):n.value.$el.style.transform=`translateX(-${r}px)`}this.addWaitTracks(),this.moveTracks.length||(this.animation.stop(),this.status=!1)})}addWaitTracks(){if(!this.waitTracks.length)return!1;this.waitTracks=this.waitTracks.filter(t=>{const e=Date.now(),{$el:s,width:n,height:r,duration:o}=t,a=this.tracks.add(n,r,o,e);if(a){s.style.top=this.tracks.trackToPx(a.index)+"px";const l=Math.ceil(this.size.width/o*1e6)/1e6;return this.moveTracks.push({start:e,step:l,value:t}),this.playAnimation(),null}return t})}push(t){this.$el.appendChild(t.$el);const e=Date.now(),{$el:s,width:n,height:r,duration:o}=t,a=this.tracks.add(n,r,o,e);if(a){s.style.top=this.tracks.trackToPx(a.index)+"px";const l=Math.ceil(this.size.width/o*1e6)/1e6;this.moveTracks.push({start:e,step:l,value:t}),this.playAnimation()}else this.waitTracks.push(t)}}exports.Barrage=C;exports.Lib=B;exports.TextBarrage=L;exports.Utils=M;