@silkytone/danmu
Version:
弹幕的简单实现,实现普通弹幕或高级弹幕。
2 lines (1 loc) • 7.09 kB
JavaScript
(function(c,u){typeof exports=="object"&&typeof module<"u"?u(exports):typeof define=="function"&&define.amd?define(["exports"],u):(c=typeof globalThis<"u"?globalThis:c||self,u(c.Danmu={}))})(this,function(c){"use strict";function u(i){return Object.prototype.toString.call(i).slice(8,-1)}function h(i,t){return u(i).toLowerCase()===t.toLowerCase()}function k(i){return h(i,"array")}function m(i){return x(i)?!1:h(i,"object")}function x(i){return h(i,"function")}function p(i){return h(i,"string")}function z(i){return h(i,"number")}function O(i){return h(i,"boolean")}function j(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(j(s))return e;for(const[n,r]of Object.entries(s)){const o=e[n];m(r)&&m(o)?e[n]=T(o,r):e[n]=r}return e},{...i})}function A(i){return p(i)?i:Object.keys(i).reduce((t,e)=>(t.push(`${e}:${i[e]};`),t),[]).join("")}function P(i){return k(i)?i.filter(Boolean).join(" "):m(i)&&!p(i)?Object.keys(i).reduce((t,e)=>(i[e]&&t.push(e),t),[]).join(" "):i}function _(i,t){for(const[e,s]of Object.entries(t))i.addEventListener(e,s)}function b(i,t={},e=[]){const s=document.createElement(i);for(const[n,r]of Object.entries(t))n==="style"?s.style.cssText=A(r):n==="class"?s.className=P(r):n==="on"?_(s,r):s.setAttribute(n,r);if(e.length){const n=e.map(r=>p(r)?document.createTextNode(r):r);s.replaceChildren(...n)}return s}const f=()=>{var i;return((i=window.performance)==null?void 0:i.now())||Date.now()},E=Object.freeze(Object.defineProperty({__proto__:null,VNode:b,getTime:f,getType:u,isArray:k,isBoolean:O,isEmpty:j,isFunction:x,isNumber:z,isObject:m,isString:p,isType:h,mergeObject:T},Symbol.toStringTag,{value:"Module"}));class v{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 w=function(i){return window.requestAnimationFrame||i.webkitRequestAnimationFrame||i.mozRequestAnimationFrame||i.oRequestAnimationFrame||i.msRequestAnimationFrame||function(){let t=0;return function(e){i.setTimeout(()=>{e(f()-t)},1e3/6)}}()}(window);class F{count=0;__limit=0;status=!1;last={fps:0,records:0};listener=new v;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=f();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=f();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=f();const s=(n=0)=>{if(this.status)if(this.getFps(),this.getRecords(),this.limit){w(s);const r=1e3/this.limit;setTimeout(()=>t(n),r-(f()-e)%r)}else t(n),w(s)};w(s)}stop(){this.status=!1}}class ${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,d=n-a;l<d;l+=1){let y=0;for(let g=0;g<a;g+=1){const S=this.occupied[l+g];if(!S.length)y+=1;else{const{end:C,delay:D}=S[S.length-1];if(C+D<s)y+=1;else{l+=g,y=0;break}}if(y>=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 d=0;d<l.count;d++)this.occupied[l.index+d].push({start:o,end:a,delay:r});return l}destroy(){this.occupied=Array.from({length:this.tracks}).map(()=>[])}}const M=Object.freeze(Object.defineProperty({__proto__:null,Animation:F,AnimationFrame:w,Listener:v,Tracks:$},Symbol.toStringTag,{value:"Module"}));class B{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 v}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 R extends B{duration;constructor(t,e=3){super(b("div",{class:"var-barrage-item is-text",style:{display:"inline-block"}},[b("span",{},[t])])),this.duration=e,this.$el.style.whiteSpace="nowrap"}}class L{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 F(this.opt.limit),this.size={width:this.$el.clientWidth,height:this.$el.clientHeight},this.tracks=new $({...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)}}c.Barrage=L,c.Lib=M,c.TextBarrage=R,c.Utils=E,Object.defineProperty(c,Symbol.toStringTag,{value:"Module"})});