如何从Mapbox GL JS获取可用的画布 [英] How to get usable canvas from Mapbox GL JS

查看:312
本文介绍了如何从Mapbox GL JS获取可用的画布的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 Mapbox GL ,并尝试获取它的快照,并将快照与另一个覆盖输出的图像合并。



我有一个 HTMLCanvasElement 关闭屏幕,我'我首先将从 Map.getCanvas()返回的画布写入其中,然后将第二个(alpha透明)画布写在上面。



问题在于,虽然我清楚地看到Map实例中的屏幕上的元素,但结果只显示第二个图像/画布,其余的是空白。



所以我只导出了地图的画布,我看到它是因为地图画布是空白的,尽管 console.log()显示了它的图像数据这是我的导出功能:

  onExport(annotationCanvas:HTMLCanvasElement){

const mergeCanvas:HTMLCanvasElement = document.createEl EMENT(画布);
const mapCanvas:HTMLCanvasElement = this.host.map.getCanvas();
const mergeCtx:CanvasRenderingContext2D = mergeCanvas.getContext('2d');

mergeCanvas.height = annotationCanvas.height;
mergeCanvas.width = annotationCanvas.width;
mergeCtx.drawImage(mapCanvas,0,0);
mergeCtx.drawImage(annotationCanvas,0,0);

const mergedDataURL = mergeCanvas.toDataURL();
const mapDataURL = mapCanvas.toDataURL();
const annotationDataURL = annotationCanvas.toDataURL();

console.log(mapDataURL); //大量数据

下载(mapDataURL,'map-data-only.png'); //空白图片@ 1920x1080
下载(mergedDataURL,'annotation.png'); //仅显示注释(第二层/画布)数据

}

这是一个错误,还是我错过了什么?



更新:我想知道这是什么,并有可能的选择。



绊倒了 Mapbox功能请求,我了解到,如果您使用 preserveDrawingBuffer 选项设置为实例化 Map false (默认值),您将无法获得包含可用图像数据的画布。但是将此选项设置为 true 会降低性能。但是在实例化Map之后你无法改变这个设置......



我希望Map能够尽可能地发挥最佳效果!!!!



所以,在这个答案上我偶然发现了关于关于three.js的问题,我了解到如果我在渲染后立即拍摄截图,我将得到我需要的画布/数据。



我试过了在捕获画布之前调用 this.host.map ['_ rerender'](),但它仍然返回空白。



然后在源代码中搜索,我发现了一个名为 _requestRenderFrame 的函数,看起来它可能是我需要的,因为我可以要求Map运行紧接在下一个渲染周期之后的函数。但是,当我发现由于某种原因,该功能是在编译的代码中省略,但在源中出现,显然是因为它只是在主人身上,而不是释放的一部分。



所以我还没有一个满意的解决方案,所以请让我知道任何见解。

解决方案

正如您在更新的问题中所提到的,解决方案是设置 preserveDrawingBuffer:true 在地图初始化时。



为了回答您的更新问题,我认为@ jfirebaugh的答案在 https://github.com/mapbox/mapbox-gl-js/issues/6448#issuecomment-378307311 总结一下非常好:

 无法动态修改preserveDrawingBuffer。必须在创建WebGL上下文时进行设置,这可能会对性能产生负面影响。 

有传言说你可以在渲染后立即获取画布数据URL,而不需要preserveDrawingBuffer,但我还没有验证,我怀疑它不符合规范。

因此,尽管可能在渲染后立即抓取画布数据URL,但不能保证规范。


I'm using Mapbox GL, and trying to get a snapshot of it, and merge the snapshot with another image overlaid for output.

I have a HTMLCanvasElement off screen, and I'm first writing the canvas returned from Map.getCanvas() to it, then writing the second (alpha transparent) canvas over that.

The problem is that, though I clearly see elements onscreen in the Map instance, the result only shows the second image/canvas written, and the rest is blank.

So I export just the map's canvas, and I see it is because the map canvas is blank, although a console.log() shows the image data from it to be a large chunk of information.

Here's my export function:

  onExport(annotationCanvas: HTMLCanvasElement) {

    const mergeCanvas: HTMLCanvasElement = document.createElement('canvas');
    const mapCanvas: HTMLCanvasElement = this.host.map.getCanvas();
    const mergeCtx: CanvasRenderingContext2D = mergeCanvas.getContext('2d');

    mergeCanvas.height = annotationCanvas.height;
    mergeCanvas.width = annotationCanvas.width;
    mergeCtx.drawImage(mapCanvas, 0, 0);
    mergeCtx.drawImage(annotationCanvas, 0, 0);

    const mergedDataURL = mergeCanvas.toDataURL();
    const mapDataURL = mapCanvas.toDataURL();
    const annotationDataURL = annotationCanvas.toDataURL();

    console.log(mapDataURL); // Lots of data

    download(mapDataURL, 'map-data-only.png'); // Blank image @ 1920x1080
    download(mergedDataURL, 'annotation.png'); // Only shows annotation (the second layer/canvas) data

  }

Is this a bug, or am I missing something?

UPDATE: I sort of figured out what this is about, and have possible options.

Upon stumbling upon a Mapbox feature request, I learned that if you instantiate your Map with the preserveDrawingBuffer option set to false (the default), you wont be able to get a canvas with usable image data. But setting this option to true degrades performance. But you can't change this setting after a Map is instantiated...

I want the Map to perform the best it possibly can!!!!

So, on this answer I stumbled on, regarding a question about three.js, I learned that if I take the screenshot immediately after rendering, I will get the canvas/data that I need.

I tried just calling this.host.map['_rerender']() right before I capture the canvas, but it still returned blankness.

Then searching around in the source code, I found a function called _requestRenderFrame, that looks like it might be what I need, because I can ask the Map to run a function immediately after the next render cycle. But as I come to find out, for some reason, that function is omitted in the compiled code, whilst present in the source, apparently because it is only in the master, and not part of the release.

So I don't really have a satisfactory solution yet, so please let me know of any insights.

解决方案

As you mentioned in your updated question the solution is to set preserveDrawingBuffer: true upon Map initialisation.

To answer your updated question I think @jfirebaugh's answer at https://github.com/mapbox/mapbox-gl-js/issues/6448#issuecomment-378307311 sums it up very well:

preserveDrawingBuffer can't be modified on the fly. It has to be set at the time the WebGL context is created, and that can have a negative effect on performance.

It's rumored that you can grab the the canvas data URL immediately after rendering, without needing preserveDrawingBuffer, but I haven't verified that, and I suspect it's not guaranteed by the spec.

So although it might be possible to grab the canvas data URL immediately after rendering, it's not guaranteed by the spec.

这篇关于如何从Mapbox GL JS获取可用的画布的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆