MapBox
MapBox is a private sector mapping platform similar to OpenLayers or OpenStreetMap. It offers a wide variety of services including basemaps, navigation, mobile SDKs and
for our purposes here - a desktop API for presenting maps in web pages.
Data can be consumed by the API in a number of formats such as GeoJSON or from a WFS. It can present vector and raster data. I have not used in anger yet, but it appears to have a
reasonable free tier for smaller sites.
Links
Basic Map Call
In this simple example we present a map and add markers manually. This is a very simple example
to demonstrate the basics before moving on to more complex stuff.
We use HTMX to display the map and send in a trigger to initialise the map after the partial
has setted in the dom.
document.body.addEventListener("initMap1", function(evt){
mapboxgl.accessToken = '***'
const map = new mapboxgl.Map({
container: 'map1',
style: 'mapbox://styles/mapbox/standard',
center: [12.550343, 55.665957],
zoom: 8
});
// Create a default Marker and add it to the map.
const marker1 = new mapboxgl.Marker()
.setLngLat([12.554729, 55.70651])
.addTo(map);
// Create a default Marker, colored black, rotated 45 degrees.
const marker2 = new mapboxgl.Marker({ color: 'black', rotation: 45 })
.setLngLat([12.65147, 55.608166])
.addTo(map);
})
## TEMPLATE SNIPPET ***
## Note for flex, the min requirement is to set the height of the map otherwise does not appear.
<div id='map1' class="map shadow-dark" style='height: 300px;' ></div>
## DJANGO VIEW ###
# Set header to trigger JS init map when loading returning the map partial
response["HX-Trigger-After-Settle"] = "initMap1"
Accessing External Data
In this example, from the MapBox site, we pull in geojosn from a public endpoint. First, the source of the data is defined and then
this data is presented on a layer.
const map = new mapboxgl.Map({
container: 'map2',
style: 'mapbox://styles/mapbox/standard',
center: [-74.0060152, 40.7127281],
zoom: 5,
maxZoom: 6
});
map.on('style.load', () => {
map.addSource('urban-areas', {
'type': 'geojson',
'data': 'https://docs.mapbox.com/mapbox-gl-js/assets/ne_50m_urban_areas.geojson'
});
map.addLayer({
'id': 'urban-areas-fill',
'type': 'fill',
'slot': 'middle',
'source': 'urban-areas',
'layout': {},
'paint': {
'fill-color': '#f08',
'fill-opacity': 0.4
}
});
});
Accessing Data from Geoserver
In this example data is pulled in from the geoserver instance at fearnought.club.
Point data is retrieved as geojson and the paint attribute is used to give colours to selected classes. The data presented is limited to the first
750 features to ensure a reasonable response time.
const apiEndPoint = new URL("https://fearnought.club/geoserver/fearnought_sheffield/ows");
const parameters = {
service: 'WFS',
version: '1.1.0',
request: 'GetFeature',
typeName: 'fearnought_sheffield:events_2024_projected',
maxFeatures: 1000,
outputFormat: 'application/json',
SrsName : 'EPSG:4326'
};
const searchParams = new URLSearchParams(parameters)
apiEndPoint.search = searchParams
const finalURL = apiEndPoint.toString()
console.log(finalURL)
const map = new mapboxgl.Map({
container: 'map3',
style: 'mapbox://styles/mapbox/standard',
center: [-1.469754, 53.383525],
zoom: 8,
maxZoom: 15
});
map.on('style.load', () => {
map.addSource('sheffield-crime', {
'type': 'geojson',
'data': finalURL,
});
map.addLayer({
'id': 'sheffield-crime',
'type': 'circle',
'slot': 'top',
'source': 'sheffield-crime',
'layout': {
'visibility': 'visible',
},
"paint": {
"circle-color": [
"match",
["get", "Crime_type"],
"Criminal damage and arson", "#fbb03b",
"Vehicle crime", "#223b53",
"Violence and sexual offences", "#e55e5e",
"Other crime", "#ccc",
"black" // Default color for other values
]
}
});
});
External Data WMS
In this example the GetMap service is used from the a geoserver WMS. This returns an image, in this case a png. This requires a bounding box for both the WMS call
and the setup of the mapBox source (hardocded in this example).
NOTE: for Images, the bbox coordinates need to be provided in [long, lat] pairs in order [top-left, top-right, bottom-right, bottom-left].
const apiEndPoint = new URL("https://fearnought.club/geoserver/fearnought_enschede/wms");
const parameters = {
service: 'WMS',
version: '1.1',
request: 'GetMap',
layers: 'fearnought_enschede:geo_enschedeboundary',
styles : '',
format: 'image/png',
srs : 'EPSG:4326',
width : 780,
height : 330,
bbox: "6.7642530835571835, 52.161286767163396, 6.9900289975756476, 52.288491432943324",
transparent : true,
};
const searchParams = new URLSearchParams(parameters)
apiEndPoint.search = searchParams
const finalURL = apiEndPoint.toString()
console.log(finalURL)
const map = new mapboxgl.Map({
container: 'map4',
style: 'mapbox://styles/mapbox/standard',
center: [6.895493, 52.220333],
zoom: 8,
maxZoom: 15
});
map.on('style.load', () => {
map.addSource('enschede-boundary', {
'type': 'image',
'url': finalURL,
'coordinates': [
[6.7642530835571835, 52.288491432943324],
[6.9900289975756476, 52.288491432943324],
[6.9900289975756476, 52.161286767163396],
[6.7642530835571835, 52.161286767163396],
]
});
map.addLayer({
id: 'enschede-boundary',
'type': 'raster',
'source': 'enschede-boundary',
});
});
Accessing tilesets from MapBox Studio
MapBox offers a UI to build custom styles. Data can be uploaded as vector or raster. These have to be converted to tilesets for display in a map (this is mandatory for them to be displayed).
In this example a boundary layer for Enschede was uploaded as a geojson and then converted to a tileset. Likewise for an example buildings layer. The
latter will only display on zoom levels of +13. Zoom-related style can be applied, which in this case is to make the buildings appear darker as we zoom in.
const map = new mapboxgl.Map({
container: 'map5',
// Custom style
style: 'mapbox://styles/craigholl/cmcx8ak7p00rg01sb5e2633eg',
center: [6.895493, 52.220333],
zoom: 10
});