Mapbox 를 이용하여 인덱스 페이지에서 전체 campground
의 위치를 Cluster 형식으로 지도에 표시하도록 했다.
👇코드 보러가기
https://github.com/Sara-Jo/BeWild/tree/9b05757c2ace87a008ad500dcc35f297b6ca54c9
clusterMap.js
파일을 추가하여 mapbox cluster
코드를 복사하여 붙여넣어준다. 위치 source
를 campground
에서 가져올 수 있도록 아래 밑줄 친 부분을 수정 해준다.unclustered-point
를 클릭 했을 때 해당 campground
의 정보가 나오고, 누르면 상세 페이지로 바로 이동할 수 있도록 맨 아래쪽 밑줄 친 부분과 같이 수정 해준다. (popUpMarkup
코드 설정은 이 다음 설명 확인)[campground.ejs]
<div id="map" style="width: 100%; height: 400px;"></div>
...
<script>
const mapToken = '<%- process.env.MAPBOX_TOKEN %>';
const campgrounds = {features: <%- JSON.stringify(campgrounds) %>};
</script>
<script src="/javascripts/clusterMap.js"></script>
[public/javascripts/clusterMap.js]
mapboxgl.accessToken = mapToken;
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/dark-v10',
center: [-103.5917, 40.6699],
zoom: 3
});
map.on('load', () => {
// Add a new source from our GeoJSON data and
// set the 'cluster' option to true. GL-JS will
// add the point_count property to your source data.
map.addSource('campgrounds', {
type: 'geojson',
// Point to GeoJSON data. This example visualizes all M1.0+ earthquakes
// from 12/22/15 to 1/21/16 as logged by USGS' Earthquake hazards program.
data: campgrounds,
cluster: true,
clusterMaxZoom: 14, // Max zoom to cluster points on
clusterRadius: 50 // Radius of each cluster when clustering points (defaults to 50)
});
map.addLayer({
id: 'clusters',
type: 'circle',
source: 'campgrounds',
filter: ['has', 'point_count'],
paint: {
// Use step expressions (<https://docs.mapbox.com/mapbox-gl-js/style-spec/#expressions-step>)
// with three steps to implement three types of circles:
// * Blue, 20px circles when point count is less than 100
// * Yellow, 30px circles when point count is between 100 and 750
// * Pink, 40px circles when point count is greater than or equal to 750
'circle-color': [
'step',
['get', 'point_count'],
'#00BCD4',
10,
'#2196F3',
30,
'#3F51B5'
],
'circle-radius': [
'step',
['get', 'point_count'],
15,
10,
30,
30,
30
]
}
});
map.addLayer({
id: 'cluster-count',
type: 'symbol',
source: 'campgrounds',
filter: ['has', 'point_count'],
layout: {
'text-field': '{point_count_abbreviated}',
'text-font': ['DIN Offc Pro Medium', 'Arial Unicode MS Bold'],
'text-size': 12
}
});
map.addLayer({
id: 'unclustered-point',
type: 'circle',
source: 'campgrounds',
filter: ['!', ['has', 'point_count']],
paint: {
'circle-color': '#11b4da',
'circle-radius': 4,
'circle-stroke-width': 1,
'circle-stroke-color': '#fff'
}
});
// inspect a cluster on click
map.on('click', 'clusters', (e) => {
const features = map.queryRenderedFeatures(e.point, {
layers: ['clusters']
});
const clusterId = features[0].properties.cluster_id;
map.getSource('campgrounds').getClusterExpansionZoom(
clusterId,
(err, zoom) => {
if (err) return;
map.easeTo({
center: features[0].geometry.coordinates,
zoom: zoom
});
}
);
});
// When a click event occurs on a feature in
// the unclustered-point layer, open a popup at
// the location of the feature, with
// description HTML from its properties.
map.on('click', 'unclustered-point', (e) => {
const { popUpMarkup } = e.features[0].properties;
const coordinates = e.features[0].geometry.coordinates.slice();
// Ensure that if the map is zoomed out such that
// multiple copies of the feature are visible, the
// popup appears over the copy being pointed to.
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}
new mapboxgl.Popup()
.setLngLat(coordinates)
.setHTML(popUpMarkup)
.addTo(map);
});
map.on('mouseenter', 'clusters', () => {
map.getCanvas().style.cursor = 'pointer';
});
map.on('mouseleave', 'clusters', () => {
map.getCanvas().style.cursor = '';
});
});