vasturiano / globe.gl

UI component for Globe Data Visualization using ThreeJS/WebGL
https://vasturiano.github.io/globe.gl/example/world-population/
MIT License
1.97k stars 293 forks source link

How to export a 2d picture from a rendered globe? #134

Open itismoej opened 1 year ago

itismoej commented 1 year ago

I want to export a 2d picture from a rendered globe which has many hexPolygon points on it. And use this picture as a background image in order to improve load-time and performance. Is it possible?

mrienstra commented 1 year ago

Check out HTMLCanvasElement.toDataURL().

You can find many code samples & tutorials on how to export <canvas> data as an image. Search for "canvas to image" or "three.js save image".

I recommend closing this issue, as the solution is not specific to this project.

rmccue commented 1 year ago

toDataURL() consistently returns a blank image for me, regardless of how I call it and across multiple browsers; you can replicate by opening https://globe.gl/example/basic/ and using window.location = document.querySelector('canvas').toDataURL( 'png' ) (directly in JS, ref.renderer().domElement.toDataURL( 'png' ))

I've seen some notes that indicate it might need "finalising" or something before using this, but I can't see any relevant methods to call that might help with that.

mrienstra commented 1 year ago

Yeah, hmm, sorry for the drive-by suggestion, it wasn't clear to me what had been tried already.

~~Looks like the library which powers this one has the same problem: https://vasturiano.github.io/three-globe/example/basic/~~

Oh, OK, that's not where the three.js renderer is setup, that's happening here: https://github.com/vasturiano/three-render-objects/blob/e771a35/src/three-render-objects.js#L373

Which is called here: https://github.com/vasturiano/globe.gl/blob/671a650/src/globe.js#L324-L329

As per https://github.com/vasturiano/globe.gl#initialisation, rendererConfig is passed to the ThreeJS WebGLRenderer constructor.

When initializing, e.g. here: https://github.com/vasturiano/globe.gl/blob/671a650/example/basic/index.html#L21

Globe()

... you need to specify preserveDrawingBuffer: true via rendererConfig:

Globe({
  rendererConfig: { preserveDrawingBuffer: true },
})

After making that change, I ran the following in the console:

const canvasEl = document.querySelector('canvas');
const imageEl = document.createElement('img');
imageEl.src = canvasEl.toDataURL();
document.body.appendChild(imageEl);

Which resulted in this image: image

itismoej commented 1 year ago

Yeah, hmm, sorry for the drive-by suggestion, it wasn't clear to me what had been tried already.

~Looks like the library which powers this one has the same problem: https://vasturiano.github.io/three-globe/example/basic/~

Oh, OK, that's not where the three.js renderer is setup, that's happening here: https://github.com/vasturiano/three-render-objects/blob/e771a35/src/three-render-objects.js#L373

Which is called here: https://github.com/vasturiano/globe.gl/blob/671a650/src/globe.js#L324-L329

As per https://github.com/vasturiano/globe.gl#initialisation, rendererConfig is passed to the ThreeJS WebGLRenderer constructor.

When initializing, e.g. here: https://github.com/vasturiano/globe.gl/blob/671a650/example/basic/index.html#L21

Globe()

... you need to specify preserveDrawingBuffer: true via rendererConfig:

Globe({
  rendererConfig: { preserveDrawingBuffer: true },
})

After making that change, I ran the following in the console:

const canvasEl = document.querySelector('canvas');
const imageEl = document.createElement('img');
imageEl.src = canvasEl.toDataURL();
document.body.appendChild(imageEl);

Which resulted in this image: image

This is not the image I'm looking for. I want the globe itself.

Assume that you have rendered a globe with many dots or hexPolygons on it; and you want to do this render of dots or hexPolygons once and export an image from it and use the image as globeImageUrl for the next times.