class GifPlayer { /** * * @param {*} template 图片模板路径:变量,{i} * @param {*} num 图片的总数{i}=0~(num-1), 默认34 * @param {*} canvas 画布 * @param {*} radioRate 播放速率比,0=不播放 默认1 */ constructor(template, num, canvas, radioRate) { this.load = false; this.canvas = canvas; this.radioRate = radioRate; this.ctx = this.canvas.getContext('2d'); // this.ctx.save(); this.#init(template, num); } async #init(template, num) { this.imgs = await this.loadImgs(template, num); this.canvas.dispatchEvent(new CustomEvent('loadend', { bubbles: false })) this.load = true; this.canvas.width = this.imgs[0].naturalWidth * window.devicePixelRatio; this.canvas.height = this.imgs[0].naturalHeight * window.devicePixelRatio; this.i = 0; this.time = Date.now(); this.playing = true; this.ctx.drawImage(this.imgs[0], 0, 0, this.canvas.width, this.canvas.height); this.#backgroudPlay(); } /** * 加载图片 * @param {*} template 图片模板路径:变量,{i} * @param {*} num 图片的总数{i}=0~(num-1), 默认34 */ loadImgs(template, num = 34) { return new Promise((resolve, reject) => { const imgs = []; const ps = []; for (let i = 0; i < num; i++) { const img = new Image(); img.src = template.replace('{i}', i); imgs[i] = img; ps.push(new Promise((resolve1, reject1) => { img.onload = resolve1; img.onerror = reject1; })); } Promise.all(ps).then(() => { resolve(imgs); }).catch(err => { reject(err); }) }) } #backgroudPlay() { if (this.radioRate === 0 || !this.playing) { requestAnimationFrame(() => { this.#backgroudPlay() }); return; } let now = Date.now(); if (now - this.time >= 50 / this.radioRate) { this.time = now; this.i++; if (this.i >= this.imgs.length) { this.i = 0; this.canvas.dispatchEvent(new CustomEvent('loopend', { bubbles: false })) } this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); // this.ctx.restore(); this.ctx.drawImage(this.imgs[this.i], 0, 0, this.canvas.width, this.canvas.height); } requestAnimationFrame(() => { this.#backgroudPlay() }); } start() { this.playing = true; } stop() { this.playing = false; } } export { GifPlayer };