Geo-fencing 생성
소개
이 튜토리얼에서는 사용자 위치를 이용하여 구역 검색 API(행정 면형 정보 API) 호출, 그 결과를 토대로 행정경계를 표시하고 어느 행정경계에 포함되는지 안내하는 과정에 대해 설명합니다.
준비
- routo.maps.Map
- routo.maps.Marker
- routo.maps.LatLng
- routo.maps.Data
- routo.maps.Data.Polygon
- REST API > 구역 검색
1. 기본 지도 생성
기본 지도를 생성합니다.
// js
$(function () {
// 1. 기본 지도 생성
const options = {
// 지도 초기 위치
center: { lat : 37.5100, lng: 127.0504 },
// 지도 로딩 시 최초 표시 레벨
zoom: 16,
// 지도 최소 표시 레벨
minZoom: 7,
// 지도 최대 표시 레벨
maxZoom: 19,
// 지도 회전 제한 여부
blockRotation: true,
// 지도에서 keyboard의 Event를 받을 Target 결정
keyboardEventTarget: document,
// Marker를 표시할 레이어의 z-index
markerZIndex: 504,
// Zoom in/out 시 resolution에 따라 고정할 것인지 여부
constrainResolution: true,
// 지도가 표시할 영역을 지정 (국내영역 / 해당 영역 밖으로 이동 불가)
restriction: { west: 124.60, south: 33.114, east: 131.875, north: 42.59 },
// routo logo 위치 지정 : leftTop, leftBottom, rightTop, rightBottom
logoPosition: 'leftBottom',
// routo logo의 상단 또는 하단의 margin 값
logoPositionMargin: 0
};
const map = new routo.maps.Map('map', options);
});
<!-- html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="map" style="width:100%;height:500px;"></div>
</body>
</html>
2. 현재 사용자의 위치 표시
Javascript navigator.geolocation를 이용하여 현재 사용자의 위치를 지도에 마커로 표시합니다.
// js
$(function () {
// 1. 기본 지도 생성
const options = {
// 지도 초기 위치
center: { lat : 37.5100, lng: 127.0504 },
// 지도 로딩 시 최초 표시 레벨
zoom: 16,
// 지도 최소 표시 레벨
minZoom: 7,
// 지도 최대 표시 레벨
maxZoom: 19,
// 지도 회전 제한 여부
blockRotation: true,
// 지도에서 keyboard의 Event를 받을 Target 결정
keyboardEventTarget: document,
// Marker를 표시할 레이어의 z-index
markerZIndex: 504,
// Zoom in/out 시 resolution에 따라 고정할 것인지 여부
constrainResolution: true,
// 지도가 표시할 영역을 지정 (국내영역 / 해당 영역 밖으로 이동 불가)
restriction: { west: 124.60, south: 33.114, east: 131.875, north: 42.59 },
// routo logo 위치 지정 : leftTop, leftBottom, rightTop, rightBottom
logoPosition: 'leftBottom',
// routo logo의 상단 또는 하단의 margin 값
logoPositionMargin: 0
};
const map = new routo.maps.Map('map', options);
// 2. 현재 사용자의 위치 표시
const getLocation = () => {
if (navigator.geolocation) { // GPS를 지원하면
navigator.geolocation.getCurrentPosition(function(position) {
// 좌표 표시
$('#coordinates').html(`<p style="margin-top:10px;font-size:15px;text-align: left;">현재 사용자 위치: ${position.coords.latitude + ' ' + position.coords.longitude}</p>`);
// 마커 추가
const lng = position.coords.longitude;
const lat = position.coords.latitude;
const markerOption = {
position: {
lat: lat,
lng: lng
},
map: map
};
const userPositionMarker = new routo.maps.Marker(markerOption);
// 마커로 지도 이동
map.setCenter(markerOption.position);
}, function(error) {
console.error(error);
}, {
enableHighAccuracy: false,
maximumAge: 0,
timeout: Infinity
});
} else {
alert('GPS를 지원하지 않습니다');
}
}
getLocation();
});
<!-- html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="map" style="width:100%;height:500px;"></div>
<div id="coordinates" style="background-color: beige;"></div>
</body>
</html>
3. 구역 검색 API를 이용한 행정경계 표시
사용자 위치 기반으로 구역 검색 API를 호출하여 행정경계 Polygon을 지도에 표시합니다.
// js
$(function () {
// 1. 기본 지도 생성
const options = {
// 지도 초기 위치
center: { lat : 37.5100, lng: 127.0504 },
// 지도 로딩 시 최초 표시 레벨
zoom: 16,
// 지도 최소 표시 레벨
minZoom: 7,
// 지도 최대 표시 레벨
maxZoom: 19,
// 지도 회전 제한 여부
blockRotation: true,
// 지도에서 keyboard의 Event를 받을 Target 결정
keyboardEventTarget: document,
// Marker를 표시할 레이어의 z-index
markerZIndex: 504,
// Zoom in/out 시 resolution에 따라 고정할 것인지 여부
constrainResolution: true,
// 지도가 표시할 영역을 지정 (국내영역 / 해당 영역 밖으로 이동 불가)
restriction: { west: 124.60, south: 33.114, east: 131.875, north: 42.59 },
// routo logo 위치 지정 : leftTop, leftBottom, rightTop, rightBottom
logoPosition: 'leftBottom',
// routo logo의 상단 또는 하단의 margin 값
logoPositionMargin: 0
};
const map = new routo.maps.Map('map', options);
// 2. 현재 사용자의 위치 표시
const getLocation = () => {
if (navigator.geolocation) { // GPS를 지원하면
navigator.geolocation.getCurrentPosition((position) => {
// 좌표 표시
$('#coordinates').html(`<p style="margin-top:10px;font-size:15px;text-align: left;">현재 사용자 위치: ${position.coords.latitude + ' ' + position.coords.longitude}</p>`);
// 마커 추가
const lng = position.coords.longitude;
const lat = position.coords.latitude;
const markerOption = {
position: {
lat: lat,
lng: lng
},
map: map
};
const userPositionMarker = new routo.maps.Marker(markerOption);
// 마커로 지도 이동
map.setCenter(markerOption.position);
// 3.구역 검색 API를 이용한 행정경계 표시
callDistrict(markerOption.position);
}, function(error) {
console.error(error);
}, {
enableHighAccuracy: false,
maximumAge: 0,
timeout: Infinity
});
} else {
alert('GPS를 지원하지 않습니다');
}
}
getLocation();
// 구역 검색 API를 이용한 행정경계 표시
const callDistrict = (position) => {
const key = `AB7B15940E89447C`;
const districtApiUrl = `https://api.routo.com/v1/district?latlng=${position.lat},${position.lng}&kind=gemd&option=shape&key=${key}`;
fetch(districtApiUrl).then(function(response) {
return response.json();
}).then(function(data) {
// 행정경계 생성
const prop = { ...data };
delete prop.geometry;
// Geometry 좌표 타입 변환(Array => LatLng)
const convertGeom = [];
for(let i in data.geometry.coordinates){
const coordinates = data.geometry.coordinates[i];
const coords = [];
for(let j in coordinates){
const coord = coordinates[j];
const latlng = new routo.maps.LatLng(coord[1], coord[0]);
const latlngJson = latlng.toJSON();
coords.push(latlngJson);
}
convertGeom.push(coords);
}
// Polygon 생성
const polygon = new routo.maps.Data.Polygon(convertGeom);
// 행정경계 추가
map.data.add({
id: 1,
geometry: polygon,
properties: prop
});
// 지도 이동
map.fitBounds(polygon.getBounds(), [100, 100, 100, 100]);
}).catch(function(error) {
console.log(error);
});
}
});
<!-- html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="map" style="width:100%;height:500px;"></div>
</body>
</html>
4. 결과 확인
사용자 위치가 현재 어떤 행정경계에 속하였는지 표시합니다.
// js
$(function () {
// 1. 기본 지도 생성
const options = {
// 지도 초기 위치
center: { lat : 37.5100, lng: 127.0504 },
// 지도 로딩 시 최초 표시 레벨
zoom: 16,
// 지도 최소 표시 레벨
minZoom: 7,
// 지도 최대 표시 레벨
maxZoom: 19,
// 지도 회전 제한 여부
blockRotation: true,
// 지도에서 keyboard의 Event를 받을 Target 결정
keyboardEventTarget: document,
// Marker를 표시할 레이어의 z-index
markerZIndex: 504,
// Zoom in/out 시 resolution에 따라 고정할 것인지 여부
constrainResolution: true,
// 지도가 표시할 영역을 지정 (국내영역 / 해당 영역 밖으로 이동 불가)
restriction: { west: 124.60, south: 33.114, east: 131.875, north: 42.59 },
// routo logo 위치 지정 : leftTop, leftBottom, rightTop, rightBottom
logoPosition: 'leftBottom',
// routo logo의 상단 또는 하단의 margin 값
logoPositionMargin: 0
};
const map = new routo.maps.Map('map', options);
// 2. 현재 사용자의 위치 표시
const getLocation = () => {
if (navigator.geolocation) { // GPS를 지원하면
navigator.geolocation.getCurrentPosition((position) => {
// 좌표 표시
$('#coordinates').html(`<p style="margin-top:10px;font-size:15px;text-align: left;">현재 사용자 위치: ${position.coords.latitude + ' ' + position.coords.longitude}</p>`);
// 마커 추가
const lng = position.coords.longitude;
const lat = position.coords.latitude;
const markerOption = {
position: {
lat: lat,
lng: lng
},
map: map
};
const userPositionMarker = new routo.maps.Marker(markerOption);
// 마커로 지도 이동
map.setCenter(markerOption.position);
// 3.구역 검색 API를 이용한 행정경계 표시
callDistrict(markerOption.position);
}, function(error) {
console.error(error);
}, {
enableHighAccuracy: false,
maximumAge: 0,
timeout: Infinity
});
} else {
alert('GPS를 지원하지 않습니다');
}
}
getLocation();
// 구역 검색 API를 이용한 행정경계 표시
const callDistrict = (position) => {
const key = `AB7B15940E89447C`;
const districtApiUrl = `https://api.routo.com/v1/district?latlng=${position.lat},${position.lng}&kind=gemd&option=shape&key=${key}`;
fetch(districtApiUrl).then(function(response) {
return response.json();
}).then(function(data) {
// 행정경계 생성
const prop = { ...data };
delete prop.geometry;
// Geometry 좌표 타입 변환(Array => LatLng)
const convertGeom = [];
for(let i in data.geometry.coordinates){
const coordinates = data.geometry.coordinates[i];
const coords = [];
for(let j in coordinates){
const coord = coordinates[j];
const latlng = new routo.maps.LatLng(coord[1], coord[0]);
const latlngJson = latlng.toJSON();
coords.push(latlngJson);
}
convertGeom.push(coords);
}
// Polygon 생성
const polygon = new routo.maps.Data.Polygon(convertGeom);
// 행정경계 추가
map.data.add({
id: 1,
geometry: polygon,
properties: prop
});
// 지도 이동
map.fitBounds(polygon.getBounds(), [100, 100, 100, 100]);
// 4. 결과 확인
let tag = `당신은 ${prop['state']} ${prop['city']} ${prop['town']} 에 있습니다.`;
for(let k in prop){
const attr = k;
const value = prop[k];
tag += `<p style="margin-top:10px;font-size:15px;text-align: left;">- ${attr}: ${value}</p>`;
}
$('#result').html(tag);
}).catch(function(error) {
console.log(error);
});
}
});
<!-- html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="map" style="width:100%;height:500px;"></div>
<div id="result" style="background-color: beige;"></div>
</body>
</html>