A powerful Blazor component library that wraps OpenLayers for interactive mapping in .NET applications.
- Features
- Demo
- Installation
- Quick Start
- Supported Platforms
- What's New in 2.0
- Usage Examples
- Map Types
- Layer Types
- Contributing
- License
- Multiple Map Providers: OpenStreetMap, Bing Maps, Mapbox, SwissTopo, and any WMTS/WMS compatible source
- Swiss Coordinate System: Built-in support for Swiss projection systems (LV03/LV95)
- Vector Layers: Full support for vector layers with customizable styles
- Rich Shapes: Points, lines, polygons, circles, and multi-geometries
- Markers: Various marker types including pins, flags, and custom icons
- Interactive Features:
- Shape drawing and editing
- Click events on features and layers
- Shape selection with events
- Popup support
- Data Formats: GeoJSON, KML, WKT, WMS, WMTS
- Heatmaps: Built-in heatmap layer support
- Blazor Ready: Works with Blazor Server, WebAssembly, and .NET MAUI Blazor
Live Demo: https://openlayers-blazor-demo.laurent-christen.ch/
Explore interactive examples including:
- Basic maps with different providers
- Vector layers and GeoJSON data
- Drawing and editing features
- Markers and popups
- Heatmaps
- Swiss coordinate system examples
dotnet add package OpenLayers.BlazorOr via Package Manager Console:
Install-Package OpenLayers.BlazorAdd the OpenLayers JavaScript and CSS files to your index.html (Blazor WebAssembly/MAUI) or _Host.cshtml/App.razor (Blazor Server):
<head>
...
<!-- OpenLayers CSS -->
<link href="https://cdn.jsdelivr.net/npm/ol@v10.6.1/ol.css" rel="stylesheet" />
<!-- OpenLayers.Blazor CSS -->
<link href="_content/OpenLayers.Blazor/OpenLayers.Blazor.css" rel="stylesheet" />
<!-- OpenLayers JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/ol@v10.6.1/dist/ol.js"></script>
...
</head>Alternative CDN sources:
<!-- From cdnjs -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/openlayers/10.6.1/ol.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/10.6.1/dist/ol.min.js"></script><OpenStreetMap Style="height:600px" Zoom="12" Center="new Coordinate(0, 51)">
<Features>
<Marker Type="MarkerType.MarkerPin" Coordinate="new Coordinate(0, 51)" Text="London" Popup />
</Features>
</OpenStreetMap><SwissMap Style="height:800px" Zoom="10" Center="new Coordinate(2600000, 1200000)">
<Features>
<Marker Type="MarkerType.MarkerPin"
Coordinate="new Coordinate(2604200, 1197650)"
Text="Bern"
BackgroundColor="#FF5733"
Popup />
</Features>
</SwissMap>- .NET 8.0
- .NET 9.0
- .NET 10.0
Works with:
- Blazor Server
- Blazor WebAssembly
- .NET MAUI Blazor (Hybrid)
- β Full vector layer support with the ability to add shapes per layer
- β Comprehensive style customization for all vector elements
- β Shape selection feature with selection events on layers
- β Automatic updates when parameters change on layers and shapes (component mode)
- β On-demand layer creation - Internal shape/drawing and marker layers are added automatically when needed
- β
Improved event handling - Fixed issue where
InteractionsEnabled = falsealso blocked mouse events
- Internal shape and drawing layers are now part of the layers collection
- Some API changes for better consistency
- Mouse events now work correctly even when interactions are disabled
- Improved memory management and disposal
- Better coordinate system transformations
<OpenStreetMap Style="height:600px" Zoom="5" Center="new Coordinate(10, 47)">
<Popup>
<div class="custom-popup">
@if (context is Marker marker)
{
<h3>@marker.Text</h3>
<p>π @marker.Coordinate.X, @marker.Coordinate.Y</p>
}
</div>
</Popup>
<Features>
<Marker Type="MarkerType.MarkerFlag"
Coordinate="new Coordinate(10, 47)"
Text="Vienna"
BackgroundColor="#449933"
Popup />
</Features>
</OpenStreetMap><OpenStreetMap Style="height:800px" Zoom="3">
<Layers>
<Layer LayerType="LayerType.VectorImage"
SourceType="SourceType.VectorGeoJson"
Url="https://openlayers.org/data/vector/ecoregions.json"
ZIndex="10"
Opacity=".5" />
</Layers>
</OpenStreetMap><OpenStreetMap @ref="_map" Style="height:600px" Zoom="6">
<Layers>
<Layer LayerType="LayerType.Vector" SourceType="SourceType.Vector">
<Shapes>
<Circle Center="new(9.674681, 46.778543)"
Radius="50000"
Stroke="red"
Fill="rgba(255,0,0,0.2)"
StrokeThickness="3" />
<Polygon Points="@_polygonPoints"
Stroke="blue"
Fill="rgba(0,0,255,0.3)"
StrokeThickness="2" />
<LineString Points="@_linePoints"
Stroke="green"
StrokeThickness="4" />
</Shapes>
</Layer>
</Layers>
</OpenStreetMap>
@code {
private Coordinate[] _polygonPoints = new[]
{
new Coordinate(5, 45),
new Coordinate(15, 45),
new Coordinate(15, 50),
new Coordinate(5, 50),
new Coordinate(5, 45)
};
private Coordinate[] _linePoints = new[]
{
new Coordinate(0, 45),
new Coordinate(10, 50),
new Coordinate(20, 45)
};
}<OpenStreetMap Style="height:600px" Zoom="5" Center="new Coordinate(0, 51)">
<Layers>
<Layer SourceType="SourceType.TileWMS"
Url="https://sedac.ciesin.columbia.edu/geoserver/ows"
Params="@(new Dictionary<string, string>
{
{ "LAYERS", "gpw-v3:gpw-v3-population-density_2000" },
{ "TILED", "true" }
})"
Opacity=".6"
CrossOrigin="anonymous" />
</Layers>
</OpenStreetMap><OpenStreetMap Style="height:600px" Zoom="2">
<Layers>
<Layer LayerType="LayerType.Heatmap"
SourceType="SourceType.VectorKML"
Url="https://openlayers.org/en/latest/examples/data/kml/2012_Earthquakes_Mag5.kml"
Options="@(new { blur = 15, radius = 5 })" />
</Layers>
</OpenStreetMap><OpenStreetMap @ref="_map"
Style="height:600px"
OnClick="OnMapClick"
OnPointerMove="OnPointerMove">
<Layers>
<Layer @ref="_layer"
LayerType="LayerType.Vector"
SourceType="SourceType.Vector"
OnFeatureClick="OnFeatureClick">
<Shapes>
<Circle @ref="_selectedShape"
Center="new(10, 47)"
Radius="50000"
Stroke="blue"
Fill="rgba(0,0,255,0.2)" />
</Shapes>
</Layer>
</Layers>
</OpenStreetMap>
<div class="mt-3">
<p>Last clicked: @_lastClickPosition</p>
<p>Mouse position: @_mousePosition</p>
</div>
@code {
private Map? _map;
private Layer? _layer;
private Shape? _selectedShape;
private string? _lastClickPosition;
private string? _mousePosition;
private async Task OnMapClick(Coordinate coordinate)
{
_lastClickPosition = $"{coordinate.X:F2}, {coordinate.Y:F2}";
StateHasChanged();
}
private void OnPointerMove(Coordinate coordinate)
{
_mousePosition = $"{coordinate.X:F2}, {coordinate.Y:F2}";
StateHasChanged();
}
private async Task OnFeatureClick(Feature feature)
{
if (feature is Shape shape)
{
shape.Stroke = "red";
await shape.UpdateShape();
}
}
}The library provides pre-configured map components:
<OpenStreetMap Style="height:600px" Zoom="12" Center="new Coordinate(0, 51)" /><BingMap Style="height:600px"
Zoom="10"
Center="new Coordinate(-74, 40)"
Key="your-bing-maps-key"
ImagerySet="Aerial" /><MapboxMap Style="height:600px"
Zoom="12"
Center="new Coordinate(-122, 37)"
AccessToken="your-mapbox-token"
StyleUrl="mapbox://styles/mapbox/streets-v11" /><SwissMap Style="height:800px"
Zoom="10"
Center="new Coordinate(2600000, 1200000)"
LayerId="ch.swisstopo.pixelkarte-farbe" />Available Swiss layers:
ch.swisstopo.pixelkarte-farbe(default color map)ch.swisstopo.pixelkarte-grau(grayscale)ch.swisstopo.swissimage(satellite imagery)ch.swisstopo.swissalti3d-reliefschattierung(relief)- And many more from geo.admin.ch
- TileOSM: OpenStreetMap tiles
- TileWMS: Web Map Service
- TileXYZ: Custom tile servers
- TileBingMaps: Bing Maps tiles
- Vector: Standard vector layer
- VectorImage: Optimized vector rendering
- VectorTile: Vector tile layer
- VectorGeoJSON: GeoJSON data
- VectorKML: KML files
- VectorWKT: Well-Known Text
- VectorWFS: Web Feature Service
- Heatmap: Density visualization
- Image: Static images with geographic bounds
- Graticule: Coordinate grid lines
Center- Map center coordinateZoom- Zoom level (1-20)Rotation- Map rotation in radiansInteractionsEnabled- Enable/disable map interactionsShowControls- Show/hide map controlsMinZoom/MaxZoom- Zoom constraints
LayerType- Type of layer (Vector, VectorImage, Tile, etc.)SourceType- Data source typeUrl- Data source URLOpacity- Layer opacity (0-1)ZIndex- Layer stacking orderVisible- Layer visibility
Coordinates- Shape geometryStroke- Outline colorStrokeThickness- Line widthFill- Fill colorPopup- Enable popup on clickZIndex- Shape stacking order
OnClick- Map click eventOnPointerMove- Mouse move eventOnFeatureClick- Feature/shape click eventOnSelectionChanged- Selection change eventOnDrawEnd- Drawing completed event
- Ensure OpenLayers CSS and JS are properly loaded
- Check browser console for errors
- Verify the map has a defined height in the
Styleattribute
- Use
SwissMapcomponent instead ofOpenStreetMap - Ensure coordinates are in LV95 format (EPSG:2056)
- Check coordinate values are in the valid range
- Check
ZIndexvalues - higher values are on top - Verify
Opacityis not set to 0 - Ensure
Visibleproperty is true - Check layer bounds match the visible extent
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Built on OpenLayers - A high-performance library for interactive maps
- Swiss projection support based on geo.admin.ch
- π« Issues: GitHub Issues
- π¬ Discussions: GitHub Discussions
- π Don't forget to star the project if you find it useful!
Made with β€οΈ for the Blazor community