The Web Developer - (Udemy)_ YelpCamp: 클러스터 맵 개요

‍정진철·2022년 8월 28일
0

web devloper (udemy)

목록 보기
31/34

1) 클러스터 맵에 지진 표시하기

clusterMap 파일 생성

참조: https://docs.mapbox.com/mapbox-gl-js/example/cluster/

  • index.ejs로 가져오기.


2) 데이터베이스 새로고침

  • 미리 등록한 cities 파일 내 경도,위도 사용
  • 캠핑장 마다 경도,위도를 랜덤으로 부여하여(coordinates) 매 캠핑장 마다 다른 지도 부여하기 (seeds 폴더 내 index.js)
  • 실제 캠핑장 위치와는 무관

onst seedDB = async() => {
    //기존의 캠핑장은 삭제.
    await Campground.deleteMany({});
    //랜덤으로 캠핑장 50개 리스트 만들기.
    for(let i=0; i<50; i++) {
       const random1000 = Math.floor(Math.random() * 1000);
       const price =Math.floor(Math.random() * 20) + 10; 
        // 캠프 객체들 생성하기.
       const camp = new Campground({
            author: '630355b563e61f00f040f291',
            location : `${cities[random1000].city}`,
            state : `${cities[random1000].state}`,
            //' 아름다운 캐년'처럼 형용사 + 명사 조합
            title: `${sample(descriptors)} ${sample(places)}`,
            description: 'Lorem ipsum, dolor sit amet consectetur adipisicing elit. Sint cum eos sed saepe, totam quo eaque maiores voluptatem mollitia aliquid? Ea consequatur cum repudiandae, totam pariatur voluptatem quia nesciunt ipsam!',
            price,
            geometry: {
                type : "Point", 
                coordinates : [
                    cities[random1000].longitude,
                    cities[random1000].latitude,
                    ]
            },
            images: [
                {
                    url: 'https://res.cloudinary.com/dorrgo67l/image/upload/v1661247793/YelpCamp/wknqgcaon0ydslx9o4f0.jpg',
                    filename: 'YelpCamp/wknqgcaon0ydslx9o4f0'

                },
                {
                    url: 'https://res.cloudinary.com/dorrgo67l/image/upload/v1661247793/YelpCamp/wknqgcaon0ydslx9o4f0.jpg',
                    filename: 'YelpCamp/wknqgcaon0ydslx9o4f0'

                }
            ]
        })
        await camp.save();
    }
}

seedDB().then(() => {
        mongoose.connection.close();
})


3) 캠프그라운드 클러스터화

  • 클러스터화된 부분과 그렇지 않은 부분 확인

map.addSource

  • 맵이 실행되고 추가되는 부분 확인
  • Geojson 데이터에서 추가하고 cluster 옵션은 true로 설정.
  • 해당 데이터 url 실행시 정보 확인 가능. (GeoJSON타입)


index.js

  • Mapbox는 데이터배열로 설정된 features키의 객체를 원하기 때문에 하위 코드처럼 기재 필요.

  • 데이터는 기존 지진 문서 url에서 'campgrounds'로 변경


결과


4) 클러스터 코드 조정하기

clusterMap.js

	mapboxgl.accessToken = mapToken;
const map = new mapboxgl.Map({
container: 'map',
// Choose from Mapbox's core styles, or make your own style with Mapbox Studio
style: 'mapbox://styles/mapbox/dark-v10',
center: [-103.5917, 40.6699],
zoom: 3
});
 

//map.on은 감지할 수 있는 이벤트
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.
//Geojson 데이터에서 추가하고 cluster 옵션은 true로 설정.
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'],
'#51bbd6',
100,
'#f1f075',
750,
'#f28cb1'
],
'circle-radius': [
'step',
['get', 'point_count'],
20,
100,
30,
750,
40
]
}
});
 
//point count ->: 해당 클러스터 내 기재된 캠핑장 숫자

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({
//single point (단일 지점)
id: 'unclustered-point',
type: 'circle',
source: 'campgrounds',
//point count 가 없을 때 표시.
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.
// 클러스터에 속하지 않은 단일 지점 클릭.
// 함수는 unclustered-point 를 클릭할 때 실행됨.

map.on('click', 'unclustered-point', (e) => {
const coordinates = e.features[0].geometry.coordinates.slice();
const mag = e.features[0].properties.mag;
const tsunami =
e.features[0].properties.tsunami === 1 ? 'yes' : 'no';
 
// 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(
`magnitude: ${mag}<br>Was there a tsunami?: ${tsunami}`
)
.addTo(map);
});
 
//mouseenter 이벤트로 마우스를 맵이 아닌 클러스터에 갖다 댔을 떄 커서 스타일을 포인터로 바꿈.

map.on('mouseenter', 'clusters', () => {
map.getCanvas().style.cursor = 'pointer';
});
map.on('mouseleave', 'clusters', () => {
map.getCanvas().style.cursor = '';
});
});


5) 클러스터 크기 및 색상 변경하기

  • 클러스터 형성 기준 갯수 변경 , 색상변경



6) 사용자 지정 팝업 추가하기

  • single point 클릭 했을 때 콘솔에 찍히는 부분
  • properties 부분이 비어있는 것 확인 가능.


  • campgrounds 콘솔창에 찍어 냈을 때 properties 가 없음.

  • Mapbox가 정보를 가져오는 방식은 예를들어
    {

    title: 'abcd',
    author: xyz,
    properties: {
    	//virtual 특성
    	pupupText: {
        	<h2> ~~~~ </h2>
        
        }
    }

    } 와 같이 properites 특성을 받아서 가져온다.

  • 따라서 campground 에도 properties를 virtual 로 심어준다.

  • 앞서 ImageSchema 에서 'thumbnail'특성을 virtual로 가져왔었음.


  • 하지만 campgrounds 소환시 properites와 popupText 확인 불가능.
  • 이유는 몽구스는 기본적으로 문서를 JSON으로 변환할 때 virtual을 포함시키지 않음.

  • 따라서 다음고 같은 코드 설정 필요.
  • 스키마에 추가.

const CampgroundSchema = new Schema({
    title: String,
    images : [ImageSchema],
    geometry: {
        type: {
            type:String,
            enum: ['Point'],
            required: true
        },
        coordinates: {
            type: [Number],
            required: true
        }
    },
    price: Number,
    description: String,
    location: String,
    author : {
        type:Schema.Types.ObjectId,
        ref: 'User'
    },
    reviews: [
        {
         type: Schema.Types.ObjectId,   
         ref: 'Review'
        }
    ]
  
}, opts);


profile
WILL is ALL

0개의 댓글