#javascript #mapbox-gl-js
Вопрос:
версия mapbox-gl-js: ^2.0.1
Я добавил пользовательские значки, следуя этому примеру: https://docs.mapbox.com/mapbox-gl-js/example/custom-marker-icons
Как я могу сгруппировать эти значки ?
Ссылки на соответствующую документацию
- https://docs.mapbox.com/mapbox-gl-js/example/cluster
- https://docs.mapbox.com/mapbox-gl-js/example/cluster-html
Что я пробовал
<script>
mapboxgl.accessToken = 'super secret';
var map = new mapboxgl.Map({
container: 'map',
zoom: 0.3,
center: [0, 20],
style: 'mapbox://styles/mapbox/light-v10'
});
map.addControl(new mapboxgl.NavigationControl());
// filters for classifying earthquakes into five categories based on magnitude
var mag1 = ['<', ['get', 'mag'], 2];
var mag2 = ['all', ['>=', ['get', 'mag'], 2], ['<', ['get', 'mag'], 3]];
var mag3 = ['all', ['>=', ['get', 'mag'], 3], ['<', ['get', 'mag'], 4]];
var mag4 = ['all', ['>=', ['get', 'mag'], 4], ['<', ['get', 'mag'], 5]];
var mag5 = ['>=', ['get', 'mag'], 5];
// colors to use for the categories
var colors = ['#fed976', '#feb24c', '#fd8d3c', '#fc4e2a', '#e31a1c'];
var geojson = {
'type': 'FeatureCollection',
'features': [
{
'type': 'Feature',
'properties': {
'message': 'Foo',
"mag": 5,
'iconSize': [60, 60],
'id': 1
},
'geometry': {
'type': 'Point',
'coordinates': [-66.324462, -16.024695]
}
},
{
'type': 'Feature',
'properties': {
'message': 'Bar',
"mag": 10,
'iconSize': [50, 50],
'id': 2
},
'geometry': {
'type': 'Point',
'coordinates': [-61.21582, -15.971891]
}
},
{
'type': 'Feature',
'properties': {
'message': 'Baz',
"mag": 1.5,
'iconSize': [40, 40],
'id': 3
},
'geometry': {
'type': 'Point',
'coordinates': [-63.292236, -18.281518]
}
}
]
};
geojson.features.forEach(function (marker) {
// Create a DOM element for each marker.
var el = document.createElement('div');
el.className = 'marker';
el.id = marker.properties.id;
el.style.backgroundImage =
'url(https://placekitten.com/g/'
marker.properties.iconSize.join('/')
'/)';
el.style.width = marker.properties.iconSize[0] 'px';
el.style.height = marker.properties.iconSize[1] 'px';
el.style.backgroundSize = '100%';
el.style.display = 'none';
el.addEventListener('click', function () {
window.alert(marker.properties.message);
});
// Add markers to the map.
new mapboxgl.Marker(el)
.setLngLat(marker.geometry.coordinates)
.addTo(map);
});
map.on('load', function () {
// add a clustered GeoJSON source for a sample set of earthquakes
map.addSource('earthquakes', {
'type': 'geojson',
'data': geojson, //'https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson',
'cluster': true,
'clusterRadius': 80,
'clusterProperties': {
// keep separate counts for each magnitude category in a cluster
'mag1': [' ', ['case', mag1, 1, 0]],
'mag2': [' ', ['case', mag2, 1, 0]],
'mag3': [' ', ['case', mag3, 1, 0]],
'mag4': [' ', ['case', mag4, 1, 0]],
'mag5': [' ', ['case', mag5, 1, 0]]
}
});
// circle and symbol layers for rendering individual earthquakes (unclustered points)
map.addLayer({
'id': 'earthquake_circle',
'type': 'circle',
'source': 'earthquakes',
'filter': ['!=', 'cluster', true],
'paint': {
'circle-color': [
'case',
mag1,
colors[0],
mag2,
colors[1],
mag3,
colors[2],
mag4,
colors[3],
colors[4]
],
'circle-opacity': 0.6,
'circle-radius': 10
}
});
// objects for caching and keeping track of HTML marker objects (for performance)
var markers = {};
var markersOnScreen = {};
function updateMarkers() {
var newMarkers = {};
var features = map.querySourceFeatures('earthquakes');
// for every cluster on the screen, create an HTML marker for it (if we didn't yet),
// and add it to the map if it's not there already
for (var i = 0; i < features.length; i ) {
var coords = features[i].geometry.coordinates;
var props = features[i].properties;
if (!props.cluster) {
document.getElementById(props.id).style.display = 'block'
continue;
}
var id = props.cluster_id;
var marker = markers[id];
if (!marker) {
var el = createDonutChart(props);
marker = markers[id] = new mapboxgl.Marker({
element: el
}).setLngLat(coords);
}
newMarkers[id] = marker;
if (!markersOnScreen[id]) {
marker.addTo(map);
}
}
// for every marker we've added previously, remove those that are no longer visible
for (id in markersOnScreen) {
if (!newMarkers[id]) markersOnScreen[id].remove();
}
markersOnScreen = newMarkers;
}
// after the GeoJSON data is loaded, update markers on the screen on every frame
map.on('render', function () {
if (!map.isSourceLoaded('earthquakes')) return;
updateMarkers();
});
});
// code for creating an SVG donut chart from feature properties
function createDonutChart(props) {
var offsets = [];
var counts = [
props.mag1,
props.mag2,
props.mag3,
props.mag4,
props.mag5
];
var total = 0;
for (var i = 0; i < counts.length; i ) {
offsets.push(total);
total = counts[i];
}
var fontSize =
total >= 1000 ? 22 : total >= 100 ? 20 : total >= 10 ? 18 : 16;
var r = total >= 1000 ? 50 : total >= 100 ? 32 : total >= 10 ? 24 : 18;
var r0 = Math.round(r * 0.6);
var w = r * 2;
var html =
'<div><svg width="'
w
'" height="'
w
'" viewbox="0 0 '
w
' '
w
'" text-anchor="middle" style="font: '
fontSize
'px sans-serif; display: block">';
for (i = 0; i < counts.length; i ) {
html = donutSegment(
offsets[i] / total,
(offsets[i] counts[i]) / total,
r,
r0,
colors[i]
);
}
html =
'<circle cx="'
r
'" cy="'
r
'" r="'
r0
'" fill="white" /><text dominant-baseline="central" transform="translate('
r
', '
r
')">'
total.toLocaleString()
'</text></svg></div>';
var el = document.createElement('div');
el.innerHTML = html;
return el.firstChild;
}
function donutSegment(start, end, r, r0, color) {
if (end - start === 1) end -= 0.00001;
var a0 = 2 * Math.PI * (start - 0.25);
var a1 = 2 * Math.PI * (end - 0.25);
var x0 = Math.cos(a0),
y0 = Math.sin(a0);
var x1 = Math.cos(a1),
y1 = Math.sin(a1);
var largeArc = end - start > 0.5 ? 1 : 0;
return [
'<path d="M',
r r0 * x0,
r r0 * y0,
'L',
r r * x0,
r r * y0,
'A',
r,
r,
0,
largeArc,
1,
r r * x1,
r r * y1,
'L',
r r0 * x1,
r r0 * y1,
'A',
r0,
r0,
0,
largeArc,
0,
r r0 * x0,
r r0 * y0,
'" fill="' color '" />'
].join(' ');
}
</script>