JS 9
mapbox datasets
mapbox styles
We use Mapbox studio to design map styles trougth tilesets and GEOjson data.
//GEOjson to rappresent map data:
{
"features": [
{
"type": "Feature",
"properties": {
"title": "Lincoln Park",
"description": "A northside park that is home to the Lincoln Park Zoo"
},
"geometry": {
"coordinates": [-87.637596, 41.940403],
"type": "Point"
}
}]
}
features.geometry(coordinates) and features.properties(other data)
Datasets are editable collections of GEOjson:
We export the dataset to create a new Tileset, a map is divided into tiles for performance.
Tilesets are used as source in map style layers (where we can add symbol custom icons).
After making our style public on mapbox studio we can also use its tileset source:
//we pass the point PROPERTY of the click EVENT to the tileset style layer
mapp.on('click', (event) => {
const features = mapp.queryRenderedFeatures(event.point, {
layers: ['chicago-parks']
});
if (!features.length) {
return;
}
const feature = features[0];
//if it matches it will generate a Popup, setting its LngLat and HTML
const popup = new mapboxgl.Popup({ offset: [0, -15] })
.setLngLat(feature.geometry.coordinates)
.setHTML(
`<h4>${feature.properties.title}</h4><p>${feature.properties.description}</p>`
)
.addTo(mapp);
});
We can add a flyTo animation effect between the points :
//instead of click we start it on LOADed map
mapp2.on('load', (e)=>{
const features = mapp2.queryRenderedFeatures(e.point, {
layers: ['chicago-parks']
});
if (!features.length) {
return;
}
let index= 0
for(const x of features) {
index+= 1
setTimeout(() => {
mapp2.flyTo({
center: x.geometry.coordinates,
zoom: 13
});
//Markers don't need to be added, already in the style
}, 2000 * index);
//each point gets 2000 of timeout before passing to the other
}
MapBox Markers, events, and properties
The Marker component can take a property argument object:
//we first create the div in which
let contenuto1= document.createElement("div")
contenuto1.className= "location1" //we could use a CSS class properties OR
contenuto1.style.backgroundImage= 'url("https://img.icons8.com/bubbles/2x/user-female.png")'
contenuto1.style.backgroundSize= "cover"
contenuto1.style.width= "60px"
contenuto1.style.height= "60px"
//we then create an object for the .Marker()
let propieta1={
element: contenuto1, //gets the DOM as Marker
draggable: true,
rotation: 30,
//scale: 0.8 //these 2 works on default marker
//color: red
offset: [ 100, -20] //X Y offset
}
new mapboxgl.Marker( propieta1 )
.setLngLat( [14, 45.2] )
.addTo( map )
For Marker() events we use on():
//we can attack events on defined markers
//remember you need setLngLat() before addTo()
let muove= new mapboxgl.Marker(scansa)
.setLngLat( [14, 45] )
.addTo(map)
//we can get the current dragged Markers coordinates
function mosso(){
let posto= muove.getLngLat()
console.log( "[" + posto.lng + " " + posto.lat + "]")
}
//then on the on() we can put the events
muove.on("dragend", mosso) //will trigger once at the end
muove.on("drag", mosso) //will trigger for each pixel of drag
muove.on("dragstart", ()=>{
console.log("Just Started") //will trigger once at the start
})
We can also use Geojson for the Markers data:
const geojson = {
'type': 'FeatureCollection',
'features': [
{
'type': 'Feature',
'properties': {
'message': 'Foo',
'iconSize': [60, 60]
},
'geometry': {
'type': 'Point',
'coordinates': [12, 44.5]
}
},
...
]
};
for (const marker of geojson.features) {
const el = document.createElement('div');
const width = marker.properties.iconSize[0];
const height = marker.properties.iconSize[1];
let lng= marker.geometry.coordinates[0]
let lat= marker.geometry.coordinates[1]
el.className = 'marker';
el.style.backgroundImage = `url(https://www.tabaccheriaguzzi.it/images/product/91/HABNOS-2-02.jpg)`;
el.style.width = `${width}px`;
el.style.height = `${height}px`;
el.style.backgroundSize= 'cover'
el.style.backgroundPosition= "center"
el.style.borderRadius = '50%'
el.style.cursor = 'pointer'
//we create the Popup
let pop= new mapboxgl.Popup()
..setHTML( `<p>${lng} and ${lat}</p>`)
//makes the div created as the marker
let marki = new mapboxgl.Marker(el)
.setLngLat(marker.geometry.coordinates)
.addTo(map);
.setPopup(pop)
}
Mapbox PopUps, properties, and events.
First, let's see how to bind a Popup to a Merker:
//we create a popUp to append to a Merker
let kers= new mapboxgl.Popup()
.addText("using the variable we can add stuff later")
let ker= new mapboxgl.Marker(drag)
.setLngLat( [13.5, 45] )
.addTo(map)
.setPopup(kers)
Remember that Popup() doesn't have the element property:
//so if you want to add DOM content you need to
const secondo= window.document.createElement("div")
secondo.innerHTML = "I know its playable"
new mapboxgl.Popup(prop)
.setDOMContent( secondo )
Now for the Popup Properties:
let promp= {
className: "rad", //will add a .class to the popup
closeButton: false, //if you want to remove the X close button
closeOnClick: false, //to close or not on click outside Popup
closeOnMove: true, //to close on mapmove or zoom
offset: [ 20, -50], //X Y offset
}
let kers= new mapboxgl.Popup(promp)
And for the PopUp Event and Instance members:
//events On Popup variables
kers.on("open", ()=>{
console.log("will on PopUp click open")
})
kers.on("close", ()=>{
console.log("will work on closeOnClick PopUps")
})
We can have events on Markers used on Popup instance:
let citta = new mapboxgl.Popup()
let macchia= new mapboxgl.Marker(lacera)
macchia.on("dragend", ()=>{
citta.setText("l'ho vista da dove " + macchia.getLngLat() )
})
Style Geojson sources with Mapbox layers
We add the Geojson as a source (with ID):
map.on('load', () => {
map.addSource('places1', {
'type': 'geojson',
'data': {
'type': 'FeatureCollection',
'features': [
{
'type': 'Feature',
'properties': {
'description': '<h2>la montagna</h2>'
},
'geometry': {
'type': 'Point',
'coordinates': [13, 45.2]
}
},
...
]
}
})
//Its source uses the ID
map.addLayer({
'id': 'places',
'type': 'circle',
'source': 'places1',
'paint': {
'circle-color': '#ff64fb',
'circle-radius': 6,
'circle-stroke-width': 3,
'circle-stroke-color': '#ffffff'
}
});
})
For the Popup on Hover :
//we add the Popup properties
const popup = new mapboxgl.Popup({
closeButton: false,
closeOnClick: false
});
//if on map mouse enters the places layer
mapp0.on('mouseenter', 'places', (e) => {
// Change the cursor style as a UI indicator.
mapp0.getCanvas().style.cursor = 'pointer';
// Copy coordinates array.
const coordinates = e.features[0].geometry.coordinates; //.slice() ?
const description = e.features[0].properties.description;
//the description is gonna be the HTML on the properties
//if the map moves and another popUp gets focused it wont change the already opened
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}
//we just add content and position to the created Popup
popup.setLngLat(coordinates).setHTML(description).addTo(mapp0);
});
We also need to include a remove() Popup on Hover off:
//on mouseLeaving from the Layer points we remove the pointer and Poup
map.on('mouseleave', 'places', () => {
map.getCanvas().style.cursor = '';
//empty style cursor on mouseleave is giving the pointer to only mouseenter
popup.remove();
});
We can use Mapbox data in our source:
map.addSource('iconi', {
'type': 'geojson',
'data': {
'type': 'FeatureCollection',
'features': [
{
'type': 'Feature',
'properties': {
'description': '<p> teatro </p>',
'icon': 'theatre-15' //its from mapbox we could use bar-15, etc
},
'geometry': {
'type': 'Point',
'coordinates': [11.5, 41.7]
}
}
...
})
map.addLayer({
'id': 'iconi1',
'type': 'symbol',
'source': 'iconi',
'layout': {
'icon-image': '{icon}', //how we include the icon
'icon-allow-overlap': true
}
});
The code is the same as the Hover:
map.on('click', 'iconi1', (e) => {
...
}
Last updated
Was this helpful?