import { Downloader, EVENT_TYPES, Parser, Player } from 'svga.lite'; import Parser1x from 'svga.lite/parser.1x'; import * as util from 'svga.lite/util'; import DB from 'svga.lite/db'; import { Lock, logger } from '../utils'; import type { Options } from './types.d'; let downloader: Downloader; let parser1x: typeof Parser1x; let parser: Parser; const parserLock = new Lock(); class SvgaPlayer { private player!: Player | null; private options!: Options; lock = new Lock(); constructor(options: Options) { this.options = options; this.render(); } /** * 加个超时时间 */ private getLocalData(db: any) { const { src, cacheTiemout } = this.options; return new Promise(async (resolve, reject) => { setTimeout(reject, cacheTiemout, 'timeout'); const data = await db.find(src); resolve(data); }); } /** * 获取解析 */ private getParser(fileData: any) { const version = util.version(fileData); if (1 == version) { if (!parser1x) { parser1x = new Parser1x({ disableWorker: true }); } return parser1x; } else { if (!parser) { parser = new Parser(); } return parser; } } /** * 获取播放数据 */ private async getSvgaData() { let data!: any; let db!: typeof DB; const { src, cacheSvga } = this.options; if (cacheSvga) { try { db = new DB(); data = await this.getLocalData(db); } catch (error) { logger.error(error); } } if (!data) { if (!downloader) { downloader = new Downloader(); } const fileData = await downloader.get(src); const parser = this.getParser(fileData); try { // parser.do 不能同时进行 // 必须等前一个结束后才能进行下一个 // 否则直接返回前一个的结果,而前一个的结果永远不会返回 await parserLock.lock(); data = await parser.do(fileData); } finally { parserLock.unlock(); } if (cacheSvga && db) { await db.insert(src, data); } } return data; } /** * 添加事件监听 */ private addEventListener() { const player = this.player; const { listener } = this.options; const types = [ 'start', 'pause', 'resume', 'stop', 'end', 'clear', 'process', ] as EVENT_TYPES[]; types.forEach((type) => { if (!player) { return; } player.$on(type, () => { listener(type); }); }); } private async render() { try { await this.lock.lock(); const { src, element, cacheSvga, cacheTiemout, listener, ...options } = this.options; // 确保在render的过程中,destroy 是阻塞的 this.player = new Player(element); this.player.set(options); this.addEventListener(); const data = await this.getSvgaData(); await this.player.mount(data); this.player.start(); } catch (e) { this.options.listener('error', e); } finally { this.lock.unlock(); } } start() { if (this.player) { this.player.start(); } } pause() { if (this.player) { this.player.pause(); } } resume() { if (this.player) { this.player.resume(); } } stop() { if (this.player) { this.player.stop(); } } clear() { if (this.player) { this.player.clear(); } } async destroy() { try { // 需要等render完了之后才能销毁,否则拿不到player await this.lock.lock(); if (this.player) { this.player.destroy(); this.player = null; } } finally { this.lock.unlock(); } } } export default SvgaPlayer;