SPRING
2022.05.02 / 16:15

±¸±Û¸Ê(Google Map) API¿¡¼­ Ä¿½ºÅÒ ¸¶Ä¿(Custom Marker) ±¸ÇöÇÏ´Â ¹æ¹ý

ÄÚÄÚ·Î
Ãßõ ¼ö 157

[ÀÚ¹Ù½ºÅ©¸³Æ®/Javascript] ±¸±Û¸Ê(Google Map) API¿¡¼­ Ä¿½ºÅÒ ¸¶Ä¿(Custom Marker) ±¸ÇöÇÏ´Â ¹æ¹ý (Add Custom Markers with the Google Maps JavaScript API)

³²¾çÁÖ°³¹ßÀÚ

¡¤

2020. 8. 28. 08:09

728x90
¹ÝÀÀÇü

¿ì¸®´Â À¥ °³¹ßÀ» ÇÏ´Ù º¸¸é ±¸±Û¸Ê, ±¸±ÛÁöµµ(Google Map)À» ´Ù·ç´Â °æ¿ì°¡ Á¾Á¾ ÀÖ½À´Ï´Ù. ±×¶§¸¶´Ù ±¸±Û¸Ê¿¡ ¿ì¸®°¡ ¿øÇÏ´Â À§Ä¡¸¦ Ç¥ÇöÇϱâ À§Çؼ­ ¸¶Ä¿¸¦ »ç¿ëÇÏ°ï ÇÏÁÒ. ±âº»ÀûÀÎ ¸¶Ä¿ ±¸ÇöÀ¸·Î ³¡³ª´Â °æ¿ìµµ ÀÖÁö¸¸ ±¸ÇöÇÏ´Â ¼­ºñ½º Ư»ö¿¡ ¸Â°Ô Ä¿½ºÅÒ ¸¶Ä¿¸¦ Àû¿ëÇØ¾ß µÇ´Â °æ¿ì°¡ ÀÖ½À´Ï´Ù. ÇÏÁö¸¸ ±¸±Û¸Ê¿¡¼­ Á¦°øÇÏ°í ÀÖ´Â APIÀÇ ¸¶Ä¿(Marker)¸¦ È°¿ëÇؼ­ ¿ì¸®ÀÇ ¼­ºñ½º¿¡ ¸Â´Â Ä¿½ºÅÒ ¸¶Ä¿¸¦ ±¸ÇöÇϱ⿡´Â ±²ÀåÈ÷ ¾î·Á¿òÀÌ ¸¹½À´Ï´Ù. (Ä¿½ºÅ͸¶ÀÌ¡ Çϱ⠳ʹ« ±î´Ù·Ó½À´Ï´Ù.)

À̹ø Æ÷½ºÆÿ¡¼­´Â Google Map API¿¡¼­ Á¦°øÇÏ´Â OverlayView Ŭ·¡½º¸¦ È°¿ëÇؼ­ Ä¿½ºÅÒ ¸¶Ä¿(Custom Marker)¸¦ ±¸ÇöÇغ¸µµ·Ï ÇÏ°Ú½À´Ï´Ù.

µé¾î°¡±â Àü¿¡

Àú´Â À̹ø Æ÷½ºÆÿ¡¼­ Vue °³¹ßȯ°æ¿¡¼­ ±¸±Û¸Ê Ä¿½ºÅÒ ¸¶Ä¿ ¿¹½Ã¸¦ ±¸ÇöÇÒ ¿¹Á¤ÀÔ´Ï´Ù. ¹°·Ð ±âº» µ¿ÀÛ ¹æ½ÄÀº °°À¸¹Ç·Î React¸¦ È°¿ëÇϼŵµ µÇ°í, Pure Javascript·Î ±¸ÇöÇϼŵµ µË´Ï´Ù. ±¸ÇöÇϱâ ÆíÇϽŠ¶óÀ̺귯¸®·Î °³¹ßȯ°æÀ» ±¸¼ºÇØÁÖ¼¼¿ä!

¿¹½Ã¿¡ »ç¿ëµÉ »ùÇõ¥ÀÌÅÍ´Â ¾Æ·¡¿Í °°½À´Ï´Ù.

»ùÇõ¥ÀÌÅÍ

const sample = [
  { latitude: 37.5047592, longitude: 127.0415586, price: "₩52" },
  { latitude: 37.5082055, longitude: 127.0363408, price: "₩66" },
  { latitude: 37.5055726, longitude: 127.0294372, price: "₩40" },
  { latitude: 37.4994, longitude: 127.03545, price: "₩39" },
  { latitude: 37.4916279, longitude: 127.0289673, price: "₩43" },
  { latitude: 37.49479, longitude: 127.03665, price: "₩54" },
  { latitude: 37.5052889, longitude: 127.0258825, price: "₩50" },
  { latitude: 37.503028, longitude: 127.0237718, price: "₩47" },
  { latitude: 37.506151, longitude: 127.028389, price: "₩50" },
  { latitude: 37.505394, longitude: 127.028807, price: "₩16" },
  { latitude: 37.4918215, longitude: 127.0299, price: "₩38" },
  { latitude: 37.504824, longitude: 127.028217, price: "₩195" },
  { latitude: 37.5012203, longitude: 127.035459, price: "₩55" },
  { latitude: 37.49869, longitude: 127.0323734, price: "₩51" },
  { latitude: 37.5028748, longitude: 127.0394336, price: "₩32" },
  { latitude: 37.5065218, longitude: 127.0303014, price: "₩41" },
  { latitude: 37.4935486, longitude: 127.0280787, price: "₩49" },
  { latitude: 37.4995308, longitude: 127.0354614, price: "₩28" },
  { latitude: 37.50664, longitude: 127.03158, price: "₩64" },
  { latitude: 37.5024767, longitude: 127.0399139, price: "₩49" },
  { latitude: 37.5013577, longitude: 127.0357776, price: "₩40" },
  { latitude: 37.5024315, longitude: 127.0387326, price: "₩36" },
  { latitude: 37.500582, longitude: 127.041064, price: "₩151" },
  { latitude: 37.506508, longitude: 127.03227, price: "₩56" },
  { latitude: 37.505964, longitude: 127.031195, price: "₩64" },
  { latitude: 37.5059947, longitude: 127.0296956, price: "₩50" },
  { latitude: 37.502935, longitude: 127.039946, price: "₩37" },
  { latitude: 37.50271, longitude: 127.040521, price: "₩37" },
  { latitude: 37.50161, longitude: 127.04103, price: "₩43" },
  { latitude: 37.49901, longitude: 127.02851, price: "₩96" },
  { latitude: 37.497393, longitude: 127.029029, price: "₩42" },
  { latitude: 37.505412, longitude: 127.025293, price: "₩28" },
  { latitude: 37.5008366, longitude: 127.0389705, price: "₩41" },
  { latitude: 37.503903, longitude: 127.0350934, price: "₩57" },
  { latitude: 37.4988, longitude: 127.034, price: "₩42" },
  { latitude: 37.50406, longitude: 127.0273, price: "₩17" },
  { latitude: 37.495657, longitude: 127.0351384, price: "₩15" },
  { latitude: 37.5012302, longitude: 127.0422585, price: "₩42" },
  { latitude: 37.494725, longitude: 127.035201, price: "₩14" },
  { latitude: 37.500849, longitude: 127.039129, price: "₩62" },
  { latitude: 37.49232, longitude: 127.031682, price: "₩14" },
  { latitude: 37.502704, longitude: 127.039724, price: "₩42" },
  { latitude: 37.500988, longitude: 127.039632, price: "₩34" },
  { latitude: 37.496069, longitude: 127.02963, price: "₩33" },
  { latitude: 37.4958567, longitude: 127.0299851, price: "₩42" },
  { latitude: 37.499953, longitude: 127.031842, price: "₩37" },
  { latitude: 37.501198, longitude: 127.040513, price: "₩37" },
  { latitude: 37.50329, longitude: 127.03675, price: "₩24" },
  { latitude: 37.5000614, longitude: 127.0247841, price: "₩22" },
  { latitude: 37.50271, longitude: 127.03991, price: "₩33" },
];

±¸ÇöÇÒ °á°ú¹°

À̹ø Æ÷½ºÆÿ¡¼­ ±¸ÇöÇÒ °á°ú¹°Àº ¿¡¾îºñ¾Øºñ(airbnb)¿¡¼­ »ç¿ëÇÏ°í ÀÖ´Â ¾Æ·¡¿Í °°Àº ±¸±Û¸Ê UI¸¦ ±¸ÇöÇغ¼ °ÍÀÔ´Ï´Ù. (Ä¿½ºÅÒ ¸¶Ä¿(Custom Marker) ºÎºÐ¸¸)

¿¡¾îºñ¾Øºñ¿¡¼­ »ç¿ëÇÏ°í ÀÖ´Â ±¸±Û¸Ê Ä¿½ºÅÒ ¸¶Ä¿

±¸ÇöÇϱâ

±¸ÇöÇϱâ Àü¿¡ Vue¿¡¼­ ±¸±Û¸ÊÀ» ½±°Ô »ç¿ëÇϱâ À§ÇØ vue2-google-maps ¶óÀ̺귯¸®¸¦ È°¿ëÇؼ­ ±¸±Û¸Ê ÄÄÆ÷³ÍÆ®¸¦ ¼¼ÆÃÇÏ°Ú½À´Ï´Ù. ¸®¾×Æ®¿¡¼­´Â ¾Æ·¡¿Í °°Àº ¶óÀ̺귯¸®¸¦ È°¿ëÇؼ­ °³¹ßÇÏ½Ã¸é µÇ°Ú³×¿ä.

ÆÐÅ°Áö ¼³Ä¡

±¸±Û¸Ê API¸¦ ½±°Ô »ç¿ëÇϱâ À§ÇØ vue2-google-maps ¶óÀ̺귯¸®¸¦ ¼³Ä¡ÇÕ´Ï´Ù.

npm install vue2-google-maps
// or
yarn add vue2-google-maps

¸®¾×Æ®¿¡¼­´Â ¾Æ·¡¿Í °°Àº ¶óÀ̺귯¸®¸¦ È°¿ëÇؼ­ °³¹ßÇÏ½Ã¸é µÇ°Ú³×¿ä.

 

google-map-react

Isomorphic component that allows rendering react components on a google map

www.npmjs.com

±¸±Û¸Ê ±âº» ¼³Á¤

±¸±Û¸ÊÀ» »ç¿ëÇϱâ À§Çؼ­´Â ±âº»ÀûÀ¸·Î ±¸±Û API Key¸¦ ¹ß±Þ¹Þ°í ¾Æ·¡¿Í °°ÀÌ ¼¼ÆÃÇØ¾ß ÇÕ´Ï´Ù. ±¸±Û Áöµµ API Å°¸¦ ¹ß±Þ¹Þ°í ¾Æ·¡ key¿¡ ³Ö¾îÁÖ¼¼¿ä.

// main.js
import Vue from "vue";
import * as VueGoogleMaps from "vue2-google-maps";

Vue.use(VueGoogleMaps, {
  load: {
    key: "google ¸Ê API Å°¸¦ ³Ö¾îÁÖ¼¼¿ä.",
    libraries: "places",
  },
});

±¸±Û¸Ê ±âº» ¼³Á¤À» ¿Ï·áÇß´Ù¸é ÄÄÆ÷³ÍÆ®¿¡ ±¸±Û¸Ê ÄÄÆ÷³ÍÆ®¸¦ Ãß°¡ÇÕ´Ï´Ù. ±¸±Û¸Ê ÄÄÆ÷³ÍÆ®°¡ Á¤»óÀûÀ¸·Î ·»´õ¸µ µÇ´ÂÁö È®ÀÎÇϱâ À§ÇØ ÀÓÀÇÀÇ ÁÂÇ¥°ªÀ¸·Î center °ªÀ» ¼³Á¤ÇÕ´Ï´Ù. ±¸±Û¸ÊÀÇ »çÀÌÁ ½ºÅ©¸° »çÀÌÁî Àüü·Î ±¸¼ºÇϱâ À§ÇØ ÄÄÆ÷³ÍÆ® ½ºÅ¸ÀÏ °ªÀ» width 100vw, height 100vh·Î ±¸¼ºÇÕ´Ï´Ù.

// App.vue
<template>
  <div id="app">
    <GmapMap
      ref="mapRef"
      :center="center"
      :zoom="16"
      style="width: 100vw; height: 100vh" // ±¸±ÛÁöµµ »çÀÌÁî 100%
    >
    </GmapMap>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      // Å×½ºÆ® ÁÂÇ¥ µ¥ÀÌÅÍ
      center: {
        lat: 37.500131499999995,
        lng: 127.03242579999998,
      },
    };
  }
};
</script>

<style>
body {
  margin: 0;
  padding: 0;
}
</style>

Å×½ºÆ® ÁÂÇ¥ µ¥ÀÌÅ͸¦ ±¸±Û¸Ê ÄÄÆ÷³ÍÆ®ÀÇ center ¼Ó¼º °ªÀ¸·Î ÇÒ´çÇϸ頾Ʒ¡¿Í °°ÀÌ ±¸±Û¸ÊÀÌ ·»´õ¸µ µÇ´Â °ÍÀ» È®ÀÎÇÒ ¼ö ÀÖ½À´Ï´Ù.

ÀÓÀÇÀÇ ÁÂÇ¥°ªÀÌ ±¸±Û¸ÊÀÇ Áß¾Ó°ªÀ¸·Î ¼³Á¤µÇ¾î ³ëÃâµÇ´Â ¸ð½À

¸¶Ä¿ »ý¼ºÇϱâ

±¸±Û¸Ê¿¡ ƯÁ¤ ÁöÁ¡¿¡ À§Ä¡¸¦ Âï±â À§Çؼ­´Â ¸¶Ä¿(Marker)¸¦ »ç¿ëÇØ¾ß ÇÕ´Ï´Ù. ¸¶Ä¿ÀÇ ±âº» µ¿ÀÛ ¿ø¸®´Â ¾Æ·¡ ±¸±Û¸Ê API ¹®¼­¸¦ Âü°íÇϼ¼¿ä.

 

Markers  |  Maps JavaScript API  |  Google Developers

Introduction A marker identifies a location on a map. By default, a marker uses a standard image. Markers can display custom images, in which case they are usually referred to as "icons." Markers and icons are objects of type Marker. You can set a custom i

developers.google.com

Àú´Â vue2-google-maps ¶óÀ̺귯¸®¿¡¼­ Á¦°øÇÏ°í ÀÖ´Â GmapMarker ÄÄÆ÷³ÍÆ®¸¦ È°¿ëÇؼ­ ¸¶Ä¿¸¦ »ý¼ºÇÏ°Ú½À´Ï´Ù. ¸¶Ä¿ µ¥ÀÌÅ͸¦ Ãß°¡ÇÕ´Ï´Ù. ¸¶Ä¿ µ¥ÀÌÅÍ´Â À§°æµµ(lat, lng)·Î ±¸¼ºµÈ Æ÷Áö¼Ç(position) ÇÁ·ÎÆÛƼ·Î ±¸¼ºµÇ¾î ÀÖ½À´Ï´Ù.

<template>
  <div id="app">
    <GmapMap
      ref="mapRef"
      :center="center"
      :zoom="16"
      style="width: 100vw; height: 100vh"
    >
      <GmapMarker
        :key="index"
        v-for="(m, index) in markers"
        :position="m.position"
      />
    </GmapMap>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      center: {
        lat: 37.500131499999995,
        lng: 127.03242579999998,
      },
      // ¸¶Ä¿ µ¥ÀÌÅÍ Ãß°¡
      markers: [
        {
          position: {
            lat: 37.500131499999995,
            lng: 127.03242579999998,
          },
        },
      ],
    };
  },
};
</script>

ÁÂÃøÀº À§ ÄÚµåÀÇ °á°ú¹°ÀÌ°í, ¿ìÃøÀº »ùÇõ¥ÀÌÅ͸¦ ¸¶Ä¿ µ¥ÀÌÅÍ Çü½Ä¿¡ ¸ÂÃç¼­ ¸¶Ä¿¸¦ »ý¼ºÇÑ °á°ú¹°ÀÔ´Ï´Ù. »ùÇõ¥ÀÌÅÍ´Â µé¾î°¡±â Àü¿¡ Á¦°øÇص帰 µ¥ÀÌÅÍÀÔ´Ï´Ù.

»ùÇõ¥ÀÌÅ͸¦ È°¿ëÇؼ­ ¸¶Ä¿¸¦ ±¸ÇöÇÑ ¸ð½À

Ä¿½ºÅÒ ¸¶Ä¿(Custom Marker) ±¸Çö

Ä¿½ºÅÒ ¸¶Ä¿´Â ±¸±Û¸Ê API¿¡¼­ Á¦°øÇÏ°í ÀÖ´Â ±â´ÉÀÔ´Ï´Ù. ÇÏÁö¸¸, Á¦°¡ Á¶±Ý ã¾Æº» °á°ú(Á¦°¡ ¸ø ã¾ÒÀ» ¼öµµ ÀÖ½À´Ï´Ù) ±¸±Û¸Ê API¿¡¼­ Á¦°øÇÏ°í ÀÖ´Â Ä¿½ºÅÒ ¸¶Ä¿(Custom Marker)´Â ±¸±Û¸Ê¿¡¼­ Á¦°øÇÏ°í ÀÖ´Â ±âº» ¸¶Ä¿ ¾ÆÀÌÄÜÀ» º¯°æÇØÁÖ´Â ¼öÁØÀ¸·Î Á¦°øÇÏ°í ÀÖ½À´Ï´Ù. Ä¿½ºÅÒ ¸¶Ä¿(Custom Marker)ÀÇ ±âº» µ¿ÀÛ ¿ø¸®´Â ¾Æ·¡ÀÇ ±¸±Û API ¹®¼­¸¦ Âü°íÇϼ¼¿ä.

 

Customizing a Google Map: Custom Markers  |  Maps JavaScript API

¿ì¸®´Â ÀÌÁ¦ ¿¡¾îºñ¾Øºñ¿¡¼­ »ç¿ëÇÏ°í ÀÖ´Â ±¸±Û¸Ê Ä¿½ºÅÒ ¸¶Ä¿¿Í ¶È°°ÀÌ ¸¸µé¾îº¼ °ÍÀÔ´Ï´Ù.

¿¡¾îºñ¾Øºñ¿¡¼­ »ç¿ëÇÏ°í ÀÖ´Â Ä¿½ºÅÒ¸¶Ä¿ µðÀÚÀÎ

¿ì¼± ±¸±Û¸Ê¿¡ ¸¶Ä¿µéÀ» ±¸¼ºÇϱâ À§ÇØ »ùÇõ¥ÀÌÅ͸¦ ÄÄÆ÷³ÍÆ®¿¡ Ãß°¡ÇØÁÖ¼¼¿ä. »ùÇõ¥ÀÌÅÍ´Â ¾Æ·¡¿Í °°½À´Ï´Ù.

// ¸¶Ä¿¸¦ ±¸ÇöÇϱâ À§ÇÑ »ùÇõ¥ÀÌÅÍ
const sample = [
  { latitude: 37.5047592, longitude: 127.0415586, price: "₩52" },
  { latitude: 37.5082055, longitude: 127.0363408, price: "₩66" },
  { latitude: 37.5055726, longitude: 127.0294372, price: "₩40" },
  { latitude: 37.4994, longitude: 127.03545, price: "₩39" },
  { latitude: 37.4916279, longitude: 127.0289673, price: "₩43" },
  { latitude: 37.49479, longitude: 127.03665, price: "₩54" },
  { latitude: 37.5052889, longitude: 127.0258825, price: "₩50" },
  { latitude: 37.503028, longitude: 127.0237718, price: "₩47" },
  { latitude: 37.506151, longitude: 127.028389, price: "₩50" },
  { latitude: 37.505394, longitude: 127.028807, price: "₩16" },
  { latitude: 37.4918215, longitude: 127.0299, price: "₩38" },
  { latitude: 37.504824, longitude: 127.028217, price: "₩195" },
  { latitude: 37.5012203, longitude: 127.035459, price: "₩55" },
  { latitude: 37.49869, longitude: 127.0323734, price: "₩51" },
  { latitude: 37.5028748, longitude: 127.0394336, price: "₩32" },
  { latitude: 37.5065218, longitude: 127.0303014, price: "₩41" },
  { latitude: 37.4935486, longitude: 127.0280787, price: "₩49" },
  { latitude: 37.4995308, longitude: 127.0354614, price: "₩28" },
  { latitude: 37.50664, longitude: 127.03158, price: "₩64" },
  { latitude: 37.5024767, longitude: 127.0399139, price: "₩49" },
  { latitude: 37.5013577, longitude: 127.0357776, price: "₩40" },
  { latitude: 37.5024315, longitude: 127.0387326, price: "₩36" },
  { latitude: 37.500582, longitude: 127.041064, price: "₩151" },
  { latitude: 37.506508, longitude: 127.03227, price: "₩56" },
  { latitude: 37.505964, longitude: 127.031195, price: "₩64" },
  { latitude: 37.5059947, longitude: 127.0296956, price: "₩50" },
  { latitude: 37.502935, longitude: 127.039946, price: "₩37" },
  { latitude: 37.50271, longitude: 127.040521, price: "₩37" },
  { latitude: 37.50161, longitude: 127.04103, price: "₩43" },
  { latitude: 37.49901, longitude: 127.02851, price: "₩96" },
  { latitude: 37.497393, longitude: 127.029029, price: "₩42" },
  { latitude: 37.505412, longitude: 127.025293, price: "₩28" },
  { latitude: 37.5008366, longitude: 127.0389705, price: "₩41" },
  { latitude: 37.503903, longitude: 127.0350934, price: "₩57" },
  { latitude: 37.4988, longitude: 127.034, price: "₩42" },
  { latitude: 37.50406, longitude: 127.0273, price: "₩17" },
  { latitude: 37.495657, longitude: 127.0351384, price: "₩15" },
  { latitude: 37.5012302, longitude: 127.0422585, price: "₩42" },
  { latitude: 37.494725, longitude: 127.035201, price: "₩14" },
  { latitude: 37.500849, longitude: 127.039129, price: "₩62" },
  { latitude: 37.49232, longitude: 127.031682, price: "₩14" },
  { latitude: 37.502704, longitude: 127.039724, price: "₩42" },
  { latitude: 37.500988, longitude: 127.039632, price: "₩34" },
  { latitude: 37.496069, longitude: 127.02963, price: "₩33" },
  { latitude: 37.4958567, longitude: 127.0299851, price: "₩42" },
  { latitude: 37.499953, longitude: 127.031842, price: "₩37" },
  { latitude: 37.501198, longitude: 127.040513, price: "₩37" },
  { latitude: 37.50329, longitude: 127.03675, price: "₩24" },
  { latitude: 37.5000614, longitude: 127.0247841, price: "₩22" },
  { latitude: 37.50271, longitude: 127.03991, price: "₩33" },
];

¹öÆ°À» Ŭ¸¯ÇßÀ» ¶§ ±¸±Û¸Ê ÄÄÆ÷³ÍÆ®¿¡ ¸¶Ä¿¸¦ Ãß°¡Çϱâ À§ÇØ ¹öÆ°À» Çϳª Ãß°¡ÇÕ´Ï´Ù. ±¸±Û¸Ê API¸¦ È°¿ëÇϱâ À§ÇØ ±¸±Û API °´Ã¼¸¦ °¡Á®¿É´Ï´Ù.

import { gmapApi as google } from "vue2-google-maps";
// like window.google

window.google °´Ã¼ ¿¹½Ã

Àú´Â computed¿¡ google API °´Ã¼¸¦ Ãß°¡Çß½À´Ï´Ù. google API °´Ã¼°¡ È°¼ºÈ­µÇ¾úÀ» ¶§ Ä¿½ºÅÒ ¸¶Ä¿ Ŭ·¡½º¸¦ ¼¼ÆÃÇϱâ À§ÇØ watch¸¦ È°¿ëÇÕ´Ï´Ù. watch¿¡¼­ google computed°ªÀÌ º¯°æµÊÀ» °¨ÁöÇϸé initCustomMarker ÇÔ¼ö¸¦ »ç¿ëÇؼ­ CustomMarker¿¡ Ä¿½ºÅÒ ¸¶Ä¿ Ŭ·¡½º¸¦ ÇÒ´çÇÕ´Ï´Ù.

<template>
  <div id="app">
    <button @click="addMarkers">add</button>
    <button @click="clearMarkers">clear</button>
    <GmapMap
      ref="mapRef"
      :center="center"
      :zoom="16"
      style="width: 100vw; height: 100vh"
    />
  </div>
</template>

<script>
import shuffle from "lodash/shuffle";
import take from "lodash/take";
import initCustomMarker from "./custom-marker";
import { gmapApi as google } from "vue2-google-maps";
let CustomMarker;
const sample = [
  { latitude: 37.5047592, longitude: 127.0415586, price: "₩52" },
  { latitude: 37.5082055, longitude: 127.0363408, price: "₩66" },
  { latitude: 37.5055726, longitude: 127.0294372, price: "₩40" },
  { latitude: 37.4994, longitude: 127.03545, price: "₩39" },
  { latitude: 37.4916279, longitude: 127.0289673, price: "₩43" },
  { latitude: 37.49479, longitude: 127.03665, price: "₩54" },
  { latitude: 37.5052889, longitude: 127.0258825, price: "₩50" },
  { latitude: 37.503028, longitude: 127.0237718, price: "₩47" },
  { latitude: 37.506151, longitude: 127.028389, price: "₩50" },
  { latitude: 37.505394, longitude: 127.028807, price: "₩16" },
  { latitude: 37.4918215, longitude: 127.0299, price: "₩38" },
  { latitude: 37.504824, longitude: 127.028217, price: "₩195" },
  { latitude: 37.5012203, longitude: 127.035459, price: "₩55" },
  { latitude: 37.49869, longitude: 127.0323734, price: "₩51" },
  { latitude: 37.5028748, longitude: 127.0394336, price: "₩32" },
  { latitude: 37.5065218, longitude: 127.0303014, price: "₩41" },
  { latitude: 37.4935486, longitude: 127.0280787, price: "₩49" },
  { latitude: 37.4995308, longitude: 127.0354614, price: "₩28" },
  { latitude: 37.50664, longitude: 127.03158, price: "₩64" },
  { latitude: 37.5024767, longitude: 127.0399139, price: "₩49" },
  { latitude: 37.5013577, longitude: 127.0357776, price: "₩40" },
  { latitude: 37.5024315, longitude: 127.0387326, price: "₩36" },
  { latitude: 37.500582, longitude: 127.041064, price: "₩151" },
  { latitude: 37.506508, longitude: 127.03227, price: "₩56" },
  { latitude: 37.505964, longitude: 127.031195, price: "₩64" },
  { latitude: 37.5059947, longitude: 127.0296956, price: "₩50" },
  { latitude: 37.502935, longitude: 127.039946, price: "₩37" },
  { latitude: 37.50271, longitude: 127.040521, price: "₩37" },
  { latitude: 37.50161, longitude: 127.04103, price: "₩43" },
  { latitude: 37.49901, longitude: 127.02851, price: "₩96" },
  { latitude: 37.497393, longitude: 127.029029, price: "₩42" },
  { latitude: 37.505412, longitude: 127.025293, price: "₩28" },
  { latitude: 37.5008366, longitude: 127.0389705, price: "₩41" },
  { latitude: 37.503903, longitude: 127.0350934, price: "₩57" },
  { latitude: 37.4988, longitude: 127.034, price: "₩42" },
  { latitude: 37.50406, longitude: 127.0273, price: "₩17" },
  { latitude: 37.495657, longitude: 127.0351384, price: "₩15" },
  { latitude: 37.5012302, longitude: 127.0422585, price: "₩42" },
  { latitude: 37.494725, longitude: 127.035201, price: "₩14" },
  { latitude: 37.500849, longitude: 127.039129, price: "₩62" },
  { latitude: 37.49232, longitude: 127.031682, price: "₩14" },
  { latitude: 37.502704, longitude: 127.039724, price: "₩42" },
  { latitude: 37.500988, longitude: 127.039632, price: "₩34" },
  { latitude: 37.496069, longitude: 127.02963, price: "₩33" },
  { latitude: 37.4958567, longitude: 127.0299851, price: "₩42" },
  { latitude: 37.499953, longitude: 127.031842, price: "₩37" },
  { latitude: 37.501198, longitude: 127.040513, price: "₩37" },
  { latitude: 37.50329, longitude: 127.03675, price: "₩24" },
  { latitude: 37.5000614, longitude: 127.0247841, price: "₩22" },
  { latitude: 37.50271, longitude: 127.03991, price: "₩33" },
];
export default {
  name: "App",
  data() {
    return {
      CustomMarker: null,
      center: {
        lat: 37.500131499999995,
        lng: 127.03242579999998,
      },
      data: sample,
      markers: [],
    };
  },
  computed: {
    google,
  },
  watch: {
    google(val) {
      CustomMarker = initCustomMarker(val);
    },
  },
  methods: {
    clearMarkers() {
      this.markers.map((marker) => {
        marker.onRemove();
      });
      this.markers = [];
    },
    addMarkers() {
      take(shuffle(this.data), 20).map(({ price, latitude, longitude }, i) => {
        const el = document.createElement("div");
        el.textContent = price;
        el.setAttribute("data-marker-index", i);

        const t = new CustomMarker(
          new this.google.maps.LatLng(latitude, longitude),
          el
        );

        this.$refs["mapRef"].$mapPromise.then((map) => {
          // Áöµµ¿¡ Ä¿½ºÅÒ ¸¶Ä¿¸¦ ¼¼ÆÃÇÑ´Ù.
          t.setMap(map);
        });

        // ¸¶Ä¿ ÀνºÅϽºµéÀ» ÀúÀåÇÑ´Ù.
        this.markers.push(t);
      });
    },
  },
};
</script>

initCustomMarker ÇÔ¼ö´Â ¾Æ·¡¿Í °°½À´Ï´Ù. ±¸±Û¸Ê APIÀÇ OverlayView Ŭ·¡½º¸¦ È°¿ëÇؼ­ Ä¿½ºÅÒ ¸¶Ä¿¸¦ ±¸ÇöÇÕ´Ï´Ù. ±¸±Û¸Ê API OverlayViewÀÇ ±âº» µ¿ÀÛ ¿ø¸®´Â ¾Æ·¡¸¦ Âü°íÇϼ¼¿ä.

 

Custom Overlays  |  Maps JavaScript API  |  Google Developers

±¸±Û¸Ê API °´Ã¼¸¦ È®ÀåÇؼ­ Ä¿½ºÅÒ¸¶Ä¿ Ŭ·¡½º¸¦ »ý¼ºÇØ¾ß µÇ±â ¶§¹®¿¡ ±¸±Û¸Ê API °´Ã¼¸¦ Àü´Þ¹Þ¾Æ¾ß ÇÕ´Ï´Ù.

// custom-marker.js
export default (google) => {
  return class CustomMarker extends google.maps.OverlayView {
    constructor(position, content, options = { classname: "custom-marker" }) {
      super();
      const { classname } = options;
      this.options = options;
      this.position = position;
      content.classList.add(classname);
      const bubbleAnchor = document.createElement("div");
      bubbleAnchor.classList.add(`${classname}-anchor`);
      bubbleAnchor.appendChild(content);
      this.containerDiv = document.createElement("div");
      this.containerDiv.classList.add(`${classname}-container`);
      this.containerDiv.appendChild(bubbleAnchor);
    }
    onAdd() {
      this.getPanes().floatPane.appendChild(this.containerDiv);
    }
    onRemove() {
      if (this.containerDiv.parentElement) {
        this.containerDiv.parentElement.removeChild(this.containerDiv);
      }
    }
    draw() {
      const divPosition = this.getProjection().fromLatLngToDivPixel(
        this.position
      );

      const display =
        Math.abs(divPosition.x) < 4000 && Math.abs(divPosition.y) < 4000
          ? "block"
          : "none";

      if (display === "block") {
        this.containerDiv.style.left = divPosition.x + "px";
        this.containerDiv.style.top = divPosition.y + "px";
      }

      if (this.containerDiv.style.display !== display) {
        this.containerDiv.style.display = display;
      }
    }
  };
};

¿ì¸®°¡ ¸¸µç Ä¿½ºÅÒ ¸¶Ä¿ÀÇ ½ºÅ¸ÀÏÀ» Ãß°¡ÇÕ´Ï´Ù. Ä¿½ºÅÒ ¸¶Ä¿ ½ºÅ¸ÀÏÀº ¿ì¸®°¡ Ä¿½ºÅÒ ¸¶Ä¿¸¦ Ãß°¡ÇÒ ÄÄÆ÷³ÍÆ®¿¡ Ãß°¡ÇÏ°Ú½À´Ï´Ù.

// ¸¶Ä¿ ½ºÅ¸ÀÏ
<style lang="scss">
//
.custom-marker {
  position: absolute;
  top: 0;
  left: 0;
  transform: translate(-50%, -100%);
  background-color: white;
  padding: 0 8px;
  border-radius: 28px;
  box-shadow: rgba(0, 0, 0, 0.08) 0px 0px 0px 1px,
    rgba(0, 0, 0, 0.18) 0px 1px 2px;
  color: #222;
  overflow-y: auto;
  height: 28px;
  line-height: 28px;
  font-weight: bold;
  cursor: pointer;
  transition: transform 0.15s ease-in-out;
  font-size: 14px;
}
.custom-marker:hover {
  transform: translate(-50%, -100%) scale(1.2);
}
.custom-marker-anchor {
  position: absolute;
  width: 100%;
  bottom: 8px;
  left: 0;
}

.custom-marker-container {
  cursor: auto;
  height: 0;
  position: absolute;
  width: 200px;
  &.active {
    .custom-marker {
      z-index: 1000;
      background-color: #f7530e;
      color: #fff;
      transform: translate(-50%, -100%) scale(1.1);
    }
  }
}
</style>

¸¶Ä¿¸¦ Ãß°¡Çϱâ À§ÇØ addMarkers ¸Þ¼­µå¸¦ Ãß°¡ÇÕ´Ï´Ù. lodash take, shuffle¸¦ ÀûÀýÇÏ°Ô È°¿ëÇؼ­ ·£´ýÀ¸·Î »ùÇõ¥ÀÌÅÍ¿¡¼­ ÀÓÀÇÀÇ 20°³ÀÇ °ªÀ» °¡Á®¿Í¼­ È­¸é¿¡ ¸¶Ä¿¸¦ Âï¾îÁִ ÄÚµåÀÔ´Ï´Ù.

{
    data() {
      return {
		...,
        data: sample, // »ùÇõ¥ÀÌÅÍ
        markers: [], // ¸¶Ä¿ ÀνºÅϽºµéÀ» ÀúÀåÇϱâ À§ÇØ markers µ¥ÀÌÅÍ Ãß°¡
      };
    },
	methods: {
      // ¸¶Ä¿ Ãß°¡
      addMarkers() {
        take(shuffle(this.data), 20).map(({ price, latitude, longitude }, i) => {
          const el = document.createElement("div");
          el.textContent = price;
          el.setAttribute("data-marker-index", i);

          const t = new CustomMarker(
            new this.google.maps.LatLng(latitude, longitude),
            el
          );

          this.$refs["mapRef"].$mapPromise.then((map) => {
            // Áöµµ¿¡ Ä¿½ºÅÒ ¸¶Ä¿¸¦ ¼¼ÆÃÇÑ´Ù.
            t.setMap(map);
          });

          // ¸¶Ä¿ ÀνºÅϽºµéÀ» ÀúÀåÇÑ´Ù.
          this.markers.push(t);
        });
      },    
    }
}

add¹öÆ°¿¡ addMarkers ¸Þ¼­µå¸¦ ¿¬°áÇÏ°í add ¹öÆ°À» ´©¸£¸é ¾Æ·¡¿Í °°ÀÌ Ä¿½ºÅÒ ¸¶Ä¿°¡ ±¸±Û¸Ê¿¡ ÂïÈ÷°Ô µË´Ï´Ù.

±¸±Û¸Ê¿¡ Ä¿½ºÅÒ ¸¶Ä¿°¡ Àû¿ëµÈ ¸ð½À

Ä¿½ºÅÒ ¸¶Ä¿¸¦ ±¸±Û¸Ê¿¡¼­ Á¦°ÅÇÏ´Â ·ÎÁ÷µµ ÇÊ¿äÇÕ´Ï´Ù. Ä¿½ºÅÒ ¸¶Ä¿¸¦ Á¦°ÅÇÏ´Â Äڵ带 ±¸ÇöÇÕ´Ï´Ù. clearMarkers ¸Þ¼­µå¸¦ Ãß°¡ÇÕ´Ï´Ù. ÄÚµå´Â ±²ÀåÈ÷ ´Ü¼øÇÕ´Ï´Ù. ¿ì¸®°¡ ¸¶Ä¿¸¦ Ãß°¡ÇÒ ¶§ markers µ¥ÀÌÅÍ¿¡ ¸ðµç ¸¶Ä¿ ÀνºÅϽº¸¦ ÀúÀåÇÑ °Í ±â¾ïÇϽÃÁÒ? ÀúÀåµÈ ¸¶Ä¿ ÀνºÅϽº¸¦ ¼øȸÇϸ鼭 ¸¶Ä¿ ÀνºÅϽºÀÇ onRemove ¸Þ¼­µå¸¦ ½ÇÇàÇØÁÖ¸é ³¡ÀÔ´Ï´Ù. markers µ¥ÀÌÅÍÀÇ ¼øȸ°¡ ³¡³ª¸é markers µ¥ÀÌÅ͸¦ ÃʱâÈ­ÇÕ´Ï´Ù.

methods: {
  clearMarkers() {
    this.markers.map((marker) => {
      marker.onRemove();
    });
    this.markers = [];
  },
  ...
}

clearMarkers ¸Þ¼­µå¸¦ È°¿ëÇؼ­ ±¸±Û¸Ê Ä¿½ºÅÒ ¸¶Ä¿¸¦ Á¦°ÅÇÏ´Â ¸ð½À

Àüü ÄÚµå

±¸±Û Áöµµ(Google Map) API Ä¿½ºÅÒ ¸¶Ä¿(Custom Marker) ±¸Çö ·ÎÁ÷ÀÇ Àüü ÄÚµå´Â ¾Æ·¡¿Í °°½À´Ï´Ù. ¾Æ·¡ Äڵ带 Âü°íÇؼ­ Ä¿½ºÅÒ ¸¶Ä¿(Custom Marker)¸¦ ±¸ÇöÇÏ½Ç ¶§ Âü°íÇØÁÖ¼¼¿ä.

<template>
  <div id="app">
    <button @click="addMarkers">add</button>
    <button @click="clearMarkers">clear</button>
    <GmapMap
      ref="mapRef"
      :center="center"
      :zoom="16"
      style="width: 100vw; height: 100vh"
    />
  </div>
</template>

<script>
import shuffle from "lodash/shuffle";
import take from "lodash/take";
import initCustomMarker from "./custom-marker";
import { gmapApi as google } from "vue2-google-maps";
let CustomMarker;

const sample = [
  { latitude: 37.5047592, longitude: 127.0415586, price: "₩52" },
  { latitude: 37.5082055, longitude: 127.0363408, price: "₩66" },
  { latitude: 37.5055726, longitude: 127.0294372, price: "₩40" },
  { latitude: 37.4994, longitude: 127.03545, price: "₩39" },
  { latitude: 37.4916279, longitude: 127.0289673, price: "₩43" },
  { latitude: 37.49479, longitude: 127.03665, price: "₩54" },
  { latitude: 37.5052889, longitude: 127.0258825, price: "₩50" },
  { latitude: 37.503028, longitude: 127.0237718, price: "₩47" },
  { latitude: 37.506151, longitude: 127.028389, price: "₩50" },
  { latitude: 37.505394, longitude: 127.028807, price: "₩16" },
  { latitude: 37.4918215, longitude: 127.0299, price: "₩38" },
  { latitude: 37.504824, longitude: 127.028217, price: "₩195" },
  { latitude: 37.5012203, longitude: 127.035459, price: "₩55" },
  { latitude: 37.49869, longitude: 127.0323734, price: "₩51" },
  { latitude: 37.5028748, longitude: 127.0394336, price: "₩32" },
  { latitude: 37.5065218, longitude: 127.0303014, price: "₩41" },
  { latitude: 37.4935486, longitude: 127.0280787, price: "₩49" },
  { latitude: 37.4995308, longitude: 127.0354614, price: "₩28" },
  { latitude: 37.50664, longitude: 127.03158, price: "₩64" },
  { latitude: 37.5024767, longitude: 127.0399139, price: "₩49" },
  { latitude: 37.5013577, longitude: 127.0357776, price: "₩40" },
  { latitude: 37.5024315, longitude: 127.0387326, price: "₩36" },
  { latitude: 37.500582, longitude: 127.041064, price: "₩151" },
  { latitude: 37.506508, longitude: 127.03227, price: "₩56" },
  { latitude: 37.505964, longitude: 127.031195, price: "₩64" },
  { latitude: 37.5059947, longitude: 127.0296956, price: "₩50" },
  { latitude: 37.502935, longitude: 127.039946, price: "₩37" },
  { latitude: 37.50271, longitude: 127.040521, price: "₩37" },
  { latitude: 37.50161, longitude: 127.04103, price: "₩43" },
  { latitude: 37.49901, longitude: 127.02851, price: "₩96" },
  { latitude: 37.497393, longitude: 127.029029, price: "₩42" },
  { latitude: 37.505412, longitude: 127.025293, price: "₩28" },
  { latitude: 37.5008366, longitude: 127.0389705, price: "₩41" },
  { latitude: 37.503903, longitude: 127.0350934, price: "₩57" },
  { latitude: 37.4988, longitude: 127.034, price: "₩42" },
  { latitude: 37.50406, longitude: 127.0273, price: "₩17" },
  { latitude: 37.495657, longitude: 127.0351384, price: "₩15" },
  { latitude: 37.5012302, longitude: 127.0422585, price: "₩42" },
  { latitude: 37.494725, longitude: 127.035201, price: "₩14" },
  { latitude: 37.500849, longitude: 127.039129, price: "₩62" },
  { latitude: 37.49232, longitude: 127.031682, price: "₩14" },
  { latitude: 37.502704, longitude: 127.039724, price: "₩42" },
  { latitude: 37.500988, longitude: 127.039632, price: "₩34" },
  { latitude: 37.496069, longitude: 127.02963, price: "₩33" },
  { latitude: 37.4958567, longitude: 127.0299851, price: "₩42" },
  { latitude: 37.499953, longitude: 127.031842, price: "₩37" },
  { latitude: 37.501198, longitude: 127.040513, price: "₩37" },
  { latitude: 37.50329, longitude: 127.03675, price: "₩24" },
  { latitude: 37.5000614, longitude: 127.0247841, price: "₩22" },
  { latitude: 37.50271, longitude: 127.03991, price: "₩33" },
];
export default {
  name: "App",
  data() {
    return {
      CustomMarker: null,
      center: {
        lat: 37.500131499999995,
        lng: 127.03242579999998,
      },
      data: sample,
      markers: [],
    };
  },
  computed: {
    google,
  },
  watch: {
    google(val) {
      CustomMarker = initCustomMarker(val);
    },
  },
  methods: {
    clearMarkers() {
      this.markers.map((marker) => {
        marker.onRemove();
      });
      this.markers = [];
    },
    addMarkers() {
      take(shuffle(this.data), 20).map(({ price, latitude, longitude }, i) => {
        const el = document.createElement("div");
        el.textContent = price;
        el.setAttribute("data-marker-index", i);

        const t = new CustomMarker(
          new this.google.maps.LatLng(latitude, longitude),
          el
        );

        this.$refs["mapRef"].$mapPromise.then((map) => {
          // Áöµµ¿¡ Ä¿½ºÅÒ ¸¶Ä¿¸¦ ¼¼ÆÃÇÑ´Ù.
          t.setMap(map);
        });

        // ¸¶Ä¿ ÀνºÅϽºµéÀ» ÀúÀåÇÑ´Ù.
        this.markers.push(t);
      });
    },
  },
};
</script>

<style>
body {
  margin: 0;
  padding: 0;
}
</style>

<style lang="scss">
.custom-marker {
  position: absolute;
  top: 0;
  left: 0;
  transform: translate(-50%, -100%);
  background-color: white;
  padding: 0 8px;
  border-radius: 28px;
  box-shadow: rgba(0, 0, 0, 0.08) 0px 0px 0px 1px,
    rgba(0, 0, 0, 0.18) 0px 1px 2px;
  color: #222;
  overflow-y: auto;
  height: 28px;
  line-height: 28px;
  font-weight: bold;
  cursor: pointer;
  transition: transform 0.15s ease-in-out;
  font-size: 14px;
}
.custom-marker:hover {
  transform: translate(-50%, -100%) scale(1.2);
}
.custom-marker-anchor {
  position: absolute;
  width: 100%;
  bottom: 8px;
  left: 0;
}

.custom-marker-container {
  cursor: auto;
  height: 0;
  position: absolute;
  width: 200px;
  &.active {
    .custom-marker {
      z-index: 1000;
      background-color: #f7530e;
      color: #fff;
      transform: translate(-50%, -100%) scale(1.1);
    }
  }
}
</style>
export default (google) => {
  return class CustomMarker extends google.maps.OverlayView {
    constructor(position, content, options = { classname: "custom-marker" }) {
      super();
      const { classname } = options;
      this.options = options;
      this.position = position;
      content.classList.add(classname);
      const bubbleAnchor = document.createElement("div");
      bubbleAnchor.classList.add(`${classname}-anchor`);
      bubbleAnchor.appendChild(content);
      this.containerDiv = document.createElement("div");
      this.containerDiv.classList.add(`${classname}-container`);
      this.containerDiv.appendChild(bubbleAnchor);
    }
    onAdd() {
      this.getPanes().floatPane.appendChild(this.containerDiv);
    }
    onRemove() {
      if (this.containerDiv.parentElement) {
        this.containerDiv.parentElement.removeChild(this.containerDiv);
      }
    }
    draw() {
      const divPosition = this.getProjection().fromLatLngToDivPixel(
        this.position
      );
      // Hide the popup when it is far out of view.
      const display =
        Math.abs(divPosition.x) < 4000 && Math.abs(divPosition.y) < 4000
          ? "block"
          : "none";

      if (display === "block") {
        this.containerDiv.style.left = divPosition.x + "px";
        this.containerDiv.style.top = divPosition.y + "px";
      }

      if (this.containerDiv.style.display !== display) {
        this.containerDiv.style.display = display;
      }
    }
  };
};
728x90
¹ÝÀÀÇü
±×¸®µåÇü

💖 ÀúÀÚ¿¡°Ô ¾ÏȣȭÆó·Î ÈÄ¿øÇϱâ 💖

¾ÆÀÌÄÜÀ» Ŭ¸¯Çϸé Áö°© ÁÖ¼Ò°¡ÀÚµ¿À¸·Î º¹»çµË´Ï´Ù

8°³ÀÇ ´ñ±Û