Hello,
I’m trying to adjust the map extent dynamically based on the size of the map, to make sure the extent fits properly and respects the aspect ratio.
The problem is that map.width only gives me values like "100%" or "800px", which I can’t use directly to calculate the actual dimensions.
The only workaround I found is to use JS to read the map size:
val mapId = map.id.orElse(“map”)
map.element.executeJs(
“”"
const el = document.getElementById(’$mapId’);
if (el) {
return [el.clientWidth, el.clientHeight];
} else {
return [0, 0];
}
“”".trimIndent()
).then { }
However, because this call is asynchronous, setting map.mapView.extent or using zoomToExtent(...) right after doesn’t reliably update the map — the extent just doesn’t apply correctly.
Do you have a recommended way to handle this ?
Thanks!
Could you clarify, do you set extent in pixels or you dynamically calculate the extent considering pixels?
Please note that extent takes values according to CRS (coordinate reference system). For instance, in EPSG:3857 it is meters, in EPSG:4326 it is degree (latitude and longitude).
Thanks for your reply.
To clarify, I’m not setting the extent in pixels, I’m calculating it dynamically , then adjusting it to fit the map container size.
1- Get the extent from GeoServer :
val allExtents = map.layers
.filterIsInstance()
.mapNotNull { layer →
if (layer.id != “tiles” && layer.visible)
getLayerExtentFromGeoserver(layer)
else null
}
val maxLayersExtent = Extent(
allExtents.minOf { it.minX },
allExtents.minOf { it.minY },
allExtents.maxOf { it.maxX },
allExtents.maxOf { it.maxY }
)
2. Get the map’s actual pixel dimensions: I use JS to get clientWidth and clientHeight:
val mapId = map.id.orElse(“map”)
map.element.executeJs("""
const el = document.getElementById(’$mapId’);
if (el) {
return [el.clientWidth, el.clientHeight];
} else {
return [0, 0];
}
“”".trimIndent()).then { jsResult →
val width = jsResult.getNumber(0)
val height = jsResult.getNumber(1)
val aspectRatio = width / height
val adjustedExtent = adjustExtentToAspectRatio(maxLayersExtent, aspectRatio)
map.mapView.extent = adjustedExtent
map.zoomToExtent(adjustedExtent)
}
Even after setting map.mapView.extent and calling zoomToExtent(…), the extent is not applied correctly,
How can I get the actual map width/height (size) from map without JS to pass into: map.fit(FitOptions(maxLayersExtent).withSize(/* Size(w, h) */)) to adjust the extent correctly?
Thanks for the suggestion @f.zehnder !
In my case, when I call map.fit(FitOptions(extent))
the extent does not fully appear in the viewport. It looks “cropped” on one axis — as if the extent’s aspect ratio and the map’s aspect ratio (width/height) don’t match, so part of the extent stays outside the visible area.
That’s why I was trying to pass the map size to withSize(…): to make sure the fit calculation uses the actual rendered width/height and the whole extent becomes visible. Without providing the size, I sometimes end up with the extent larger than the visible map and not fully displayed.
@Subscribe
@SuppressWarnings("kotlin:S1172")
private fun onInit(event: InitEvent) {
val extent = Extent(-1.8674325306490491, 44.671768059029716, 6.86824470581692, 45.35320099891573)
networkMap.mapView.extent = extent
networkMap.fit(FitOptions(extent))
}
Normally, I should see the extent fully as shown in the first image,:
but instead, I get a view like in the second image
I think the issue might be that the size ratio of the map doesn’t match the extent’s ratio. As a result, the extent appears cropped or zoomed in the wrong way, making some parts of it not visible on the map.
Since my data is scattered, I want the users to be able to see it fully.
Do you have any suggestions to help with this, or adjustments I need to make?
Thank you!
I cannot create a DataVector because I’m inside a generic function.
I tried creating a polygon from the Extent manually, similar to your example, but I still encounter the same issue:
map.mapView.extent = maxLayersExtent
val factory = GeometryUtils.getGeometryFactory()
val coords = arrayOf(
Coordinate(maxLayersExtent.minX, maxLayersExtent.maxY), // top-left
Coordinate(maxLayersExtent.minX, maxLayersExtent.minY), // bottom-left
Coordinate(maxLayersExtent.maxX, maxLayersExtent.minY), // bottom-right
Coordinate(maxLayersExtent.maxX, maxLayersExtent.maxY), // top-right
Coordinate(maxLayersExtent.minX, maxLayersExtent.maxY) // fermer le ring
)
val ring = factory.createLinearRing(coords)
val polygon = factory.createPolygon(ring)
map.fit(FitOptions(polygon))
does not fit inside the first extent, as minX of -1.83 is outside of the displaying extent of -4.87.
In the attached project, I did change the extent in the descriptor and it is working.
If with the same programm, I try to change the extent (this you want), I get the result which you have.
The problem here is, that you need to scroll sideways as the relation from height to width is changed and it is not possible to display this polygon with the selected size of the map ( what you guessed already ).
The networkMap.fit(new FitOptions(polygon) is working !
You might play with the height of the map you display after changing the extent. mapExtentIssue.zip (89.8 KB)