Skip to content

openlayers module

OpenLayers implementation of the map widget.

OpenLayersMap (MapWidget)

OpenLayers implementation of the map widget.

Source code in anymap/openlayers.py
class OpenLayersMap(MapWidget):
    """OpenLayers implementation of the map widget."""

    # OpenLayers-specific traits
    tile_layer = traitlets.Unicode("OSM").tag(sync=True)
    projection = traitlets.Unicode("EPSG:3857").tag(sync=True)

    # Define the JavaScript module path
    _esm = _esm_openlayers
    _css = _css_openlayers

    def __init__(
        self,
        center: List[float] = [0.0, 0.0],
        zoom: float = 2.0,
        tile_layer: str = "OSM",
        projection: str = "EPSG:3857",
        width: str = "100%",
        height: str = "600px",
        **kwargs,
    ):
        """Initialize OpenLayers map widget.

        Args:
            center: Map center as [longitude, latitude] (note: OpenLayers uses lon/lat order)
            zoom: Initial zoom level
            tile_layer: Tile layer provider name or URL template
            projection: Map projection (default: EPSG:3857)
            width: Widget width
            height: Widget height
            **kwargs: Additional widget arguments
        """
        super().__init__(
            center=center,
            zoom=zoom,
            width=width,
            height=height,
            **kwargs,
        )
        self.tile_layer = tile_layer
        self.projection = projection

    def add_tile_layer(
        self,
        url_template: str,
        attribution: str = "",
        layer_id: str = None,
        **options,
    ) -> None:
        """Add a tile layer to the map.

        Args:
            url_template: URL template for the tile layer
            attribution: Attribution text for the layer
            layer_id: Unique identifier for the layer
            **options: Additional layer options
        """
        if layer_id is None:
            layer_id = f"tile_layer_{len(self._layers)}"

        layer_config = {
            "type": "tile",
            "url": url_template,
            "attribution": attribution,
            **options,
        }
        self.add_layer(layer_id, layer_config)

    def add_marker(
        self,
        coordinate: List[float],
        popup: str = "",
        tooltip: str = "",
        icon: Optional[Dict[str, Any]] = None,
        **options,
    ) -> str:
        """Add a marker to the map.

        Args:
            coordinate: Marker position as [longitude, latitude]
            popup: Popup text
            tooltip: Tooltip text
            icon: Icon configuration
            **options: Additional marker options

        Returns:
            Marker ID
        """
        marker_id = f"marker_{len(self._layers)}"

        marker_config = {
            "type": "marker",
            "coordinate": coordinate,
            "popup": popup,
            "tooltip": tooltip,
            **options,
        }

        if icon:
            marker_config["icon"] = icon

        self.add_layer(marker_id, marker_config)
        return marker_id

    def add_circle(
        self,
        center: List[float],
        radius: float,
        color: str = "blue",
        fillColor: str = "blue",
        fillOpacity: float = 0.2,
        strokeWidth: float = 2,
        **options,
    ) -> str:
        """Add a circle to the map.

        Args:
            center: Circle center as [longitude, latitude]
            radius: Circle radius in meters
            color: Circle stroke color
            fillColor: Circle fill color
            fillOpacity: Circle fill opacity
            strokeWidth: Circle stroke width
            **options: Additional circle options

        Returns:
            Circle ID
        """
        circle_id = f"circle_{len(self._layers)}"

        circle_config = {
            "type": "circle",
            "center": center,
            "radius": radius,
            "color": color,
            "fillColor": fillColor,
            "fillOpacity": fillOpacity,
            "strokeWidth": strokeWidth,
            **options,
        }

        self.add_layer(circle_id, circle_config)
        return circle_id

    def add_polygon(
        self,
        coordinates: List[List[List[float]]],
        color: str = "blue",
        fillColor: str = "blue",
        fillOpacity: float = 0.2,
        strokeWidth: float = 2,
        **options,
    ) -> str:
        """Add a polygon to the map.

        Args:
            coordinates: Polygon coordinates as [[[lon, lat], [lon, lat], ...]]
            color: Polygon stroke color
            fillColor: Polygon fill color
            fillOpacity: Polygon fill opacity
            strokeWidth: Polygon stroke width
            **options: Additional polygon options

        Returns:
            Polygon ID
        """
        polygon_id = f"polygon_{len(self._layers)}"

        polygon_config = {
            "type": "polygon",
            "coordinates": coordinates,
            "color": color,
            "fillColor": fillColor,
            "fillOpacity": fillOpacity,
            "strokeWidth": strokeWidth,
            **options,
        }

        self.add_layer(polygon_id, polygon_config)
        return polygon_id

    def add_linestring(
        self,
        coordinates: List[List[float]],
        color: str = "blue",
        strokeWidth: float = 3,
        **options,
    ) -> str:
        """Add a line string to the map.

        Args:
            coordinates: Line coordinates as [[lon, lat], [lon, lat], ...]
            color: Line color
            strokeWidth: Line stroke width
            **options: Additional line options

        Returns:
            LineString ID
        """
        linestring_id = f"linestring_{len(self._layers)}"

        linestring_config = {
            "type": "linestring",
            "coordinates": coordinates,
            "color": color,
            "strokeWidth": strokeWidth,
            **options,
        }

        self.add_layer(linestring_id, linestring_config)
        return linestring_id

    def add_geojson(
        self,
        data: Union[str, Dict[str, Any]],
        style: Optional[Dict[str, Any]] = None,
        **options,
    ) -> str:
        """Add GeoJSON data to the map.

        Args:
            data: GeoJSON data as string or dict
            style: Style configuration
            **options: Additional GeoJSON options

        Returns:
            GeoJSON layer ID
        """
        geojson_id = f"geojson_{len(self._layers)}"

        geojson_config = {
            "type": "geojson",
            "data": data,
            **options,
        }

        if style:
            geojson_config["style"] = style

        self.add_layer(geojson_id, geojson_config)
        return geojson_id

    def add_vector_layer(
        self,
        features: List[Dict[str, Any]],
        style: Optional[Dict[str, Any]] = None,
        layer_id: str = None,
        **options,
    ) -> str:
        """Add a vector layer with features.

        Args:
            features: List of feature objects
            style: Style configuration for the layer
            layer_id: Unique identifier for the layer
            **options: Additional layer options

        Returns:
            Vector layer ID
        """
        if layer_id is None:
            layer_id = f"vector_{len(self._layers)}"

        layer_config = {
            "type": "vector",
            "features": features,
            "style": style or {},
            **options,
        }

        self.add_layer(layer_id, layer_config)
        return layer_id

    def fit_extent(self, extent: List[float]) -> None:
        """Fit the map view to given extent.

        Args:
            extent: Extent as [minX, minY, maxX, maxY]
        """
        self.call_js_method("fitExtent", extent)

    def transform_coordinate(
        self, coordinate: List[float], from_proj: str, to_proj: str
    ) -> List[float]:
        """Transform coordinate from one projection to another.

        Args:
            coordinate: Coordinate as [x, y]
            from_proj: Source projection
            to_proj: Target projection

        Returns:
            Transformed coordinate
        """
        # This would typically be handled on the JavaScript side
        self.call_js_method("transformCoordinate", coordinate, from_proj, to_proj)
        return coordinate  # Placeholder - real transformation happens in JS

    def _generate_html_template(
        self, map_state: Dict[str, Any], title: str, **kwargs
    ) -> str:
        """Generate the HTML template with map state for OpenLayers."""

        # Get tile layer URL template
        tile_providers = {
            "OSM": "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
            "CartoDB.Positron": "https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png",
            "CartoDB.DarkMatter": "https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_all/{z}/{x}/{y}.png",
            "Stamen.Terrain": "https://stamen-tiles-{s}.a.ssl.fastly.net/terrain/{z}/{x}/{y}.jpg",
            "Stamen.Watercolor": "https://stamen-tiles-{s}.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.jpg",
        }

        tile_url = tile_providers.get(map_state.get("tile_layer", "OSM"))
        if not tile_url:
            tile_url = map_state.get("tile_layer", tile_providers["OSM"])

        html_template = f"""<!DOCTYPE html>
<html>
<head>
    <title>{title}</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol@v10.6.1/ol.css"
          crossorigin=""/>
    <style>
        body {{
            margin: 0;
            padding: 0;
            font-family: Arial, sans-serif;
        }}
        #map {{
            width: {map_state.get('width', '100%')};
            height: {map_state.get('height', '600px')};
        }}
        .ol-popup {{
            position: absolute;
            background-color: white;
            box-shadow: 0 1px 4px rgba(0,0,0,0.2);
            padding: 15px;
            border-radius: 10px;
            border: 1px solid #cccccc;
            bottom: 12px;
            left: -50px;
            min-width: 280px;
        }}
        .ol-popup:after, .ol-popup:before {{
            top: 100%;
            border: solid transparent;
            content: " ";
            height: 0;
            width: 0;
            position: absolute;
            pointer-events: none;
        }}
        .ol-popup:after {{
            border-color: rgba(255, 255, 255, 0);
            border-top-color: white;
            border-width: 10px;
            left: 48px;
            margin-left: -10px;
        }}
        .ol-popup:before {{
            border-color: rgba(204, 204, 204, 0);
            border-top-color: #cccccc;
            border-width: 11px;
            left: 48px;
            margin-left: -11px;
        }}
        .ol-popup-closer {{
            text-decoration: none;
            position: absolute;
            top: 2px;
            right: 8px;
        }}
        .ol-popup-closer:after {{
            content: "✖";
        }}
    </style>
</head>
<body>
    <div id="map"></div>
    <div id="popup" class="ol-popup">
        <a href="#" id="popup-closer" class="ol-popup-closer"></a>
        <div id="popup-content"></div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/ol@v10.6.1/dist/ol.js"
            crossorigin=""></script>
    <script>
        // Import OpenLayers modules
        const {{Map, View}} = ol;
        const {{Tile: TileLayer, Vector: VectorLayer}} = ol.layer;
        const {{OSM, XYZ, Vector: VectorSource}} = ol.source;
        const {{Feature}} = ol;
        const {{Point, Circle: CircleGeom, Polygon, LineString}} = ol.geom;
        const {{Style, Fill, Stroke, Icon, Circle: CircleStyle}} = ol.style;
        const {{fromLonLat, toLonLat}} = ol.proj;
        const {{Overlay}} = ol;
        const {{GeoJSON}} = ol.format;

        // Initialize the map
        const view = new View({{
            center: fromLonLat({map_state.get('center', [0, 0])}),
            zoom: {map_state.get('zoom', 2)},
            projection: '{map_state.get('projection', 'EPSG:3857')}'
        }});

        const map = new Map({{
            target: 'map',
            view: view
        }});

        // Add base tile layer
        let baseSource;
        if ('{map_state.get('tile_layer', 'OSM')}' === 'OSM') {{
            baseSource = new OSM();
        }} else {{
            baseSource = new XYZ({{
                url: '{tile_url}',
                attributions: '© Map data providers'
            }});
        }}
        const baseLayer = new TileLayer({{
            source: baseSource
        }});
        map.addLayer(baseLayer);

        // Setup popup
        const container = document.getElementById('popup');
        const content = document.getElementById('popup-content');
        const closer = document.getElementById('popup-closer');

        const overlay = new Overlay({{
            element: container,
            autoPan: {{
                animation: {{
                    duration: 250,
                }}
            }}
        }});
        map.addOverlay(overlay);

        closer.onclick = function() {{
            overlay.setPosition(undefined);
            closer.blur();
            return false;
        }};

        // Add layers
        const layers = {json.dumps(map_state.get('_layers', {}))};
        for (const layerId in layers) {{
            const layer = layers[layerId];
            let olLayer = null;

            if (layer.type === 'tile') {{
                olLayer = new TileLayer({{
                    source: new XYZ({{
                        url: layer.url,
                        attributions: layer.attribution || ''
                    }})
                }});
            }} else if (layer.type === 'marker') {{
                const feature = new Feature({{
                    geometry: new Point(fromLonLat(layer.coordinate))
                }});

                if (layer.popup) {{
                    feature.set('popup', layer.popup);
                }}

                const vectorSource = new VectorSource({{
                    features: [feature]
                }});

                olLayer = new VectorLayer({{
                    source: vectorSource,
                    style: new Style({{
                        image: new CircleStyle({{
                            radius: 8,
                            fill: new Fill({{color: 'red'}}),
                            stroke: new Stroke({{color: 'white', width: 2}})
                        }})
                    }})
                }});
            }} else if (layer.type === 'circle') {{
                const feature = new Feature({{
                    geometry: new CircleGeom(fromLonLat(layer.center), layer.radius)
                }});

                const vectorSource = new VectorSource({{
                    features: [feature]
                }});

                olLayer = new VectorLayer({{
                    source: vectorSource,
                    style: new Style({{
                        fill: new Fill({{
                            color: layer.fillColor || 'blue',
                            opacity: layer.fillOpacity || 0.2
                        }}),
                        stroke: new Stroke({{
                            color: layer.color || 'blue',
                            width: layer.strokeWidth || 2
                        }})
                    }})
                }});
            }} else if (layer.type === 'polygon') {{
                const feature = new Feature({{
                    geometry: new Polygon(layer.coordinates.map(ring =>
                        ring.map(coord => fromLonLat(coord))
                    ))
                }});

                const vectorSource = new VectorSource({{
                    features: [feature]
                }});

                olLayer = new VectorLayer({{
                    source: vectorSource,
                    style: new Style({{
                        fill: new Fill({{
                            color: layer.fillColor || 'blue',
                            opacity: layer.fillOpacity || 0.2
                        }}),
                        stroke: new Stroke({{
                            color: layer.color || 'blue',
                            width: layer.strokeWidth || 2
                        }})
                    }})
                }});
            }} else if (layer.type === 'linestring') {{
                const feature = new Feature({{
                    geometry: new LineString(layer.coordinates.map(coord => fromLonLat(coord)))
                }});

                const vectorSource = new VectorSource({{
                    features: [feature]
                }});

                olLayer = new VectorLayer({{
                    source: vectorSource,
                    style: new Style({{
                        stroke: new Stroke({{
                            color: layer.color || 'blue',
                            width: layer.strokeWidth || 3
                        }})
                    }})
                }});
            }} else if (layer.type === 'geojson') {{
                const vectorSource = new VectorSource({{
                    features: new GeoJSON().readFeatures(layer.data, {{
                        featureProjection: 'EPSG:3857'
                    }})
                }});

                olLayer = new VectorLayer({{
                    source: vectorSource
                }});
            }}

            if (olLayer) {{
                map.addLayer(olLayer);
            }}
        }}

        // Handle map clicks for popups
        map.on('singleclick', function(evt) {{
            const feature = map.forEachFeatureAtPixel(evt.pixel, function(feature) {{
                return feature;
            }});

            if (feature && feature.get('popup')) {{
                const coordinate = evt.coordinate;
                content.innerHTML = feature.get('popup');
                overlay.setPosition(coordinate);
            }} else {{
                overlay.setPosition(undefined);
            }}
        }});
    </script>
</body>
</html>"""
        return html_template

__init__(self, center=[0.0, 0.0], zoom=2.0, tile_layer='OSM', projection='EPSG:3857', width='100%', height='600px', **kwargs) special

Initialize OpenLayers map widget.

Parameters:

Name Type Description Default
center List[float]

Map center as [longitude, latitude] (note: OpenLayers uses lon/lat order)

[0.0, 0.0]
zoom float

Initial zoom level

2.0
tile_layer str

Tile layer provider name or URL template

'OSM'
projection str

Map projection (default: EPSG:3857)

'EPSG:3857'
width str

Widget width

'100%'
height str

Widget height

'600px'
**kwargs

Additional widget arguments

{}
Source code in anymap/openlayers.py
def __init__(
    self,
    center: List[float] = [0.0, 0.0],
    zoom: float = 2.0,
    tile_layer: str = "OSM",
    projection: str = "EPSG:3857",
    width: str = "100%",
    height: str = "600px",
    **kwargs,
):
    """Initialize OpenLayers map widget.

    Args:
        center: Map center as [longitude, latitude] (note: OpenLayers uses lon/lat order)
        zoom: Initial zoom level
        tile_layer: Tile layer provider name or URL template
        projection: Map projection (default: EPSG:3857)
        width: Widget width
        height: Widget height
        **kwargs: Additional widget arguments
    """
    super().__init__(
        center=center,
        zoom=zoom,
        width=width,
        height=height,
        **kwargs,
    )
    self.tile_layer = tile_layer
    self.projection = projection

add_circle(self, center, radius, color='blue', fillColor='blue', fillOpacity=0.2, strokeWidth=2, **options)

Add a circle to the map.

Parameters:

Name Type Description Default
center List[float]

Circle center as [longitude, latitude]

required
radius float

Circle radius in meters

required
color str

Circle stroke color

'blue'
fillColor str

Circle fill color

'blue'
fillOpacity float

Circle fill opacity

0.2
strokeWidth float

Circle stroke width

2
**options

Additional circle options

{}

Returns:

Type Description
str

Circle ID

Source code in anymap/openlayers.py
def add_circle(
    self,
    center: List[float],
    radius: float,
    color: str = "blue",
    fillColor: str = "blue",
    fillOpacity: float = 0.2,
    strokeWidth: float = 2,
    **options,
) -> str:
    """Add a circle to the map.

    Args:
        center: Circle center as [longitude, latitude]
        radius: Circle radius in meters
        color: Circle stroke color
        fillColor: Circle fill color
        fillOpacity: Circle fill opacity
        strokeWidth: Circle stroke width
        **options: Additional circle options

    Returns:
        Circle ID
    """
    circle_id = f"circle_{len(self._layers)}"

    circle_config = {
        "type": "circle",
        "center": center,
        "radius": radius,
        "color": color,
        "fillColor": fillColor,
        "fillOpacity": fillOpacity,
        "strokeWidth": strokeWidth,
        **options,
    }

    self.add_layer(circle_id, circle_config)
    return circle_id

add_geojson(self, data, style=None, **options)

Add GeoJSON data to the map.

Parameters:

Name Type Description Default
data Union[str, Dict[str, Any]]

GeoJSON data as string or dict

required
style Optional[Dict[str, Any]]

Style configuration

None
**options

Additional GeoJSON options

{}

Returns:

Type Description
str

GeoJSON layer ID

Source code in anymap/openlayers.py
def add_geojson(
    self,
    data: Union[str, Dict[str, Any]],
    style: Optional[Dict[str, Any]] = None,
    **options,
) -> str:
    """Add GeoJSON data to the map.

    Args:
        data: GeoJSON data as string or dict
        style: Style configuration
        **options: Additional GeoJSON options

    Returns:
        GeoJSON layer ID
    """
    geojson_id = f"geojson_{len(self._layers)}"

    geojson_config = {
        "type": "geojson",
        "data": data,
        **options,
    }

    if style:
        geojson_config["style"] = style

    self.add_layer(geojson_id, geojson_config)
    return geojson_id

add_linestring(self, coordinates, color='blue', strokeWidth=3, **options)

Add a line string to the map.

Parameters:

Name Type Description Default
coordinates List[List[float]]

Line coordinates as [[lon, lat], [lon, lat], ...]

required
color str

Line color

'blue'
strokeWidth float

Line stroke width

3
**options

Additional line options

{}

Returns:

Type Description
str

LineString ID

Source code in anymap/openlayers.py
def add_linestring(
    self,
    coordinates: List[List[float]],
    color: str = "blue",
    strokeWidth: float = 3,
    **options,
) -> str:
    """Add a line string to the map.

    Args:
        coordinates: Line coordinates as [[lon, lat], [lon, lat], ...]
        color: Line color
        strokeWidth: Line stroke width
        **options: Additional line options

    Returns:
        LineString ID
    """
    linestring_id = f"linestring_{len(self._layers)}"

    linestring_config = {
        "type": "linestring",
        "coordinates": coordinates,
        "color": color,
        "strokeWidth": strokeWidth,
        **options,
    }

    self.add_layer(linestring_id, linestring_config)
    return linestring_id

add_marker(self, coordinate, popup='', tooltip='', icon=None, **options)

Add a marker to the map.

Parameters:

Name Type Description Default
coordinate List[float]

Marker position as [longitude, latitude]

required
popup str

Popup text

''
tooltip str

Tooltip text

''
icon Optional[Dict[str, Any]]

Icon configuration

None
**options

Additional marker options

{}

Returns:

Type Description
str

Marker ID

Source code in anymap/openlayers.py
def add_marker(
    self,
    coordinate: List[float],
    popup: str = "",
    tooltip: str = "",
    icon: Optional[Dict[str, Any]] = None,
    **options,
) -> str:
    """Add a marker to the map.

    Args:
        coordinate: Marker position as [longitude, latitude]
        popup: Popup text
        tooltip: Tooltip text
        icon: Icon configuration
        **options: Additional marker options

    Returns:
        Marker ID
    """
    marker_id = f"marker_{len(self._layers)}"

    marker_config = {
        "type": "marker",
        "coordinate": coordinate,
        "popup": popup,
        "tooltip": tooltip,
        **options,
    }

    if icon:
        marker_config["icon"] = icon

    self.add_layer(marker_id, marker_config)
    return marker_id

add_polygon(self, coordinates, color='blue', fillColor='blue', fillOpacity=0.2, strokeWidth=2, **options)

Add a polygon to the map.

Parameters:

Name Type Description Default
coordinates List[List[List[float]]]

Polygon coordinates as [[[lon, lat], [lon, lat], ...]]

required
color str

Polygon stroke color

'blue'
fillColor str

Polygon fill color

'blue'
fillOpacity float

Polygon fill opacity

0.2
strokeWidth float

Polygon stroke width

2
**options

Additional polygon options

{}

Returns:

Type Description
str

Polygon ID

Source code in anymap/openlayers.py
def add_polygon(
    self,
    coordinates: List[List[List[float]]],
    color: str = "blue",
    fillColor: str = "blue",
    fillOpacity: float = 0.2,
    strokeWidth: float = 2,
    **options,
) -> str:
    """Add a polygon to the map.

    Args:
        coordinates: Polygon coordinates as [[[lon, lat], [lon, lat], ...]]
        color: Polygon stroke color
        fillColor: Polygon fill color
        fillOpacity: Polygon fill opacity
        strokeWidth: Polygon stroke width
        **options: Additional polygon options

    Returns:
        Polygon ID
    """
    polygon_id = f"polygon_{len(self._layers)}"

    polygon_config = {
        "type": "polygon",
        "coordinates": coordinates,
        "color": color,
        "fillColor": fillColor,
        "fillOpacity": fillOpacity,
        "strokeWidth": strokeWidth,
        **options,
    }

    self.add_layer(polygon_id, polygon_config)
    return polygon_id

add_tile_layer(self, url_template, attribution='', layer_id=None, **options)

Add a tile layer to the map.

Parameters:

Name Type Description Default
url_template str

URL template for the tile layer

required
attribution str

Attribution text for the layer

''
layer_id str

Unique identifier for the layer

None
**options

Additional layer options

{}
Source code in anymap/openlayers.py
def add_tile_layer(
    self,
    url_template: str,
    attribution: str = "",
    layer_id: str = None,
    **options,
) -> None:
    """Add a tile layer to the map.

    Args:
        url_template: URL template for the tile layer
        attribution: Attribution text for the layer
        layer_id: Unique identifier for the layer
        **options: Additional layer options
    """
    if layer_id is None:
        layer_id = f"tile_layer_{len(self._layers)}"

    layer_config = {
        "type": "tile",
        "url": url_template,
        "attribution": attribution,
        **options,
    }
    self.add_layer(layer_id, layer_config)

add_vector_layer(self, features, style=None, layer_id=None, **options)

Add a vector layer with features.

Parameters:

Name Type Description Default
features List[Dict[str, Any]]

List of feature objects

required
style Optional[Dict[str, Any]]

Style configuration for the layer

None
layer_id str

Unique identifier for the layer

None
**options

Additional layer options

{}

Returns:

Type Description
str

Vector layer ID

Source code in anymap/openlayers.py
def add_vector_layer(
    self,
    features: List[Dict[str, Any]],
    style: Optional[Dict[str, Any]] = None,
    layer_id: str = None,
    **options,
) -> str:
    """Add a vector layer with features.

    Args:
        features: List of feature objects
        style: Style configuration for the layer
        layer_id: Unique identifier for the layer
        **options: Additional layer options

    Returns:
        Vector layer ID
    """
    if layer_id is None:
        layer_id = f"vector_{len(self._layers)}"

    layer_config = {
        "type": "vector",
        "features": features,
        "style": style or {},
        **options,
    }

    self.add_layer(layer_id, layer_config)
    return layer_id

fit_extent(self, extent)

Fit the map view to given extent.

Parameters:

Name Type Description Default
extent List[float]

Extent as [minX, minY, maxX, maxY]

required
Source code in anymap/openlayers.py
def fit_extent(self, extent: List[float]) -> None:
    """Fit the map view to given extent.

    Args:
        extent: Extent as [minX, minY, maxX, maxY]
    """
    self.call_js_method("fitExtent", extent)

transform_coordinate(self, coordinate, from_proj, to_proj)

Transform coordinate from one projection to another.

Parameters:

Name Type Description Default
coordinate List[float]

Coordinate as [x, y]

required
from_proj str

Source projection

required
to_proj str

Target projection

required

Returns:

Type Description
List[float]

Transformed coordinate

Source code in anymap/openlayers.py
def transform_coordinate(
    self, coordinate: List[float], from_proj: str, to_proj: str
) -> List[float]:
    """Transform coordinate from one projection to another.

    Args:
        coordinate: Coordinate as [x, y]
        from_proj: Source projection
        to_proj: Target projection

    Returns:
        Transformed coordinate
    """
    # This would typically be handled on the JavaScript side
    self.call_js_method("transformCoordinate", coordinate, from_proj, to_proj)
    return coordinate  # Placeholder - real transformation happens in JS