Hello!
I didn’t investigate this deeply, but OpenLayers has an example of exporting a map to PNG… See OpenLayers :: Map Export.
If you just need to download an image, you can copy the code from the example and invoke it in the Map context:
@ViewComponent
private GeoMap map;
@Subscribe(id = "exportMap", subject = "clickListener")
public void onExportMapClick(final ClickEvent<JmixButton> event) {
map.getElement().executeJs(" // code from example");
}
Note that you need to slightly change the code. In the OpenLayers example, the link is already added to the page, but you need to create it, invoke click(), and then remove it.
Export map to PNG in Jmix
@ViewComponent
private GeoMap map;
@Subscribe(id = "exportMap", subject = "clickListener")
public void onExportMapClick(final ClickEvent<JmixButton> event) {
map.getElement().executeJs("""
const mapCanvas = document.createElement('canvas');
const size = this.olMap.getSize();
mapCanvas.width = size[0];
mapCanvas.height = size[1];
const mapContext = mapCanvas.getContext('2d');
Array.prototype.forEach.call(
this.olMap.getViewport().querySelectorAll('.ol-layer canvas, canvas.ol-layer'),
function (canvas) {
if (canvas.width > 0) {
const opacity =
canvas.parentNode.style.opacity || canvas.style.opacity;
mapContext.globalAlpha = opacity === '' ? 1 : Number(opacity);
let matrix;
const transform = canvas.style.transform;
if (transform) {
// Get the transform parameters from the style's transform matrix
matrix = transform
.match(/^matrix\(([^\(]*)\)$/)[1]
.split(',')
.map(Number);
} else {
matrix = [
parseFloat(canvas.style.width) / canvas.width,
0,
0,
parseFloat(canvas.style.height) / canvas.height,
0,
0,
];
}
// Apply the transform to the export map context
CanvasRenderingContext2D.prototype.setTransform.apply(
mapContext,
matrix,
);
const backgroundColor = canvas.parentNode.style.backgroundColor;
if (backgroundColor) {
mapContext.fillStyle = backgroundColor;
mapContext.fillRect(0, 0, canvas.width, canvas.height);
}
mapContext.drawImage(canvas, 0, 0);
}
},
);
mapContext.globalAlpha = 1;
mapContext.setTransform(1, 0, 0, 1, 0, 0);
var a = document.createElement('a');
document.body.appendChild(a);
a.download = "map.png";
a.href = mapCanvas.toDataURL();
a.click();
document.body.removeChild(a);
""");
}
If you need to get image data on the client side, for instance from a different component, you can use the same code. However, you need to find the <jmix-openlayers-map> component using document and invoke getOpenLayersMap(). This method returns the OpenLayers map instance.