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.