You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在已绘制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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 11:15:07