우선 가장 애를 먹은 설치 부분이다. 우선 v-world에서 제공하는 WebGL의 3d 지도를 사용하기위해서는 해당 라이브러리를 설치해주어야한다.
하지만 당연 npm에서 제공하는 라이브러리는 따로없고 오직 CDN 방법을 통해서만 설치가 가능하다.
이때 가장 먼저 생각나는 것은 당연 "<script>를 react, vue 차원에서 추가하면 되는 거겠지?" 라고 생각할 수 있다.
그럼 우선 시행착오부터 살펴보자. 위 하이퍼링크를 통해 해당 사이트에 들어가면
<script type="text/javascript" src="http://map.vworld.kr/js/webglMapInit.js.do?version=2.0&apiKey=[인증키]"></script>
const script = document.createElement("script");
script.src = "http://map.vworld.kr/js/webglMapInit.js.do?version=2.0&apiKey=[apikey]&domain=[domainurl]";
script.async = true;
document.head.appendChild(script);
vw
객체가 없다. => 뭔소리임? var v_protocol="https://";
var vworldUrl='https://map.vworld.kr';
var vworld2DCache='https://2d.vworld.kr/2DCache';
var vworldBaseMapUrl='https://xdworld.vworld.kr/2d';
var vworldStyledMapUrl='https://2d.vworld.kr/stmap';
var vworldIsValid = 'true';
var vworldErrMsg = '';
var vworldApiKey = '본인 key 값';
var vworld3DUrl = '/js/webglMapInit.js.do'; document.write(""); document.write(""); document.write("");
vw
객체를 찾아볼 수 없다.즉, FE에서 v-world의 WebGL을 사용하고 싶다면
index.html
에 위 <script> 태그를 추가해주어야한다. 물론 FE의 근본적인 원칙에 어긋나지만 어쩔 수 없다....
아니면 해당 페이지만 따로 vanilla로 작성하여 spring static폴더에 넣어주면 된다.
vw.value = window.vw
var mapOptions = new vw.value.MapOptions(
vw.value.BasemapType.GRAPHIC,
"",
vw.value.DensityType.FULL,
vw.value.DensityType.BASIC,
false,
new vw.value.CameraPosition(
new vw.value.CoordZ(126.921883, 37.524370, 482400),
new vw.value.Direction(0, -90, 0),
),
new vw.value.CameraPosition(
new vw.value.CoordZ(126.921883, 37.524370, 2982400),
new vw.value.Direction(0, -90, 0)
)
);
map3d.value = new vw.value.Map("vmap", mapOptions);
ws3d.value = window.ws3d;
vw3dViewer.value = window.ws3d.viewer;
vw
객체에 접근하여 기본적인 Map을 만들어주는 코드를 작성한 후vw3dViewer
를 ref 변수에 저장한다.vw3d
변수를 생성하여 담아준다.이제 map을 생성하였다면 v-world에서 기능을 찾아보고 없는 부분에 한하여 Cesium.js에서 구현하면 된다.
이때 코드가 이상하게 적용이 안 되어서 애를 먹었던 2부분에 대하여 설명하겠다.
vw3dViewer.value.entities.add({
name: "flood",
position: position,
cylinder: {
length: height,
topRadius: radius,
bottomRadius: radius,
material: ws3d.value.common.Color.ROYALBLUE.withAlpha(0.5),
outline: true,
outlineColor: ws3d.value.common.Color.ROYALBLUE.withAlpha(0.5),
},
});
참고로 예제 코드가 너무 잘 되어있으니 가서 확인해보면 된다.
하지만 예제 코드와 다른 점이 한 곳 있다. 바로 색상을 입혀주는 부분이다. 저때 Cesium 객체의 color 값은 들어가지 않으니 앞서 vw객체에서 파생되었던 ws3d 객체를 사용하면 된다.
요구사항 중 하나는 어떠한 이벤트가 발생하면 해당되는 아이콘에 대하여 모두 팝업을 띄워졌으면 좋겠다는 요구사항이었다.
이때 v-world에 올린 질문을 보면 알 수 있는데 작성일(23.08.12) 기준으로 아직 2개의 팝업은 지원하지 않는다. 따라서 Cesium.js를 사용해야하는데 이때 2가지의 단점이 또 존재한다.
const canvas = document.createElement('canvas');
canvas.width = 500;
canvas.height = 300;
const image = new Image();
const svgString = `<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
<foreignObject width="100%" height="100%">
<div xmlns="http://www.w3.org/1999/xhtml">
<div>뭔갈 작성하셈</div>
</div>
</foreignObject>
</svg>`;
image.src = 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(svgString)));
image.onload = function () {
canvas!.getContext('2d').drawImage(image, 0, 0);
vw3dViewer.value.entities.add({
id: child.id,
position: Cesium.Cartesian3.fromDegrees(child.equipLat, child.equipLon, 200),
billboard: {
image: canvas,
horizontalOrigin:Cesium.VerticalOrigin.CENTER,
eyeOffset: new Cesium.Cartesian3(125.0, 0,0.0),
},
description: '<p>Copy Wright by KJW</p>'
});
};
for(const data of DummyData){
const selectedObj = map3d.value.getObjectById(data.id);
if ( selectedObj != null ) {
selectedObj.show();
selectedObj.hide();
}
}
클러스터링
을 할 수 없다는 것이 문제이다.vw.value.NavigationZoom.initHome();
function setLod1 (){
map3d.value.getElementById('facility_build').hide();
map3d.value.getElementById('facility_build_lod1').show();
map3d.value.getElementById('facility_build_lod1').setStyle({
color: {
conditions:[
["true", "rgba(185,185,185,1.0)"],
]
}
})
}
const msg = new SpeechSynthesisUtterance('tts 내용을 입력하세요');
speechSynthesis.speak(msg);
function degToRad(deg:number) {
return deg * (Math.PI / 180);
}
function getDistance(lat1:number, lon1:number, lat2:number, lon2:number) {
const earthRadiusKm = 6371;
const dLat = degToRad(lat2 - lat1);
const dLon = degToRad(lon2 - lon1);
const a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(degToRad(lat1)) * Math.cos(degToRad(lat2)) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
const distance = earthRadiusKm * c;
return distance;
}