저번 포스팅에서 이어서 이번에는 현재 위치를 실시간으로 표현해보자
현재 위치 실시간으로 표시하기
//================================================= 현위치 실시간 업데이트
function current_update() {
$.ajax({
url: '/h/get/current_point.php',
method: 'GET',
dataType: 'json',
success: function(data) {
current_value = data;
// 문자열을 배열로 변환 후 숫자로 변환
current_point = current_value.split(',').map(Number);
current_lat = current_point[0];
current_lng = current_point[1];
// 기존 마커 제거
if (currentMarker) {
map.removeLayer(currentMarker);
}
currentMarker = L.marker([current_lat, current_lng], {
icon: currentIcon
})
.addTo(map)
.bindPopup("현재 위치");
},
error: function(jqXHR, textStatus, errorThrown) {
console.error('오류:', textStatus, errorThrown);
}
});
}
너무 뒤죽박죽인 것 같아서...
코드 가독성을 위해 싹 정리했다.
추가)
1) 현위치 실시간 마커로 받아오기
2) 출발지와 도착지 바꾸기
3) 현위치 버튼 누르면 지도 뷰 다시 조정하고 출발지도 다시 설정하기
전체 코드
[index.html]
<?php
include($_SERVER['DOCUMENT_ROOT'] . "/h/db/db.php");
$user_id = $_SESSION['id'];
$sql = "SELECT * FROM `route` WHERE `id` = " . $user_id . "";
$user_id;
$res = mysqli_query($conn, $sql);
$row = mysqli_fetch_array($res);
($row['current_point'] != null) ? $current_point = $row['current_point'] : $current_point = '1';
?>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>e-navi</title>
<link rel="stylesheet" href="/h/css/index.css?css=3">
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<link rel="stylesheet" href="https://unpkg.com/leaflet-routing-machine/dist/leaflet-routing-machine.css" />
</head>
<body>
<div id="popup">
<div class="search_left">
<button class="btn btn_change" onclick="position_change()">
<div>
<span>▲</span>
<span>▼</span>
</div>
</button>
</div>
<div class="search">
<input type="text" id="current" class="current" value='<?php echo $current_point; ?>'>
<input type="text" id="start" class="start" placeholder="출발지 입력">
<input type="text" id="end" class="end" placeholder="도착지 입력">
</div>
<div class="search_right">
<button class="btn btn_current" onclick="set_current()">현위치</button>
<button class="btn btn_search" onclick="get_route()">찾기</button>
</div>
</div>
<div id="map"></div>
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<script src="https://unpkg.com/leaflet-routing-machine/dist/leaflet-routing-machine.js"></script>
<script src="https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.js"></script>
<script src="/h/plugins/jquery/jquery.min.js"></script>
<script>
//================================================= 변수 정의
var current_value; // 위도, 경도 (문자열)
var current_point; // [위도, 경도] (배열로 변환)
var current_lat; // 위도
var current_lng; // 경도
var map; // 맵
var currentIcon; // 현재 아이콘 설정
var currentMarker; // 현재 위치 마커 띄우기
var startMarker; // 출발지 마커 띄우기
var endMarker; // 도착지 마커 띄우기
var control; // 경로 탐색 기능
//================================================= 초기 설정
$(document).ready(function() {
$.ajax({
url: '/h/get/current_point.php',
method: 'GET',
dataType: 'json',
success: function(data) {
//----------------------------------------------- 초기 위치 1회 가져오기
current_value = data;
// 문자열을 배열로 변환 후 숫자로 변환
current_point = current_value.split(',').map(Number);
current_lat = current_point[0];
current_lng = current_point[1];
//----------------------------------------------- 지도 생성 # 코드 위치 옮기지 말 것
// 지도의 맨 처음 위치를 현위치로 설정
map = L.map('map').setView(current_point, 16);
// OpenStreetMap 지도 타일 레이어 추가
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
}).addTo(map);
//----------------------------------------------- 역지오코딩한 현재 위치 출발지에 넣기 (1회)
nearbuilding(current_lat, current_lng);
//----------------------------------------------- 현재 위치 마커 찍기 (1회)
currentIcon = L.icon({
iconUrl: '/h/img/current.png',
iconSize: [15, 15],
iconAnchor: [7.5, 7.5],
});
currentMarker = L.marker([current_lat, current_lng], {
icon: currentIcon
})
.addTo(map)
.bindPopup("현재 위치");
//----------------------------------------------- 경로 탐색 기능 불러오기
control = L.Routing.control({
waypoints: [],
routeWhileDragging: true,
geocoder: L.Control.Geocoder.nominatim(),
createMarker: function() {
return null;
} // 기본 마커 비활성화
}).addTo(map);
//----------------------------------------------- 길찾기 팝업 숨기기
control.getContainer().style.display = 'none';
//----------------------------------------------- 확대/축소 컨트롤 숨기기
var zoomControl = map.zoomControl;
if (zoomControl) {
zoomControl.remove();
}
//현위치 업데이트
setInterval(current_update, 1000);
},
error: function(jqXHR, textStatus, errorThrown) {
console.error('오류:', textStatus, errorThrown);
}
});
});
/* function 모음 */
//================================================= 현위치 실시간 업데이트
function current_update() {
$.ajax({
url: '/h/get/current_point.php',
method: 'GET',
dataType: 'json',
success: function(data) {
current_value = data;
// 문자열을 배열로 변환 후 숫자로 변환
current_point = current_value.split(',').map(Number);
current_lat = current_point[0];
current_lng = current_point[1];
// 기존 마커 제거
if (currentMarker) {
map.removeLayer(currentMarker);
}
currentMarker = L.marker([current_lat, current_lng], {
icon: currentIcon
})
.addTo(map)
.bindPopup("현재 위치");
},
error: function(jqXHR, textStatus, errorThrown) {
console.error('오류:', textStatus, errorThrown);
}
});
}
//================================================= 역지오코딩으로 가까운 건물 찾기
function nearbuilding(lat, lng) {
var url = `https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lng}&format=json`;
fetch(url)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok ' + response.statusText);
}
return response.json();
})
.then(data => {
if (data && data.display_name) {
var city = data.address.city;
var borough = data.address.borough;
var road = data.address.road;
var address = city + ' ' + borough + ' ' + road
document.getElementById('start').value = address; // 출발지 입력란에 설정
} else {
alert('가장 가까운 위치를 찾을 수 없습니다.');
}
})
.catch(error => {
console.error('Error:', error);
alert('위치를 찾는 중 오류가 발생했습니다.');
});
}
//================================================= 경로 찾기 함수
function get_route() {
var start = document.getElementById('start').value;
var end = document.getElementById('end').value;
if (start && end) {
L.Control.Geocoder.nominatim().geocode(start, function(results) {
if (results.length > 0) {
var startLatLng = results[0].center;
L.Control.Geocoder.nominatim().geocode(end, function(results) {
if (results.length > 0) {
var endLatLng = results[0].center;
// 출발지와 도착지 설정
control.setWaypoints([
L.latLng(startLatLng.lat, startLatLng.lng),
L.latLng(endLatLng.lat, endLatLng.lng)
]);
// 기존 마커 제거
if (startMarker) {
map.removeLayer(startMarker);
}
if (endMarker) {
map.removeLayer(endMarker);
}
// 출발지 마커 추가
var startIcon = L.icon({
iconUrl: '/h/img/start.png', // start.png의 경로
iconSize: [30, 41], // 아이콘 크기
iconAnchor: [15, 41], // 아이콘 기준점
});
startMarker = L.marker(startLatLng, {
icon: startIcon
})
.addTo(map)
.bindPopup("출발지: " + start);
// 도착지 마커 추가
var endIcon = L.icon({
iconUrl: '/h/img/end.png', // end.png의 경로
iconSize: [30, 41], // 아이콘 크기
iconAnchor: [15, 41], // 아이콘 기준점
});
endMarker = L.marker(endLatLng, {
icon: endIcon
}).addTo(map).bindPopup("도착지: " + end);
// 경로 정보 요청
// 이벤트 리스너가 중복 추가되지 않도록 설정
control.once('routesfound', function(e) {
var routes = e.routes;
// 경로 정보를 가져온 후 지도 뷰를 설정
var firstRoute = routes[0];
var waypoints = firstRoute.coordinates;
var bounds = L.latLngBounds(waypoints); // 모든 경로의 경계 계산
map.fitBounds(bounds); // 경로에 맞게 지도를 조정
var all = waypoints.map(coord => `"${coord.lat}, ${coord.lng}"`).join(',');
var distance = firstRoute.summary.totalDistance;
var routeTime = firstRoute.summary.totalTime;
var index = firstRoute.instructions.map(instruction => instruction.index);
var locations = index.map(index => {
var coord = waypoints[index];
return coord ? `${coord.lat}, ${coord.lng}` : null;
}).filter(coord => coord !== null);
// AJAX 요청으로 데이터베이스 업데이트
update_db(routes, start, end, locations, distance, routeTime, index, all);
});
} else {
alert('도착지를 찾을 수 없습니다.');
}
});
} else {
alert('출발지를 찾을 수 없습니다.');
}
});
} else {
alert('출발지와 도착지를 모두 입력하세요.');
}
}
//================================================= 데이터베이스 업데이트 함수
function update_db(routes, start, end, locations, distance, routeTime, index, all) {
var xhr = new XMLHttpRequest();
xhr.open("POST", "update_route.php", true);
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
// console.log('데이터베이스 업데이트 성공:', xhr.responseText);
} else {
console.error('업데이트 실패:', xhr.status, xhr.statusText);
}
}
};
xhr.send(JSON.stringify({
start_point: start,
end_point: end,
locations: JSON.stringify(locations).slice(1, -1),
distance: distance,
route_time: routeTime,
all: all
}));
// console.log(routes);
// console.log(index);
// console.log(all);
// console.log(JSON.stringify(locations).slice(1, -1));
}
//================================================= 출발지와 도착지 서로 변경
function position_change() {
// 값 잃어버릴 수 있으니 저장함
var startValue = $('#start').val();
var endValue = $('#end').val();
$('#start').val(endValue);
$('#end').val(startValue);
}
//================================================= 출발지 현위치로 설정
function set_current() {
nearbuilding(current_lat, current_lng);
//지도 뷰를 현위치로 돌려놓기!!!!!!!!!!!!!!
map.setView([current_lat, current_lng], 16);
}
</script>
</body>
</html>
[current_point.php] (현 위치 위도,경도 반환)
<?php
include($_SERVER['DOCUMENT_ROOT'] . "/h/db/db.php");
$user_id = $_SESSION['id'];
$sql = "SELECT current_point FROM `route` WHERE `id` = $user_id";
$res = mysqli_query($conn, $sql);
$row = mysqli_fetch_array($res);
($row['current_point'] != null) ? $current_point = $row['current_point'] : $current_point = '1';
echo json_encode($current_point);
?>
[update_route.php] (DB에 검색된 경로 저장)
<?php
include($_SERVER['DOCUMENT_ROOT'] . "/h/db/db.php");
// JSON 형식의 POST 데이터 읽기
$data = json_decode(file_get_contents("php://input"), true);
// 로그 파일에 데이터 기록
file_put_contents('log.txt', print_r($data, true), FILE_APPEND);
// POST 데이터 받기
$user_id = $_SESSION['id'];
$current_point = $data['current_point'];
$start_point = $data['start_point'];
$end_point = $data['end_point'];
$locations = $data['locations'];
$distance = $data['distance'];
$route_time = (int)$data['route_time'];
$all = $data['all'];
// 먼저 ID가 1인 레코드가 존재하는지 확인
$sql_check = "SELECT * FROM `route` WHERE `id` = '" . $user_id . "'";
$result = $conn->query($sql_check);
if ($result->num_rows > 0) {
$sql_up = "UPDATE `route` set
`user` = '" . $user_id . "',
`start_point` = '" . $start_point . "',
`end_point` = '" . $end_point . "',
`locations` = '" . $locations . "',
`distance` = '" . $distance . "',
`route_time` = '" . $route_time . "',
`all` = '" . $all . "'
WHERE id= '" . $user_id . "'
";
$res_up = mysqli_query($conn, $sql_up);
if ($res_up) {
echo "업데이트 성공";
} else {
echo "업데이트 실패: " . mysqli_error($conn);
}
} else {
// ID가 1인 레코드가 없을 경우 새 레코드 생성
$sql_in = "INSERT INTO `route`
(
`user`,
`start_point`,
`end_point`,
`locations`,
`distance`,
`route_time`,
`all`
)
VALUES
(
'" . $user_id . "',
'" . $start_point . "',
'" . $end_point . "',
'" . $locations . "',
'" . $distance . "',
'" . $route_time . "',
'" . $all . "'
)
';
";
$res_in = mysqli_query($conn, $sql_in);
if ($res_in) {
echo "생성 성공";
} else {
echo "생성 실패: " . mysqli_error($conn);
}
}
$conn->close();
제대로 따라오셨다면 폴더구조는 다음과 같다.
[결과 화면]
1) 현위치 실시간 마커로 받아오기
2) 출발지와 도착지 바꾸기
3) 현위치 버튼 누르면 지도 뷰 다시 조정하고 출발지도 다시 설정하기
세가지 기능 모두 잘 작동한다 :)
'Project > 내비게이션' 카테고리의 다른 글
[OSM] 내비게이션 어플리케이션 개발 (1) (1) | 2024.09.23 |
---|---|
[OSM]OpenStreetMap을 이용한 내비게이션 만들기 - 3 (16) | 2024.09.19 |
[OSM]OpenStreetMap을 이용한 내비게이션 만들기 - 2 (2) | 2024.09.13 |
[OSM]OpenStreetMap을 이용한 내비게이션 만들기 - 1 (2) | 2024.09.09 |