☀️在cesium中使用动图的几种方式
2025年5月20日 08:15
前言
最近在做cesium
的时候遇到一个需求, 需要在地图上面展示动图。
经过查阅资料,大致实现方式如下:
- 通过第三方库将动图分解成每一帧
- 通过
CallbackProperty
方法,实现轮播每帧图片
网络的动图格式很多,在日常中主要使用的还是gif
格式和apng
格式。这两种,所以下面也主要介绍怎么在cesium
中加载这两种动图点位。
gif图片
这边用libgif.js
这个第三方库来帮助我们解析gif
文件
引入libgif
libgif
地址:libgif.js
这个库目前没有找到好用的库,只要用第三方引入的方式进行引入。
将这个文件下载下来,在index.html
中引入
这里我准备了一张gif
动图进行演示
实现过程
根据官网的使用例子,我们需要一个img
标签,并且new
一个SuperGif
// 加载gif动图
const loadGifImg = () => {
const map = getMap() // 获取地图对象
let gifImg = document.createElement('img')
gifImg.setAttribute('rel:animated_src', '/img/sum.gif')
gifImg.setAttribute('rel:auto_play', '1')
const imgDiv = document.createElement('div')
imgDiv.appendChild(gifImg)
const superGif = new SuperGif({ gif: gifImg })
}
上面的代码中,我创建了一个div
和一个img
并且设置了两个属性
其中rel:animated_src
是必须的,SuperGif
内部会读取这个属性
rel:auto_play
则是是否自动播放,不加也没关系
最后new
了一个superGif
superGif.load(function () {
map.entities.add({
position: Cesium.Cartesian3.fromDegrees(120.9677706, 30.7985748),
billboard: {
image: new Cesium.CallbackProperty(() => {
return superGif.get_canvas().toDataURL()
}, false),
scale: 0.25
}
})
})
superGif
有一个load
事件表示加载完毕,像上面我加载完毕之后创建了一个点位实体
,并且img
是new
了一个CallbackProperty
对象。
完整代码
完整代码如下:
// 加载gif动图
const loadGifImg = () => {
const map = getMap()
let gifImg = document.createElement('img')
gifImg.setAttribute('rel:animated_src', '/img/sum.gif')
gifImg.setAttribute('rel:auto_play', '1')
const imgDiv = document.createElement('div')
imgDiv.appendChild(gifImg)
const superGif = new SuperGif({ gif: gifImg })
superGif.load(function () {
map.entities.add({
position: Cesium.Cartesian3.fromDegrees(120.9677706, 30.7985748),
billboard: {
image: new Cesium.CallbackProperty(() => {
return superGif.get_canvas().toDataURL()
}, false),
scale: 0.25
}
})
})
}
效果如下:
apng图片
和gif
一样,apng
也需要一个第三方库来进行解析
apng-js 是一个用于解析和渲染 APNG(动画 PNG)文件的 JavaScript 库。它提供了丰富的 API,可以让开发者完全控制 APNG 动画的播放、暂停、复位等操作。
这个库直接用npm
下载就好了
安装依赖
// pnpm
pnpm add apng-js
// npm
npm install apng-js
代码实现
- 将图片文件转化为
ArrayBuffer
属性对象
let blob = await fetch('/img/wind.png').then(res => res.blob())
const reader = new FileReader()
let canvas = document.createElement('canvas')
let ctx = canvas.getContext('2d')
reader.readAsArrayBuffer(blob)
reader.onload = async () => {
console.log('👉 ~ reader.onload= ~ reader.result:', reader.result)
}
- 使用
apng- js
进行解析
import parseAPNG from 'apng-js'
let apng = reader.result
let player = await apng.getPlayer(ctx)
player.play()
- 创建图片点位
map.entities.add({
position: Cesium.Cartesian3.fromDegrees(120.9677706, 30.7985748),
billboard: {
image: new Cesium.CallbackProperty(() => {
return player.currentFrame.imageElement
}, false)
}
})
完整代码
// 加载apng动图
const loadApngImg = async () => {
const map = getMap()
let blob = await fetch('/img/wind.png').then(res => res.blob())
const reader = new FileReader()
let canvas = document.createElement('canvas')
let ctx = canvas.getContext('2d')
reader.readAsArrayBuffer(blob)
reader.onload = async () => {
let apng = parseAPNG(reader.result)
let player = await apng.getPlayer(ctx)
player.play()
map.entities.add({
position: Cesium.Cartesian3.fromDegrees(120.9677706, 30.7985748),
billboard: {
image: new Cesium.CallbackProperty(() => {
return player.currentFrame.imageElement
}, false)
}
})
}
}
效果如下:
这边的
apng
图片,是我在网上别人的例子里面找到的。如果在用的过程中,有发现各种报错,可以检查一下图片的格式是不是不对
结尾
cesium
中并没有办法直接使用动图,如果想要用动图或者视频,思路基本都是一样的,通过解析动图,得到每一帧图片,再通过更新图片的方式来实现动态。