custom-svga 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -0
- package/dist/ShapeRenderer-BbtJ_1XO.js +1 -0
- package/dist/ShapeRenderer-Cuwcq2MV.cjs +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +331 -0
- package/dist/index.esm.js +1 -0
- package/dist/index.global.js +1 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# 🎬 Custom SVGA
|
|
4
|
+
|
|
5
|
+
**A lightweight, tree-shakable SVGA animation player for Vue 3 & modern web.**
|
|
6
|
+
|
|
7
|
+
支持按需懒加载 · OffscreenCanvas 离屏渲染 · 动态精灵/文本替换 · TypeScript 全量类型
|
|
8
|
+
|
|
9
|
+
[](https://www.npmjs.com/package/custom-svga)
|
|
10
|
+
[](https://www.npmjs.com/package/custom-svga)
|
|
11
|
+
[](https://bundlephobia.com/package/custom-svga)
|
|
12
|
+
[](LICENSE)
|
|
13
|
+
[](https://www.typescriptlang.org/)
|
|
14
|
+
|
|
15
|
+
[English](#-features) · [中文说明](#-中文说明) · [API 文档](#-api-文档) · [更新日志](CHANGELOG.md)
|
|
16
|
+
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## ✨ Features
|
|
22
|
+
|
|
23
|
+
| 特性 | 说明 |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| 📦 **极致轻量** | gzip 后核心 ~30KB,无任何 UI 框架依赖 |
|
|
26
|
+
| 🌳 **Tree-shakable** | 完整 ESM 支持,按需引入方法,未使用代码自动剔除 |
|
|
27
|
+
| 🚀 **按需懒加载** | Parser / ShapeRenderer / Loader 全部支持动态 `import()`,首屏最小化 |
|
|
28
|
+
| ⚡ **OffscreenCanvas 渲染** | 主流渲染管线 0 主线程占用,60fps 不卡顿 |
|
|
29
|
+
| 👷 **共享 Web Worker** | 多 Player 实例复用同一 Worker,解析结果缓存共享 |
|
|
30
|
+
| 🧠 **LRU 智能缓存** | 自动管理解析后的 MovieData,避免重复解析 |
|
|
31
|
+
| 🎨 **动态形状渲染** | 内置 Path2D 矢量绘制,支持 rect / ellipse / SVG path |
|
|
32
|
+
| 🖼️ **运行时图片替换** | 不重编 SVGA 即可替换图层(URL / Base64 / ImageBitmap) |
|
|
33
|
+
| 📝 **动态文本注入** | 在动画播放中实时替换文本图层 |
|
|
34
|
+
| 🎯 **TypeScript 一等公民** | 完整 `.d.ts` 类型定义,IDE 智能提示开箱即用 |
|
|
35
|
+
| 🌐 **多产物输出** | ESM / CJS / IIFE 全场景覆盖(npm、script 标签、CDN) |
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 📥 Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# npm
|
|
43
|
+
npm install custom-svga
|
|
44
|
+
|
|
45
|
+
# yarn
|
|
46
|
+
yarn add custom-svga
|
|
47
|
+
|
|
48
|
+
# pnpm
|
|
49
|
+
pnpm add custom-svga
|
|
50
|
+
|
|
51
|
+
## 全局用法
|
|
52
|
+
|
|
53
|
+
<!-- unpkg -->
|
|
54
|
+
<script src="https://unpkg.com/custom-svga@latest/dist/index.global.js"></script>
|
|
55
|
+
|
|
56
|
+
<!-- jsDelivr -->
|
|
57
|
+
<script src="https://cdn.jsdelivr.net/npm/custom-svga@latest/dist/index.global.js"></script>
|
|
58
|
+
|
|
59
|
+
<script>
|
|
60
|
+
// 全局变量:CustomSvga
|
|
61
|
+
const { Player, Parser } = CustomSvga;
|
|
62
|
+
</script>
|
|
63
|
+
|
|
64
|
+
##
|
|
65
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class i{static instance;constructor(){}static getInstance(){return i.instance||(i.instance=new i),i.instance}drawShapes(e,h){for(const t of h){let a=null;if(t.type===0&&t.shape&&t.shape.d)a=new Path2D(t.shape.d);else if(t.type===1&&t.rect){const{x:s,y:n,width:l,height:r,cornerRadius:o}=t.rect;a=new Path2D,o>0?a.roundRect(s,n,l,r,o):a.rect(s,n,l,r)}else if(t.type===2&&t.ellipse){const{x:s,y:n,radiusX:l,radiusY:r}=t.ellipse;a=new Path2D,a.ellipse(s,n,l,r,0,0,2*Math.PI)}if(a&&t.styles){const{fill:s,stroke:n,strokeWidth:l,lineCap:r,lineJoin:o,miterLimit:f,lineDash:c}=t.styles;if(t.transform){e.save();const{a:p,b:y,c:d,d:m,tx:u,ty:w}=t.transform;e.transform(p,y,d,m,u,w)}s&&(e.fillStyle="rgba("+s.r*255+", "+s.g*255+", "+s.b*255+", "+s.a+")",e.fill(a)),n&&(e.strokeStyle="rgba("+n.r*255+", "+n.g*255+", "+n.b*255+", "+n.a+")",e.lineWidth=l||1,r&&(e.lineCap=r.toLowerCase()),o&&(e.lineJoin=o.toLowerCase()),f&&(e.miterLimit=f),c&&c.length>0?e.setLineDash(c):e.setLineDash([]),e.stroke(a)),t.transform&&e.restore()}}}}export{i as ShapeRenderer};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";class i{static instance;constructor(){}static getInstance(){return i.instance||(i.instance=new i),i.instance}drawShapes(e,h){for(const t of h){let a=null;if(t.type===0&&t.shape&&t.shape.d)a=new Path2D(t.shape.d);else if(t.type===1&&t.rect){const{x:s,y:n,width:l,height:r,cornerRadius:o}=t.rect;a=new Path2D,o>0?a.roundRect(s,n,l,r,o):a.rect(s,n,l,r)}else if(t.type===2&&t.ellipse){const{x:s,y:n,radiusX:l,radiusY:r}=t.ellipse;a=new Path2D,a.ellipse(s,n,l,r,0,0,2*Math.PI)}if(a&&t.styles){const{fill:s,stroke:n,strokeWidth:l,lineCap:r,lineJoin:o,miterLimit:f,lineDash:c}=t.styles;if(t.transform){e.save();const{a:p,b:y,c:d,d:u,tx:m,ty:w}=t.transform;e.transform(p,y,d,u,m,w)}s&&(e.fillStyle="rgba("+s.r*255+", "+s.g*255+", "+s.b*255+", "+s.a+")",e.fill(a)),n&&(e.strokeStyle="rgba("+n.r*255+", "+n.g*255+", "+n.b*255+", "+n.a+")",e.lineWidth=l||1,r&&(e.lineCap=r.toLowerCase()),o&&(e.lineJoin=o.toLowerCase()),f&&(e.miterLimit=f),c&&c.length>0?e.setLineDash(c):e.setLineDash([]),e.stroke(a)),t.transform&&e.restore()}}}}exports.ShapeRenderer=i;
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var F=typeof document<"u"?document.currentScript:null,d=(n=>(n.INIT="init",n.VISIBILITY="visibility",n.SET_MOVIE="setMovie",n.SET_IMAGE="setImage",n.SET_DYNAMIC_TEXT="setDynamicText",n.DRAW_EXTERNAL_POSTER="drawExternalPoster",n.PLAY="play",n.STOP="stop",n.PAUSE="pause",n.STEP_TO_FRAME="stepToFrame",n.STEP_TO_PERCENTAGE="stepToPercentage",n.CLEAR="clear",n.CLEAR_DYNAMIC_OBJECTS="clearDynamicObjects",n.CLEAR_DYNAMIC_OBJECT="clearDynamicObject",n.DESTROY="destroy",n.PARSE="parse",n.PARSE_OFFSCREEN="parse_offscreen",n.RELEASE_CACHE="releaseCache",n))(d||{}),k=(n=>(n.SUCCESS="SUCCESS",n.ERROR="ERROR",n.EVENT="event",n))(k||{}),g=(n=>(n.READY="ready",n.ON_START="onStart",n.ON_STOP="onStop",n.ON_PAUSE="onPause",n.ON_PROCESS="onProcess",n.ON_LOOP_END="onLoopEnd",n.ON_REQUEST_MOVIE_DATA="onRequestMovieData",n))(g||{});let w=null,D=null;const R=new Map;let W=0,C={};function Y(n){C={...C,...n}}const x=new Map;let L=null;function G(n){L=n}function I(){if(!w){if(C.workerCreator)w=C.workerCreator();else if(C.workerUrl)w=new Worker(C.workerUrl);else{let n;try{typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:F&&F.tagName.toUpperCase()==="SCRIPT"&&F.src||new URL("index.cjs",document.baseURI).href}<"u"&&(typeof document>"u"?require("url").pathToFileURL(__filename).href:F&&F.tagName.toUpperCase()==="SCRIPT"&&F.src||new URL("index.cjs",document.baseURI).href)?n=new URL("./svga.worker.ts",typeof document>"u"?require("url").pathToFileURL(__filename).href:F&&F.tagName.toUpperCase()==="SCRIPT"&&F.src||new URL("index.cjs",document.baseURI).href):n="./svga.worker.ts"}catch{n="./svga.worker.ts"}w=new Worker(n,{type:"module"})}w.onmessage=n=>{const{type:e,id:t,name:s,args:a,taskId:i}=n.data;if(i!==void 0){L&&L(n.data);return}const r=R.get(t);r&&e===k.EVENT&&(s===g.ON_START&&r.onStart?r.onStart():s===g.ON_STOP&&r.onStop?r.onStop():s===g.ON_PAUSE&&r.onPause?r.onPause():s===g.ON_LOOP_END&&r.onLoopEnd?r.onLoopEnd():s===g.ON_PROCESS&&r.onProcess?r.onProcess(a[0]):s===g.ON_REQUEST_MOVIE_DATA&&r.resendMovieData())}}return w}class V{id;canvas;observerIsVisible=!0;worker;onStart;onPause;onStop;onLoopEnd;onProcess;_dynamicKeys=new Set;_config;_shapeRendererInstance=null;_movieData=null;constructor(e,t){this.canvas=e,this.id=`renderer_${W++}`,this._config=Object.assign({loop:0,useIntersectionObserver:!0,useSharedRAF:!0,invisibleBehavior:"pause"},t),R.set(this.id,this),this.worker=I();const s=e.transferControlToOffscreen();this.worker.postMessage({type:d.INIT,id:this.id,canvas:s,config:this._config},[s]),this._config.useIntersectionObserver!==!1&&(!D&&typeof IntersectionObserver<"u"&&(D=new IntersectionObserver(a=>{a.forEach(i=>{Array.from(R.values()).filter(r=>r.canvas===i.target).forEach(r=>{r.observerIsVisible=i.isIntersecting,r.worker.postMessage({type:d.VISIBILITY,id:r.id,visible:r.observerIsVisible})})})})),D&&D.observe(this.canvas))}async resendMovieData(){if(this._movieData){const e=this._movieData.movieDataId||"movie_direct_"+Math.random().toString(36).substring(2)+Date.now(),t={},s=[];if(typeof createImageBitmap<"u"&&this._movieData.images){for(const[i,r]of Object.entries(this._movieData.images))if(r instanceof ImageBitmap)try{const o=await createImageBitmap(r);t[i]=o,s.push(o)}catch(o){console.warn("[\u79BB\u5C4F\u6E32\u67D3\u5668] \u91CD\u65B0\u53D1\u9001\u52A8\u753B\u6570\u636E\u65F6\u514B\u9686\u4F4D\u56FE\u5931\u8D25\uFF1A",o)}}const a={...this._movieData,images:t,imageBytes:void 0};x.set(this.id,e),this.worker.postMessage({type:d.SET_MOVIE,id:this.id,movieData:a,movieDataId:e},s)}}async setMovie(e){this._movieData=e;const t=e.movieDataId||"movie_direct_"+Math.random().toString(36).substring(2)+Date.now();x.set(this.id,t),this.worker.postMessage({type:d.SET_MOVIE,id:this.id,movieData:null,movieDataId:t})}async setImage(e,t){if(this._dynamicKeys.add(t),typeof createImageBitmap<"u")try{const s=await createImageBitmap(e);this.worker.postMessage({type:d.SET_IMAGE,id:this.id,key:t,image:s},[s])}catch(s){console.warn("[\u79BB\u5C4F\u6E32\u67D3\u5668] \u8BBE\u7F6E\u52A8\u6001\u56FE\u7247\u65F6\u514B\u9686\u4F4D\u56FE\u5BF9\u8C61\u5931\u8D25\uFF1A",s)}}setDynamicText(e,t){this._dynamicKeys.add(t),this.worker.postMessage({type:d.SET_DYNAMIC_TEXT,id:this.id,key:t,text:e})}setShapeRenderer(e){this._shapeRendererInstance=e}async drawExternalPoster(e){try{const t=await(await fetch(e)).blob(),s=await createImageBitmap(t);this.worker.postMessage({type:d.DRAW_EXTERNAL_POSTER,id:this.id,image:s},[s])}catch(t){console.warn("[\u79BB\u5C4F\u6E32\u67D3\u5668] \u8F7D\u5165\u5E76\u751F\u6210\u9759\u6001\u6D77\u62A5\u6D77\u62A5\u5931\u8D25\uFF1A",t)}}play(e){this.worker.postMessage({type:d.PLAY,id:this.id,config:e})}stop(){this.worker.postMessage({type:d.STOP,id:this.id})}pause(){this.worker.postMessage({type:d.PAUSE,id:this.id})}stepToFrame(e,t=!1){this.worker.postMessage({type:d.STEP_TO_FRAME,id:this.id,frame:e,andPlay:t})}stepToPercentage(e,t){this.worker.postMessage({type:d.STEP_TO_PERCENTAGE,id:this.id,percentage:e,andPlay:t})}clear(){this.worker.postMessage({type:d.CLEAR,id:this.id})}clearDynamicObject(e){this._dynamicKeys.delete(e),this.worker.postMessage({type:d.CLEAR_DYNAMIC_OBJECT,id:this.id,key:e})}clearDynamicObjects(){this._dynamicKeys.clear(),this.worker.postMessage({type:d.CLEAR_DYNAMIC_OBJECTS,id:this.id})}getMemoryInfo(){if(!this._movieData)return{fileSize:0,imageMemory:0,dictionaryMemory:0,version:"",fps:0,frames:0,width:0,height:0,dynamicKeys:[],desc:"\u672A\u52A0\u8F7D\u4EFB\u4F55\u52A8\u6548"};let e=0;this._movieData.images&&Object.values(this._movieData.images).forEach(c=>{c&&c.width&&(e+=c.width*c.height*4)});const t=JSON.stringify({params:this._movieData.params,sprites:this._movieData.sprites}).length,s=this._movieData.fileSize||0,a=this._movieData.version||"",i=this._movieData.params.fps||20,r=this._movieData.params.frames||0,o=this._movieData.params.viewBoxWidth||0,u=this._movieData.params.viewBoxHeight||0,h=Array.from(this._dynamicKeys);return{fileSize:s,imageMemory:e,dictionaryMemory:t,version:a,fps:i,frames:r,width:o,height:u,dynamicKeys:h,desc:`\u6E90\u6587\u4EF6\u5927\u5C0F: ${(s/1024).toFixed(2)} KB | \u9884\u4F30\u663E\u5B58(\u4F4D\u56FE\u4E0E\u7ED3\u6784): ${((e+t)/1024/1024).toFixed(2)} MB`}}destroy(){D&&D.unobserve(this.canvas),x.delete(this.id),R.delete(this.id),this.worker.postMessage({type:d.DESTROY,id:this.id})}}class N{static async loadUrl(e){const t=await fetch(e);if(!t.ok)throw new Error(`\u65E0\u6CD5\u4ECE ${e} \u52A0\u8F7D SVGA \u6587\u4EF6: ${t.statusText}`);return await t.arrayBuffer()}static async loadFile(e){return new Promise((t,s)=>{const a=new FileReader;a.onload=()=>{a.result instanceof ArrayBuffer?t(a.result):s(new Error("\u65E0\u6CD5\u8BFB\u53D6\u6587\u4EF6\u7684 ArrayBuffer \u6570\u636E"))},a.onerror=()=>s(a.error),a.readAsArrayBuffer(e)})}}let K=0;const M=new Map,f=new Map,$=20,S=new Map,p=new Map,T=new Map;function H(){if(f.size>$){const n=f.keys().next().value;n&&l.destroyCache(n)}}G(n=>{const{taskId:e,type:t,data:s,error:a}=n,i=M.get(e);if(i){const{useImageBitmap:r}=i;if(t===k.SUCCESS)if(s&&s.images&&!r){const o=[],u=s.images,h={};Object.keys(u).forEach(c=>{const m=u[c];if(m instanceof Uint8Array&&m.length>0){const y=new Promise(v=>{let E="image/png";m[0]===255&&m[1]===216?E="image/jpeg":m[0]===71&&m[1]===73&&m[2]===70?E="image/gif":m[0]===82&&m[1]===73&&m[2]===70&&m[3]===70&&(E="image/webp");const b=new Blob([m],{type:E}),P=URL.createObjectURL(b),A=new Image;A.onload=()=>{h[c]=A,URL.revokeObjectURL(P),v()},A.onerror=()=>{h[c]=A,URL.revokeObjectURL(P),v()},A.src=P});o.push(y)}else h[c]=m}),o.length>0?Promise.all(o).then(()=>{Object.keys(u).forEach(c=>{u[c]=null}),s.images=h,i.resolve(s)}).catch(c=>{i.reject(c)}):(s.images=h,i.resolve(s))}else i.resolve(s);else i.reject(new Error(a||"\u89E3\u6790 SVGA \u6587\u4EF6\u5931\u8D25"));M.delete(e)}});class l{static getCachedVideoItem(e){return f.get(e)}static async loadUrl(e,t){const s=t?.cache!==!1;if(s&&f.has(e)){const i=f.get(e);return f.delete(e),f.set(e,i),i}if(S.has(e))return S.get(e);const a=(async()=>{try{const i=await N.loadUrl(e),r=await l.parseBuffer(i,{...t,movieDataId:e});return s&&(f.set(e,r),H()),r}catch(i){throw S.delete(e),i}finally{S.delete(e)}})();return S.set(e,a),a}static async loadFile(e,t){const s=await N.loadFile(e);return await l.parseBuffer(s,t)}static parseBuffer(e,t){const s=t?.useImageBitmap??!1,a=t?.cache!==!1,i=t?.movieDataId||"movie_direct_"+Math.random().toString(36).substring(2)+Date.now();return new Promise((r,o)=>{try{const u=I(),h=++K;M.set(h,{resolve:r,reject:o,useImageBitmap:s}),u.postMessage({type:d.PARSE,taskId:h,buffer:e,fileSize:e.byteLength,movieDataId:i,useImageBitmap:s,cache:a},[e])}catch(u){u instanceof Error?o(u):o(new Error("\u672A\u77E5\u9519\u8BEF"))}})}static async load(e,t){const s=t?.cache!==!1;if(s&&p.has(e)){const i=p.get(e);return p.delete(e),p.set(e,i),i}if(T.has(e))return T.get(e);const a=(async()=>{try{const i=await N.loadUrl(e),r=await l.parseBufferOffscreen(i,e,t);if(s&&(p.set(e,r),p.size>$)){const o=p.keys().next().value;o&&l.destroyOffscreenCache(o)}return r}catch(i){throw T.delete(e),i}finally{T.delete(e)}})();return T.set(e,a),a}static parseBufferOffscreen(e,t,s){const a=s?.cache!==!1;return new Promise((i,r)=>{try{const o=I(),u=++K;M.set(u,{resolve:i,reject:r}),o.postMessage({type:d.PARSE_OFFSCREEN,taskId:u,buffer:e,fileSize:e.byteLength,movieDataId:t,cache:a},[e])}catch(o){o instanceof Error?r(o):r(new Error("\u672A\u77E5\u9519\u8BEF"))}})}static destroyCache(e){const t=f.get(e);t&&t.images&&Object.keys(t.images).forEach(s=>{const a=t.images[s];a&&(typeof a.close=="function"?a.close():a instanceof HTMLImageElement&&(a.src="")),t.images[s]=null}),f.delete(e)}static clearCache(){Array.from(f.keys()).forEach(e=>{l.destroyCache(e)}),f.clear()}static destroyOffscreenCache(e,t=!0){p.delete(e);try{I().postMessage({type:d.RELEASE_CACHE,movieDataId:e,force:t})}catch(s){console.warn("[Parser] \u53D1\u9001\u624B\u52A8\u9500\u6BC1\u6D88\u606F\u5931\u8D25\uFF1A",s)}}static clearOffscreenCache(){p.clear();try{I().postMessage({type:d.RELEASE_CACHE,movieDataId:void 0,force:!0})}catch(e){console.warn("[Parser] \u53D1\u9001\u6E05\u7A7A\u6240\u6709\u79BB\u5C4F\u7F13\u5B58\u6D88\u606F\u5931\u8D25\uFF1A",e)}}static destroy(e){if(e==null){l.clearCache(),l.clearOffscreenCache();return}if(typeof e=="string"){l.destroyCache(e),l.destroyOffscreenCache(e);return}if(typeof e=="object"){const{url:t,mainThread:s,offscreen:a}=e,i=s!==void 0?s:a===void 0,r=a!==void 0?a:s===void 0;t?(i&&l.destroyCache(t),r&&l.destroyOffscreenCache(t)):(i&&l.clearCache(),r&&l.clearOffscreenCache())}}static setWorkerConfig(e){Y(e)}}var q=Object.freeze({__proto__:null,Parser:l});const _=()=>typeof globalThis.requestAnimationFrame<"u"?globalThis.requestAnimationFrame.bind(globalThis):n=>setTimeout(()=>n(performance.now()),16.666666666666668),z=()=>typeof globalThis.cancelAnimationFrame<"u"?globalThis.cancelAnimationFrame.bind(globalThis):n=>clearTimeout(n);class B{static instance;sharedTasks=new Set;sharedRafId=0;standaloneTasks=new Map;static getInstance(){return B.instance||(B.instance=new B),B.instance}add(e,t=!0){if(t)this.sharedTasks.add(e),this.sharedTasks.size===1&&this.sharedRafId===0&&this.startShared();else if(!this.standaloneTasks.has(e)){const s=i=>{try{e(i)}catch(o){console.error("[SVGA \u5B9A\u65F6\u5668] \u72EC\u7ACB\u6E32\u67D3\u4EFB\u52A1\u6267\u884C\u5F02\u5E38\uFF1A",o)}const r=_()(s);this.standaloneTasks.set(e,r)},a=_()(s);this.standaloneTasks.set(e,a)}}remove(e){if(this.sharedTasks.has(e)&&(this.sharedTasks.delete(e),this.sharedTasks.size===0&&this.stopShared()),this.standaloneTasks.has(e)){const t=this.standaloneTasks.get(e);t&&z()(t),this.standaloneTasks.delete(e)}}startShared(){const e=t=>{this.sharedTasks.forEach(s=>{try{s(t)}catch(a){console.error("[SVGA \u5B9A\u65F6\u5668] \u5171\u4EAB\u6E32\u67D3\u4EFB\u52A1\u6267\u884C\u5F02\u5E38\uFF1A",a)}}),this.sharedTasks.size>0?this.sharedRafId=_()(e):this.sharedRafId=0};this.sharedRafId=_()(e)}stopShared(){this.sharedRafId!==0&&(z()(this.sharedRafId),this.sharedRafId=0)}}const U=B.getInstance(),j=new WeakMap;let O=null;class J{canvas;ctx;observerIsVisible=!0;movieData=null;isPlaying=!1;currentFrame=0;runtimeFps=20;totalFrames=0;shapeRendererInstance=null;lastTime=0;config;currentLoop=0;onStart;onPause;onStop;onLoopEnd;onProcess;dynamicElements={};startFrame=0;endFrame=0;frameCache=new Map;constructor(e,t){if(this.canvas=e,this.config=Object.assign({loop:0,useIntersectionObserver:!0,useSharedRAF:!0,useOffscreenCanvas:!1,invisibleBehavior:"pause"},t),this.ctx=e.getContext("2d"),!this.ctx)throw new Error("\u83B7\u53D6 2D \u4E0A\u4E0B\u6587\u5931\u8D25");j.set(e,this),this.initObserver()}initObserver(){typeof IntersectionObserver<"u"&&this.config.useIntersectionObserver!==!1&&(this.observerIsVisible=!0,O||(O=new IntersectionObserver(e=>{e.forEach(t=>{const s=j.get(t.target);s&&(s.observerIsVisible=t.isIntersecting)})})),O.observe(this.canvas))}setMovie(e){this.frameCache.clear(),this.movieData=e,this.totalFrames=e.params.frames||1,this.canvas.width=e.params.viewBoxWidth||300,this.canvas.height=e.params.viewBoxHeight||300,this.startFrame=Math.max(0,this.config.startFrame??0),this.endFrame=Math.min(this.totalFrames-1,this.config.endFrame??this.totalFrames-1),this.endFrame<this.startFrame&&(this.endFrame=this.startFrame),this.currentFrame=this.config.direction==="backward"?this.endFrame:this.startFrame,this.currentLoop=0}setImage(e,t){this.frameCache.clear(),this.dynamicElements[t]||(this.dynamicElements[t]={}),this.dynamicElements[t].image=e}setDynamicText(e,t){this.frameCache.clear(),this.dynamicElements[t]||(this.dynamicElements[t]={}),this.dynamicElements[t].text=e}clearDynamicObject(e){this.frameCache.clear(),this.dynamicElements[e]&&delete this.dynamicElements[e]}clearDynamicObjects(){this.frameCache.clear(),this.dynamicElements={}}async drawExternalPoster(e){return new Promise(t=>{const s=new Image;s.crossOrigin="anonymous",s.onload=()=>{if(this.isPlaying||this.movieData){t();return}const a=this.canvas.getBoundingClientRect();if(a.width>0&&a.height>0){const u=window.devicePixelRatio||1;this.canvas.width=a.width*u,this.canvas.height=a.height*u}else this.canvas.width=s.width,this.canvas.height=s.height;this.clearCanvas();const i=Math.min(this.canvas.width/s.width,this.canvas.height/s.height),r=s.width*i,o=s.height*i;this.ctx.drawImage(s,(this.canvas.width-r)/2,(this.canvas.height-o)/2,r,o),t()},s.onerror=()=>t(),s.src=e})}stepToFrame(e,t=!1){e<0||e>=this.totalFrames||(this.currentFrame=e,this.drawFrame(this.currentFrame),t?this.play():this.stop())}stepToPercentage(e,t=!1){const s=Math.floor(e*this.totalFrames);this.stepToFrame(s<this.totalFrames?s:this.totalFrames-1,t)}setShapeRenderer(e){this.shapeRendererInstance=e}getMemoryInfo(){if(!this.movieData)return{fileSize:0,imageMemory:0,dictionaryMemory:0,version:"",fps:0,frames:0,width:0,height:0,dynamicKeys:[],desc:"\u672A\u52A0\u8F7D\u4EFB\u4F55\u52A8\u6548"};let e=0;this.movieData.images&&Object.values(this.movieData.images).forEach(c=>{c&&typeof c=="object"&&"width"in c&&"height"in c&&(e+=c.width*c.height*4)});const t=JSON.stringify({params:this.movieData.params,sprites:this.movieData.sprites}).length,s=this.movieData.fileSize||0,a=this.movieData.version||"",i=this.movieData.params.fps||20,r=this.movieData.params.frames||0,o=this.movieData.params.viewBoxWidth||0,u=this.movieData.params.viewBoxHeight||0,h=Object.keys(this.dynamicElements);return{fileSize:s,imageMemory:e,dictionaryMemory:t,version:a,fps:i,frames:r,width:o,height:u,dynamicKeys:h,desc:`\u6E90\u6587\u4EF6\u5927\u5C0F: ${(s/1024).toFixed(2)} KB | \u9884\u4F30\u663E\u5B58(\u4F4D\u56FE\u4E0E\u7ED3\u6784): ${((e+t)/1024/1024).toFixed(2)} MB`}}play(e){!this.movieData||this.isPlaying||(e&&(e.fps!==void 0&&(this.config.fps=e.fps),e.loop!==void 0&&(this.config.loop=e.loop,this.currentLoop=0),e.fillMode!==void 0&&(this.config.fillMode=e.fillMode),e.startFrame!==void 0&&(this.config.startFrame=e.startFrame),e.endFrame!==void 0&&(this.config.endFrame=e.endFrame),e.useIntersectionObserver!==void 0&&(this.config.useIntersectionObserver=e.useIntersectionObserver),e.invisibleBehavior!==void 0&&(this.config.invisibleBehavior=e.invisibleBehavior),e.useSharedRAF!==void 0&&(this.config.useSharedRAF=e.useSharedRAF),e.cacheFrames!==void 0&&(this.config.cacheFrames!==e.cacheFrames&&this.frameCache.clear(),this.config.cacheFrames=e.cacheFrames),e.direction!==void 0&&(this.config.direction=e.direction)),this.startFrame=Math.max(0,this.config.startFrame??0),this.endFrame=Math.min(this.totalFrames-1,this.config.endFrame??this.totalFrames-1),this.endFrame<this.startFrame&&(this.endFrame=this.startFrame),(this.currentFrame<this.startFrame||this.currentFrame>this.endFrame)&&(this.currentFrame=this.config.direction==="backward"?this.endFrame:this.startFrame),this.runtimeFps=this.config.fps||this.movieData.params.fps||20,this.isPlaying=!0,this.onStart?.(),this.lastTime=performance.now(),U.add(this.loop,this.config.useSharedRAF!==!1))}stop(){this.isPlaying&&(this.isPlaying=!1,this.onStop?.()),U.remove(this.loop)}pause(){this.isPlaying&&(this.isPlaying=!1,this.onPause?.()),U.remove(this.loop)}reset(){this.stop(),this.currentFrame=0,this.currentLoop=0,this.clearCanvas(),this.movieData&&this.drawFrame(0)}clear(){this.stop(),this.clearCanvas(),this.frameCache.clear(),this.movieData=null,this.currentFrame=0,this.currentLoop=0}destroy(){this.clear(),this.clearDynamicObjects(),this.frameCache.clear(),O&&O.unobserve(this.canvas),j.delete(this.canvas),this.canvas=null,this.ctx=null,this.shapeRendererInstance=null}loop=e=>{if(!this.isPlaying)return;const t=1e3/this.runtimeFps,s=e-this.lastTime;if(s>=t){this.lastTime=e-s%t;const a=!this.observerIsVisible,i=this.config.invisibleBehavior==="pause"||!this.config.invisibleBehavior;if(a&&i)return;if(a||this.drawFrame(this.currentFrame),this.onProcess?.(this.currentFrame),this.config.direction!=="backward"){if(this.currentFrame++,this.currentFrame>this.endFrame||this.currentFrame>=this.totalFrames){if(this.currentLoop++,this.onLoopEnd?.(),this.config.loop&&this.config.loop>0&&this.currentLoop>=this.config.loop){this.stop(),this.config.fillMode==="backwards"?this.stepToFrame(this.startFrame):this.config.fillMode==="clear"?this.clearCanvas():this.drawFrame(this.endFrame);return}this.currentFrame=this.startFrame}}else if(this.currentFrame--,this.currentFrame<this.startFrame){if(this.currentLoop++,this.onLoopEnd?.(),this.config.loop&&this.config.loop>0&&this.currentLoop>=this.config.loop){this.stop(),this.config.fillMode==="backwards"?this.stepToFrame(this.endFrame):this.config.fillMode==="clear"?this.clearCanvas():this.drawFrame(this.startFrame);return}this.currentFrame=this.endFrame}}};clearCanvas(){this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height)}drawFrame(e){if(!this.movieData)return;if(this.config.cacheFrames&&this.frameCache.has(e)){const a=this.frameCache.get(e);this.clearCanvas(),this.ctx.drawImage(a,0,0);return}this.clearCanvas();const{sprites:t,images:s}=this.movieData;for(const a of t){const i=a.frames?.[e];if(!i||i.alpha===0)continue;if(this.ctx.save(),this.ctx.globalAlpha=i.alpha,i.transform){const{a:u,b:h,c,d:m,tx:y,ty:v}=i.transform;this.ctx.transform(u,h,c,m,y,v)}if(i.clipPath){const u=new Path2D(i.clipPath);this.ctx.clip(u)}let r=null;if(a.imageKey){const u=this.dynamicElements[a.imageKey];u&&u.image?r=u.image:s&&s[a.imageKey]&&(r=s[a.imageKey])}const o=i.layout;if(r){let u=0,h=0;"width"in r&&(u=r.width),"height"in r&&(h=r.height),o?this.ctx.drawImage(r,o.x||0,o.y||0,Math.max(o.width,0)||u,Math.max(o.height,0)||h):this.ctx.drawImage(r,0,0)}if(a.imageKey&&this.dynamicElements[a.imageKey]&&this.dynamicElements[a.imageKey].text){const u=this.dynamicElements[a.imageKey].text,h=u.size||"14px",c=u.family||"Arial",m=u.color||"#000000",y=u.offset||{x:0,y:0},v=typeof h=="number"?`${h}px ${c}`:`${h} ${c}`;this.ctx.font=v,this.ctx.fillStyle=m,this.ctx.textBaseline="middle",this.ctx.textAlign="center";let E=y.x,b=y.y;o&&(E+=o.x+o.width/2,b+=o.y+o.height/2),this.ctx.fillText(u.text,E,b)}i.shapes&&i.shapes.length>0&&this.shapeRendererInstance&&this.shapeRendererInstance.drawShapes(this.ctx,i.shapes),this.ctx.restore()}if(this.config.cacheFrames){const a=document.createElement("canvas");a.width=this.canvas.width,a.height=this.canvas.height,a.getContext("2d")?.drawImage(this.canvas,0,0),this.frameCache.set(e,a)}}}class X{renderer;constructor(e,t){let s;e instanceof HTMLDivElement?(s=document.createElement("canvas"),s.style.width="100%",s.style.height="100%",e.appendChild(s)):s=e,t?.useOffscreenCanvas&&typeof s.transferControlToOffscreen=="function"&&typeof Worker<"u"?this.renderer=new V(s,t):this.renderer=new J(s,t)}async setVideoItem(e){this.renderer.clear();const t=this.renderer instanceof V;if(t){if(e&&typeof e=="object"&&!e.isOffscreen&&(e.sprites||e.images))throw new Error("[SVGA \u64AD\u653E\u5668\u4E25\u91CD\u9519\u8BEF] \u5F53\u524D\u5DF2\u5F00\u542F Offscreen \u79BB\u5C4F\u6E32\u67D3\u4F18\u5316\uFF01\u5728\u79BB\u5C4F\u6E32\u67D3\u6A21\u5F0F\u4E0B\uFF0C\u4E25\u683C\u7981\u6B62\u5411\u64AD\u653E\u5668 setVideoItem \u4F20\u9012\u4E3B\u7EBF\u7A0B\u7684\u5B8C\u6574\u590D\u6742 MovieData \u6570\u636E\uFF08\u8FD9\u4F1A\u5BFC\u81F4\u4E3B\u7EBF\u7A0B\u4E8C\u6B21\u53CD\u5E8F\u5217\u5316\u4E0E\u591A\u4EFD\u56FE\u50CF\u7559\u5B58\uFF0C\u4F7F\u624B\u673A\u5185\u5B58\u6210\u500D\u66B4\u589E\uFF09\u3002\u8BF7\u6539\u7528\u4E3A\u79BB\u5C4F\u6A21\u5F0F\u4E13\u5C5E\u89E3\u8026\u8BBE\u8BA1\u7684\u52A0\u8F7D\u65B9\u6CD5\u3010Parser.load(url)\u3011\u83B7\u53D6\u4EC5\u542B ID \u7684\u8F7B\u91CF\u53E5\u67C4\uFF0C\u6216\u8005\u76F4\u63A5\u4F20\u5165 String \u7C7B\u578B\u7684 URL \u81EA\u9002\u5E94\u79BB\u5C4F\u6D41\u3002")}else if(e&&typeof e=="object"&&e.isOffscreen)throw new Error("[SVGA \u64AD\u653E\u5668\u4E25\u91CD\u9519\u8BEF] \u5F53\u524D\u4F7F\u7528\u7684\u662F\u4E3B\u7EBF\u7A0B\u4F20\u7EDF\u6E32\u67D3\u5668\uFF0C\u4F46\u5374\u4F20\u5165\u4E86\u5B50\u7EBF\u7A0B\u4E13\u7528\u7684\u79BB\u5C4F\u8F7B\u91CF\u5316\u5143\u6570\u636E\u53E5\u67C4 (isOffscreen: true)\uFF01\u8FD9\u5C06\u5BFC\u81F4\u4E3B\u7EBF\u7A0B\u6CA1\u6709\u4EFB\u4F55\u53EF\u4EE5\u7528\u4E8E\u7ED8\u5236\u548C\u53CD\u5E8F\u5217\u5316\u7684\u56FE\u50CF/\u7CBE\u7075\u5E8F\u5217\u6811\u4FE1\u606F\u3002\u5728\u666E\u901A\u6E32\u67D3\u6A21\u5F0F\u4E0B\uFF0C\u8BF7\u4F7F\u7528\u4E3B\u7EBF\u7A0B\u52A0\u8F7D\u65B9\u6CD5\u3010Parser.loadUrl(url)\u3011\u6216\u3010Parser.loadFile(file)\u3011\u3002");if(typeof e=="string")if(t){await this.renderer.setMovie({movieDataId:e});return}else{const{Parser:a}=await Promise.resolve().then(function(){return q}),i=a.getCachedVideoItem(e)||await a.loadUrl(e);i&&await this.renderer.setMovie(i);return}let s=!1;if(e&&e.sprites)for(const a of e.sprites){if(s)break;if(a.frames){for(const i of a.frames)if(i.shapes&&i.shapes.length>0){s=!0;break}}}if(s){const{ShapeRenderer:a}=await Promise.resolve().then(function(){return require("./ShapeRenderer-Cuwcq2MV.cjs")});this.renderer.setShapeRenderer(a.getInstance())}await this.renderer.setMovie(e)}play(e){this.renderer.play(e)}playRange(e,t,s){this.renderer.play(Object.assign({startFrame:e,endFrame:t},s))}pause(){this.renderer.pause()}stop(){this.renderer.stop()}onStart(e){this.renderer.onStart=e}onPause(e){this.renderer.onPause=e}onStop(e){this.renderer.onStop=e}onLoopEnd(e){this.renderer.onLoopEnd=e}onProcess(e){this.renderer.onProcess=e}stepToFrame(e,t=!1){this.renderer.stepToFrame(e,t)}stepToPercentage(e,t=!1){this.renderer.stepToPercentage(e,t)}async setImage(e,t){if(typeof e=="string"){const s=new Image;s.crossOrigin="anonymous";const a=new Promise((i,r)=>{s.onload=()=>i(s),s.onerror=o=>r(o)});s.src=e;try{const i=await a;await this.renderer.setImage(i,t)}catch(i){console.warn(`[Player] \u52A8\u6001\u52A0\u8F7D\u56FE\u7247\u94FE\u63A5 ${e} \u5931\u8D25\uFF1A`,i)}}else await this.renderer.setImage(e,t)}setText(e,t){typeof e=="string"?this.renderer.setDynamicText({text:e},t):this.renderer.setDynamicText(e,t)}clearDynamicObject(e){this.renderer.clearDynamicObject(e)}clearDynamicObjects(){this.renderer.clearDynamicObjects()}async renderPoster(e){await this.renderer.drawExternalPoster(e)}getMemoryInfo(){return this.renderer.getMemoryInfo()}clear(){this.renderer.clear()}destroy(){this.renderer.destroy()}}exports.Parser=l,exports.Player=X;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SVGA 动效相关类型定义
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* 动态替换文本配置项
|
|
7
|
+
*/
|
|
8
|
+
interface DynamicText {
|
|
9
|
+
/** 文本内容 */
|
|
10
|
+
text: string;
|
|
11
|
+
/** 字体大小,如 '14px' 或数字 14 */
|
|
12
|
+
size?: string | number;
|
|
13
|
+
/** 字体族,如 'Arial' 或 'sans-serif' */
|
|
14
|
+
family?: string;
|
|
15
|
+
/** 字体颜色,十六进制或英文缩写,如 '#000000' 或 'red' */
|
|
16
|
+
color?: string;
|
|
17
|
+
/** 文本在原有占位符中心基础上的相对偏移量 */
|
|
18
|
+
offset?: {
|
|
19
|
+
x: number;
|
|
20
|
+
y: number;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 播放器配置项
|
|
25
|
+
*/
|
|
26
|
+
interface PlayConfig {
|
|
27
|
+
/**
|
|
28
|
+
* 循环次数
|
|
29
|
+
* @description 0 代表无限循环
|
|
30
|
+
* @default 0
|
|
31
|
+
*/
|
|
32
|
+
loop?: number;
|
|
33
|
+
/**
|
|
34
|
+
* 自定义运行帧率
|
|
35
|
+
* @description 覆盖源文件内置帧率,如 60
|
|
36
|
+
*/
|
|
37
|
+
fps?: number;
|
|
38
|
+
/**
|
|
39
|
+
* 播放结束时的行为
|
|
40
|
+
* @description
|
|
41
|
+
* - "forwards": 停在最后一帧
|
|
42
|
+
* - "backwards": 回到第一帧
|
|
43
|
+
* - "clear": 清空画布
|
|
44
|
+
* @default "forwards"
|
|
45
|
+
*/
|
|
46
|
+
fillMode?: 'forwards' | 'backwards' | 'clear';
|
|
47
|
+
/**
|
|
48
|
+
* 开始播放的帧数
|
|
49
|
+
* @description 可用于裁切动效指定片段的起始时间
|
|
50
|
+
*/
|
|
51
|
+
startFrame?: number;
|
|
52
|
+
/**
|
|
53
|
+
* 结束播放的帧数
|
|
54
|
+
* @description 可用于裁切动效指定片段的结束时间
|
|
55
|
+
*/
|
|
56
|
+
endFrame?: number;
|
|
57
|
+
/**
|
|
58
|
+
* 是否在视图不可见时开启优化
|
|
59
|
+
* @description 默认开启,当 Canvas 移除视口时通过 IntersectionObserver 响应状态
|
|
60
|
+
* @default true
|
|
61
|
+
*/
|
|
62
|
+
useIntersectionObserver?: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* 判定容器不可见(脱离视口)时的优化行为
|
|
65
|
+
* @description
|
|
66
|
+
* - "pause": 暂停播放,动画完全静止在当前帧
|
|
67
|
+
* - "skip": 仅仅跳过 Canvas 绘制流程,但后台帧数/时间轴依旧正常走动计算
|
|
68
|
+
* @default "pause"
|
|
69
|
+
*/
|
|
70
|
+
invisibleBehavior?: 'pause' | 'skip';
|
|
71
|
+
/**
|
|
72
|
+
* 是否使用共享的 requestAnimationFrame 调度器
|
|
73
|
+
* @description 默认开启,当页面有多个 SVGA 实例时共用一个 RAF 能有效提高性能
|
|
74
|
+
* @default true
|
|
75
|
+
*/
|
|
76
|
+
useSharedRAF?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* 是否开启离屏渲染优化
|
|
79
|
+
* @description 默认为 false,若浏览器支持将采用 OffscreenCanvas 处理绘制
|
|
80
|
+
* @default false
|
|
81
|
+
*/
|
|
82
|
+
useOffscreenCanvas?: boolean;
|
|
83
|
+
/**
|
|
84
|
+
* 是否对已绘制的帧进行缓存
|
|
85
|
+
* @description 开启后,在首次绘制时将帧渲染结果缓存为位图,二次播放及跳转时直接贴图,极大降低 CPU/GPU 渲染运算,特别适合包含大量 Path Shapes / Clip 遮罩的动效。
|
|
86
|
+
* @default false
|
|
87
|
+
*/
|
|
88
|
+
cacheFrames?: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* 播放方向
|
|
91
|
+
* @description
|
|
92
|
+
* - "forward": 顺序播放
|
|
93
|
+
* - "backward": 逆序/倒序播放
|
|
94
|
+
* @default "forward"
|
|
95
|
+
*/
|
|
96
|
+
direction?: 'forward' | 'backward';
|
|
97
|
+
}
|
|
98
|
+
interface ParserDestroyOptions {
|
|
99
|
+
/** 指定清除缓存的特定 URL */
|
|
100
|
+
url?: string;
|
|
101
|
+
/** 是否清除主线程的缓存。若指定为 true,将清除主线程缓存 */
|
|
102
|
+
mainThread?: boolean;
|
|
103
|
+
/** 是否清除子线程/离屏的缓存。若指定为 true,将清除离屏缓存 */
|
|
104
|
+
offscreen?: boolean;
|
|
105
|
+
}
|
|
106
|
+
interface WorkerConfig {
|
|
107
|
+
/** 自定义 Web Worker 的 URL 地址 */
|
|
108
|
+
workerUrl?: string;
|
|
109
|
+
/** 自定义创建 Web Worker 实例的工厂函数,优先级高于 workerUrl */
|
|
110
|
+
workerCreator?: () => Worker;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
declare class Parser {
|
|
114
|
+
/**
|
|
115
|
+
* 获取已缓存的动画数据(同步)
|
|
116
|
+
* @param url 需要获取的缓存 key 地址
|
|
117
|
+
*/
|
|
118
|
+
static getCachedVideoItem(url: string): any;
|
|
119
|
+
/**
|
|
120
|
+
* 加载网络资源,内置 LRU / 字典缓存机制
|
|
121
|
+
* @param url SVGA 文件在线地址
|
|
122
|
+
* @param options 参数配置选项,包含 useImageBitmap 和 cache。cache 默认为 true。
|
|
123
|
+
*/
|
|
124
|
+
static loadUrl(url: string, options?: {
|
|
125
|
+
useImageBitmap?: boolean;
|
|
126
|
+
movieDataId?: string;
|
|
127
|
+
cache?: boolean;
|
|
128
|
+
}): Promise<any>;
|
|
129
|
+
/**
|
|
130
|
+
* 加载本地文件(本地文件通常不存共享缓存)
|
|
131
|
+
* @param file 本地 File 对象
|
|
132
|
+
* @param options 参数配置选项,支持 useImageBitmap 与 cache
|
|
133
|
+
*/
|
|
134
|
+
static loadFile(file: File | Blob, options?: {
|
|
135
|
+
useImageBitmap?: boolean;
|
|
136
|
+
cache?: boolean;
|
|
137
|
+
}): Promise<any>;
|
|
138
|
+
/**
|
|
139
|
+
* 使用共享 Web Worker 解析 SVGA ArrayBuffer
|
|
140
|
+
* @param buffer 载入的 ArrayBuffer 文件数据
|
|
141
|
+
* @param options 参数配置选项,包含 useImageBitmap, movieDataId 以及 cache
|
|
142
|
+
* @returns 解析出的 MovieEntity 数据
|
|
143
|
+
*/
|
|
144
|
+
static parseBuffer(buffer: ArrayBuffer, options?: {
|
|
145
|
+
useImageBitmap?: boolean;
|
|
146
|
+
movieDataId?: string;
|
|
147
|
+
cache?: boolean;
|
|
148
|
+
}): Promise<any>;
|
|
149
|
+
/**
|
|
150
|
+
* 专用于离屏渲染的加载方法 (Worker-only offscreen render pipeline)
|
|
151
|
+
* 此方法内,所有的精灵图层、Proto 解码与最终的 ImageBitmap 直接留在子线程缓存中,
|
|
152
|
+
* 绝对不传输/拷贝回主线程,只返回轻量级元数据数据 `{ movieDataId, isOffscreen: true, params: { ... } }`
|
|
153
|
+
*
|
|
154
|
+
* @param url SVGA 文件在线地址
|
|
155
|
+
* @param options 参数配置,默认开启缓存
|
|
156
|
+
*/
|
|
157
|
+
static load(url: string, options?: {
|
|
158
|
+
cache?: boolean;
|
|
159
|
+
}): Promise<{
|
|
160
|
+
movieDataId: string;
|
|
161
|
+
isOffscreen: true;
|
|
162
|
+
params: {
|
|
163
|
+
viewBoxWidth: number;
|
|
164
|
+
viewBoxHeight: number;
|
|
165
|
+
fps: number;
|
|
166
|
+
frames: number;
|
|
167
|
+
};
|
|
168
|
+
}>;
|
|
169
|
+
/**
|
|
170
|
+
* 使用共享 Web Worker 仅在子线程解析并留存 SVGA 离屏渲染数据
|
|
171
|
+
*/
|
|
172
|
+
static parseBufferOffscreen(buffer: ArrayBuffer, movieDataId: string, options?: {
|
|
173
|
+
cache?: boolean;
|
|
174
|
+
}): Promise<{
|
|
175
|
+
movieDataId: string;
|
|
176
|
+
isOffscreen: true;
|
|
177
|
+
params: {
|
|
178
|
+
viewBoxWidth: number;
|
|
179
|
+
viewBoxHeight: number;
|
|
180
|
+
fps: number;
|
|
181
|
+
frames: number;
|
|
182
|
+
};
|
|
183
|
+
}>;
|
|
184
|
+
/**
|
|
185
|
+
* 释放指定的主线程传统渲染缓存,防止 H5 长期运行导致内存/显存溢出
|
|
186
|
+
* @param url 需要清理的缓存 key
|
|
187
|
+
*/
|
|
188
|
+
static destroyCache(url: string): void;
|
|
189
|
+
/**
|
|
190
|
+
* 清空所有主线程传统渲染的动画缓存数据
|
|
191
|
+
*/
|
|
192
|
+
static clearCache(): void;
|
|
193
|
+
/**
|
|
194
|
+
* 释放指定的离屏渲染缓存(包含 Worker 子线程中的解码缓存)
|
|
195
|
+
* @param movieDataId 缓存中的唯一标识 ID(即 load 方法返回的 movieDataId)
|
|
196
|
+
* @param force 是否强制销毁(若为 true,即使引用计数大于 0 也会被强行清理)
|
|
197
|
+
*/
|
|
198
|
+
static destroyOffscreenCache(movieDataId: string, force?: boolean): void;
|
|
199
|
+
/**
|
|
200
|
+
* 清空所有离屏渲染的动画缓存数据,并通知 Worker 彻底释放所有缓存
|
|
201
|
+
*/
|
|
202
|
+
static clearOffscreenCache(): void;
|
|
203
|
+
/**
|
|
204
|
+
* 销毁并清除主线程和子线程中的缓存。
|
|
205
|
+
* - 不传参数:默认全量清空主线程与子线程的所有动画缓存。
|
|
206
|
+
* - 传入字符串 URL:双端(主、子线程)中清空对应 URL 的动画缓存。
|
|
207
|
+
* - 传入 options 选项:支持配置可选 url 参数,有是否清除主线程/子线程所有缓存等配置。
|
|
208
|
+
*/
|
|
209
|
+
static destroy(arg?: string | ParserDestroyOptions): void;
|
|
210
|
+
/**
|
|
211
|
+
* 配置全局共享的 Web Worker。
|
|
212
|
+
* 支持通过自定义 URL 或 Worker 创建工厂函数配置,利于在 IIFE/CommonJS 等不原生支持 import.meta.url 的环境中运行。
|
|
213
|
+
* @param config Web Worker 配置参数
|
|
214
|
+
*/
|
|
215
|
+
static setWorkerConfig(config: WorkerConfig): void;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
declare class Player {
|
|
219
|
+
/** 渲染器实例 */
|
|
220
|
+
private renderer;
|
|
221
|
+
/**
|
|
222
|
+
* 构造函数
|
|
223
|
+
* @param element 要绘图的 canvas 或 div 节点
|
|
224
|
+
* @param config 初始化配置
|
|
225
|
+
*/
|
|
226
|
+
constructor(element: HTMLCanvasElement | HTMLDivElement, config?: PlayConfig);
|
|
227
|
+
/**
|
|
228
|
+
* 设置解析好的动画数据并准备播放
|
|
229
|
+
* @param videoItem 已经使用 Parser 解析好的 MovieEntity,或者已有的缓存 id/url 地址
|
|
230
|
+
*/
|
|
231
|
+
setVideoItem(videoItem: any): Promise<void>;
|
|
232
|
+
/**
|
|
233
|
+
* 触发播放
|
|
234
|
+
* @param config 单次播放应用覆盖的配置(支持修改帧率与循环次数等)
|
|
235
|
+
*/
|
|
236
|
+
play(config?: PlayConfig): void;
|
|
237
|
+
/**
|
|
238
|
+
* 播放指定范围的帧
|
|
239
|
+
* @param startFrame 开始帧
|
|
240
|
+
* @param endFrame 结束帧
|
|
241
|
+
* @param config 可选:单次播放应用覆盖的配置(支持修改帧率与循环次数等)
|
|
242
|
+
*/
|
|
243
|
+
playRange(startFrame: number, endFrame: number, config?: Omit<PlayConfig, 'startFrame' | 'endFrame'>): void;
|
|
244
|
+
/**
|
|
245
|
+
* 暂停
|
|
246
|
+
*/
|
|
247
|
+
pause(): void;
|
|
248
|
+
/**
|
|
249
|
+
* 停止并回到第一帧
|
|
250
|
+
*/
|
|
251
|
+
stop(): void;
|
|
252
|
+
/**
|
|
253
|
+
* 绑定开始播放事件
|
|
254
|
+
*/
|
|
255
|
+
onStart(callback: () => void): void;
|
|
256
|
+
/**
|
|
257
|
+
* 绑定暂停播放事件
|
|
258
|
+
*/
|
|
259
|
+
onPause(callback: () => void): void;
|
|
260
|
+
/**
|
|
261
|
+
* 绑定停止播放事件
|
|
262
|
+
*/
|
|
263
|
+
onStop(callback: () => void): void;
|
|
264
|
+
/**
|
|
265
|
+
* 绑定当前循环结束事件
|
|
266
|
+
*/
|
|
267
|
+
onLoopEnd(callback: () => void): void;
|
|
268
|
+
/**
|
|
269
|
+
* 绑定播放进度更新事件(每渲染一帧触发)
|
|
270
|
+
*/
|
|
271
|
+
onProcess(callback: (frame: number) => void): void;
|
|
272
|
+
/**
|
|
273
|
+
* 跳转到指定帧并选择是否继续播放
|
|
274
|
+
*/
|
|
275
|
+
stepToFrame(frame: number, andPlay?: boolean): void;
|
|
276
|
+
/**
|
|
277
|
+
* 跳转到指定进度并选择是否继续播放
|
|
278
|
+
*/
|
|
279
|
+
stepToPercentage(percentage: number, andPlay?: boolean): void;
|
|
280
|
+
/**
|
|
281
|
+
* 动态替换图像,支持传 HTMLImageElement, ImageBitmap, HTMLCanvasElement 实例,或普通的图片在线链接/Base64 字符串
|
|
282
|
+
* @param image 图像源或图片链接
|
|
283
|
+
* @param key 目标图层/图像键值
|
|
284
|
+
*/
|
|
285
|
+
setImage(image: HTMLImageElement | ImageBitmap | HTMLCanvasElement | string, key: string): Promise<void>;
|
|
286
|
+
/**
|
|
287
|
+
* 动态添加文本,支持纯字符串或者完整的属性配置项
|
|
288
|
+
* @param text 文本配置或直接传入字符串
|
|
289
|
+
* @param key 目标图层/文本键值
|
|
290
|
+
*/
|
|
291
|
+
setText(text: string | DynamicText, key: string): void;
|
|
292
|
+
/**
|
|
293
|
+
* 清除某个指定的动态替换配置
|
|
294
|
+
* @param key 需要清除的动态替换 key
|
|
295
|
+
*/
|
|
296
|
+
clearDynamicObject(key: string): void;
|
|
297
|
+
/**
|
|
298
|
+
* 清空所有动态替换元素
|
|
299
|
+
*/
|
|
300
|
+
clearDynamicObjects(): void;
|
|
301
|
+
/**
|
|
302
|
+
* (外部图片)把外链图片当做静态海报直接渲染到 Canvas 上面
|
|
303
|
+
*/
|
|
304
|
+
renderPoster(imageUrl: string): Promise<void>;
|
|
305
|
+
/**
|
|
306
|
+
* 获取当前播放动效的预估文件大小及内存占用信息
|
|
307
|
+
* @returns 包含文件大小、位图对象预估内存及总体估算的描述
|
|
308
|
+
*/
|
|
309
|
+
getMemoryInfo(): {
|
|
310
|
+
fileSize: number;
|
|
311
|
+
imageMemory: number;
|
|
312
|
+
dictionaryMemory: number;
|
|
313
|
+
version: string;
|
|
314
|
+
fps: number;
|
|
315
|
+
frames: number;
|
|
316
|
+
width: number;
|
|
317
|
+
height: number;
|
|
318
|
+
dynamicKeys: string[];
|
|
319
|
+
desc: string;
|
|
320
|
+
};
|
|
321
|
+
/**
|
|
322
|
+
* 清空画布和内存引用
|
|
323
|
+
*/
|
|
324
|
+
clear(): void;
|
|
325
|
+
/**
|
|
326
|
+
* 彻底销毁播放器实例
|
|
327
|
+
*/
|
|
328
|
+
destroy(): void;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export { Parser, Player };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var m=(n=>(n.INIT="init",n.VISIBILITY="visibility",n.SET_MOVIE="setMovie",n.SET_IMAGE="setImage",n.SET_DYNAMIC_TEXT="setDynamicText",n.DRAW_EXTERNAL_POSTER="drawExternalPoster",n.PLAY="play",n.STOP="stop",n.PAUSE="pause",n.STEP_TO_FRAME="stepToFrame",n.STEP_TO_PERCENTAGE="stepToPercentage",n.CLEAR="clear",n.CLEAR_DYNAMIC_OBJECTS="clearDynamicObjects",n.CLEAR_DYNAMIC_OBJECT="clearDynamicObject",n.DESTROY="destroy",n.PARSE="parse",n.PARSE_OFFSCREEN="parse_offscreen",n.RELEASE_CACHE="releaseCache",n))(m||{}),P=(n=>(n.SUCCESS="SUCCESS",n.ERROR="ERROR",n.EVENT="event",n))(P||{}),p=(n=>(n.READY="ready",n.ON_START="onStart",n.ON_STOP="onStop",n.ON_PAUSE="onPause",n.ON_PROCESS="onProcess",n.ON_LOOP_END="onLoopEnd",n.ON_REQUEST_MOVIE_DATA="onRequestMovieData",n))(p||{});let v=null,w=null;const b=new Map;let z=0,D={};function W(n){D={...D,...n}}const k=new Map;let x=null;function Y(n){x=n}function A(){if(!v){if(D.workerCreator)v=D.workerCreator();else if(D.workerUrl)v=new Worker(D.workerUrl);else{let n;try{typeof import.meta<"u"&&import.meta.url?n=new URL("./svga.worker.ts",import.meta.url):n="./svga.worker.ts"}catch{n="./svga.worker.ts"}v=new Worker(n,{type:"module"})}v.onmessage=n=>{const{type:e,id:t,name:s,args:a,taskId:i}=n.data;if(i!==void 0){x&&x(n.data);return}const r=b.get(t);r&&e===P.EVENT&&(s===p.ON_START&&r.onStart?r.onStart():s===p.ON_STOP&&r.onStop?r.onStop():s===p.ON_PAUSE&&r.onPause?r.onPause():s===p.ON_LOOP_END&&r.onLoopEnd?r.onLoopEnd():s===p.ON_PROCESS&&r.onProcess?r.onProcess(a[0]):s===p.ON_REQUEST_MOVIE_DATA&&r.resendMovieData())}}return v}class V{id;canvas;observerIsVisible=!0;worker;onStart;onPause;onStop;onLoopEnd;onProcess;_dynamicKeys=new Set;_config;_shapeRendererInstance=null;_movieData=null;constructor(e,t){this.canvas=e,this.id=`renderer_${z++}`,this._config=Object.assign({loop:0,useIntersectionObserver:!0,useSharedRAF:!0,invisibleBehavior:"pause"},t),b.set(this.id,this),this.worker=A();const s=e.transferControlToOffscreen();this.worker.postMessage({type:m.INIT,id:this.id,canvas:s,config:this._config},[s]),this._config.useIntersectionObserver!==!1&&(!w&&typeof IntersectionObserver<"u"&&(w=new IntersectionObserver(a=>{a.forEach(i=>{Array.from(b.values()).filter(r=>r.canvas===i.target).forEach(r=>{r.observerIsVisible=i.isIntersecting,r.worker.postMessage({type:m.VISIBILITY,id:r.id,visible:r.observerIsVisible})})})})),w&&w.observe(this.canvas))}async resendMovieData(){if(this._movieData){const e=this._movieData.movieDataId||"movie_direct_"+Math.random().toString(36).substring(2)+Date.now(),t={},s=[];if(typeof createImageBitmap<"u"&&this._movieData.images){for(const[i,r]of Object.entries(this._movieData.images))if(r instanceof ImageBitmap)try{const o=await createImageBitmap(r);t[i]=o,s.push(o)}catch(o){console.warn("[\u79BB\u5C4F\u6E32\u67D3\u5668] \u91CD\u65B0\u53D1\u9001\u52A8\u753B\u6570\u636E\u65F6\u514B\u9686\u4F4D\u56FE\u5931\u8D25\uFF1A",o)}}const a={...this._movieData,images:t,imageBytes:void 0};k.set(this.id,e),this.worker.postMessage({type:m.SET_MOVIE,id:this.id,movieData:a,movieDataId:e},s)}}async setMovie(e){this._movieData=e;const t=e.movieDataId||"movie_direct_"+Math.random().toString(36).substring(2)+Date.now();k.set(this.id,t),this.worker.postMessage({type:m.SET_MOVIE,id:this.id,movieData:null,movieDataId:t})}async setImage(e,t){if(this._dynamicKeys.add(t),typeof createImageBitmap<"u")try{const s=await createImageBitmap(e);this.worker.postMessage({type:m.SET_IMAGE,id:this.id,key:t,image:s},[s])}catch(s){console.warn("[\u79BB\u5C4F\u6E32\u67D3\u5668] \u8BBE\u7F6E\u52A8\u6001\u56FE\u7247\u65F6\u514B\u9686\u4F4D\u56FE\u5BF9\u8C61\u5931\u8D25\uFF1A",s)}}setDynamicText(e,t){this._dynamicKeys.add(t),this.worker.postMessage({type:m.SET_DYNAMIC_TEXT,id:this.id,key:t,text:e})}setShapeRenderer(e){this._shapeRendererInstance=e}async drawExternalPoster(e){try{const t=await(await fetch(e)).blob(),s=await createImageBitmap(t);this.worker.postMessage({type:m.DRAW_EXTERNAL_POSTER,id:this.id,image:s},[s])}catch(t){console.warn("[\u79BB\u5C4F\u6E32\u67D3\u5668] \u8F7D\u5165\u5E76\u751F\u6210\u9759\u6001\u6D77\u62A5\u6D77\u62A5\u5931\u8D25\uFF1A",t)}}play(e){this.worker.postMessage({type:m.PLAY,id:this.id,config:e})}stop(){this.worker.postMessage({type:m.STOP,id:this.id})}pause(){this.worker.postMessage({type:m.PAUSE,id:this.id})}stepToFrame(e,t=!1){this.worker.postMessage({type:m.STEP_TO_FRAME,id:this.id,frame:e,andPlay:t})}stepToPercentage(e,t){this.worker.postMessage({type:m.STEP_TO_PERCENTAGE,id:this.id,percentage:e,andPlay:t})}clear(){this.worker.postMessage({type:m.CLEAR,id:this.id})}clearDynamicObject(e){this._dynamicKeys.delete(e),this.worker.postMessage({type:m.CLEAR_DYNAMIC_OBJECT,id:this.id,key:e})}clearDynamicObjects(){this._dynamicKeys.clear(),this.worker.postMessage({type:m.CLEAR_DYNAMIC_OBJECTS,id:this.id})}getMemoryInfo(){if(!this._movieData)return{fileSize:0,imageMemory:0,dictionaryMemory:0,version:"",fps:0,frames:0,width:0,height:0,dynamicKeys:[],desc:"\u672A\u52A0\u8F7D\u4EFB\u4F55\u52A8\u6548"};let e=0;this._movieData.images&&Object.values(this._movieData.images).forEach(h=>{h&&h.width&&(e+=h.width*h.height*4)});const t=JSON.stringify({params:this._movieData.params,sprites:this._movieData.sprites}).length,s=this._movieData.fileSize||0,a=this._movieData.version||"",i=this._movieData.params.fps||20,r=this._movieData.params.frames||0,o=this._movieData.params.viewBoxWidth||0,u=this._movieData.params.viewBoxHeight||0,c=Array.from(this._dynamicKeys);return{fileSize:s,imageMemory:e,dictionaryMemory:t,version:a,fps:i,frames:r,width:o,height:u,dynamicKeys:c,desc:`\u6E90\u6587\u4EF6\u5927\u5C0F: ${(s/1024).toFixed(2)} KB | \u9884\u4F30\u663E\u5B58(\u4F4D\u56FE\u4E0E\u7ED3\u6784): ${((e+t)/1024/1024).toFixed(2)} MB`}}destroy(){w&&w.unobserve(this.canvas),k.delete(this.id),b.delete(this.id),this.worker.postMessage({type:m.DESTROY,id:this.id})}}class L{static async loadUrl(e){const t=await fetch(e);if(!t.ok)throw new Error(`\u65E0\u6CD5\u4ECE ${e} \u52A0\u8F7D SVGA \u6587\u4EF6: ${t.statusText}`);return await t.arrayBuffer()}static async loadFile(e){return new Promise((t,s)=>{const a=new FileReader;a.onload=()=>{a.result instanceof ArrayBuffer?t(a.result):s(new Error("\u65E0\u6CD5\u8BFB\u53D6\u6587\u4EF6\u7684 ArrayBuffer \u6570\u636E"))},a.onerror=()=>s(a.error),a.readAsArrayBuffer(e)})}}let U=0;const M=new Map,f=new Map,K=20,I=new Map,F=new Map,S=new Map;function G(){if(f.size>K){const n=f.keys().next().value;n&&l.destroyCache(n)}}Y(n=>{const{taskId:e,type:t,data:s,error:a}=n,i=M.get(e);if(i){const{useImageBitmap:r}=i;if(t===P.SUCCESS)if(s&&s.images&&!r){const o=[],u=s.images,c={};Object.keys(u).forEach(h=>{const d=u[h];if(d instanceof Uint8Array&&d.length>0){const g=new Promise(y=>{let E="image/png";d[0]===255&&d[1]===216?E="image/jpeg":d[0]===71&&d[1]===73&&d[2]===70?E="image/gif":d[0]===82&&d[1]===73&&d[2]===70&&d[3]===70&&(E="image/webp");const T=new Blob([d],{type:E}),_=URL.createObjectURL(T),C=new Image;C.onload=()=>{c[h]=C,URL.revokeObjectURL(_),y()},C.onerror=()=>{c[h]=C,URL.revokeObjectURL(_),y()},C.src=_});o.push(g)}else c[h]=d}),o.length>0?Promise.all(o).then(()=>{Object.keys(u).forEach(h=>{u[h]=null}),s.images=c,i.resolve(s)}).catch(h=>{i.reject(h)}):(s.images=c,i.resolve(s))}else i.resolve(s);else i.reject(new Error(a||"\u89E3\u6790 SVGA \u6587\u4EF6\u5931\u8D25"));M.delete(e)}});class l{static getCachedVideoItem(e){return f.get(e)}static async loadUrl(e,t){const s=t?.cache!==!1;if(s&&f.has(e)){const i=f.get(e);return f.delete(e),f.set(e,i),i}if(I.has(e))return I.get(e);const a=(async()=>{try{const i=await L.loadUrl(e),r=await l.parseBuffer(i,{...t,movieDataId:e});return s&&(f.set(e,r),G()),r}catch(i){throw I.delete(e),i}finally{I.delete(e)}})();return I.set(e,a),a}static async loadFile(e,t){const s=await L.loadFile(e);return await l.parseBuffer(s,t)}static parseBuffer(e,t){const s=t?.useImageBitmap??!1,a=t?.cache!==!1,i=t?.movieDataId||"movie_direct_"+Math.random().toString(36).substring(2)+Date.now();return new Promise((r,o)=>{try{const u=A(),c=++U;M.set(c,{resolve:r,reject:o,useImageBitmap:s}),u.postMessage({type:m.PARSE,taskId:c,buffer:e,fileSize:e.byteLength,movieDataId:i,useImageBitmap:s,cache:a},[e])}catch(u){u instanceof Error?o(u):o(new Error("\u672A\u77E5\u9519\u8BEF"))}})}static async load(e,t){const s=t?.cache!==!1;if(s&&F.has(e)){const i=F.get(e);return F.delete(e),F.set(e,i),i}if(S.has(e))return S.get(e);const a=(async()=>{try{const i=await L.loadUrl(e),r=await l.parseBufferOffscreen(i,e,t);if(s&&(F.set(e,r),F.size>K)){const o=F.keys().next().value;o&&l.destroyOffscreenCache(o)}return r}catch(i){throw S.delete(e),i}finally{S.delete(e)}})();return S.set(e,a),a}static parseBufferOffscreen(e,t,s){const a=s?.cache!==!1;return new Promise((i,r)=>{try{const o=A(),u=++U;M.set(u,{resolve:i,reject:r}),o.postMessage({type:m.PARSE_OFFSCREEN,taskId:u,buffer:e,fileSize:e.byteLength,movieDataId:t,cache:a},[e])}catch(o){o instanceof Error?r(o):r(new Error("\u672A\u77E5\u9519\u8BEF"))}})}static destroyCache(e){const t=f.get(e);t&&t.images&&Object.keys(t.images).forEach(s=>{const a=t.images[s];a&&(typeof a.close=="function"?a.close():a instanceof HTMLImageElement&&(a.src="")),t.images[s]=null}),f.delete(e)}static clearCache(){Array.from(f.keys()).forEach(e=>{l.destroyCache(e)}),f.clear()}static destroyOffscreenCache(e,t=!0){F.delete(e);try{A().postMessage({type:m.RELEASE_CACHE,movieDataId:e,force:t})}catch(s){console.warn("[Parser] \u53D1\u9001\u624B\u52A8\u9500\u6BC1\u6D88\u606F\u5931\u8D25\uFF1A",s)}}static clearOffscreenCache(){F.clear();try{A().postMessage({type:m.RELEASE_CACHE,movieDataId:void 0,force:!0})}catch(e){console.warn("[Parser] \u53D1\u9001\u6E05\u7A7A\u6240\u6709\u79BB\u5C4F\u7F13\u5B58\u6D88\u606F\u5931\u8D25\uFF1A",e)}}static destroy(e){if(e==null){l.clearCache(),l.clearOffscreenCache();return}if(typeof e=="string"){l.destroyCache(e),l.destroyOffscreenCache(e);return}if(typeof e=="object"){const{url:t,mainThread:s,offscreen:a}=e,i=s!==void 0?s:a===void 0,r=a!==void 0?a:s===void 0;t?(i&&l.destroyCache(t),r&&l.destroyOffscreenCache(t)):(i&&l.clearCache(),r&&l.clearOffscreenCache())}}static setWorkerConfig(e){W(e)}}var H=Object.freeze({__proto__:null,Parser:l});const R=()=>typeof globalThis.requestAnimationFrame<"u"?globalThis.requestAnimationFrame.bind(globalThis):n=>setTimeout(()=>n(performance.now()),16.666666666666668),$=()=>typeof globalThis.cancelAnimationFrame<"u"?globalThis.cancelAnimationFrame.bind(globalThis):n=>clearTimeout(n);class B{static instance;sharedTasks=new Set;sharedRafId=0;standaloneTasks=new Map;static getInstance(){return B.instance||(B.instance=new B),B.instance}add(e,t=!0){if(t)this.sharedTasks.add(e),this.sharedTasks.size===1&&this.sharedRafId===0&&this.startShared();else if(!this.standaloneTasks.has(e)){const s=i=>{try{e(i)}catch(o){console.error("[SVGA \u5B9A\u65F6\u5668] \u72EC\u7ACB\u6E32\u67D3\u4EFB\u52A1\u6267\u884C\u5F02\u5E38\uFF1A",o)}const r=R()(s);this.standaloneTasks.set(e,r)},a=R()(s);this.standaloneTasks.set(e,a)}}remove(e){if(this.sharedTasks.has(e)&&(this.sharedTasks.delete(e),this.sharedTasks.size===0&&this.stopShared()),this.standaloneTasks.has(e)){const t=this.standaloneTasks.get(e);t&&$()(t),this.standaloneTasks.delete(e)}}startShared(){const e=t=>{this.sharedTasks.forEach(s=>{try{s(t)}catch(a){console.error("[SVGA \u5B9A\u65F6\u5668] \u5171\u4EAB\u6E32\u67D3\u4EFB\u52A1\u6267\u884C\u5F02\u5E38\uFF1A",a)}}),this.sharedTasks.size>0?this.sharedRafId=R()(e):this.sharedRafId=0};this.sharedRafId=R()(e)}stopShared(){this.sharedRafId!==0&&($()(this.sharedRafId),this.sharedRafId=0)}}const N=B.getInstance(),j=new WeakMap;let O=null;class J{canvas;ctx;observerIsVisible=!0;movieData=null;isPlaying=!1;currentFrame=0;runtimeFps=20;totalFrames=0;shapeRendererInstance=null;lastTime=0;config;currentLoop=0;onStart;onPause;onStop;onLoopEnd;onProcess;dynamicElements={};startFrame=0;endFrame=0;frameCache=new Map;constructor(e,t){if(this.canvas=e,this.config=Object.assign({loop:0,useIntersectionObserver:!0,useSharedRAF:!0,useOffscreenCanvas:!1,invisibleBehavior:"pause"},t),this.ctx=e.getContext("2d"),!this.ctx)throw new Error("\u83B7\u53D6 2D \u4E0A\u4E0B\u6587\u5931\u8D25");j.set(e,this),this.initObserver()}initObserver(){typeof IntersectionObserver<"u"&&this.config.useIntersectionObserver!==!1&&(this.observerIsVisible=!0,O||(O=new IntersectionObserver(e=>{e.forEach(t=>{const s=j.get(t.target);s&&(s.observerIsVisible=t.isIntersecting)})})),O.observe(this.canvas))}setMovie(e){this.frameCache.clear(),this.movieData=e,this.totalFrames=e.params.frames||1,this.canvas.width=e.params.viewBoxWidth||300,this.canvas.height=e.params.viewBoxHeight||300,this.startFrame=Math.max(0,this.config.startFrame??0),this.endFrame=Math.min(this.totalFrames-1,this.config.endFrame??this.totalFrames-1),this.endFrame<this.startFrame&&(this.endFrame=this.startFrame),this.currentFrame=this.config.direction==="backward"?this.endFrame:this.startFrame,this.currentLoop=0}setImage(e,t){this.frameCache.clear(),this.dynamicElements[t]||(this.dynamicElements[t]={}),this.dynamicElements[t].image=e}setDynamicText(e,t){this.frameCache.clear(),this.dynamicElements[t]||(this.dynamicElements[t]={}),this.dynamicElements[t].text=e}clearDynamicObject(e){this.frameCache.clear(),this.dynamicElements[e]&&delete this.dynamicElements[e]}clearDynamicObjects(){this.frameCache.clear(),this.dynamicElements={}}async drawExternalPoster(e){return new Promise(t=>{const s=new Image;s.crossOrigin="anonymous",s.onload=()=>{if(this.isPlaying||this.movieData){t();return}const a=this.canvas.getBoundingClientRect();if(a.width>0&&a.height>0){const u=window.devicePixelRatio||1;this.canvas.width=a.width*u,this.canvas.height=a.height*u}else this.canvas.width=s.width,this.canvas.height=s.height;this.clearCanvas();const i=Math.min(this.canvas.width/s.width,this.canvas.height/s.height),r=s.width*i,o=s.height*i;this.ctx.drawImage(s,(this.canvas.width-r)/2,(this.canvas.height-o)/2,r,o),t()},s.onerror=()=>t(),s.src=e})}stepToFrame(e,t=!1){e<0||e>=this.totalFrames||(this.currentFrame=e,this.drawFrame(this.currentFrame),t?this.play():this.stop())}stepToPercentage(e,t=!1){const s=Math.floor(e*this.totalFrames);this.stepToFrame(s<this.totalFrames?s:this.totalFrames-1,t)}setShapeRenderer(e){this.shapeRendererInstance=e}getMemoryInfo(){if(!this.movieData)return{fileSize:0,imageMemory:0,dictionaryMemory:0,version:"",fps:0,frames:0,width:0,height:0,dynamicKeys:[],desc:"\u672A\u52A0\u8F7D\u4EFB\u4F55\u52A8\u6548"};let e=0;this.movieData.images&&Object.values(this.movieData.images).forEach(h=>{h&&typeof h=="object"&&"width"in h&&"height"in h&&(e+=h.width*h.height*4)});const t=JSON.stringify({params:this.movieData.params,sprites:this.movieData.sprites}).length,s=this.movieData.fileSize||0,a=this.movieData.version||"",i=this.movieData.params.fps||20,r=this.movieData.params.frames||0,o=this.movieData.params.viewBoxWidth||0,u=this.movieData.params.viewBoxHeight||0,c=Object.keys(this.dynamicElements);return{fileSize:s,imageMemory:e,dictionaryMemory:t,version:a,fps:i,frames:r,width:o,height:u,dynamicKeys:c,desc:`\u6E90\u6587\u4EF6\u5927\u5C0F: ${(s/1024).toFixed(2)} KB | \u9884\u4F30\u663E\u5B58(\u4F4D\u56FE\u4E0E\u7ED3\u6784): ${((e+t)/1024/1024).toFixed(2)} MB`}}play(e){!this.movieData||this.isPlaying||(e&&(e.fps!==void 0&&(this.config.fps=e.fps),e.loop!==void 0&&(this.config.loop=e.loop,this.currentLoop=0),e.fillMode!==void 0&&(this.config.fillMode=e.fillMode),e.startFrame!==void 0&&(this.config.startFrame=e.startFrame),e.endFrame!==void 0&&(this.config.endFrame=e.endFrame),e.useIntersectionObserver!==void 0&&(this.config.useIntersectionObserver=e.useIntersectionObserver),e.invisibleBehavior!==void 0&&(this.config.invisibleBehavior=e.invisibleBehavior),e.useSharedRAF!==void 0&&(this.config.useSharedRAF=e.useSharedRAF),e.cacheFrames!==void 0&&(this.config.cacheFrames!==e.cacheFrames&&this.frameCache.clear(),this.config.cacheFrames=e.cacheFrames),e.direction!==void 0&&(this.config.direction=e.direction)),this.startFrame=Math.max(0,this.config.startFrame??0),this.endFrame=Math.min(this.totalFrames-1,this.config.endFrame??this.totalFrames-1),this.endFrame<this.startFrame&&(this.endFrame=this.startFrame),(this.currentFrame<this.startFrame||this.currentFrame>this.endFrame)&&(this.currentFrame=this.config.direction==="backward"?this.endFrame:this.startFrame),this.runtimeFps=this.config.fps||this.movieData.params.fps||20,this.isPlaying=!0,this.onStart?.(),this.lastTime=performance.now(),N.add(this.loop,this.config.useSharedRAF!==!1))}stop(){this.isPlaying&&(this.isPlaying=!1,this.onStop?.()),N.remove(this.loop)}pause(){this.isPlaying&&(this.isPlaying=!1,this.onPause?.()),N.remove(this.loop)}reset(){this.stop(),this.currentFrame=0,this.currentLoop=0,this.clearCanvas(),this.movieData&&this.drawFrame(0)}clear(){this.stop(),this.clearCanvas(),this.frameCache.clear(),this.movieData=null,this.currentFrame=0,this.currentLoop=0}destroy(){this.clear(),this.clearDynamicObjects(),this.frameCache.clear(),O&&O.unobserve(this.canvas),j.delete(this.canvas),this.canvas=null,this.ctx=null,this.shapeRendererInstance=null}loop=e=>{if(!this.isPlaying)return;const t=1e3/this.runtimeFps,s=e-this.lastTime;if(s>=t){this.lastTime=e-s%t;const a=!this.observerIsVisible,i=this.config.invisibleBehavior==="pause"||!this.config.invisibleBehavior;if(a&&i)return;if(a||this.drawFrame(this.currentFrame),this.onProcess?.(this.currentFrame),this.config.direction!=="backward"){if(this.currentFrame++,this.currentFrame>this.endFrame||this.currentFrame>=this.totalFrames){if(this.currentLoop++,this.onLoopEnd?.(),this.config.loop&&this.config.loop>0&&this.currentLoop>=this.config.loop){this.stop(),this.config.fillMode==="backwards"?this.stepToFrame(this.startFrame):this.config.fillMode==="clear"?this.clearCanvas():this.drawFrame(this.endFrame);return}this.currentFrame=this.startFrame}}else if(this.currentFrame--,this.currentFrame<this.startFrame){if(this.currentLoop++,this.onLoopEnd?.(),this.config.loop&&this.config.loop>0&&this.currentLoop>=this.config.loop){this.stop(),this.config.fillMode==="backwards"?this.stepToFrame(this.endFrame):this.config.fillMode==="clear"?this.clearCanvas():this.drawFrame(this.startFrame);return}this.currentFrame=this.endFrame}}};clearCanvas(){this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height)}drawFrame(e){if(!this.movieData)return;if(this.config.cacheFrames&&this.frameCache.has(e)){const a=this.frameCache.get(e);this.clearCanvas(),this.ctx.drawImage(a,0,0);return}this.clearCanvas();const{sprites:t,images:s}=this.movieData;for(const a of t){const i=a.frames?.[e];if(!i||i.alpha===0)continue;if(this.ctx.save(),this.ctx.globalAlpha=i.alpha,i.transform){const{a:u,b:c,c:h,d,tx:g,ty:y}=i.transform;this.ctx.transform(u,c,h,d,g,y)}if(i.clipPath){const u=new Path2D(i.clipPath);this.ctx.clip(u)}let r=null;if(a.imageKey){const u=this.dynamicElements[a.imageKey];u&&u.image?r=u.image:s&&s[a.imageKey]&&(r=s[a.imageKey])}const o=i.layout;if(r){let u=0,c=0;"width"in r&&(u=r.width),"height"in r&&(c=r.height),o?this.ctx.drawImage(r,o.x||0,o.y||0,Math.max(o.width,0)||u,Math.max(o.height,0)||c):this.ctx.drawImage(r,0,0)}if(a.imageKey&&this.dynamicElements[a.imageKey]&&this.dynamicElements[a.imageKey].text){const u=this.dynamicElements[a.imageKey].text,c=u.size||"14px",h=u.family||"Arial",d=u.color||"#000000",g=u.offset||{x:0,y:0},y=typeof c=="number"?`${c}px ${h}`:`${c} ${h}`;this.ctx.font=y,this.ctx.fillStyle=d,this.ctx.textBaseline="middle",this.ctx.textAlign="center";let E=g.x,T=g.y;o&&(E+=o.x+o.width/2,T+=o.y+o.height/2),this.ctx.fillText(u.text,E,T)}i.shapes&&i.shapes.length>0&&this.shapeRendererInstance&&this.shapeRendererInstance.drawShapes(this.ctx,i.shapes),this.ctx.restore()}if(this.config.cacheFrames){const a=document.createElement("canvas");a.width=this.canvas.width,a.height=this.canvas.height,a.getContext("2d")?.drawImage(this.canvas,0,0),this.frameCache.set(e,a)}}}class X{renderer;constructor(e,t){let s;e instanceof HTMLDivElement?(s=document.createElement("canvas"),s.style.width="100%",s.style.height="100%",e.appendChild(s)):s=e,t?.useOffscreenCanvas&&typeof s.transferControlToOffscreen=="function"&&typeof Worker<"u"?this.renderer=new V(s,t):this.renderer=new J(s,t)}async setVideoItem(e){this.renderer.clear();const t=this.renderer instanceof V;if(t){if(e&&typeof e=="object"&&!e.isOffscreen&&(e.sprites||e.images))throw new Error("[SVGA \u64AD\u653E\u5668\u4E25\u91CD\u9519\u8BEF] \u5F53\u524D\u5DF2\u5F00\u542F Offscreen \u79BB\u5C4F\u6E32\u67D3\u4F18\u5316\uFF01\u5728\u79BB\u5C4F\u6E32\u67D3\u6A21\u5F0F\u4E0B\uFF0C\u4E25\u683C\u7981\u6B62\u5411\u64AD\u653E\u5668 setVideoItem \u4F20\u9012\u4E3B\u7EBF\u7A0B\u7684\u5B8C\u6574\u590D\u6742 MovieData \u6570\u636E\uFF08\u8FD9\u4F1A\u5BFC\u81F4\u4E3B\u7EBF\u7A0B\u4E8C\u6B21\u53CD\u5E8F\u5217\u5316\u4E0E\u591A\u4EFD\u56FE\u50CF\u7559\u5B58\uFF0C\u4F7F\u624B\u673A\u5185\u5B58\u6210\u500D\u66B4\u589E\uFF09\u3002\u8BF7\u6539\u7528\u4E3A\u79BB\u5C4F\u6A21\u5F0F\u4E13\u5C5E\u89E3\u8026\u8BBE\u8BA1\u7684\u52A0\u8F7D\u65B9\u6CD5\u3010Parser.load(url)\u3011\u83B7\u53D6\u4EC5\u542B ID \u7684\u8F7B\u91CF\u53E5\u67C4\uFF0C\u6216\u8005\u76F4\u63A5\u4F20\u5165 String \u7C7B\u578B\u7684 URL \u81EA\u9002\u5E94\u79BB\u5C4F\u6D41\u3002")}else if(e&&typeof e=="object"&&e.isOffscreen)throw new Error("[SVGA \u64AD\u653E\u5668\u4E25\u91CD\u9519\u8BEF] \u5F53\u524D\u4F7F\u7528\u7684\u662F\u4E3B\u7EBF\u7A0B\u4F20\u7EDF\u6E32\u67D3\u5668\uFF0C\u4F46\u5374\u4F20\u5165\u4E86\u5B50\u7EBF\u7A0B\u4E13\u7528\u7684\u79BB\u5C4F\u8F7B\u91CF\u5316\u5143\u6570\u636E\u53E5\u67C4 (isOffscreen: true)\uFF01\u8FD9\u5C06\u5BFC\u81F4\u4E3B\u7EBF\u7A0B\u6CA1\u6709\u4EFB\u4F55\u53EF\u4EE5\u7528\u4E8E\u7ED8\u5236\u548C\u53CD\u5E8F\u5217\u5316\u7684\u56FE\u50CF/\u7CBE\u7075\u5E8F\u5217\u6811\u4FE1\u606F\u3002\u5728\u666E\u901A\u6E32\u67D3\u6A21\u5F0F\u4E0B\uFF0C\u8BF7\u4F7F\u7528\u4E3B\u7EBF\u7A0B\u52A0\u8F7D\u65B9\u6CD5\u3010Parser.loadUrl(url)\u3011\u6216\u3010Parser.loadFile(file)\u3011\u3002");if(typeof e=="string")if(t){await this.renderer.setMovie({movieDataId:e});return}else{const{Parser:a}=await Promise.resolve().then(function(){return H}),i=a.getCachedVideoItem(e)||await a.loadUrl(e);i&&await this.renderer.setMovie(i);return}let s=!1;if(e&&e.sprites)for(const a of e.sprites){if(s)break;if(a.frames){for(const i of a.frames)if(i.shapes&&i.shapes.length>0){s=!0;break}}}if(s){const{ShapeRenderer:a}=await import("./ShapeRenderer-BbtJ_1XO.js");this.renderer.setShapeRenderer(a.getInstance())}await this.renderer.setMovie(e)}play(e){this.renderer.play(e)}playRange(e,t,s){this.renderer.play(Object.assign({startFrame:e,endFrame:t},s))}pause(){this.renderer.pause()}stop(){this.renderer.stop()}onStart(e){this.renderer.onStart=e}onPause(e){this.renderer.onPause=e}onStop(e){this.renderer.onStop=e}onLoopEnd(e){this.renderer.onLoopEnd=e}onProcess(e){this.renderer.onProcess=e}stepToFrame(e,t=!1){this.renderer.stepToFrame(e,t)}stepToPercentage(e,t=!1){this.renderer.stepToPercentage(e,t)}async setImage(e,t){if(typeof e=="string"){const s=new Image;s.crossOrigin="anonymous";const a=new Promise((i,r)=>{s.onload=()=>i(s),s.onerror=o=>r(o)});s.src=e;try{const i=await a;await this.renderer.setImage(i,t)}catch(i){console.warn(`[Player] \u52A8\u6001\u52A0\u8F7D\u56FE\u7247\u94FE\u63A5 ${e} \u5931\u8D25\uFF1A`,i)}}else await this.renderer.setImage(e,t)}setText(e,t){typeof e=="string"?this.renderer.setDynamicText({text:e},t):this.renderer.setDynamicText(e,t)}clearDynamicObject(e){this.renderer.clearDynamicObject(e)}clearDynamicObjects(){this.renderer.clearDynamicObjects()}async renderPoster(e){await this.renderer.drawExternalPoster(e)}getMemoryInfo(){return this.renderer.getMemoryInfo()}clear(){this.renderer.clear()}destroy(){this.renderer.destroy()}}export{l as Parser,X as Player};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var CustomSvga=function(e){"use strict";var t,s=typeof document<"u"?document.currentScript:null,a=((t=a||{}).INIT="init",t.VISIBILITY="visibility",t.SET_MOVIE="setMovie",t.SET_IMAGE="setImage",t.SET_DYNAMIC_TEXT="setDynamicText",t.DRAW_EXTERNAL_POSTER="drawExternalPoster",t.PLAY="play",t.STOP="stop",t.PAUSE="pause",t.STEP_TO_FRAME="stepToFrame",t.STEP_TO_PERCENTAGE="stepToPercentage",t.CLEAR="clear",t.CLEAR_DYNAMIC_OBJECTS="clearDynamicObjects",t.CLEAR_DYNAMIC_OBJECT="clearDynamicObject",t.DESTROY="destroy",t.PARSE="parse",t.PARSE_OFFSCREEN="parse_offscreen",t.RELEASE_CACHE="releaseCache",t),i=(e=>(e.SUCCESS="SUCCESS",e.ERROR="ERROR",e.EVENT="event",e))(i||{}),r=(e=>(e.READY="ready",e.ON_START="onStart",e.ON_STOP="onStop",e.ON_PAUSE="onPause",e.ON_PROCESS="onProcess",e.ON_LOOP_END="onLoopEnd",e.ON_REQUEST_MOVIE_DATA="onRequestMovieData",e))(r||{});let n=null,o=null;const c=new Map;let h=0,d={};const m=new Map;let l=null;function f(){if(!n){if(d.workerCreator)n=d.workerCreator();else if(d.workerUrl)n=new Worker(d.workerUrl);else{let e;try{e=typeof{url:s&&"SCRIPT"===s.tagName.toUpperCase()&&s.src||new URL("index.global.js",document.baseURI).href}<"u"&&(s&&"SCRIPT"===s.tagName.toUpperCase()&&s.src||new URL("index.global.js",document.baseURI).href)?new URL("./svga.worker.ts",s&&"SCRIPT"===s.tagName.toUpperCase()&&s.src||new URL("index.global.js",document.baseURI).href):"./svga.worker.ts"}catch{e="./svga.worker.ts"}n=new Worker(e,{type:"module"})}n.onmessage=e=>{const{type:t,id:s,name:a,args:n,taskId:o}=e.data;if(void 0!==o)return void(l&&l(e.data));const h=c.get(s);h&&t===i.EVENT&&(a===r.ON_START&&h.onStart?h.onStart():a===r.ON_STOP&&h.onStop?h.onStop():a===r.ON_PAUSE&&h.onPause?h.onPause():a===r.ON_LOOP_END&&h.onLoopEnd?h.onLoopEnd():a===r.ON_PROCESS&&h.onProcess?h.onProcess(n[0]):a===r.ON_REQUEST_MOVIE_DATA&&h.resendMovieData())}}return n}class p{id;canvas;observerIsVisible=!0;worker;onStart;onPause;onStop;onLoopEnd;onProcess;_dynamicKeys=new Set;_config;_shapeRendererInstance=null;_movieData=null;constructor(e,t){this.canvas=e,this.id="renderer_"+h++,this._config=Object.assign({loop:0,useIntersectionObserver:!0,useSharedRAF:!0,invisibleBehavior:"pause"},t),c.set(this.id,this),this.worker=f();const s=e.transferControlToOffscreen();this.worker.postMessage({type:a.INIT,id:this.id,canvas:s,config:this._config},[s]),!1!==this._config.useIntersectionObserver&&(!o&&typeof IntersectionObserver<"u"&&(o=new IntersectionObserver(e=>{e.forEach(e=>{Array.from(c.values()).filter(t=>t.canvas===e.target).forEach(t=>{t.observerIsVisible=e.isIntersecting,t.worker.postMessage({type:a.VISIBILITY,id:t.id,visible:t.observerIsVisible})})})})),o&&o.observe(this.canvas))}async resendMovieData(){if(this._movieData){const e=this._movieData.movieDataId||"movie_direct_"+Math.random().toString(36).substring(2)+Date.now(),t={},s=[];if(typeof createImageBitmap<"u"&&this._movieData.images)for(const[e,a]of Object.entries(this._movieData.images))if(a instanceof ImageBitmap)try{const i=await createImageBitmap(a);t[e]=i,s.push(i)}catch(e){console.warn("[离屏渲染器] 重新发送动画数据时克隆位图失败:",e)}const i={...this._movieData,images:t,imageBytes:void 0};m.set(this.id,e),this.worker.postMessage({type:a.SET_MOVIE,id:this.id,movieData:i,movieDataId:e},s)}}async setMovie(e){this._movieData=e;const t=e.movieDataId||"movie_direct_"+Math.random().toString(36).substring(2)+Date.now();m.set(this.id,t),this.worker.postMessage({type:a.SET_MOVIE,id:this.id,movieData:null,movieDataId:t})}async setImage(e,t){if(this._dynamicKeys.add(t),typeof createImageBitmap<"u")try{const s=await createImageBitmap(e);this.worker.postMessage({type:a.SET_IMAGE,id:this.id,key:t,image:s},[s])}catch(e){console.warn("[离屏渲染器] 设置动态图片时克隆位图对象失败:",e)}}setDynamicText(e,t){this._dynamicKeys.add(t),this.worker.postMessage({type:a.SET_DYNAMIC_TEXT,id:this.id,key:t,text:e})}setShapeRenderer(e){this._shapeRendererInstance=e}async drawExternalPoster(e){try{const t=await(await fetch(e)).blob(),s=await createImageBitmap(t);this.worker.postMessage({type:a.DRAW_EXTERNAL_POSTER,id:this.id,image:s},[s])}catch(e){console.warn("[离屏渲染器] 载入并生成静态海报海报失败:",e)}}play(e){this.worker.postMessage({type:a.PLAY,id:this.id,config:e})}stop(){this.worker.postMessage({type:a.STOP,id:this.id})}pause(){this.worker.postMessage({type:a.PAUSE,id:this.id})}stepToFrame(e,t=!1){this.worker.postMessage({type:a.STEP_TO_FRAME,id:this.id,frame:e,andPlay:t})}stepToPercentage(e,t){this.worker.postMessage({type:a.STEP_TO_PERCENTAGE,id:this.id,percentage:e,andPlay:t})}clear(){this.worker.postMessage({type:a.CLEAR,id:this.id})}clearDynamicObject(e){this._dynamicKeys.delete(e),this.worker.postMessage({type:a.CLEAR_DYNAMIC_OBJECT,id:this.id,key:e})}clearDynamicObjects(){this._dynamicKeys.clear(),this.worker.postMessage({type:a.CLEAR_DYNAMIC_OBJECTS,id:this.id})}getMemoryInfo(){if(!this._movieData)return{fileSize:0,imageMemory:0,dictionaryMemory:0,version:"",fps:0,frames:0,width:0,height:0,dynamicKeys:[],desc:"未加载任何动效"};let e=0;this._movieData.images&&Object.values(this._movieData.images).forEach(t=>{t&&t.width&&(e+=t.width*t.height*4)});const t=JSON.stringify({params:this._movieData.params,sprites:this._movieData.sprites}).length,s=this._movieData.fileSize||0,a=this._movieData.version||"",i=this._movieData.params.fps||20,r=this._movieData.params.frames||0,n=this._movieData.params.viewBoxWidth||0,o=this._movieData.params.viewBoxHeight||0,c=Array.from(this._dynamicKeys);return{fileSize:s,imageMemory:e,dictionaryMemory:t,version:a,fps:i,frames:r,width:n,height:o,dynamicKeys:c,desc:`源文件大小: ${(s/1024).toFixed(2)} KB | 预估显存(位图与结构): ${((e+t)/1024/1024).toFixed(2)} MB`}}destroy(){o&&o.unobserve(this.canvas),m.delete(this.id),c.delete(this.id),this.worker.postMessage({type:a.DESTROY,id:this.id})}}class g{static async loadUrl(e){const t=await fetch(e);if(!t.ok)throw new Error(`无法从 ${e} 加载 SVGA 文件: ${t.statusText}`);return await t.arrayBuffer()}static async loadFile(e){return new Promise((t,s)=>{const a=new FileReader;a.onload=()=>{a.result instanceof ArrayBuffer?t(a.result):s(new Error("无法读取文件的 ArrayBuffer 数据"))},a.onerror=()=>s(a.error),a.readAsArrayBuffer(e)})}}let y=0;const v=new Map,u=new Map,w=new Map,E=new Map,I=new Map;!function(e){l=e}(e=>{const{taskId:t,type:s,data:a,error:r}=e,n=v.get(t);if(n){const{useImageBitmap:e}=n;if(s===i.SUCCESS)if(a&&a.images&&!e){const e=[],t=a.images,s={};Object.keys(t).forEach(a=>{const i=t[a];if(i instanceof Uint8Array&&i.length>0){const t=new Promise(e=>{let t="image/png";255===i[0]&&216===i[1]?t="image/jpeg":71===i[0]&&73===i[1]&&70===i[2]?t="image/gif":82===i[0]&&73===i[1]&&70===i[2]&&70===i[3]&&(t="image/webp");const r=new Blob([i],{type:t}),n=URL.createObjectURL(r),o=new Image;o.onload=()=>{s[a]=o,URL.revokeObjectURL(n),e()},o.onerror=()=>{s[a]=o,URL.revokeObjectURL(n),e()},o.src=n});e.push(t)}else s[a]=i}),e.length>0?Promise.all(e).then(()=>{Object.keys(t).forEach(e=>{t[e]=null}),a.images=s,n.resolve(a)}).catch(e=>{n.reject(e)}):(a.images=s,n.resolve(a))}else n.resolve(a);else n.reject(new Error(r||"解析 SVGA 文件失败"));v.delete(t)}});class F{static getCachedVideoItem(e){return u.get(e)}static async loadUrl(e,t){const s=!1!==t?.cache;if(s&&u.has(e)){const t=u.get(e);return u.delete(e),u.set(e,t),t}if(w.has(e))return w.get(e);const a=(async()=>{try{const a=await g.loadUrl(e),i=await F.parseBuffer(a,{...t,movieDataId:e});return s&&(u.set(e,i),function(){if(u.size>20){const e=u.keys().next().value;e&&F.destroyCache(e)}}()),i}catch(t){throw w.delete(e),t}finally{w.delete(e)}})();return w.set(e,a),a}static async loadFile(e,t){const s=await g.loadFile(e);return await F.parseBuffer(s,t)}static parseBuffer(e,t){const s=t?.useImageBitmap??!1,i=!1!==t?.cache,r=t?.movieDataId||"movie_direct_"+Math.random().toString(36).substring(2)+Date.now();return new Promise((t,n)=>{try{const o=f(),c=++y;v.set(c,{resolve:t,reject:n,useImageBitmap:s}),o.postMessage({type:a.PARSE,taskId:c,buffer:e,fileSize:e.byteLength,movieDataId:r,useImageBitmap:s,cache:i},[e])}catch(e){e instanceof Error?n(e):n(new Error("未知错误"))}})}static async load(e,t){const s=!1!==t?.cache;if(s&&E.has(e)){const t=E.get(e);return E.delete(e),E.set(e,t),t}if(I.has(e))return I.get(e);const a=(async()=>{try{const a=await g.loadUrl(e),i=await F.parseBufferOffscreen(a,e,t);if(s&&(E.set(e,i),E.size>20)){const e=E.keys().next().value;e&&F.destroyOffscreenCache(e)}return i}catch(t){throw I.delete(e),t}finally{I.delete(e)}})();return I.set(e,a),a}static parseBufferOffscreen(e,t,s){const i=!1!==s?.cache;return new Promise((s,r)=>{try{const n=f(),o=++y;v.set(o,{resolve:s,reject:r}),n.postMessage({type:a.PARSE_OFFSCREEN,taskId:o,buffer:e,fileSize:e.byteLength,movieDataId:t,cache:i},[e])}catch(e){e instanceof Error?r(e):r(new Error("未知错误"))}})}static destroyCache(e){const t=u.get(e);t&&t.images&&Object.keys(t.images).forEach(e=>{const s=t.images[e];s&&("function"==typeof s.close?s.close():s instanceof HTMLImageElement&&(s.src="")),t.images[e]=null}),u.delete(e)}static clearCache(){Array.from(u.keys()).forEach(e=>{F.destroyCache(e)}),u.clear()}static destroyOffscreenCache(e,t=!0){E.delete(e);try{f().postMessage({type:a.RELEASE_CACHE,movieDataId:e,force:t})}catch(e){console.warn("[Parser] 发送手动销毁消息失败:",e)}}static clearOffscreenCache(){E.clear();try{f().postMessage({type:a.RELEASE_CACHE,movieDataId:void 0,force:!0})}catch(e){console.warn("[Parser] 发送清空所有离屏缓存消息失败:",e)}}static destroy(e){if(null==e)return F.clearCache(),void F.clearOffscreenCache();if("string"==typeof e)return F.destroyCache(e),void F.destroyOffscreenCache(e);if("object"==typeof e){const{url:t,mainThread:s,offscreen:a}=e,i=void 0!==s?s:void 0===a,r=void 0!==a?a:void 0===s;t?(i&&F.destroyCache(t),r&&F.destroyOffscreenCache(t)):(i&&F.clearCache(),r&&F.clearOffscreenCache())}}static setWorkerConfig(e){!function(e){d={...d,...e}}(e)}}var S=Object.freeze({__proto__:null,Parser:F});const b=()=>typeof globalThis.requestAnimationFrame<"u"?globalThis.requestAnimationFrame.bind(globalThis):e=>setTimeout(()=>e(performance.now()),16.666666666666668),T=()=>typeof globalThis.cancelAnimationFrame<"u"?globalThis.cancelAnimationFrame.bind(globalThis):e=>clearTimeout(e);class O{static instance;sharedTasks=new Set;sharedRafId=0;standaloneTasks=new Map;static getInstance(){return O.instance||(O.instance=new O),O.instance}add(e,t=!0){if(t)this.sharedTasks.add(e),1===this.sharedTasks.size&&0===this.sharedRafId&&this.startShared();else if(!this.standaloneTasks.has(e)){const t=s=>{try{e(s)}catch(e){console.error("[SVGA 定时器] 独立渲染任务执行异常:",e)}const a=b()(t);this.standaloneTasks.set(e,a)},s=b()(t);this.standaloneTasks.set(e,s)}}remove(e){if(this.sharedTasks.has(e)&&(this.sharedTasks.delete(e),0===this.sharedTasks.size&&this.stopShared()),this.standaloneTasks.has(e)){const t=this.standaloneTasks.get(e);t&&T()(t),this.standaloneTasks.delete(e)}}startShared(){const e=t=>{this.sharedTasks.forEach(e=>{try{e(t)}catch(e){console.error("[SVGA 定时器] 共享渲染任务执行异常:",e)}}),this.sharedTasks.size>0?this.sharedRafId=b()(e):this.sharedRafId=0};this.sharedRafId=b()(e)}stopShared(){0!==this.sharedRafId&&(T()(this.sharedRafId),this.sharedRafId=0)}}const D=O.getInstance(),_=new WeakMap;let C=null;class P{canvas;ctx;observerIsVisible=!0;movieData=null;isPlaying=!1;currentFrame=0;runtimeFps=20;totalFrames=0;shapeRendererInstance=null;lastTime=0;config;currentLoop=0;onStart;onPause;onStop;onLoopEnd;onProcess;dynamicElements={};startFrame=0;endFrame=0;frameCache=new Map;constructor(e,t){if(this.canvas=e,this.config=Object.assign({loop:0,useIntersectionObserver:!0,useSharedRAF:!0,useOffscreenCanvas:!1,invisibleBehavior:"pause"},t),this.ctx=e.getContext("2d"),!this.ctx)throw new Error("获取 2D 上下文失败");_.set(e,this),this.initObserver()}initObserver(){typeof IntersectionObserver<"u"&&!1!==this.config.useIntersectionObserver&&(this.observerIsVisible=!0,C||(C=new IntersectionObserver(e=>{e.forEach(e=>{const t=_.get(e.target);t&&(t.observerIsVisible=e.isIntersecting)})})),C.observe(this.canvas))}setMovie(e){this.frameCache.clear(),this.movieData=e,this.totalFrames=e.params.frames||1,this.canvas.width=e.params.viewBoxWidth||300,this.canvas.height=e.params.viewBoxHeight||300,this.startFrame=Math.max(0,this.config.startFrame??0),this.endFrame=Math.min(this.totalFrames-1,this.config.endFrame??this.totalFrames-1),this.endFrame<this.startFrame&&(this.endFrame=this.startFrame),this.currentFrame="backward"===this.config.direction?this.endFrame:this.startFrame,this.currentLoop=0}setImage(e,t){this.frameCache.clear(),this.dynamicElements[t]||(this.dynamicElements[t]={}),this.dynamicElements[t].image=e}setDynamicText(e,t){this.frameCache.clear(),this.dynamicElements[t]||(this.dynamicElements[t]={}),this.dynamicElements[t].text=e}clearDynamicObject(e){this.frameCache.clear(),this.dynamicElements[e]&&delete this.dynamicElements[e]}clearDynamicObjects(){this.frameCache.clear(),this.dynamicElements={}}async drawExternalPoster(e){return new Promise(t=>{const s=new Image;s.crossOrigin="anonymous",s.onload=()=>{if(this.isPlaying||this.movieData)return void t();const e=this.canvas.getBoundingClientRect();if(e.width>0&&e.height>0){const t=window.devicePixelRatio||1;this.canvas.width=e.width*t,this.canvas.height=e.height*t}else this.canvas.width=s.width,this.canvas.height=s.height;this.clearCanvas();const a=Math.min(this.canvas.width/s.width,this.canvas.height/s.height),i=s.width*a,r=s.height*a;this.ctx.drawImage(s,(this.canvas.width-i)/2,(this.canvas.height-r)/2,i,r),t()},s.onerror=()=>t(),s.src=e})}stepToFrame(e,t=!1){e<0||e>=this.totalFrames||(this.currentFrame=e,this.drawFrame(this.currentFrame),t?this.play():this.stop())}stepToPercentage(e,t=!1){const s=Math.floor(e*this.totalFrames);this.stepToFrame(s<this.totalFrames?s:this.totalFrames-1,t)}setShapeRenderer(e){this.shapeRendererInstance=e}getMemoryInfo(){if(!this.movieData)return{fileSize:0,imageMemory:0,dictionaryMemory:0,version:"",fps:0,frames:0,width:0,height:0,dynamicKeys:[],desc:"未加载任何动效"};let e=0;this.movieData.images&&Object.values(this.movieData.images).forEach(t=>{t&&"object"==typeof t&&"width"in t&&"height"in t&&(e+=t.width*t.height*4)});const t=JSON.stringify({params:this.movieData.params,sprites:this.movieData.sprites}).length,s=this.movieData.fileSize||0,a=this.movieData.version||"",i=this.movieData.params.fps||20,r=this.movieData.params.frames||0,n=this.movieData.params.viewBoxWidth||0,o=this.movieData.params.viewBoxHeight||0,c=Object.keys(this.dynamicElements);return{fileSize:s,imageMemory:e,dictionaryMemory:t,version:a,fps:i,frames:r,width:n,height:o,dynamicKeys:c,desc:`源文件大小: ${(s/1024).toFixed(2)} KB | 预估显存(位图与结构): ${((e+t)/1024/1024).toFixed(2)} MB`}}play(e){!this.movieData||this.isPlaying||(e&&(void 0!==e.fps&&(this.config.fps=e.fps),void 0!==e.loop&&(this.config.loop=e.loop,this.currentLoop=0),void 0!==e.fillMode&&(this.config.fillMode=e.fillMode),void 0!==e.startFrame&&(this.config.startFrame=e.startFrame),void 0!==e.endFrame&&(this.config.endFrame=e.endFrame),void 0!==e.useIntersectionObserver&&(this.config.useIntersectionObserver=e.useIntersectionObserver),void 0!==e.invisibleBehavior&&(this.config.invisibleBehavior=e.invisibleBehavior),void 0!==e.useSharedRAF&&(this.config.useSharedRAF=e.useSharedRAF),void 0!==e.cacheFrames&&(this.config.cacheFrames!==e.cacheFrames&&this.frameCache.clear(),this.config.cacheFrames=e.cacheFrames),void 0!==e.direction&&(this.config.direction=e.direction)),this.startFrame=Math.max(0,this.config.startFrame??0),this.endFrame=Math.min(this.totalFrames-1,this.config.endFrame??this.totalFrames-1),this.endFrame<this.startFrame&&(this.endFrame=this.startFrame),(this.currentFrame<this.startFrame||this.currentFrame>this.endFrame)&&(this.currentFrame="backward"===this.config.direction?this.endFrame:this.startFrame),this.runtimeFps=this.config.fps||this.movieData.params.fps||20,this.isPlaying=!0,this.onStart?.(),this.lastTime=performance.now(),D.add(this.loop,!1!==this.config.useSharedRAF))}stop(){this.isPlaying&&(this.isPlaying=!1,this.onStop?.()),D.remove(this.loop)}pause(){this.isPlaying&&(this.isPlaying=!1,this.onPause?.()),D.remove(this.loop)}reset(){this.stop(),this.currentFrame=0,this.currentLoop=0,this.clearCanvas(),this.movieData&&this.drawFrame(0)}clear(){this.stop(),this.clearCanvas(),this.frameCache.clear(),this.movieData=null,this.currentFrame=0,this.currentLoop=0}destroy(){this.clear(),this.clearDynamicObjects(),this.frameCache.clear(),C&&C.unobserve(this.canvas),_.delete(this.canvas),this.canvas=null,this.ctx=null,this.shapeRendererInstance=null}loop=e=>{if(!this.isPlaying)return;const t=1e3/this.runtimeFps,s=e-this.lastTime;if(s>=t){this.lastTime=e-s%t;const a=!this.observerIsVisible,i="pause"===this.config.invisibleBehavior||!this.config.invisibleBehavior;if(a&&i)return;if(a||this.drawFrame(this.currentFrame),this.onProcess?.(this.currentFrame),"backward"!==this.config.direction){if(this.currentFrame++,this.currentFrame>this.endFrame||this.currentFrame>=this.totalFrames){if(this.currentLoop++,this.onLoopEnd?.(),this.config.loop&&this.config.loop>0&&this.currentLoop>=this.config.loop)return this.stop(),void("backwards"===this.config.fillMode?this.stepToFrame(this.startFrame):"clear"===this.config.fillMode?this.clearCanvas():this.drawFrame(this.endFrame));this.currentFrame=this.startFrame}}else if(this.currentFrame--,this.currentFrame<this.startFrame){if(this.currentLoop++,this.onLoopEnd?.(),this.config.loop&&this.config.loop>0&&this.currentLoop>=this.config.loop)return this.stop(),void("backwards"===this.config.fillMode?this.stepToFrame(this.endFrame):"clear"===this.config.fillMode?this.clearCanvas():this.drawFrame(this.startFrame));this.currentFrame=this.endFrame}}};clearCanvas(){this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height)}drawFrame(e){if(!this.movieData)return;if(this.config.cacheFrames&&this.frameCache.has(e)){const t=this.frameCache.get(e);return this.clearCanvas(),void this.ctx.drawImage(t,0,0)}this.clearCanvas();const{sprites:t,images:s}=this.movieData;for(const a of t){const t=a.frames?.[e];if(!t||0===t.alpha)continue;if(this.ctx.save(),this.ctx.globalAlpha=t.alpha,t.transform){const{a:e,b:s,c:a,d:i,tx:r,ty:n}=t.transform;this.ctx.transform(e,s,a,i,r,n)}if(t.clipPath){const e=new Path2D(t.clipPath);this.ctx.clip(e)}let i=null;if(a.imageKey){const e=this.dynamicElements[a.imageKey];e&&e.image?i=e.image:s&&s[a.imageKey]&&(i=s[a.imageKey])}const r=t.layout;if(i){let e=0,t=0;"width"in i&&(e=i.width),"height"in i&&(t=i.height),r?this.ctx.drawImage(i,r.x||0,r.y||0,Math.max(r.width,0)||e,Math.max(r.height,0)||t):this.ctx.drawImage(i,0,0)}if(a.imageKey&&this.dynamicElements[a.imageKey]&&this.dynamicElements[a.imageKey].text){const e=this.dynamicElements[a.imageKey].text,t=e.size||"14px",s=e.family||"Arial",i=e.color||"#000000",n=e.offset||{x:0,y:0},o="number"==typeof t?`${t}px ${s}`:`${t} ${s}`;this.ctx.font=o,this.ctx.fillStyle=i,this.ctx.textBaseline="middle",this.ctx.textAlign="center";let c=n.x,h=n.y;r&&(c+=r.x+r.width/2,h+=r.y+r.height/2),this.ctx.fillText(e.text,c,h)}t.shapes&&t.shapes.length>0&&this.shapeRendererInstance&&this.shapeRendererInstance.drawShapes(this.ctx,t.shapes),this.ctx.restore()}if(this.config.cacheFrames){const t=document.createElement("canvas");t.width=this.canvas.width,t.height=this.canvas.height,t.getContext("2d")?.drawImage(this.canvas,0,0),this.frameCache.set(e,t)}}}class R{static instance;constructor(){}static getInstance(){return R.instance||(R.instance=new R),R.instance}drawShapes(e,t){for(const s of t){let t=null;if(0===s.type&&s.shape&&s.shape.d)t=new Path2D(s.shape.d);else if(1===s.type&&s.rect){const{x:e,y:a,width:i,height:r,cornerRadius:n}=s.rect;t=new Path2D,n>0?t.roundRect(e,a,i,r,n):t.rect(e,a,i,r)}else if(2===s.type&&s.ellipse){const{x:e,y:a,radiusX:i,radiusY:r}=s.ellipse;t=new Path2D,t.ellipse(e,a,i,r,0,0,2*Math.PI)}if(t&&s.styles){const{fill:a,stroke:i,strokeWidth:r,lineCap:n,lineJoin:o,miterLimit:c,lineDash:h}=s.styles;if(s.transform){e.save();const{a:t,b:a,c:i,d:r,tx:n,ty:o}=s.transform;e.transform(t,a,i,r,n,o)}a&&(e.fillStyle="rgba("+255*a.r+", "+255*a.g+", "+255*a.b+", "+a.a+")",e.fill(t)),i&&(e.strokeStyle="rgba("+255*i.r+", "+255*i.g+", "+255*i.b+", "+i.a+")",e.lineWidth=r||1,n&&(e.lineCap=n.toLowerCase()),o&&(e.lineJoin=o.toLowerCase()),c&&(e.miterLimit=c),h&&h.length>0?e.setLineDash(h):e.setLineDash([]),e.stroke(t)),s.transform&&e.restore()}}}}var M=Object.freeze({__proto__:null,ShapeRenderer:R});return e.Parser=F,e.Player=class{renderer;constructor(e,t){let s;e instanceof HTMLDivElement?(s=document.createElement("canvas"),s.style.width="100%",s.style.height="100%",e.appendChild(s)):s=e,t?.useOffscreenCanvas&&"function"==typeof s.transferControlToOffscreen&&typeof Worker<"u"?this.renderer=new p(s,t):this.renderer=new P(s,t)}async setVideoItem(e){this.renderer.clear();const t=this.renderer instanceof p;if(t){if(e&&"object"==typeof e&&!e.isOffscreen&&(e.sprites||e.images))throw new Error("[SVGA 播放器严重错误] 当前已开启 Offscreen 离屏渲染优化!在离屏渲染模式下,严格禁止向播放器 setVideoItem 传递主线程的完整复杂 MovieData 数据(这会导致主线程二次反序列化与多份图像留存,使手机内存成倍暴增)。请改用为离屏模式专属解耦设计的加载方法【Parser.load(url)】获取仅含 ID 的轻量句柄,或者直接传入 String 类型的 URL 自适应离屏流。")}else if(e&&"object"==typeof e&&e.isOffscreen)throw new Error("[SVGA 播放器严重错误] 当前使用的是主线程传统渲染器,但却传入了子线程专用的离屏轻量化元数据句柄 (isOffscreen: true)!这将导致主线程没有任何可以用于绘制和反序列化的图像/精灵序列树信息。在普通渲染模式下,请使用主线程加载方法【Parser.loadUrl(url)】或【Parser.loadFile(file)】。");if("string"==typeof e){if(t)return void await this.renderer.setMovie({movieDataId:e});{const{Parser:t}=await Promise.resolve().then(function(){return S}),s=t.getCachedVideoItem(e)||await t.loadUrl(e);return void(s&&await this.renderer.setMovie(s))}}let s=!1;if(e&&e.sprites)for(const t of e.sprites){if(s)break;if(t.frames)for(const e of t.frames)if(e.shapes&&e.shapes.length>0){s=!0;break}}if(s){const{ShapeRenderer:e}=await Promise.resolve().then(function(){return M});this.renderer.setShapeRenderer(e.getInstance())}await this.renderer.setMovie(e)}play(e){this.renderer.play(e)}playRange(e,t,s){this.renderer.play(Object.assign({startFrame:e,endFrame:t},s))}pause(){this.renderer.pause()}stop(){this.renderer.stop()}onStart(e){this.renderer.onStart=e}onPause(e){this.renderer.onPause=e}onStop(e){this.renderer.onStop=e}onLoopEnd(e){this.renderer.onLoopEnd=e}onProcess(e){this.renderer.onProcess=e}stepToFrame(e,t=!1){this.renderer.stepToFrame(e,t)}stepToPercentage(e,t=!1){this.renderer.stepToPercentage(e,t)}async setImage(e,t){if("string"==typeof e){const s=new Image;s.crossOrigin="anonymous";const a=new Promise((e,t)=>{s.onload=()=>e(s),s.onerror=e=>t(e)});s.src=e;try{const e=await a;await this.renderer.setImage(e,t)}catch(t){console.warn(`[Player] 动态加载图片链接 ${e} 失败:`,t)}}else await this.renderer.setImage(e,t)}setText(e,t){"string"==typeof e?this.renderer.setDynamicText({text:e},t):this.renderer.setDynamicText(e,t)}clearDynamicObject(e){this.renderer.clearDynamicObject(e)}clearDynamicObjects(){this.renderer.clearDynamicObjects()}async renderPoster(e){await this.renderer.drawExternalPoster(e)}getMemoryInfo(){return this.renderer.getMemoryInfo()}clear(){this.renderer.clear()}destroy(){this.renderer.destroy()}},e}({});
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "custom-svga",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A lightweight, tree-shakable SVGA animation player for Vue 3 & modern web. Supports dynamic imports, OffscreenCanvas + Web Worker, and in-flight sprite/text replacement. ~30KB gzipped, zero deps on UI frameworks.(面向 Vue3 与现代浏览器的轻量 SVGA 动画播放器。支持动态导入懒加载、OffscreenCanvas 离屏渲染、动态精灵/文本替换,gzip 后约 30KB,零 UI 框架依赖。)",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "DreamLife(Zhou)",
|
|
7
|
+
"email": "1707979815@qq.com"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"main": "./dist/index.cjs",
|
|
11
|
+
"module": "./dist/index.esm.js",
|
|
12
|
+
"unpkg": "./dist/index.global.js",
|
|
13
|
+
"jsdelivr": "./dist/index.global.js",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"import": "./dist/index.esm.js",
|
|
19
|
+
"require": "./dist/index.cjs",
|
|
20
|
+
"default": "./dist/index.global.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build:tsup": "tsup",
|
|
28
|
+
"build:rollup": "npm run clean && rollup -c",
|
|
29
|
+
"clean": "rimraf dist"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@rollup/plugin-commonjs": "^26.0.0",
|
|
33
|
+
"@rollup/plugin-node-resolve": "^15.0.0",
|
|
34
|
+
"@rollup/plugin-terser": "^0.4.0",
|
|
35
|
+
"rimraf": "^5.0.0",
|
|
36
|
+
"rollup": "^4.0.0",
|
|
37
|
+
"rollup-plugin-dts": "^6.0.0",
|
|
38
|
+
"rollup-plugin-esbuild": "^6.2.1",
|
|
39
|
+
"tsup": "^8.0.0",
|
|
40
|
+
"typescript": "^5.0.0"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"fflate": "^0.8.3",
|
|
44
|
+
"protobufjs": "^8.7.0"
|
|
45
|
+
}
|
|
46
|
+
}
|