OpenLayers rendercomplete回调内访问this上下文生成GIF的问题求解
问题根源
你遇到的帧重复问题和this上下文无关,核心是同步循环和异步渲染的执行顺序冲突:
- 你的for循环是同步执行的,会在极短时间内连续调用
setTimeSurface10更新时间参数、触发renderSync,等到第一个rendercomplete回调触发时,循环已经跑完所有次数,currentTimeSurface10已经更新到了最后一个时间值,所有回调读取的都是最终状态的地图内容。 - 你在循环结束后直接调用了
this.gif.render(),此时大部分帧还没完成添加操作,GIF生成逻辑提前执行自然只能拿到重复内容。
修复方案
将同步循环改成顺序异步执行,保证上一帧的内容采集完成后再处理下一帧,所有帧添加完成后再触发GIF渲染:
// 首先封装单帧采集逻辑为Promise,方便异步等待 async function captureFrame() { return new Promise((resolve) => { this.map.once('rendercomplete', () => { const divElement = document.querySelector(".map"); const mapCanvas = document.createElement('canvas'); mapCanvas.width = divElement.offsetWidth; mapCanvas.height = divElement.offsetHeight; const 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}); resolve(); }); }.bind(this)); } // 用async函数控制执行顺序 async function generateGif() { // 先重置时间初始值,避免之前的状态影响 this.currentTimeSurface10 = null; for(let i = 0 ; i < this.dateArraySurface10.length-2 ; i++) { this.setTimeSurface10(); this.map.renderSync(); // 等待当前帧采集完成再进入下一次循环 await captureFrame.call(this); } // 所有帧添加完成后再触发渲染 this.gif.on('finished', function(blob) { window.open(URL.createObjectURL(blob)); }); this.gif.render(); } // 调用执行 generateGif.call(this);
如果要更简单的处理this,也可以把所有普通函数改成箭头函数,就不需要手动bind绑定上下文。
内容的提问来源于stack exchange,提问作者Curious
相关产品推荐
相关产品推荐

