[TIL] Vue - Kakao Map API (5)

jeongjwon·2024년 1월 22일
0

Vue

목록 보기
16/19

참고
https://www.youtube.com/watch?v=FHXnPSM6rHk
https://apis.map.kakao.com/web/documentation/#Map_setCenter

Kakao Map API - Polyline 경로 삭제

지난 시간에 경로 삭제 및 생성 중이던 경로 작업을 취소하는 구현이다.



step 1. 생성 중인 경로 취소

새로운 경로 버튼을 눌러 지도에 경로를 추가할 수 있을 때 현재는 해제 버튼만 존재하는데,
작업 중간에 취소하기 위해 해제 버튼을 완료 버튼으로, 그리고 취소 버튼을 추가해준다.

//App.vue
 <div class="map-wrapper" ref="kakaomap">
      <div class="map-controll" v-if="activeSegment">
        <button class="btn-commit-seg" @click="commitPath()">완료</button
        ><!-- 경로 종료할 때 버튼 -->
        <button @click="cancelPath()">취소</button>
      </div>
 </div>


취소 버튼 클릭 이벤트 핸들러인 cancelPath() 메서드는 현재 활성화된 activeSegment 는 dipsose 되게하고, 완료취소 버튼이 사라지게 한다. segment 의 dipsose 메서드는 바로 설명하겠다.

//App.vue
cancelPath() {
      this.activeSegment.dispose(); //경로 제거용
      this.activeSegment = null; //버튼 사라지게 함
},


dispose 메서드는 경로를 제거하는 역할을 한다. 일단 커서 복귀를 위해 함수 내에서 commit 메서드를 실행하는데, 이때 추가된 코드로 존재하는 currentSegment 는 null 로 초기화시킴으로써 아예 segment 를 없앨 수 있다.

//segment.js
commit() {
    //경로 작성 완료
    this.done = true;
    //리스너 해제해야함
    window.kakao.maps.event.removeListener(
      this.map,
      "click",
      this.listeners.click
    );
    //커서를 가져오는 API가 없기에
    this.map.setCursor(DEFAULT_KAKAOMAP_CURSOR);
    console.log("해제 완료");
    
  //+추가
    if (this.currentSegment) {
      this.currentSegment = null;
    }
  }
 dispose() {
    console.log("경로 제거");
    this.commit(); //커서 복귀
    this.poly.setMap(null);
  }

그리고 지도로 그려놓았던 Polyline 즉 경로들을 지도에서 제거하기 위해서 setMap(null) 메서드를 실행한다.



실행 화면











step 2. 생성된 경로 삭제

이미 생성된 경로는 목록으로 렌더링이 되게 구현해놓았다.
그렇다면 생성된 경로 삭제를 위해서는 목록 옆에 각각의 항목에 삭제 버튼이 존재해야한다.

<div class="list-of-seg">
        <div class="segment" v-for="(seg, index) in segments" :key="index">
          <h4>{{ seg.name }}</h4>
          <button @click="deletePath(seg, index)">삭제</button>
        </div>
</div>

v-for 바인딩을 통해 존재하는 경로들의 배열인 segments 들을 반복문을 돌며 seg.name 과 삭제 버튼이 렌더링된다. 삭제 버튼 클릭 이벤트 핸들러는 deletePath(seg,index) 이다.



 /**
     * @param seg 지울 세그먼트(경로)
     * @param index 인덱스값
     */

    deletePath(seg, index) {
      this.segments.splice(index, 1); //1개만 삭제
      seg.dispose();
    },

deletePath 메서드의 매개변수인 seg 는 생성된 경로를 의미하고, index 는 segments 배열들 중 해당 경로가 어떤 인덱스인지 가리킨다. 이 메서드는 이미 생성된 경로를 삭제하는 것이기 때문에 단지 segements 배열에서 해당 인덱스 하나를 삭제 시켜주면 되기에 splice 배열 메서드를 사용하게 제거한다. 그리고 또한 dipose 시켜줌으로써 아예 세그먼트에서 삭제시킨다.



실행 화면











전체코드

App.vue
<template>
  <div id="app">
    <div class="path-list">
      <h3>경로</h3>
      <button @click="processNewPath()">새로운 경로</button>
      <div class="list-of-seg">
        <div class="segment" v-for="(seg, index) in segments" :key="index">
          <h4>{{ seg.name }}</h4>
          <button @click="deletePath(seg, index)">삭제</button>
        </div>
      </div>
    </div>
    <div class="map-wrapper" ref="kakaomap">
      <div class="map-controll" v-if="activeSegment">
        <button class="btn-commit-seg" @click="commitPath()">완료</button
        ><!-- 경로 종료할 때 버튼 -->
        <button @click="cancelPath()">취소</button>
      </div>
    </div>
  </div>
</template>

<script>
import startSegment from "./segment";

export default {
  name: "App",
  components: {
    // KakaoMap,
  },
  data() {
    return {
      mapInstance: null,
      activeSegment: null,
      segments: [], //list of pathes
  	};
  },
  mounted() {
    //init map here
    var container = this.$refs.kakaomap;
    var options = {
      center: new window.kakao.maps.LatLng(33.450701, 126.570667),
      level: 3,
    };

    //지도 생성 및 객체 리턴
    this.mapInstance = new window.kakao.maps.Map(container, options);
},
  methods: {
    processNewPath() {
      console.log("[new path] start");
      //지도 객체 전달
      this.activeSegment = startSegment(this.mapInstance);
    },
    commitPath() {
      this.activeSegment.commit();
      this.segments.push(this.activeSegment);
      this.activeSegment = null; //버튼 사라지게 함
    },
    cancelPath() {
      this.activeSegment.dispose(); //경로 제거용
      this.activeSegment = null; //버튼 사라지게 함
    },

    /**
     * @param seg 지울 세그먼트(경로)
     * @param index 인덱스값
     */

    deletePath(seg, index) {
      this.segments.splice(index, 1); //1개만 삭제
      seg.dispose();
    },
 },
};
</script>

<style lang="scss">
html,
body {
  height: 100%;
  margin: 0;
}
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
  height: 100%;
  width: 100%;
  display: flex;
  flex-direction: column;
  .path-list {
    width: 240px;
  }
  .list-of-seg {
    .segment {
      display: flex;
      padding-right: 8px;
      margin: 4px 0px;
      h4 {
        margin: 0;
        flex: 1 1 auto;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        padding: 4px 8px;
      }
      button {
        white-space: nowrap;
        padding: 4px 8px;
        border: 1px solid #ccc;
        background-color: white;
        border-radius: 4px;
        color: #777;
        &:hover {
          background-color: #efefef;
          color: #333;
          cursor: pointer;
        }
        &:active {
          background-color: #ddd;
          color: #000;
        }
      }
    }
  }
  .map-wrapper {
    flex: 1 1 auto;
    .map-controll {
      position: absolute;
      top: 5px;
      left: 5px;
      z-index: 1000;
    }
  }
}
</style>


segment.js
const DEFAULT_KAKAOMAP_CURSOR =
  "url(&quot;http://t1.daumcdn.net/mapjsapi/images/2x/cursor/openhand.cur.ico&quot;) 7 5, url(&quot;http://t1.daumcdn.net/mapjsapi/images/2x/cursor/openhand.cur.ico&quot;), default";
/*
 *   경로를 나타내는 클래스
 */
class Segment {
  /**
   *
   * @param {kakao.maps.Map} mapInstance 지도 인스턴스
   * @param {object} props 경로 메타 정보들(이름 거리 등..)
   */

  constructor(mapInstance, props) {
    this.map = mapInstance;
    this.done = false;
    this.points = []; //list for LatLng
    this.poly = new window.kakao.maps.Polyline({
      map: this.map,
      path: [],
      strokeWeight: 2,
      strokeColor: "#FF00FF",
      strokeOpacity: 0.8,
      strokeStyle: "solid", //실선
    });
    this.listeners = {};
    this.props = props || {};
    this.installListners();
  }
  get name() {
    return this.props.name || "NO NAME";
  }
  installListners() {
    //클릭 리스너 등록
    const adder = (e) => {
      console.log("[pos]", e.latLng);
      this.points.push(e.latLng); //각 점을 등록
      this.render();
    };
    // this.listeners.click = { click: null };
    this.listeners.click = adder;
    window.kakao.maps.event.addListener(this.map, "click", adder);
    this.map.setCursor("crosshair");
  }
  render() {
    //경로를 그림
    this.poly.setPath(this.points);
  }
  commit() {
    //경로 작성 완료
    this.done = true;
    //리스너 해제해야함
    window.kakao.maps.event.removeListener(
      this.map,
      "click",
      this.listeners.click
    );
    //커서를 가져오는 API가 없기에
    this.map.setCursor(DEFAULT_KAKAOMAP_CURSOR);
    console.log("해제 완료");

    if (this.currentSegment) {
      this.currentSegment = null;
    }
  }
  dispose() {
    console.log("경로 제거");
    this.commit(); //커서 복귀
    this.poly.setMap(null);
  }
}
let currentSegment;
const startSegment = (mapInstance) => {
  currentSegment = new Segment(mapInstance);
  return currentSegment;
};
export default startSegment;










마치며

지난 polyline 을 배우고 segment 생성자를 시작한 터라 오늘 배운 삭제 부분은 쉽게 느껴졌다. dispose 메서드를 통해 커서 복귀를 시키고 생성된 경로 폴리라인은 setMap(null) 을 통해 제거되는 것과 세그먼트 객체인 currentSegment 또한 null로 만들어주면서 지도에서 아예 제거되는 것을 알게되었다. 경로 생성, 삭제를 알아보았으니 다음은 편집이다.



0개의 댓글