如何在已绘制canvas元素上叠加绘制?OpenLayers循环导出地图仅首帧问题
OpenLayers多时间步WMS图层导出帧重复问题修复
核心问题原因
- 同步for循环不会等待WMS异步瓦片加载完成,10次循环几乎同时执行,导出的都是未更新的初始帧内容
rendercomplete事件绑定错误:代码中this.map.on('rendercomplete', this.flagCallback())是直接调用flagCallback函数,并未将函数本身注册为事件回调,监听逻辑完全失效map.renderSync()仅能同步渲染本地已加载的资源,不会等待远程WMS瓦片请求返回,调用后立即导出的还是上一帧的内容
修正后的实现方案
采用异步串行逻辑,每一步更新时间参数后,等待地图渲染完成再执行导出,全部完成后再处理下一帧:
// 改造为异步函数 mapToCanvasList: async function () { // 先解绑之前可能存在的rendercomplete监听,避免重复触发 this.map.un('rendercomplete', this.flagCallback); for(let i = 0 ; i < 10 ; i++) { // 更新时间参数 this.setTimeSurface10(); // 等待当前帧渲染完成 await new Promise((resolve) => { const onRenderComplete = () => { // 渲染完成后解绑当前监听,避免影响下一轮 this.map.un('rendercomplete', onRenderComplete); resolve(); }; this.map.on('rendercomplete', onRenderComplete); // 手动触发地图重绘 this.map.render(); }); // 渲染完成后再执行导出 this.myCallback(); } // 所有帧添加完成后可以在这里触发gif导出逻辑 // this.gif.render(...) }, myCallback: function () { var mapCanvas = document.createElement('canvas'); var divElement = document.querySelector(".map"); mapCanvas.width = divElement.offsetWidth; mapCanvas.height = divElement.offsetHeight; var mapContext = mapCanvas.getContext('2d'); Array.prototype.forEach.call( document.querySelectorAll('.ol-layer canvas'), function (canvas) { if (canvas.width > 0) { const opacity = canvas.parentNode.style.opacity; mapContext.globalAlpha = opacity === '' ? 1 : Number(opacity); const transform = canvas.style.transform; const matrix = transform .match(/^matrix\(([^\(]*)\)$/)[1] .split(',') .map(Number); CanvasRenderingContext2D.prototype.setTransform.apply(mapContext,matrix); mapContext.drawImage(canvas, 0, 0); } } ); this.gif.addFrame(mapCanvas, {copy:true, delay: 200}); mapCanvas.remove(); }, setTimeSurface10: function () { if (this.currentTimeSurface10 === null) { this.currentTimeSurface10 = this.startTimeSurface10; } else if (this.currentTimeSurface10 >= this.endTimeSurface10) { this.currentTimeSurface10 = this.startTimeSurface10; } else { this.currentTimeSurface10 = new Date( this.currentTimeSurface10.setMinutes(this.currentTimeSurface10.getMinutes() + 60) ); } this.surface10.getSource().updateParams({ TIME: this.currentTimeSurface10.toISOString().split(".")[0] + "Z" }); }
额外注意点
如果WMS服务加载速度较慢,可以在rendercomplete触发后再加100-200ms的延迟再执行导出,避免部分瓦片还没绘制到canvas上的情况。
内容的提问来源于stack exchange,提问作者Curious
相关产品推荐
相关产品推荐

