普通视图

发现新文章,点击刷新页面。
今天 — 2025年5月20日首页

☀️在cesium中使用动图的几种方式

作者 贾斯克
2025年5月20日 08:15

前言

最近在做cesium的时候遇到一个需求, 需要在地图上面展示动图。

经过查阅资料,大致实现方式如下:

  1. 通过第三方库将动图分解成每一帧
  2. 通过CallbackProperty方法,实现轮播每帧图片

网络的动图格式很多,在日常中主要使用的还是gif格式和apng格式。这两种,所以下面也主要介绍怎么在cesium中加载这两种动图点位。

gif图片

这边用libgif.js这个第三方库来帮助我们解析gif文件

引入libgif

libgif地址:libgif.js

这个库目前没有找到好用的库,只要用第三方引入的方式进行引入。

image-20250519210306663

将这个文件下载下来,在index.html中引入

image-20250519210353885

这里我准备了一张gif动图进行演示

sum.gif

image-20250519211609564

实现过程

根据官网的使用例子,我们需要一个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事件表示加载完毕,像上面我加载完毕之后创建了一个点位实体,并且imgnew了一个CallbackProperty对象。

image-20250519212943954

完整代码

完整代码如下:

// 加载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
      }
    })
  })
}

效果如下:

1.gif

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)
 }

image-20250519214930428

  • 使用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)
      }
    })
  }
}

效果如下:

2

这边的apng图片,是我在网上别人的例子里面找到的。如果在用的过程中,有发现各种报错,可以检查一下图片的格式是不是不对

结尾

cesium中并没有办法直接使用动图,如果想要用动图或者视频,思路基本都是一样的,通过解析动图,得到每一帧图片,再通过更新图片的方式来实现动态。

❌
❌