Map extent issue

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!

Hello Aycha!

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?

Hi @masmoudiaicha16

You don’t need the size of the map.

For displaying the map where a GeoPolygon has to fit

map.fit(new FitOptions(getEditedEntity().getSitPolygon().getBoundary())
						.withDuration(1000)
						.withEasing(Easing.LINEAR)
						.withMaxZoom(14));

and for a GeoPoint

map.setCenter(point);
map.fit(new FitOptions(new PointFeature(point))
.withDuration(1000)
.withEasing(Easing.LINEAR)
.withMaxZoom(14)

Let me know, if you have problems with that :wink:

Regards

Felix

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.

Did you check if you have some scrollbars on the map ?

I have some samples with Multipoint and every point is on the map.
image

<formLayout height="100%">
  <maps:geoMap id="map" minWidth="48em" width="100%" height="56em">
    <maps:mapView projection="EPSG:4326"/>
      <maps:layers>
        
        <maps:tile id="tile">
          <maps:osmSource id="osmSource"
                   url="https://wmts10.geo.admin.ch/1.0.0/ch.swisstopo.pixelkarte-farbe/default/current/3857/{z}/{x}/{y}.jpeg"/>
        </maps:tile>

        <maps:vector id="vectorLayer" updateWhileInteracting="true" updateWhileAnimating="true">
          <maps:dataVectorSource id="source" dataContainer="tSiteDc" property="sitWktWgs84"/>
        </maps:vector>

    </maps:layers>
  </maps:geoMap>
</formLayout>

Perhaps you can supply a testproject ?

Regards

Felix

Thank you for your response @f.zehnder !
Here is a very simple code:

<layout expand="networkMap">
    <button id="printMap" icon="lumo:download" themeNames="success primary" alignSelf="CENTER" text="msg://fr.altereo.addon.network.view.mapnetwork/mapNetwork.buttonPrintMap" />
    <maps:geoMap id="networkMap" height="100%" width="100%">
        <maps:mapView projection="EPSG:4326">
            <maps:extent minX="-4.87"
                         minY="41.31"
                         maxX="9.63"
                         maxY="51.14" />
        </maps:mapView>
        <maps:layers>
            <maps:tile id="tiles">
                <maps:osmSource/>
            </maps:tile>
        </maps:layers>
    </maps:geoMap>
</layout>
@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,:
image

but instead, I get a view like in the second image :slight_smile:
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!

Hi @masmoudiaicha16

Attached you find a project where you can see the desired polygon which fits every time to the map.

You can now play with extent and you will see, that the polygon is only partitially displayed if you limit the map to small.

Let me know, if I understand your problem, correctly :wink:

Best Regards
Felix

mapExtentIssue.zip (89.6 KB)

Hi, thank you again!
I’m facing two constraints:

  1. I need to provide an extent (I will use it later)
  2. 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))