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
    评论
好的,您想了解有关自定义几何体的内容,我很乐意为您解答。首先,让我们了解一下什么是几何体。 在Cesium中,几何体是由一些点、线和三角形组成的图形。几何体可以在地球上显示各种形状的物体,如建筑、飞机、汽车等。Cesium提供了一些内置的几何体,如BoxGeometry、CylinderGeometry、SphereGeometry等,但是有时候我们需要展示一些特殊形状的物体,这时候就需要自定义几何体了。 下面是一个简单的自定义几何体的例子: ```javascript var geometry = new Cesium.Geometry({ attributes: { position: new Cesium.GeometryAttribute({ componentDatatype: Cesium.ComponentDatatype.DOUBLE, componentsPerAttribute: 3, values: new Float64Array([ 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0 ]) }) }, indices: new Uint16Array([ 0, 1, 2, 0, 2, 3 ]), primitiveType: Cesium.PrimitiveType.TRIANGLES }); ``` 这个例子中,我们创建了一个由四个点组成的矩形,并用这些点的索引定义了两个三角形。这个几何体可以用来在地球上显示一个矩形。 接下来,让我们逐步了解这个例子中的代码。首先是Cesium.GeometryAttribute。 Cesium.GeometryAttribute是几何体属性的容器。在这个例子中,我们定义了一个名为position的属性,它有三个分量:x、y和z。这个属性使用的数据类型是Cesium.ComponentDatatype.DOUBLE,表示每个分量有一个双精度浮点数。componentsPerAttribute表示每个属性有几个分量。在这个例子中,每个属性都有三个分量。最后,我们用一个Float64Array数组来定义这个属性的值。 接下来是indices,它定义了几何体使用哪些点来组成三角形。在这个例子中,我们定义了两个三角形,每个三角形使用三个顶点。在indices数组中,我们用顶点在attributes数组中的索引来定义每个三角形。 最后,我们定义了几何体的primitiveType,它表示几何体的类型。在这个例子中,我们使用的是三角形类型,所以primitiveType为Cesium.PrimitiveType.TRIANGLES。 希望这个例子可以帮助您更好地理解自定义几何体的实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值