动画
LDataAnimationService是二维中基于数据源更新的动画服务,主要应用是格点填色图层在时间和高度上的数据动画播放。数据动画的实现原理是不断更新数据解析器中的当前高度层currentZIdx
或者当前时次currentTIdx
。
为了更方便的实现动画逻辑,QE内置了动画服务,用户只需要负责将数据更新到provider一遍之后(如果数据本身取回来就是多维度的,则直接可以动画,无需边加载边动画),就可以实现流畅平滑的动画效果。
创建动画
创建一个动画步骤如下:
数据动画本质是更新数据源的动画,分时间数据动画和高度数据动画,所以,我们的数据源应该是一个多时次或者多高度层的数据,即provider构建的标准格点数据格式GridData[time][level]中time的length或者level的length应大于1。
用于动画的图层,需要是实现了IAnimationableLayer接口的图层。QE内置的二维图层中LPixelLayer,LCanvasPixelLayer等图层可以。
将之前的数据源和图层都传进动画服务,对动画参数进行设置。
代码如下:
getBinary("public/demos/data/year.ano.zip").then(buffers => {//获取数据
const provider = new QEGridDataProvider(buffers[0]); //构建provider
const layer = new LPixelLayer().setDrawOptions({ //创建图层
fillColor: "color-temp-ano#res", //格点颜色
fillMode: GridDataGLFillMode.pixel2, //绘制方式
}).setDataSource(provider); //设置数据源
map.addLayer(layer); //添加图层到地图上
const aniService = new LDataAnimationService(provider, { //创建数据动画服务
layer: layer, //动画的图层
map: map, //所在的地图
all: provider.allGrids().length //动画的最长数量
});
aniService.start(); //开启动画
});
这样一个最基础的动画就完成了(假设所有时次全部存放于一个数据中)!
动画速度
可以通过设置动画参数timerInterval
每帧时间间隔来调整动画的快慢。默认的时间间隔是30ms
const aniService = new LDataAnimationService(provider, { //创建数据动画服务
layer: layer, //动画的图层
map: map, //所在的地图
all: provider.allGrids().length, //动画的最长数量
timerInterval: 100 //单位毫秒
});
更多动画配置参数请查看IDataAnimationServiceOptions
自动补帧
LPixelLayer的构建参数interpFromPreSource若设置为true,即表示对格点数据进行自动补帧,即会记录上一次数据源,并根据当前数据源中对应的tz小数部分进行补帧,使动画效果更加平滑。也就是当每次动画的索引递增时,对于有小数的,会对小数部分进行补帧。动画配置参数索引递增量delta
,默认是0.05,如currenTIdx=0时,下一次就是0.05,0.1,0.15...以此类推。如果没有开启图层的自动补帧功能,即使索引增量小于1,也不会进行补帧。
getBinary("public/demos/data/year.ano.zip").then(buffers => {//获取数据
const provider = new QEGridDataProvider(buffers[0]); //构建provider
const layer = new LPixelLayer({
interpFromPreSource: true //开启自动补帧
}).setDrawOptions({ //设置样式
fillColor: "color-temp-ano#res", //格点颜色
fillMode: GridDataGLFillMode.pixel2, //绘制方式
}).setDataSource(provider); //设置数据源
map.addLayer(layer); //添加图层到地图上
const aniService = new LDataAnimationService(provider, { //创建数据动画服务
layer: layer, //动画的图层
map: map, //所在的地图
all: provider.allGrids().length //动画的最长数量
});
aniService.start(); //开启动画
});
叠加等值线
将LPixelLayer样式设置中的显示等值线开启,数据动画中也能显示等值线的变化。
getBinary("public/demos/data/year.ano.zip").then(buffers => {//获取数据
const provider = new QEGridDataProvider(buffers[0]); //构建provider
const layer = new LPixelLayer({
interpFromPreSource: true //开启自动补帧
}).setDrawOptions({ //设置样式
fillColor: "color-temp-ano#res", //格点颜色
fillMode: GridDataGLFillMode.pixel2, //绘制方式
lineWidth: 2, //等值线宽度
lineColor: "white", //等值线颜色
showLine: true //是否显示等值线
}).setDataSource(provider); //设置数据源
map.addLayer(layer); //添加图层到地图上
const aniService = new LDataAnimationService(provider, { layer: layer, map: map, all: provider.allGrids().length });//创建动画服务,传参有数据源,图层,地图,时次数
aniService.start(); //开启动画
});
完整示例
边载入边播放
如果我们的数据是单时次数据,需要加载多个时次的数据来进行动画播放时,我们的provider也支持动态载入。让先加载的数据先进行显示,避免等所有时次都加载了再显示,会出现等待时间过长的情况。我们可以通过格点类数据解析器不断更新其中的GridData来实现,即调用provider的updateGrid方法。当数据没有载入完成时,会自动暂停播放直到数据源中出现该时次的数据后会继续播放。
以下示例为气温预报色斑图动画,数据是单时次数据。
let provider: QEGridDataProvider;
let tIdx = 0; //时次计数器
return getBinaries([ //请求一些列二进制数据
"public/demos/data/t1.china.zip",
"public/demos/data/t2.china.zip",
"public/demos/data/t3.china.zip"
], files => { //每个请求完成时的回调
if (!provider) { //判断provider是否赋值过,如果没有
provider = new QEGridDataProvider(files[0], //先用第一个数据构建provider
{ meta: { dataOffset: -70 } as any } //设置数据偏移量覆盖数据头中的原有的
);
provider.currentZIdx = 19; //设置当前高度维度值
const style: IPixelLayerStyleOptions = { //绘制样式
fillColor: "color-temp#res", //格点颜色:
fillMode: GridDataGLFillMode.shaded1, //显示方式:双线性插值色斑图
}
const layer = new LPixelLayer({ //创建LPixelLayer图层
name: "温度预报", //图层name
interpFromPreSource: true //进行自动补帧(使动画效果更平滑)
})
.setDrawOptions(style) //设置样式
.setDataSource(provider); //设置数据源
map.addLayer(layer); //图层添加到地图上
const animationService = new LDataAnimationService(//构建数据动画服务
provider, //传入数据源
{
all: 3, //动画的总共时次数量
delta: 0.05, //每次动画的索引递增量
layer: layer, //动画的图层
map: map //所在的地图
}
);
animationService.start(); //开始动画
} else { //如果provider已经赋值过
const current = new QEGridDataProvider(files[0], { meta: { dataOffset: -70 } as any });//使用当前获取到的数据再构建一个provider
provider.lock(); //数据源锁定,指框架内置的注册在provider上的事件将暂停触发,比如onTChanged,onZChanged等
current.allGrids()[0].forEach((zGrid, idx) => { //遍历刚构建的provider的每个高度层数据
provider.updateGrid(zGrid, tIdx, idx, current.gridOptions.zValues[idx], false); //向provider上增加该时次(tIdx)的该高度上(idx)的GridData,最后一个参数false表示setActive即是否设置为当前时次以及当前高度
});
provider.unlock(); //数据源解锁
}
tIdx++; //时次计数加1
});
叠加格点填值
数据动画中叠加格点填值图层时,格点填值图层中的格点值应该是要跟随动画变化一起变化的,所以需要将LGridLabelLayer
的构建参数trackDataSource
设置为true,表示监听数据源消息,在数据源更新后会自动刷新图层。
const labelLayer = new LGridLabelLayer({ //创建格点标签图层
trackDataSource: true //监听数据源消息,在数据源更新后会自动刷新图层
}).setDrawOptions({ //设置样式
text: { //格点文本样式
data: "#decimal?len=1" //取格点值并保留1位小数
}
}).setDataSource(provider); //设置数据源
map.addLayer(labelLayer); //将格点填值图层添加到地图上
播放动画时,显示每帧数据时间
动画中传入的数据源,格点类provider中有onIntTChanged(监听时间整数部分发生变化) 和 onTChanged(监听时间发生变化) 这两种方法来监听数据源的变化,在里面传入回调函数,就可以在时次发生变化时被调用。
更多示例
关于动画的更多示例可以参考栅格填色图层中的描述。
No Comments