그누보드 카카오 맵 연동 (2)
제작 방법 설명 :
지난 시간에 이어서 플러그인 좀 더 구체화 하는 작업을 해볼까 한다.
우선 지도를 확대 시키면 왼쪽에 메뉴가 아작스로 정보가 바뀌는건데 지도와 연동 되서 해야되서...
맛집 배달 게시판 플러그인에 보면 주소가 등록은 됐는데~ 위도와 경로는 빠져 있어서 수정 작업해야 한다.
여기서 부터 포스팅 글 남겨 본다.
구글링으로 찾아보니까 curl 로 지도 api 이용해서 조회하는 함수를 찾았다.
function kakao_request($path, $query, $content_type = 'json', $api_key)
{
$api_server = 'https://dapi.kakao.com';
$headers = array('Authorization: KakaoAK '.$api_key.'');
$opts = array(
CURLOPT_URL => $api_server . $path . '.' . $content_type . '?' . $query,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSLVERSION => 1,
CURLOPT_HEADER => false,
CURLOPT_HTTPHEADER => $headers
);
$curl_session = curl_init();
curl_setopt_array($curl_session, $opts);
$return_data = curl_exec($curl_session);
if (curl_errno($curl_session)) {
throw new Exception(curl_error($curl_session));
} else {
curl_close($curl_session);
return json_decode($return_data, true);
}
}
위에 함수를 이용해서 사용법을 풀이하자면 아래 소스 코드 참고하면 된다.
여기 매뉴얼을 참고하면 된다.
https://developers.kakao.com/docs/latest/ko/local/dev-guide#coord-to-address
일단 query 짜는 부분을 수정 해야 한다.
wr_gps로 필드를 만들어 주고 여기다가 insert 할때는 point로 저장해야된다.
point로 쓸때 mysql 버전 마다 다르기 때문에 아래 주소 참고해서 한다.
버전때가 MySQL 5.1.35 이전이면 아래꺼로 쓰면된다.
INSERT INTO t1 (pt_col) VALUES (GeomFromWKB(Point(1,2)));
이후 버전이면 아래꺼 쓰면된다.
INSERT INTO t1 (pt_col) VALUES(Point(1,2));
사실상 POINT로 쓰면 될것이다 mysql 버전때 5.5, 5.7 그리고 8이상 쓰는 경우가 있다.
$path = '/v2/local/search/address';
$content_type = 'json'; // json or xml
$params = http_build_query(array(
'page' => 1,
'size' => 10,
'query' => $wr_3
));
$res = kakao_request($path, $params, $content_type, $config['cf_kakao_rest_key']);
$gps = $res['documents'][0]['y'].",".$res['documents'][0]['x'];
$wr_gps = " (POINT(".$gps.")) ";
// 쿼리 짜는건 이렇게..
$sql = "wr_gps = $wr_gps";
그 다음에는 조회를 할때는 이 방식으로 한다.
https://jichun.tistory.com/191
$cord = $_REQUEST['min_map_latitude']." ".$_REQUEST['min_map_longitude'].", ".$_REQUEST['max_map_latitude']." ".$_REQUEST['max_map_longitude'];
if($cord) {
$sql_search .= " where MBRContains(GeomFromText('LineString($cord)'), `wr_gps`)";
}
여기서 현재 위치가 안된다.
찾아보니까 현재 위치 소스는 정상적인데 시스템 환경이 제대로 주어지지 않아서 그렇다.
조건은 이렇다.
- https (기본)
- localhost (예외)
https://devtalk.kakao.com/t/getcurrentposition-geolocation/108794
<?php
if (!$sst) {
$sst = "wr_id";
$sod = "asc";
}
$sql_search = " where wr_is_comment = 0 ";
$sql_order = " order by $sst $sod ";
$sql_common = " from {$g5['foodelivery_form_table']} ";
$sql = " select count(*) as cnt {$sql_common} {$sql_search} {$sql_order} ";
$row = sql_fetch($sql);
$total_count = $row['cnt'];
$rows = 10;
$total_page = ceil($total_count / $rows); // 전체 페이지 계산
if ($page < 1) { $page = 1; } // 페이지가 없으면 첫 페이지 (1 페이지)
$from_record = ($page - 1) * $rows; // 시작 열을 구함
$sql = " select * {$sql_common} {$sql_search} {$sql_order} limit {$from_record}, {$rows} ";
$result = sql_query($sql);
add_stylesheet('<link rel="stylesheet" href="'.BV_MAP_PLUGIN_URL.'/style.css">', 0);
?>
<div class="beaver_map_area">
<div class="map_area">
<div id="map"></div>
<a id="currentPositionBtn" href="#" onclick="getCurrentPositionEvent(); return false;">
<span class="current"><i class="fa fa-crosshairs"></i>현위치</span>
</a>
</div>
<div class="map_list">
<div class="wrapper">
<div class="head">
<span class="total_count">조회 <?php echo $total_count ?>건</span>
</div>
<ul class="body">
<?php
for ($i=0;$row = sql_fetch_array($result);$i++) {
$img = get_fd_image_data($row['token_id'],'limit 1');
?>
<li>
<a class="list_item" href="<?php echo get_pretty_url(FD,$row['wr_id'])?>" target="_blank">
<div class="thumb_area">
<?php foreach ($img as $item) { ?>
<img class="thumb" src="<?=$item['bf_thumburl']?>" width="<?=$item['bf_width']?>" height="<?=$item['bf_height']?>" />
<?php } ?>
</div>
<div class="content_area">
<div class="title">
<?php echo $row['wr_subject']?>
</div>
<div class="content">
<?php echo $row['wr_content']?>
</div>
</div>
</a>
</li>
<?php } ?>
<?php if($i == 0) echo "<li id='empty_map'>조회 된 정보가 없습니다.</li>"; ?>
</ul>
<div id="page_navigation">
<?php echo get_paging(G5_IS_MOBILE ? $config['cf_mobile_pages'] : $config['cf_write_pages'], $page, $total_page, $qstr.'&page='); ?>
</div>
</div>
</div>
</div>
여기서 스크립트 부분은 아래 처럼 하면된다.
var plugin_url = "<?=BV_MAP_PLUGIN_URL?>";
var current_latitude = '';
var current_longitude = '';
var kakaoMap = '';
var kakaoMarkers = [];
var kakaoMarkerCluster = '';
var kakaoCustomOverlays = [];
var latlng_bounds = '';
var latlng_north_east,
latlng_south_west,
max_map_latitude,
max_map_longitude,
min_map_latitude,
min_map_longitude;
function ajaxMapLoad(){
kakaoMap = map;
for(i=0; i<kakaoMarkers.length; i++){
kakaoMarkers[i].setMap(null);
}
for(i=0; i<kakaoCustomOverlays.length; i++){
kakaoCustomOverlays[i].setMap(null);
}
kakaoMarkers = [];
kakaoCustomOverlays = [];
if(kakaoMap){
latlng_bounds = kakaoMap.getBounds();
latlng_north_east = latlng_bounds.getNorthEast();
latlng_south_west = latlng_bounds.getSouthWest();
max_map_latitude = latlng_north_east.getLat();
max_map_longitude = latlng_north_east.getLng();
min_map_latitude = latlng_south_west.getLat();
min_map_longitude = latlng_south_west.getLng();
}
let ajax_data = {
'min_map_latitude':min_map_latitude,
'max_map_latitude':max_map_latitude,
'min_map_longitude':min_map_longitude,
'max_map_longitude':max_map_longitude,
};
$.ajax({
type: 'post',
url: plugin_url + '/get_map_data.php',
data: ajax_data,
dataType:'html',
success: function (data) {
let response = $(data);
$('.map_list').html(response.find('.map_list .wrapper'));
ajaxMenuLoad(ajax_data);
}
});
}
function ajaxMenuLoad(ajax_data) {
$.ajax({
type: 'post',
url: plugin_url + '/get_list_data.php',
data: ajax_data,
dataType:'json',
success: function (data) {
$.each(data.result,function(i,item){
let latitude = parseFloat(item.latitude);
let longitude = parseFloat(item.longitude);
kakaoMarkers[i] = new kakao.maps.Marker({
position: new kakao.maps.LatLng(latitude, longitude)
});
kakaoMarkers[i].setMap(kakaoMap);
kakao.maps.event.addListener(kakaoMarkers[i], 'click', function() {
kakaoCustomOverlays[i].setMap(kakaoMap);
});
kakaoCustomOverlays[i] = new kakao.maps.CustomOverlay({
position: new kakao.maps.LatLng(latitude, longitude),
content: `
<div class="kakao_custom_overlay">
<div class="map_item_overlay_html">
<a class="list_item" href="${item.href}" target="_blank">
<div class="thumb_area">
<img class="thumb" src="${item.bf_thumburl}" width="${item.bf_width}" height="${item.bf_height}" />
</div>
<div class="content_area">
<div class="title">
${item.shop_name}
</div>
</div>
</a>
</div>
<span class="arrow"></span>
</div>`
});
});
if(kakaoMarkerCluster){
kakaoMarkerCluster.clear();
}
kakaoMarkerCluster = new kakao.maps.MarkerClusterer({
map: kakaoMap,
averageCenter: true,
minLevel: 1,
gridSize: 60,
disableClickZoom: true,
calculator: [9, 99, 999, 9999,99999],
styles: [{
width : '50px',
height : '50px',
background: 'rgba(126, 142, 227, .7)',
borderRadius: '28px',
color: '#FFF',
textAlign: 'center',
fontWeight: 'bold',
fontSize: '20px',
lineHeight: '50px',
border: '2px solid rgba(126, 142, 227, .9)'
},
{
width : '56px',
height : '56px',
background: 'rgba(255, 134, 74, .7)',
borderRadius: '31px',
color: '#FFF',
textAlign: 'center',
fontWeight: 'bold',
fontSize: '20px',
lineHeight: '56px',
border: '2px solid rgba(255, 134, 74, .9)'
},
{
width : '60px',
height : '60px',
background: 'rgba(255, 72, 50, .7)',
borderRadius: '33px',
color: '#FFF',
textAlign: 'center',
fontWeight: 'bold',
fontSize: '18px',
lineHeight: '60px',
border: '2px solid rgba(255, 72, 50, .9)'
},
{
width : '60px',
height : '60px',
background: 'rgba(217, 84, 189, .7)',
borderRadius: '33px',
color: '#FFF',
textAlign: 'center',
fontWeight: 'bold',
fontSize: '18px',
lineHeight: '60px',
border: '2px solid rgba(217, 84, 189, .9)'
},
{
width : '60px',
height : '60px',
background: 'rgba(147, 84, 217, .7)',
borderRadius: '33px',
color: '#FFF',
textAlign: 'center',
fontWeight: 'bold',
fontSize: '18px',
lineHeight: '60px',
border: '2px solid rgba(147, 84, 217, .9)'
}
]
});
kakaoMarkerCluster.addMarkers(kakaoMarkers);
kakao.maps.event.addListener(kakaoMarkerCluster, 'clusterclick', function(cluster) {
var latlng_bounds = cluster.getBounds();
latlng_north_east = latlng_bounds.getNorthEast();
latlng_south_west = latlng_bounds.getSouthWest();
max_map_latitude = latlng_north_east.getLat();
max_map_longitude = latlng_north_east.getLng();
min_map_latitude = latlng_south_west.getLat();
min_map_longitude = latlng_south_west.getLng();
let ajax_data = {
'min_map_latitude':min_map_latitude,
'max_map_latitude':max_map_latitude,
'min_map_longitude':min_map_longitude,
'max_map_longitude':max_map_longitude,
};
$.ajax({
type: 'post',
url: plugin_url + '/get_map_data.php',
data: ajax_data,
dataType:'html',
success: function (data) {
let response = $(data);
$('.map_list').html(response.find('.map_list .wrapper'));
}
});
});
},
error: function (request, status, error) {
console.log('code: '+request.status+"\n"+'message: '+request.responseText+"\n"+'error: '+error);
return false;
}
})
}
var marker = '';
var container = document.getElementById('map');
var position = new kakao.maps.LatLng(37.493619044107106, 127.06653626780998);
var options = {
center: position,
level: 14,
disableDoubleClick: false,
disableDoubleClickZoom: false,
draggable: true
};
var map = new kakao.maps.Map(container, options);
var mapTypeControl = new kakao.maps.MapTypeControl();
map.addControl(mapTypeControl, kakao.maps.ControlPosition.TOPRIGHT);
var zoomControl = new kakao.maps.ZoomControl();
map.addControl(zoomControl, kakao.maps.ControlPosition.RIGHT);
ajaxMapLoad();
kakao.maps.event.addListener(map, 'idle', function() {
if(marker) marker.setMap(null);
ajaxMapLoad();
});
function getCurrentPositionEvent() {
//GPS를 지원하면
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
current_latitude = position.coords.latitude;
console.log(current_latitude);
current_longitude = position.coords.longitude;
//카카오지도 현위치를 센터로
if(map){
var change_position = new daum.maps.LatLng(current_latitude, current_longitude);
map.setCenter(change_position);
}
}, function error(e) {
if(e.code==1){
alert('사용자가 위치정보 권한을 제공하지 않습니다.');
} else if(e.code==2){
alert('브라우저가 위치를 가져올 수 없습니다.');
} else if(e==3){
alert(e.code);
} else {
alert(e.message);
}
}, {
enableHighAccuracy: true,
maximumAge: 0,
timeout: 2000
});
}
//GPS를 지원하지 않으면
else {
alert('현위치 기능을 사용할 수 없습니다. 현위치 접근권한이 있는지 확인하시기 바랍니다.');
}
}
$(document).ready(function(){
$('body').attr('oncontextmenu','return false');
$('body').attr('ondragstart','return false');
$('body').attr('onselectstart','return false');
});
/get_list_data.php 파일을 만든다.
include_once "./_common.php";
$sql_search = " where wr_is_comment = 0 ";
$cord = $_REQUEST['min_map_latitude']." ".$_REQUEST['min_map_longitude'].", ".$_REQUEST['max_map_latitude']." ".$_REQUEST['max_map_longitude'];
if($cord) {
$sql_search .= " and MBRContains(GeomFromText('LineString($cord)'), `wr_gps`)";
}
$sql_order = " order by wr_id asc ";
$sql_common = " from {$g5['foodelivery_form_table']} ";
$sql = " select *, X(wr_gps)AS latitude, Y(wr_gps) AS longitude {$sql_common} {$sql_search} {$sql_order} ";
$rr = sql_query($sql);
$data = [];
for ($i=0;$row = sql_fetch_array($rr);$i++) {
$data['result'][$i]['shop_name'] = $row['wr_subject'];
$data['result'][$i]['href'] = get_pretty_url(FD,$row['wr_id']);
$data['result'][$i]['longitude'] = $row['longitude'];
$data['result'][$i]['latitude'] = $row['latitude'];
$img = get_fd_image_data($row['token_id'],'limit 1');
foreach ($img as $value) {
$data['result'][$i]['bf_thumburl'] = $value['bf_thumburl'];
$data['result'][$i]['bf_width'] = $value['bf_width'];
$data['result'][$i]['bf_height'] = $value['bf_height'];
}
}
echo json_encode($data,JSON_UNESCAPED_UNICODE);
/get_map_data.php 파일을 만든다.
include_once "./_common.php";
$sql_search = " where wr_is_comment = 0 ";
$cord = $_REQUEST['min_map_latitude']." ".$_REQUEST['min_map_longitude'].", ".$_REQUEST['max_map_latitude']." ".$_REQUEST['max_map_longitude'];
if($cord) {
$sql_search .= " and MBRContains(GeomFromText('LineString($cord)'), `wr_gps`)";
}
$sql_order = " order by wr_id asc ";
$sql_common = " from {$g5['foodelivery_form_table']} ";
$sql = " select count(*) as cnt {$sql_common} {$sql_search} {$sql_order} ";
$row = sql_fetch($sql);
$total_count = $row['cnt'];
$rows = 10;
$total_page = ceil($total_count / $rows); // 전체 페이지 계산
if ($page < 1) { $page = 1; } // 페이지가 없으면 첫 페이지 (1 페이지)
$from_record = ($page - 1) * $rows; // 시작 열을 구함
$sql = " select *, X(wr_gps)AS latitude, Y(wr_gps) AS longitude {$sql_common} {$sql_search} {$sql_order} limit {$from_record}, {$rows} ";
$result = sql_query($sql);
?>
<div class="beaver_map_area">
<div class="map_area">
<div id="map"></div>
<a id="currentPositionBtn" href="#" onclick="getCurrentPositionEvent(); return false;">
<span class="current"><i class="fa fa-crosshairs"></i>현위치</span>
</a>
</div>
<div class="map_list">
<div class="wrapper">
<div class="head">
<span class="total_count">조회 <?php echo $total_count ?>건</span>
</div>
<ul class="body">
<?php
for ($i=0;$row = sql_fetch_array($result);$i++) {
$img = get_fd_image_data($row['token_id'],'limit 1');
?>
<li>
<a class="list_item" href="<?php echo get_pretty_url(FD,$row['wr_id'])?>" target="_blank">
<div class="thumb_area">
<?php foreach ($img as $item) { ?>
<img class="thumb" src="<?=$item['bf_thumburl']?>" width="<?=$item['bf_width']?>" height="<?=$item['bf_height']?>" />
<?php } ?>
</div>
<div class="content_area">
<div class="title">
<?php echo $row['wr_subject']?>
</div>
<div class="content">
<?php echo $row['wr_content']?>
</div>
</div>
</a>
</li>
<?php } ?>
<?php if($i == 0) echo "<li id='empty_map'>조회 된 정보가 없습니다.</li>"; ?>
</ul>
<div id="page_navigation">
<?php echo get_paging(G5_IS_MOBILE ? $config['cf_mobile_pages'] : $config['cf_write_pages'], $page, $total_page, $qstr.'&page='); ?>
</div>
</div>
</div>
</div>
맺음말 :
마커 클러스터러를 이용해서 하려 했더니 어떻게 할줄 몰라서 삼일동안 쌩고생 했다.. 카카오 개발자 센터에서 질문 답변 해보니까 이해를 못한가 쓸때 없는 코드 주는데..
결국엔 냑에서 컨텐츠몰에 있던거 사이트 들어가서 분석 해서.. 어렵게 가져다 활용함.. 백단은 겨우야 만들었는데 힘들다.
이렇게 아래 이미지 처럼 클러스터 마커 누르면 이 지역에 좌표를 이용해서 정보를 가져올 수 있게 만들었다~
깃헙에 저장 해야겠다.