찬이
453
2020-11-28 21:03:34 작성 2020-11-28 21:03:57 수정됨
2
144

Vue.js 다음지도 API 관련질문


<Map.js>

import loadScriptOnce from 'load-script-once';

const DAUM_KAKAO_API_JS_KEY = 'MyKey(수정)'
const DAUM_KAKAO_MAP_LIB_URL = `//dapi.kakao.com/v2/maps/sdk.js?appkey=${DAUM_KAKAO_API_JS_KEY}&libraries=drawing,clusterer,services&autoload=false`

class Map {
  constructor () {
    this.map = null
    Map.initialize()
    console.log("로드됨");
  }

  async mount (elementId) {
    await Map.initialize()

    // re-use map
    if (Map.cachedMaps[elementId]) {
      this.map = Map.cachedMaps[elementId]
      const oldElement = this.map.getNode()
      const newElement = document.getElementById(elementId)
      newElement.parentNode.replaceChild(oldElement, newElement)

    // create map
    } else {
      this.map = new Map.daum.maps.Map(
        document.getElementById(elementId),
        {
          center: new Map.daum.maps.LatLng(35.65919598808177, 127.73894402702498),
          level: 13,
        },
      )
      this.map.setCopyrightPosition(Map.daum.maps.CopyrightPosition.BOTTOMRIGHT, true)
      this.map.clusters = {}
      this.map.markersWithoutCluster = []
      Map.cachedMaps[elementId] = this.map
    }
    return this
  }

  addMarkerClusters (clusterSpecs = []) {
    clusterSpecs.forEach(({ key, color, zIndex = 0, singleIconURL = null }) => {
      if (this.map.clusters[key]) return

      const cluster = this.map.clusters[key] = new Map.daum.maps.MarkerClusterer({
        map: this.map,
        averageCenter: true,
        gridSize: 30,
        minClusterSize: 2,
        minLevel: 10,
        disableClickZoom: false,
        calculator: [10, 20], // 0~9, 10~19, 20~
        styles: [
          {
            width: '30px',
            height: '30px',
            background: color,
            opacity: 0.95,
            border: '2px solid white',
            borderRadius: '100%',
            color: 'white',
            textAlign: 'center',
            lineHeight: '27px',
            fontSize: '20px',
            fontWeight: 'bold',
          },
          {
            width: '36px',
            height: '36px',
            background: color,
            opacity: 0.95,
            border: '2px solid white',
            borderRadius: '100%',
            color: 'white',
            textAlign: 'center',
            lineHeight: '33px',
            fontSize: '22px',
            fontWeight: 'bold',
          },
          {
            width: '48px',
            height: '48px',
            background: color,
            opacity: 0.95,
            border: '2px solid white',
            borderRadius: '100%',
            color: 'white',
            textAlign: 'center',
            lineHeight: '44px',
            fontSize: '25px',
            fontWeight: 'bold',
          },
        ],
      })

      cluster._icon = new Map.daum.maps.MarkerImage(
        singleIconURL,
        new Map.daum.maps.Size(15, 15),
      )

      cluster._zIndex = zIndex
    })
    return this
  }

  addMarkers (markerSpecs = []) {
    const markerSpecsWithoutClusterKey = []
    const markerSpecsByClusterKey = markerSpecs.reduce((result, spec) => {
      if (!spec.clusterKey) {
        markerSpecsWithoutClusterKey.push(spec)
        return result
      }
      if (!result[spec.clusterKey]) {
        result[spec.clusterKey] = []
      }
      result[spec.clusterKey].push(spec)
      return result
    }, {})

    markerSpecsWithoutClusterKey.forEach(({ lat, lng, title = null, onClick = null }) => {
      const marker = new Map.daum.maps.Marker({
        map: this.map,
        position: new Map.daum.maps.LatLng(lat, lng),
        title,
      })

      if (onClick) {
        Map.daum.maps.event.addListener(marker, 'click', onClick)
      }

      this.map.markersWithoutCluster.push(marker)
    })

    for (let clusterKey in markerSpecsByClusterKey) {
      const cluster = this.map.clusters[clusterKey]
      cluster.addMarkers(
        markerSpecsByClusterKey[clusterKey].map(({ lat, lng, title = null, onClick = null }) => {
          const marker = new Map.daum.maps.Marker({
            title,
            position: new Map.daum.maps.LatLng(lat, lng),
            image: cluster._icon,
            zIndex: cluster._zIndex,
          })

          if (onClick) {
            Map.daum.maps.event.addListener(marker, 'click', onClick)
          }

          return marker
        })
      )
    }
  }

  clearMarkers () {
    // remove cluster markers
    for (let k in this.map.clusters) {
      const cluster = this.map.clusters[k]
      cluster.clear()
    }

    this.map.markersWithoutCluster.forEach(marker => {
      marker.setMap(null)
    })

    this.map.markersWithoutCluster = []
  }

  setCenter ({ lat, lng, maxLevel = 8 }) {
    if (this.map.getLevel() > maxLevel) {
      this.map.setLevel(maxLevel)
    }
    this.map.panTo(
      new Map.daum.maps.LatLng(lat, lng)
    )
  }
}

Map.cachedMaps = {}
Map.daum = null
Map.initialize = function () {
  return new Promise((resolve, reject) => {
    loadScriptOnce(DAUM_KAKAO_MAP_LIB_URL, (err) => {
      if (err) return reject(err)
      Map.daum = window.daum
      Map.daum.maps.load(() => resolve())
    })
  })
}

export default Map


<TestMap.vue> 
컴포넌트로 지도를 부를 수 있게 만든곳

<template>
  <div :id="elementId" :style="{ width, height }">
    <!-- daum kakao map -->
  </div>
</template>

<script>
import Map from "@/utils/map";
// ...

export default {
  props: {
    elementId: {
      type: String,
      required: true,
    },
    markers: {
      type: Array,
      default() {
        return [];
      },
      required: true,
    },
    width: {
      type: String,
      required: false,
      default: "100%",
    },
    height: {
      type: String,
      required: false,
      default: "640px",
    },
  },
  data() {
    return {
      map: null,
    };
  },
  watch: {
    markers: {
      handler() {
        if (typeof window === "undefined") return; // SSR
        this.initMap(this.markers);
      },
      immediate: true,
    },
  },
  methods: {
    async initMap(markers) {
      if (!this.map) {
        const map = new Map();
        await map.mount(this.elementId);

        map.addMarkerClusters([
          {
            key: "cluster1",
            color: "#222529",
            zIndex: 0,
            singleIconURL: require("@/assets/images/logo.svg"),
          },
          {
            key: "cluster2",
            color: "#209cee",
            zIndex: 1,
            singleIconURL: require("@/assets/images/logo.svg"),
          },
        ]);

        this.map = map;
      } else {
        this.map.clearMarkers();
      }

      this.map.addMarkers(
        markers.map((marker) => {
          const {
            name,
            type,
            location: { lat, lng },
          } = marker;
          return {
            lat,
            lng,
            clusterKey: type,
            title: name,
            onClick: () => {
              this.$emit("click-marker", marker);
            },
          };
        })
      );
    },
    setCenter(lat, lng) {
      this.map && this.map.setCenter({ lat, lng, maxLevel: 10 });
    },
  },
};
</script>


< CallMap.vue>
Map 컴포넌트를 사용하는 UI

<template>
  <test-map :elementId="elementId" :markers="markers"></test-map>
</template>

<script>
import TestMap from "@/components/TestMap";
// ...

export default {
  components: { TestMap },
  data() {
    return {
      elementId: "checkMap",
      markers: [
        {
          lat: "35.65919598808177",
          lng: "127.73894402702498",
        },
      ]
    };
  },
  methods: {},
};
</script>


<< 오류 메시지 (브라우저)>>

TestMap.vue?0de1:76 
Uncaught (in promise) TypeError: Cannot read property 'lat' of undefined
    at eval (TestMap.vue?0de1:76)
    at Array.map (<anonymous>)
    at _callee$ (TestMap.vue?0de1:75)
    at tryCatch (runtime.js?96cf:63)
    at Generator.invoke [as _invoke] (runtime.js?96cf:293)
    at Generator.eval [as next] (runtime.js?96cf:118)
    at asyncGeneratorStep (asyncToGenerator.js?1da1:3)
    at _next (asyncToGenerator.js?1da1:25)



제가 props 에 대한 개념을 정확히 짚지 않아서 그런지
markers 에 넘겨줘야되는 값을 제대로 못넘겨주고 있습니다.
도움 부탁드립니다.
감사합니다. 

0
  • 답변 2

  • 무스타피
    188
    2020-11-30 23:51:32

    lat 이 정의가 안되어있데요

    initmap 안에서 markers.map 안에 marker을 받으시고 그냥 lat 적으시면 안되죵 marker.lat적으셔야죠

    lng도 마찬가지입니다.

  • 찬이
    453
    2020-12-11 15:18:21

    감사합니다. 해보겠습니다.

  • 로그인을 하시면 답변을 등록할 수 있습니다.