Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Tags more
Archives
Today
Total
관리 메뉴

Front-end Developer

React (카카오 맵) 마커 종류별로 나누기 본문

React

React (카카오 맵) 마커 종류별로 나누기

Brad Daeho Lee 2021. 4. 24. 22:16

 

해당 마커의 게시물 개수가 10개 이상인 마커와 10개 미만인 마커를 구분하기 위해서 마커의 종류를 노멀마커와 핫 마커로 만들었습니다.

 

 

게시물 추가했을 때

 

게시물 삭제했을 때

 

Map.js

normal 마커와 hot 마커의 이미지를 다르게 구현해서 구분했습니다. 그리고 게시물을 작성할 때 이 게시물이 hot 마커 게시물인지 normal 마커 게시물인지 알려주었습니다.

 

더보기
const Map = (props) => {
    const [ is_write, setWrite ] = useState(false);
    const [ is_writeModal, setWriteModal ] = useState(false);
    const [ hot, setHot ] = useState(false);
    const normalMarker = useSelector((state) => state.marker.normal)
    const hotMarker = useSelector((state) => state.marker.hot)

    useEffect(() => {
    const container = document.getElementById('myMap'); //지도 표시할 div
      const options = {
        center: new kakao.maps.LatLng(37.545642179638556, 126.98117041998981), //지도 중심 좌표
        level: 8 //지도의 확대 레벨
      };
    const map = new kakao.maps.Map(container, options);//지도를 생성합니다.

	// noraml마커와 hot마커 이미지입니다.
    var normalImageSrc = "https://cdn0.iconfinder.com/data/icons/small-n-flat/24/678111-map-marker-128.png"
    var hotImageSrc = "https://t1.daumcdn.net/localimg/localimages/07/mapapidoc/markerStar.png";

    // 게시물 수가 10개 미만인 마커를 표시합니다.
    normalMarker.map((p, idx) => {

      var imageSize = new kakao.maps.Size(35, 35);

      var markerImage = new kakao.maps.MarkerImage(normalImageSrc, imageSize);

      const markers = new kakao.maps.Marker({
        // 지도 중심좌표에 마커를 생성합니다.
        map: map,
        position: new kakao.maps.LatLng(p.latitude, p.longitude) ,
        image: markerImage,
      });
	  
      //마커이름과 주소가 마커위에 생성되게 합니다.
      var iwContent =   `<div style="padding:8px;text-overflow: ellipsis;overflow: hidden;white-space: nowrap;">` +
                        `<div style="font-weight: 600; margin-bottom: 3px;">${p.title}</div>` +
                        `<div>${p.address}</div>` +
                        `</div>`

      var infowindow = new kakao.maps.InfoWindow({
          content : iwContent
      });

      kakao.maps.event.addListener(markers, 'mouseover', function(){
          infowindow.open(map, markers)
      })
      
      kakao.maps.event.addListener(markers, 'mouseout', function(){
        infowindow.close(map, markers)
      })
      // 마커를 클릭했을 때 게시물 작성버튼과 해당 게시물이 생성되게 설정했습니다.
      kakao.maps.event.addListener(markers, 'click', function(){
        markerDetail(p.id)
      })
    })
    
    // 게시물 수가 10개 이상인 마커를 표시합니다.
    hotMarker.map((p, idx) => {

      var imageSize = new kakao.maps.Size(30, 45);

      var markerImage = new kakao.maps.MarkerImage(hotImageSrc, imageSize);

      const markers = new kakao.maps.Marker({
        // 지도 중심좌표에 마커를 생성합니다.
        map: map,
        position: new kakao.maps.LatLng(p.latitude, p.longitude) ,
        title: p.title,
        image: markerImage,
      });
      
      kakao.maps.event.addListener(markers, 'click', function(){
        markerDetail(p.id)
        setHot(true)
      })

      var iwContent =   `<div style="padding:8px;text-overflow: ellipsis;overflow: hidden;white-space: nowrap;">` +
                        `<div style="font-weight: 600; margin-bottom: 3px;">${p.title}</div>` +
                        `<div>${p.address}</div>` +
                        `</div>`

      var _infowindow = new kakao.maps.InfoWindow({
          content : iwContent
      });

      kakao.maps.event.addListener(markers, 'mouseover', function(){
        _infowindow.open(map, markers)
      })
      
      kakao.maps.event.addListener(markers, 'mouseout', function(){
        _infowindow.close(map, markers)
      })
    })

    
    // 마커가 생성될때 바로 화면상에 새로생성된 마커를 보여주기 위해 배열안에 normalMarker를 넣어놨습니다.
  }, [normalMarker])


  const markerDetail = (id) => {
    setmarkerId(id)
    // 게시물 작성 버튼이 보입니다.
    setWrite(true)
    // 게시물 component를 보여줍니다.
    props.showPost()
    // 해당 마커에 저장된 게시물 정보를 가져옵니다.
    dispatch(postActions.getPostAX(id))
  }
  
  return(
    <React.Fragment>
      	//맵을 보여주는 컴포넌트 입니다.
        <MapContainer id='myMap'>
        </ MapContainer>
        
        //마커가 눌렀을 때 그리고 로그인 상태일 때 게시글 작성 버튼이 보이게 했습니다.
        {is_write && is_login ? 
          <AddBtn>
          <Fab color="primary" aria-label="add" variant="extended" onClick={() => {
            window.scrollTo(0,0)
            setWriteModal(true)
          }}>
            <AddIcon /><Word>게시글추가</Word>
          </Fab>
          </AddBtn>
          : null}
 		
       {is_writeModal? <PostWrite markerId = {markerId} close={closeWriteModal} hot={hot} />
      : null}
      
    </React.Fragment>
  )

}

const MapContainer = styled.div`
  position: relative;
  margin: auto;
  margin-bottom: 60px;
  width: 900px;
  height: 500px;
  @media (max-width: 1000px){
    width: 85%;
  };
  @media (max-width: 450px){
    width: 95%;
    height: 400px;
  }
`

const AddBtn = styled.div`
  position: fixed;
  right: 30px;
  bottom: 100px;
  z-index: 10;
`

const Word = styled.span`
  @media (max-width:614px){
    display: none
  }
`

 

marker.js

서버에서도 마커를 보내줄 때 normal 마커와 hot 마커를 구분해서 보내주지만 게시물을 작성하거나 삭제했을 때  지도에서 마커가 바로 변하게하려면 redux store에 marker정보를 즉시 변경해줘야 합니다.

 

마커 게시물을 추가할 때는 markerClass값을 넘겨주어서 hot마커인지 normal마커인지 구분을 하고 데이터 변경을 했습니다. 하지만 게시물 추가할 때는 markerClass값을 미리 넘겨줄 수가 없어서 normal 마커 리스트에 해당 마커 아이디가 들어가있는지 확인하면서 마커 종류를 파악했습니다. 

 

더보기
import { createAction, handleActions } from "redux-actions";
import { produce } from "immer";
import axios from 'axios';
import { history } from "../configureStore"
import { config } from "../../shared/config"

const ADD_BOARD = "ADD_BOARD";
const REMOVE_BOARD = "REMOVE_BOARD";

const addBoard = createAction(ADD_BOARD, (markerId, markerClass) => ({markerId, markerClass}))
const removeBoard = createAction(REMOVE_BOARD, (markerId, markerClass) => ({markerId, markerClass}))

const initialState = {
  normal: [],
  hot: [],
}


export default handleActions(
  {
  // 게시물을 추가할 때 해당 마커의 게시물 카운트를 1 더합니다.
    // 그리고 게시물의 숫자가 9에서 10이되면 normal marker에서 hot marker리스트로 마커정보를 옮깁니다.
    [ADD_BOARD]: (state, action) => produce(state, (draft) => {
      
      if (action.payload.markerClass == "normal"){
        let idx = draft.normal.findIndex(m => m.id === action.payload.markerId);
        draft.normal[idx].boardcount += 1;
        if (draft.normal[idx].boardcount == 10){
          // hot 마커로 옮기고
          draft.hot.push(draft.normal[idx])
          // normal에있는 정보를 없앱니다.
          draft.normal.splice(idx, 1)
        }
      }
      else{
        // 이미 hot마커이기때문에 게시물 개수 1을 더해도 똑같이 hot 마커입니다.
        let idx = draft.hot.findIndex(m => m.id === action.payload.markerId);
        draft.hot[idx].boardcount += 1;
      }
    }),
    
    // 게시물을 삭제했을 때 마커 게시물 개수 1개를 빼고 
    // hot marker에서 -1을 했을 때 게시물 개수가 9개이면 
    // 해당 마커를 normal에 추가하고 hot에서 삭제합니다.
    [REMOVE_BOARD]: (state, action) => produce(state, (draft) => {
      if (draft.normal.findIndex(m => m.id === action.payload.markerId) !== -1){
        let idx = draft.normal.findIndex(m => m.id === action.payload.markerId);
        draft.normal[idx].boardcount -= 1;
      } else{
        let idx = draft.hot.findIndex(m => m.id === action.payload.markerId);
        draft.hot[idx].boardcount -= 1;
        if (draft.hot[idx].boardcount == 9){
          draft.normal.push(draft.hot[idx])
          draft.hot.splice(idx, 1)
        }
      }
    })
  },
  initialState
)

const actionCreators = {
  addBoard,
  removeBoard,
}

export {actionCreators}
Comments