Complete vector map client based on Mapbox GL JS built using C#
The map view has almost all the features of Mapbox GL JS, such as:
- Support for mapbox default styles (streets, dark, satellite, etc...), any style hosted using Mapbox Studio, or a custom style defined in your C#/JSON code (demo)
- Support for GeoJSON polygons, lines, markers, images, videos, etc... (GeoJSON demo)
- Data binding support for WPF using dependency properties (MVVM demo)
- Can work completely offline without access token (vector map demo and raster/satellite map demo)
- Comes built-in with a map server that can serve mbtiles, png/pbf/jpg tiles, and fonts.
- Can be used with any custom tile source (Bing tiles demo)
- Upto date support for Mapbox style specification
- Compatable with Mapbox/Openmaptiles vector tile specification
- Conversion between lat/lon and pixels, for overlaying WPF elements on map (projection demo)
- Both WPF and WinForms are supported
- MIT License
Vector maps are the new generation of maps. Traditional map controls download maps from the internet in form of square image tiles, Vector maps download them in form of vector drawings (like SVG). They are then rendered on the client in realtime according to a style specification.
Vector maps are fast, fluent, scalable, highly customizable, and suitable for offline storage as well.
<Window x:Class="DemosWPF.HelloWorldWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mapbox="clr-namespace:MapboxNetWPF;assembly=MapboxNetWPF"
mc:Ignorable="d"
Title="Hello World" Height="600" Width="800" WindowState="Maximized">
<Grid>
<mapbox:Map Name="Map" Center="40.729917, -73.990428" Zoom="12"></mapbox:Map>
</Grid>
</Window>
Note: Don't forget to write your access token in the code. Without it, some online demos won't work.
Map.AccessToken = accessToken;
MapboxNet comes with a built-in server for serving both vector and raster tiles
// firstly, we create a server using the mbtiles
var server = new MapboxNetCore.MapServer(@"tiles\zurich-raster.mbtiles");
server.GlyphsPath = @"fonts\";
server.Start();
// Creating a custom style that takes our MapServer tiles as a raster source
// Converted from the javascript equivalent using https://jsfiddle.net/aliashrafx/c7pxomjb/39/
var style = new Dictionary<string, object>
{
["version"] = 8,
["name"] = "Custom style",
["sources"] = new Dictionary<string, object>
{
["satellite"] = new Dictionary<string, object>
{
["type"] = "raster",
["tileSize"] = 256,
["tiles"] = new object[] {
server.TilesURL, // using tile URL here
},
},
},
["layers"] = new object[] {
new Dictionary<string, object> {
["id"] = "satellite",
["type"] = "raster",
["source"] = "satellite",
["minzoom"] = 0,
["maxzoom"] = 22,
["layout"] = new Dictionary<string, object> {
},
["paint"] = new Dictionary<string, object> {
},
},
},
["glyphs"] = server.GlyphsURL,
["id"] = "14004506-1129-4d81-9889-800854993041",
};
// You can create a hybrid satellite view as well by using a style that takes both Vector Tiles as Raster Tiles
Map.MapStyle = style;
Note: You can convert your JSON into C# nested code using this script
You can run MapboxNet completely offline using tile stored in your file system. The demo comes with a aliflux-style.json
style that can be customized with MapServer URLs.
// Starting the MapServer on a random port, that serves the vector tiles stored in .mbtiles format
var server = new MapboxNetCore.MapServer(@"tiles\zurich.mbtiles");
server.GlyphsPath = @"fonts\";
server.Start();
// pulling the style json stored as an embedded resource in this project, and decoding it into C# dynamic object
var json = MapboxNetCore.Core.GetEmbeddedResource(this.GetType(), "DemosWPF.aliflux-style.json");
dynamic style = MapboxNetCore.Core.DecodeJsonPlain(json);
// modifying the style a bit so that it uses our tile server as a source
style.sources.openmaptiles.tiles.Add(server.TilesURL);
style.glyphs = server.GlyphsURL;
Map.MapStyle = style;
Note: Be careful in mixing and matching tiles and styles. The version/vendor incompatability may make things disappear.
Yes you can. MapboxNet comes with a built-in tile server for this purpose.
Yes you can. You can create your own style that uses your custom tile URL.
Yes you can. This is possible using fill-extrusion layers.
Yes you can. This can be done via GeoJSON layers and styles.
Please refer to this demo to see how GeoJSON looks like in C#. The code is generated using a JSON to nested C# converter. You can also read JSON as a string and parse it in runtime using MapboxNetCore.Core.DecodeJsonPlain
function (demo).
Can be done via RemoveAttribution
property, but I won't recommend doing it. If you're using a custom style of your own, the logo won't be visible by default.
I'm using CefSharp to emulate Google V8 VM that executes Mapbox GL JS and renders it inside the WPF/WinForms window.
CefSharp WPF architecture is built in such a way that each frame is rendered in an external process and copied as a bitmap to the WPF container. There is a thread that aims to improve this issue using DirectX rendering, so stay tuned.
If you can't wait, you may use MapboxNet WinForms component in WPF using WindowsFormsHost control.
The project is probably the only pure vector map client in C#/.Net. Therefore, it actively needs some good contribution support. Bug reports, suggestions and pull requests are all welcome. Please submit them to the GitHub issue tracker.
For latest releases and announcements, check out my site: aliashraf.net
This software is released under the MIT License. Please read LICENSE for information on the software availability and distribution.
Copyright (c) 2019 Ali Ashraf