본문 바로가기
Research/Javascript

Javascript-웹사이트에 지도 추가하기(Tutorial)

by RIEM 2023. 5. 2.

웹사이트에 지도 추가하기(자바스크립트)

https://developers.google.com/codelabs/maps-platform/maps-platform-101-js?hl=ko#0

 

1.시작하기 전에

자바스크립트로 구글 맵스에 몇 개의 핀을 찍어서 렌더링 해주는 작업을 해보자.

 

수행하는 내용

  • Maps JavaScript API 동적으로 로드
  • 첫 지도 로드
  • 마커 및 마커 클러스터링 사용
  • Maps JavaScript API 이벤트 시스템 사용하여 사용자 상호작용 제공
  • 동적으로 지도 조정
  • 지도에 그리기

2. 사전 준비사항

이게 필요하다

  • Maps JavaScript API
  • MarkerClustererPlus 오픈소스 마커 클러스터링 라이브러리

 

3. 설정하기

  1. API키 만들기
  2. 마켓 플레이스에서 Google Maps Platform API 및 SDK 설정. https://console.cloud.google.com/marketplace?hl=ko

 

프로젝트 파일을 가져온 뒤에, /starter 경로에서 npm 패키지들을 npm install로 설치하고, npm start로 실행해주자.

 

package.json

{
 "name": "codelab-js-maps-api-101",
 "version": "1.0.0",
 "description": "An example app to accompany the Google Maps Platform 101: JavaScript codelab",
 "main": "/src/app.js",
 "scripts": {
   "start": "webpack-dev-server --progress --hot --open",
   "test": "echo \"Error: no test specified\" && exit 1"
 },

 "author": "Alex Muramoto",
 "license": "Apache-2.0",
 "dependencies": {
   "@google/markerclustererplus": "^5.0.3",
   "@googlemaps/js-api-loader": "^1.12.1",
   "webpack": "^4.42.1",
   "webpack-cli": "^3.3.11",
   "webpack-dev-server": "^3.10.3"
 }
}

참고로 코드 위에서 자바스크립트를 쓰려면 위 패키지들을 설치해야 한다.

https://www.npmjs.com/package/@googlemaps/map-loader

 

4. Maps JavaScript API 로드

웹용 구글 맵스 플랫폼을 사용하기 위해서는 Maps JavaScript API를 사용한다고 한다. 이 API 덕분에 지도, 마커, 그리기 등을 자바스크립트로 제어할 수 있다.

 

5. 지도 표시하기

// get Loader class from package
import { Loader } from "@googlemaps/js-api-loader";

// create apiOptions obj
const apiOptions = {
apiKey: "AIzaSyAOpVCT2pyx9Y4gOz3VHodjLEhLfdl56cU",
};

const loader = new Loader(apiOptions);

// Promise
loader.load().then(() => {
console.log("Mas JS API Loaded!");
const map = displayMap();
});

function displayMap() {
const mapOptions = {
  center: { lat: -33.860664, lng: 151.208138 },
  zoom: 14,
};
const mapDiv = document.getElementById("map");

// Create instance of Google.maps.Map
// - To create new map to mark something
const map = new google.maps.Map(mapDiv, mapOptions);
return map;
}

promise를 위해 loader.load().then()으로 해야한다. 튜토리얼에서는 load()가 빠져있다.

 

6. 클라우드 기반 지도 스타일 지정(선택)

7. 지도에 마커 추가하기

 

/**
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { Loader } from "@googlemaps/js-api-loader";
import MarkerClusterer from "@google/markerclustererplus";

// Toilet Data SEOUL
// https://data.seoul.go.kr/dataList/OA-365/S/1/datasetView.do
const API_KEY = "5761714251736c61313131596d466857";

// // 변수명 타입  변수설명  값설명
// KEY  String(필수)  인증키 OpenAPI 에서 발급된 인증키
// TYPE String(필수)  요청파일타입  xml : xml, xml파일 : xmlf, 엑셀파일 : xls, json파일 : json
// SERVICE  String(필수)  서비스명  GeoInfoPublicToiletWGS
// START_INDEX  INTEGER(필수) 요청시작위치  정수 입력 (페이징 시작번호 입니다 : 데이터 행 시작번호)
// END_INDEX  INTEGER(필수) 요청종료위치  정수 입력 (페이징 끝번호 입니다 : 데이터 행 끝번호)
// OBJECTID NUMBER(선택)  고유번호  고유번호

let testVar;

async function getData() {
const url = `http://openapi.seoul.go.kr:8088/${API_KEY}/json/GeoInfoPublicToiletWGS/1/1000`;
const response = await fetch(url);
const data = await response.json();
const row = data["GeoInfoPublicToiletWGS"]["row"];
const toiletData = {};
for (let i = 0; i < row.length; i++) {
  toiletData[i] = {
    // row[i]["GU_NM"],
    // row[i]["HNR_NAM"],
    lat: Number(row[i]["LAT"]),
    lng: Number(row[i]["LNG"]),
  };
}

// return toiletData;
console.log(toiletData);
}

getData();

// Google Maps API
const apiOptions = {
apiKey: "AIzaSyAOpVCT2pyx9Y4gOz3VHodjLEhLfdl56cU",
};

const loader = new Loader(apiOptions);

loader.load().then(() => {
console.log("Maps JS API loaded");

const watchID = navigator.geolocation.watchPosition((pos) => {
  const userCenter = [pos.coords.latitude, pos.coords.longitude];
  console.log(userCenter);

  const map = displayMap(userCenter);
  const markers = addMarkers(map);

  clusterMarkers(map, markers);
  addPanToMarker(map, markers);
});
});

function displayMap(userCenter) {
const mapOptions = {
  center: { lat: userCenter[0], lng: userCenter[1] },
  zoom: 17,
  mapId: "YOUR_MAP_ID",
};
const mapDiv = document.getElementById("map");
return new google.maps.Map(mapDiv, mapOptions);
}

function addMarkers(map) {
// const locations = {
//   operaHouse: { lat: -33.8567844, lng: 151.213108 },
//   tarongaZoo: { lat: -33.8472767, lng: 151.2188164 },
//   manlyBeach: { lat: -33.8209738, lng: 151.2563253 },
//   hyderPark: { lat: -33.8690081, lng: 151.2052393 },
//   theRocks: { lat: -33.8587568, lng: 151.2058246 },
//   circularQuay: { lat: -33.858761, lng: 151.2055688 },
//   harbourBridge: { lat: -33.852228, lng: 151.2038374 },
//   kingsCross: { lat: -33.8737375, lng: 151.222569 },
//   botanicGardens: { lat: -33.864167, lng: 151.216387 },
//   museumOfSydney: { lat: -33.8636005, lng: 151.2092542 },
//   maritimeMuseum: { lat: -33.869395, lng: 151.198648 },
//   kingStreetWharf: { lat: -33.8665445, lng: 151.1989808 },
//   aquarium: { lat: -33.869627, lng: 151.202146 },
//   darlingHarbour: { lat: -33.87488, lng: 151.1987113 },
//   barangaroo: { lat: -33.8605523, lng: 151.1972205 },
// };

const locations = {
  0: { lat: 37.5014009, lng: 127.1586471 },
  1: { lat: 37.6449368, lng: 127.0737283 },
...,
  997: { lat: 37.5798176, lng: 126.8142929 },
  998: { lat: 37.5437052, lng: 126.8452413 },
  999: { lat: 37.5472954, lng: 126.8740311 },
};

const markers = [];
for (const location in locations) {
  const markerOptions = {
    map: map,
    position: locations[location],
    icon: "./img/custom_pin.png",
  };
  const marker = new google.maps.Marker(markerOptions);
  markers.push(marker);
}
return markers;
}

function clusterMarkers(map, markers) {
const clustererOptions = { imagePath: "./img/m" };
const markerCluster = new MarkerClusterer(map, markers, clustererOptions);
}

function addPanToMarker(map, markers) {
let circle;
markers.map((marker) => {
  marker.addListener("click", (event) => {
    const location = { lat: event.latLng.lat(), lng: event.latLng.lng() };
    map.panTo(location);
    if (circle) {
      circle.setMap(null);
    }
    circle = drawCircle(map, location);
  });
});
}

function drawCircle(map, location) {
const circleOptions = {
  strokeColor: "#FF0000",
  strokeOpacity: 0.5,
  strokeWeight: 1,
  map: map,
  center: location,
  radius: 100,
};
const circle = new google.maps.Circle(circleOptions);
return circle;
}




구글 Maps API 사용법

 

https://www.daleseo.com/google-maps-api/

 

<!DOCTYPE html>
<html>

<head>
<title>Simple Map</title>
<meta name="viewport" content="initial-scale=1.0">
<meta charset="utf-8">
<link href="styles.css" rel="stylesheet">
  <script src="app.js"></script>
<script
defer
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAOpVCT2pyx9Y4gOz3VHodjLEhLfdl56cU&callback=initMap"
></script>
</head>

<body>
<div style="height: 600px" id="map"></div>
</body>

</html>

완성본

window.initMap = function () {
const map = new google.maps.Map(document.getElementById("map"), {
  center: { lat: 37.5400456, lng: 126.9921017 },
  zoom: 10,
});

const malls = [
  { label: "C", name: "코엑스몰", lat: 37.5115557, lng: 127.0595261 },
  { label: "G", name: "고투몰", lat: 37.5062379, lng: 127.0050378 },
  { label: "D", name: "동대문시장", lat: 37.566596, lng: 127.007702 },
  { label: "I", name: "IFC몰", lat: 37.5251644, lng: 126.9255491 },
  { label: "L", name: "롯데월드타워몰", lat: 37.5125585, lng: 127.1025353 },
  { label: "M", name: "명동지하상가", lat: 37.563692, lng: 126.9822107 },
  { label: "T", name: "타임스퀘어", lat: 37.5173108, lng: 126.9033793 },
];

// create boundary obj
const bounds = new google.maps.LatLngBounds();
// information window pop up when clicked
const infowindow = new google.maps.InfoWindow();

malls.forEach(({ label, name, lat, lng }) => {
  const marker = new google.maps.Marker({
    position: { lat, lng },
    label,
    map: map,
  });
  bounds.extend(marker.position);

  marker.addListener("click", () => {
    map.panTo(marker.position); // move center to clicked marker
    infowindow.setContent(name);
    infowindow.open({
      anchor: marker,
      map,
    });
  });
});
map.fitBounds(bounds);
};

마커로 위치 표시

window.initMap = function () {
const map = new google.maps.Map(document.getElementById("map"), {
  center: { lat: 37.5400456, lng: 126.9921017 },
  zoom: 10,
});

const malls = [
  { label: "C", name: "코엑스몰", lat: 37.5115557, lng: 127.0595261 },
  { label: "G", name: "고투몰", lat: 37.5062379, lng: 127.0050378 },
  { label: "D", name: "동대문시장", lat: 37.566596, lng: 127.007702 },
  { label: "I", name: "IFC몰", lat: 37.5251644, lng: 126.9255491 },
  { label: "L", name: "롯데월드타워몰", lat: 37.5125585, lng: 127.1025353 },
  { label: "M", name: "명동지하상가", lat: 37.563692, lng: 126.9822107 },
  { label: "T", name: "타임스퀘어", lat: 37.5173108, lng: 126.9033793 },
];

// create boundary obj
const bounds = new google.maps.LatLngBounds();
// information window pop up when clicked
const infowindow = new google.maps.InfoWindow();

malls.forEach(({ label, name, lat, lng }) => {
  const marker = new google.maps.Marker({
    position: { lat, lng },
    label,
    map: map,
  });
  bounds.extend(marker.position);

  marker.addListener("click", () => {
    map.panTo(marker.position); // move center to clicked marker
    infowindow.setContent(name);
    infowindow.open({
      anchor: marker,
      map,
    });
  });
});
map.fitBounds(bounds);
};

지도 경계 조정

마커 위치를 고려하여 딱 맞게 지도를 축소하기

 

window.initMap = function () {
const map = new google.maps.Map(document.getElementById("map"), {
  center: { lat: 37.5400456, lng: 126.9921017 },
  zoom: 10,
});

const malls = [
  { label: "C", name: "코엑스몰", lat: 37.5115557, lng: 127.0595261 },
  { label: "G", name: "고투몰", lat: 37.5062379, lng: 127.0050378 },
  { label: "D", name: "동대문시장", lat: 37.566596, lng: 127.007702 },
  { label: "I", name: "IFC몰", lat: 37.5251644, lng: 126.9255491 },
  { label: "L", name: "롯데월드타워몰", lat: 37.5125585, lng: 127.1025353 },
  { label: "M", name: "명동지하상가", lat: 37.563692, lng: 126.9822107 },
  { label: "T", name: "타임스퀘어", lat: 37.5173108, lng: 126.9033793 },
];

// create boundary obj
const bounds = new google.maps.LatLngBounds();
// information window pop up when clicked
const infowindow = new google.maps.InfoWindow();

malls.forEach(({ label, name, lat, lng }) => {
  const marker = new google.maps.Marker({
    position: { lat, lng },
    label,
    map: map,
  });
  bounds.extend(marker.position);

  marker.addListener("click", () => {
    map.panTo(marker.position); // move center to clicked marker
    infowindow.setContent(name);
    infowindow.open({
      anchor: marker,
      map,
    });
  });
});
map.fitBounds(bounds);
};

클릭 시 정보 보여주기

window.initMap = function () {
const map = new google.maps.Map(document.getElementById("map"), {
  center: { lat: 37.5400456, lng: 126.9921017 },
  zoom: 10,
});

const malls = [
  { label: "C", name: "코엑스몰", lat: 37.5115557, lng: 127.0595261 },
  { label: "G", name: "고투몰", lat: 37.5062379, lng: 127.0050378 },
  { label: "D", name: "동대문시장", lat: 37.566596, lng: 127.007702 },
  { label: "I", name: "IFC몰", lat: 37.5251644, lng: 126.9255491 },
  { label: "L", name: "롯데월드타워몰", lat: 37.5125585, lng: 127.1025353 },
  { label: "M", name: "명동지하상가", lat: 37.563692, lng: 126.9822107 },
  { label: "T", name: "타임스퀘어", lat: 37.5173108, lng: 126.9033793 },
];

// create boundary obj
const bounds = new google.maps.LatLngBounds();
// information window pop up when clicked
const infowindow = new google.maps.InfoWindow();

malls.forEach(({ label, name, lat, lng }) => {
  const marker = new google.maps.Marker({
    position: { lat, lng },
    label,
    map: map,
  });
  bounds.extend(marker.position);

  marker.addListener("click", () => {
    map.panTo(marker.position); // move center to clicked marker
    infowindow.setContent(name);
    infowindow.open({
      anchor: marker,
      map,
    });
  });
});
map.fitBounds(bounds);
};

지도 중심 이동하기

window.initMap = function () {
const map = new google.maps.Map(document.getElementById("map"), {
  center: { lat: 37.5400456, lng: 126.9921017 },
  zoom: 10,
});

const malls = [
  { label: "C", name: "코엑스몰", lat: 37.5115557, lng: 127.0595261 },
  { label: "G", name: "고투몰", lat: 37.5062379, lng: 127.0050378 },
  { label: "D", name: "동대문시장", lat: 37.566596, lng: 127.007702 },
  { label: "I", name: "IFC몰", lat: 37.5251644, lng: 126.9255491 },
  { label: "L", name: "롯데월드타워몰", lat: 37.5125585, lng: 127.1025353 },
  { label: "M", name: "명동지하상가", lat: 37.563692, lng: 126.9822107 },
  { label: "T", name: "타임스퀘어", lat: 37.5173108, lng: 126.9033793 },
];

// create boundary obj
const bounds = new google.maps.LatLngBounds();
// information window pop up when clicked
const infowindow = new google.maps.InfoWindow();

malls.forEach(({ label, name, lat, lng }) => {
  const marker = new google.maps.Marker({
    position: { lat, lng },
    label,
    map: map,
  });
  bounds.extend(marker.position);

  marker.addListener("click", () => {
    map.panTo(marker.position); // move center to clicked marker
    infowindow.setContent(name);
    infowindow.open({
      anchor: marker,
      map,
    });
  });
});
map.fitBounds(bounds);
};

마커로 위치 표시


댓글