Cesium显示Gif动图-自定义entities组件

引言

Cesium本身并不支持显示动图,网上的教程大多都是采用Loop,Callback方式来实现。这些实现方式都需要自己管理动图资源,不够优雅。如果能够通过自定义组件,像其他资源通过一样通过wiewer.entities.add()接口来添加就棒了!

这里采用 GIS-CL 大神的方案,自定义Cesium的entities组件。不过GIS-CL实现的太过复杂,有很多自己开发的组件js,这里给精简一下。

思路

  1. 使用gifuct-js加载动图,把GIf解析为一帧一帧的图片数据,并临时存储资源。
  2. 实现entitis.prototype.getValue(time)函数,函数中以此获取当前帧的数据。
  3. 实现entitis.prototype.destroy函数用来销毁资源。

代码样例

自定义entitis组件 GifImageProperty.js

import * as Cesium from 'cesium'
import { parseGIF, decompressFrames } from 'gifuct-js'


function GifImageProperty(options) {
    this._url = null;
    this._lastFrameTime = null;
    this._frames = null;
    var that = this;

    this._gifCanvas = document.createElement('canvas');
    this._gifCanvas.width = 1;
    this._gifCanvas.height = 1;
    this._gifCtx = null;
    this._frameIndex = -1;
    this._gif = null;

    if (options.url) {
        this.url = options.url;
    }
}
Object.defineProperties(GifImageProperty.prototype, {
    url: {
        get: function () {
            return this._url;
        },
        set: function (val) {
            this._url = val;
            if (this._url) {
                var that = this;
                Cesium.Resource.fetchArrayBuffer({ url: this._url}).then(function (buff) {
                    that._gif = parseGIF(buff);
                    that._frames = decompressFrames(that._gif, true);
                    that._frameIndex = -1;
                    that._lastFrameTime = null;
                    if (!that._gifCanvas) {
                        that._gifCanvas = document.createElement('canvas');
                    }
                    that._gifCanvas.width = that._frames[0].dims.width;
                    that._gifCanvas.height = that._frames[0].dims.height;
                    that._gifCtx = that._gifCanvas.getContext('2d');
                    that._gifCtx.fillStyle = 'transparent';
                    that._gifCtx.clearRect(0, 0, that._gifCanvas.width, that._gifCanvas.height);
                })
            } else {
                this._frames = null;
                this._gif = null;
            }
        }
    }
})
/**
 * 
 */
GifImageProperty.prototype.destroy = function () {
    this._frames = null;
    this._gif = null;
}
/**
 * 
 * @param {any} frame
 * @private
 */
GifImageProperty.prototype.renderFrame = function (frame) {
    if (frame.canvas) {
        this._gifCanvas = frame.canvas;
        return;
    }
    frame.canvas = document.createElement("canvas");

    var x = Cesium.defaultValue(frame.dims.left, 0),
        y = Cesium.defaultValue(frame.dims.top, 0);
    var w = Cesium.defaultValue(frame.dims.width, this._gifCanvas.width),
        h = Cesium.defaultValue(frame.dims.height, this._gifCanvas.height);
    frame.canvas.width = w;
    frame.canvas.height = h;
    if (x == 0 && y == 0 && w == this._gifCanvas.width
        && h == this._gifCanvas.height) {
        var imgData = this._gifCtx.getImageData(0, 0, w, h)
        imgData.data.set(frame.patch);
        this._gifCtx.putImageData(imgData, 0, 0);
    } else {
        var tempCv;
        if (this._tempCv) {
            tempCv = this._tempCv;
        } else {
            tempCv = document.createElement("canvas");
        }
        tempCv.width = w;
        tempCv.height = h;
        var tempCtx = tempCv.getContext('2d');
        var tempImgData = tempCtx.createImageData(w, h);
        tempImgData.data.set(frame.patch);
        tempCtx.putImageData(tempImgData, 0, 0);
        this._gifCtx.drawImage(tempCv, x, y, w, h);

    }

    var currCtx = frame.canvas.getContext("2d")
    var currImgData = currCtx.createImageData(w, h);
    currImgData.data.set(
        this._gifCtx.getImageData(0, 0, w, h).data
    );
    currCtx.putImageData(currImgData, 0, 0);
    this._gifCanvas = frame.canvas;
}
/**
 * 
 * @param {any} time
 */
GifImageProperty.prototype.getValue = function (time) {
    if (!this._frames || !this._frames.length) {
        return this._gifCanvas;
    }
    this._currentTime = new Date();
    if (!this._lastFrameTime) {
        this._lastFrameTime = new Date();
    }
    var deltTime = this._currentTime.getTime() - this._lastFrameTime.getTime();
    // console.log("test-", this._frameIndex + "@" + deltTime)
    if (this._frameIndex >= 0) {

        if (this._frameIndex < this._frames.length) {
            let costTime = 1000
            if (this._frames[this._frameIndex].delay) {
                costTime = this._frames[this._frameIndex].delay
            }
            if (costTime <= deltTime) {
                this.renderFrame(this._frames[this._frameIndex]);
                this._lastFrameTime = this._currentTime;
                this._frameIndex++;
            }
        } else {
            this._frameIndex = 0;
            this._lastFrameTime = this._currentTime
        }
    } else {
        this._lastFrameTime = this._currentTime
        this._frameIndex = 0;
    }

    return this._gifCanvas;
}

Cesium.GifImageProperty = GifImageProperty;

Cesium地图添加动图显示

window.gisViewer.entities.add({
  position: Cesium.Cartesian3.fromDegrees(116.39, 39.91, 2.61),
  billboard: {
      image: new Cesium.GifImageProperty({
          url: 'wrjGif-图片地址'
      }),
      width: 50,
      height: 50
  }
})

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值