引言
Cesium本身并不支持显示动图,网上的教程大多都是采用Loop,Callback方式来实现。这些实现方式都需要自己管理动图资源,不够优雅。如果能够通过自定义组件,像其他资源通过一样通过wiewer.entities.add()接口来添加就棒了!
这里采用 GIS-CL 大神的方案,自定义Cesium的entities组件。不过GIS-CL实现的太过复杂,有很多自己开发的组件js,这里给精简一下。
思路
- 使用gifuct-js加载动图,把GIf解析为一帧一帧的图片数据,并临时存储资源。
- 实现entitis.prototype.getValue(time)函数,函数中以此获取当前帧的数据。
- 实现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
}
})