이번장에서는 Leaflet Draw 기능중에 Poly Line으로 지도에 표시할때마다 거리와 총거리를 표현해보겠습니다.
- 네이버 지도에 보면 거리측정을 하면 마우스로 찍은 점마다 미터를 표시를 하는데 해당 기능을 구현해보겠습니다.
전체소스
<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
<body>
<main role="main" class="inner cover">
<h1 class="cover-heading">LeafletJs Tutorial</h1>
<!-- <p class="lead">- openstreetmap</p> -->
<!-- <div id="map"></div> -->
<!-- <br> -->
<p class="lead">leaflet draw 예제</p>
<div id="map"></div>
</main>
</body>
<script>
let lon = "";
let lat = "";
let leafletMap = "";
let startMarker = "";
let finishMarker = "";
let contextMenuFlag = true;
let lineArray = [];
let drawControl = "";
let layerType = "";
let polygon = new L.featureGroup();
let drawlon = "";
let drawlat = "";
let drawnItems = "";
let layer = "";
//apikey
const apiKey = $("#apiKey").val();
$(function(){
init();
});
function init(){
navigator.geolocation.getCurrentPosition(onGeoOk,onGeoError);
}
//현재 좌표값 가져오기
function onGeoOk(position){
lon = position.coords.latitude;
lat = position.coords.longitude;
console.log("You live in", lon, lat);
//wmts 가져오기
vworldWmts();
}
function onGeoError(){
alert("Can't find you. No weather for you.");
}
function vworldWmts(){
//leaflet 지도 띄우기 (EPSG : 4326)
leafletMap = L.map('map').setView([lon, lat], 15)
L.tileLayer("http://api.vworld.kr/req/wmts/1.0.0/"+apiKey+"/Base/{z}/{y}/{x}.png").addTo(leafletMap);
//해당 플래그가 true일때만 동작
//맵에 오른쪽마우스 클릭이벤트
leafletMap.on('click', leftMouseClick);
leafletMap.on('contextmenu', rightMouseClick);
//layer 변경
changeLayer(leafletMap)
//leaflet 그리기
initLeafletDraw(leafletMap)
}
//layer 변경
function changeLayer(leafletMap){
drawnItems = L.featureGroup().addTo(leafletMap);
const vworld = L.tileLayer("http://api.vworld.kr/req/wmts/1.0.0/"+apiKey+"/Base/{z}/{y}/{x}.png", { maxZoom: 18});
//레이어 변경
L.control.layers({
'vworld' : vworld.addTo(leafletMap),
'osm': L.tileLayer("http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution: 'osm'
}),
'google': L.tileLayer('http://www.google.cn/maps/vt?lyrs=s@189&gl=cn&x={x}&y={y}&z={z}', {
attribution: 'google'
})
}, { 'drawlayer': drawnItems }, { position: 'topleft', collapsed: false }).addTo(leafletMap);
}
//leaflet 그리기
function initLeafletDraw(leafletMap){
drawControl = new L.Control.Draw({
edit : false,
// edit: {
// featureGroup: drawnItems,
// poly: {
// allowIntersection: false,
// remove: false
// }
// },
draw: {
polygon: {
allowIntersection: false,
showArea: true
}
}
});
leafletMap.addControl(drawControl);
//created
leafletMap.on(L.Draw.Event.CREATED, function (event) {
layer = event.layer;
layerType = event.layerType;
drawnItems.addLayer(layer);
//polyline 일경우
if(layerType == 'polyline') {
createAreaTooltip(layer);
}
});
//그리기 도구 열때
leafletMap.on('draw:toolbaropened', function (e) {
contextMenuFlag = false;
});
//그리기 도구 닫힐때
leafletMap.on('draw:toolbarclosed', function (e) {
contextMenuFlag = true;
});
//도구모음 클릭시 layerType
leafletMap.on('draw:drawstart', function (e) {
layerType = e.layerType;
});
}
//tooltip 생성
function createAreaTooltip(layer) {
console.log(layer.areaTooltip);
if(layer.areaTooltip) {
return;
}
layer.areaTooltip = L.tooltip({
permanent: true,
direction: 'center',
className: 'area-tooltip'
});
layer.on('remove', function(event) {
layer.areaTooltip.remove();
});
layer.on('add', function(event) {
updateAreaTooltip(layer);
layer.areaTooltip.addTo(leafletMap);
});
if(leafletMap.hasLayer(layer)) {
updateAreaTooltip(layer);
console.log(layer.areaTooltip);
//얘가문제
layer.areaTooltip.addTo(leafletMap);
}
}
//툴팁 content 업데이트
function updateAreaTooltip(layer) {
let latlng = "";
let content = "";
if(layerType == "polyline"){
latlng = layer.getCenter();
let coords = layer.getLatLngs();
let length = 0;
for (let i = 0; i < coords.length - 1; i++) {
length += coords[i].distanceTo(coords[i + 1]);
}
console.log(coords[coords.length - 1]);
//반올림
let totalMeter = meterCalcurate(length);
content = "<div class='list-group'><a style='text-align: center;' href='javascript:void(0);' class='list-group-item list-group-item-action'>총거리 : "+totalMeter+"</a></div>"
latlng = [coords[coords.length - 1].lat, coords[coords.length - 1].lng];
}
//ha -> 제곱미터로 변환후 소수 첫째자리까지 반올림후 3째자리까지 나누기
layer.areaTooltip
.setContent(content)
.setLatLng(latlng);
//polyline인경우 offset 처리
if(layerType == "polyline"){
layer.areaTooltip.options.offset = [0,80];
}
}
//왼쪽마우스 클릭
function leftMouseClick(e){
if(!contextMenuFlag){
//선
if(layerType == "polyline"){
lineArray.push(e.latlng);
console.log(lineArray);
let length = lineArray.length;
const polyLineIcon = L.icon({
iconUrl: '/images/start-marker.png',
iconSize: [30, 30], // size of the icon
});
drawlon = lineArray[length-1].lat;
drawlat = lineArray[length-1].lng;
polyLineMarker = new L.marker([drawlon, drawlat], {
draggable: false,
autoPan: false,
icon: polyLineIcon
});
polyLineMarker.addTo(leafletMap);
if(length > 1){
let distance = lineArray[length-2].distanceTo(lineArray[length-1]);
//미터 -> 키로미터로 변환
distance = meterCalcurate(distance);
polyLineMarker.bindTooltip(distance, {direction: 'top',noWrap: true, opacity: 0.9, permanent: true}).openTooltip();
}
}
}
}
// m -> km로 계산
function meterCalcurate(distance){
distance = Math.round(distance);
if(distance >= 1000){
distance = (distance / 1000).toFixed(2) + "km";
}else{
distance = distance + "m";
}
return distance;
}
//오른쪽 마우스 클릭
function rightMouseClick(e) {
const lon = e.latlng.lat;
const lat = e.latlng.lng;
const popDiv = "<div class='list-group'><a style='text-align: center;' href='javascript:void(0);' onclick='startBtnClicked("+lon+", "+lat+")' class='list-group-item list-group-item-action'>출발</a><a style='text-align: center;' href='javascript:void(0);' onclick='finishBtnClicked("+lon+", "+lat+")' class='list-group-item list-group-item-action'>도착</a><a href='javascript:void(0);' onclick='distanceMeasure()' class='list-group-item list-group-item-action'>거리측정</a></div>";
console.log("팝업 lon : " + lon, "lat : " + lat)
//contextMenuFlag가 true일때만 팝업 show
if(contextMenuFlag){
//오른쪽마우스 클릭이벤트
const popup = L.popup()
.setLatLng([lon, lat])
.setContent(popDiv)
.openOn(leafletMap);
}
}
//출발버튼 클릭
function startBtnClicked(lon, lat){
if(startMarker != ""){
startMarker.remove();
}
leafletMap.closePopup();
const startIcon = L.icon({
iconUrl: '/images/start-marker.png',
iconSize: [30, 30], // size of the icon
});
startMarker = new L.marker([lon, lat], {
draggable: true,
autoPan: false,
icon: startIcon
});
startMarker.addTo(leafletMap);
//마커 마우스 이벤트
markerMouseEvent(startMarker);
}
//도착버튼 클릭
function finishBtnClicked(lon, lat){
if(finishMarker != ""){
finishMarker.remove();
}
leafletMap.closePopup();
const finishIcon = L.icon({
iconUrl: '/images/finish-marker.png',
iconSize: [30, 30], // size of the icon
});
finishMarker = new L.marker([lon, lat], {
draggable: true,
autoPan: false,
icon: finishIcon
});
finishMarker.addTo(leafletMap);
//마커 마우스 이벤트
markerMouseEvent(finishMarker);
}
//마커 마우스 이벤트
function markerMouseEvent(marker){
marker.on('mouseover', function (e) {
marker.bindTooltip("끌어서 이동", {direction: 'top',noWrap: true, opacity: 0.9}).openTooltip();
//class명 추가
// marker._icon.classList.add("btn__close");
});
marker.on('mouseout', function (e) {
// marker._icon.classList.remove("btn__close");
});
marker.on('click', function (e) {
marker.remove();
});
}
</script>
- 저는 왼쪽마우스를 클릭할때마다 마커를 찍고 해당 마커 좌표를 배열에 넣고, 마커가 2개이상일경우에 가장 마지막으로 찍은 마커와 그 직전에 찍은 마커의 좌표사이의 거리를 계산해서 popup으로 표시를 하였습니다.
그리고 draw:created를 보면 그림그리기 완료시 레이어에 찍힌 마커들 사이의 거리를 합쳐서 총거리를 구해서 팝업으로 표현하였습니다.
'LeafletJs' 카테고리의 다른 글
[LeafletJs] Leaflet Draw Circle 총반경 구하기 (0) | 2023.01.05 |
---|---|
[LeafletJs] Leaflet Draw Polygon 면적 재기 (0) | 2023.01.05 |
[LeafletJs] Leaflet draw 사용 (0) | 2023.01.05 |
[leafletjs] 배경지도 레이어 변경 (0) | 2023.01.05 |
[leafletjs] wmts 배경지도에 오른쪽 마우스 클릭시 출발 도착 marker 찍기 (0) | 2023.01.03 |