之前写了一篇关于SVGA和Lottie动画使用的,现在有一个新的需求,要实现一个效果比较炫的引导动画,想用SVGA实现,但是要求里面的一些数字是动态可配的。查了下SVGA支持替换图层,跟UI配合调研成功替换,用了两种SVGA库来实现。
UI准备:
UI在出图的时候,对图层做好命名,导出SVGA后,告诉开发可配置图层的名称。
PS: 在这里预览SVGA文件,也可以查看所有图层的key。
联调过程:
引入svga,根据图层的key动态替换元素,再播放动画。
这里我先用的svgaplayer-web-lite去做,因为之前的svga动画也是用的这个库。但是当时跟UI还在调研,以为新建的图层要用文本框,出了一个有问题的svga文件,用这个库报错,换成svgaplayer-web就可以正常渲染。另外网上看的替换svga图层的教程都是用的svgaplayer-web,就先用这个实现了。
后来发现不用文本框,普通图层就行,又用lite实现了一下,相比较起来,lite更轻量,性能更好。
参考文章:https://blog.csdn.net/weixin_44309374/article/details/106995401
SVGAPlayer-web实现
文档:链接
API:支持两个替换方法,可以替换为图片或文字。(开始也是被这个误导了,以为替换文字要插入文本框类型,后来发现就是普通图层,既可以替换文字也可以替换图片。)
1 2 3 4 5 6 7 8 9 10 11 12
| player.setImage('http://yourserver.com/xxx.png', 'ImageKey');
player.setText('Hello, World!', 'ImageKey');
player.setText({ text: 'Hello, World!, family: 'Arial', size: "24px", color: "#ffe0a4", offset: {x: 0.0, y: 0.0} }, 'ImageKey'); // 可自定义文本样式
|
大概实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| import SVGA from 'svgaplayerweb';
this.canvas = document.getElementById('canvas') this.player = new SVGA.Player(this.canvas); this.parser = new SVGA.Parser(this.canvas); this.player.loops = 1 this.player.clearsAfterStop = false this.player.setClipsToBounds(true)
this.parser.load(svgaUrl, (videoItem) => { console.log(`svga${index}加载完成`) this.svga1 = videoItem this.startAnim1() })
async startAnim1 () { console.log(`播放svga1`) this.player.setVideoItem(this.svga1); this.player.setText({ text: '150', family: 'Arial', size: "24px", color: "#000", offset: {x: 0.0, y: 0.0} }, 'jineshuru'); this.player.loops = 1 this.player.onFrame(frame => { }) this.player.startAnimationWithRange({location: 0, length: 30}) this.player.loops = 0 this.player.startAnimationWithRange({location: 30, length: 30}) this.canvas.onclick = () => { console.log(`svga1点击`) this.canvas.onclick = void 0 this.onAnim1Click() } }, onAnim1Click () { this.player.loops = 1 this.player.startAnimationWithRange({location: 60, length: 20})
this.player.onFinished(() => { console.log(`svga1结束`) this.canSvg2Play = true this.player.onFrame(void 0) this.player.onFinished(void 0) this.startAnim2() }) },
|
通过player.setText替换图层为指定文案。
再通过修改player.loops,然后player.startAnimationWithRange控制播放动画区间。
动画1我们先播放入场部分,然后循环播放后面的部分,等待用户点击,再播放动画2。这里的几段动画公用的一个canvas和player,不停的调整属性和播放的帧数区间。
SVGAPlayer-web-lite实现
文档:链接
API: 支持两个替换方法,替换元素和替换动态元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| const image = new Image() image.src = 'https://xxx.com/xxx.png' svga.replaceElements['key'] = image
const text = 'hello gg' const fontCanvas = document.getElementById('font') const fontContext = fontCanvas.getContext('2d') fontCanvas.height = 30 fontContext.font = '30px Arial' fontContext.textAlign = 'center' fontContext.textBaseline = 'middle' fontContext.fillStyle = '#000' fontContext.fillText(text, fontCanvas.clientWidth / 2, fontCanvas.clientHeight / 2) svga.dynamicElements['key'] = fontCanvas
await player.mount(svga)
|
这里我们暂时用到的就是替换元素。可以看到不管是替代元素还是替换动态元素,都可以替换为图片或者canvas。这个canvas中我们可以自己写入text,相对于SVGAPlayer-web,插入文字要麻烦一些,但是自由度更高。
实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| export const createTextCanvas = ({ text = 'text', size = 120, color = '#000', weight = 'bold', fontFamily = 'noto', // arial, serif x = 0, y = 0, maxWidth, }) => { const canvas = document.createElement('canvas') const ctx = canvas.getContext('2d') ctx.textAlign = 'center' ctx.textBaseline = 'middle' ctx.fillStyle = color ctx.font = `${weight} ${size}px ${fontFamily}` if (maxWidth) { ctx.fillText(text, x, y, maxWidth) } else { ctx.fillText(text, x, y) } return canvas }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| import { Parser, Player, DB } from 'svga' import { createTextCanvas } from './util'
this.canvas = document.getElementById('canvas') this.player = new Player({ container: this.canvas, loop: 1, playMode: 'forwards', fillMode: 'forwards', }) this.db = new DB()
let svga = await this.db.find(svgaUrl) if (!svga) { const parser = new Parser({ isDisableImageBitmapShim: true }) svga = await parser.load(svgaUrl) await this.db.insert(svgaUrl, svga) } this.svga1 = svga this.startAnim1()
async startAnim1() { console.log(`播放svga1`) this.svga1.replaceElements['key1'] = createTextCanvas({ text: this.num1 + '元', size: 100, color: '#FFFEC0', x: 150, y: 70, })
await this.player.mount(this.svga1)
this.player.onProcess = () => { console.log(this.player.currentFrame) switch (this.player.currentFrame) { case this.anim1BtnFrame: this.canvas.onclick = () => { console.log(`svga1点击`) this.canvas.onclick = void 0 this.$emit('step1Click') this.onAnim1Click() } break } } this.player.setConfig({ startFrame: 0, loopStartFrame: this.anim1LoopFrame, }) this.player.start() }, onAnim1Click() { this.canSvg2Play = true this.player.onProcess = void 0 this.player.onEnd = void 0 this.player.pause() this.startAnim2() },
|