-
Blazor에서 카카오 지도 API 적용하기HelloJkw 개발 2022. 3. 5. 14:16
카카오 지도 API 개발하는 과정에서 겪은 일.
blazor를 선택하면서 js를 쓸 일은 없겠거니 했지만,
js로만 되어있는 라이브러리를 사용하게 되면 어쩔 수 없어 JS Interop을 사용해서 개발해야 한다.
처음에는 단순 함수로 개발했다.
ts로 바꾸는 등 변화 과정을 기록한다.
blazor project에 typescript를 적용하는 과정은 여기서 확인.
2022.03.04 - [분류 전체보기] - Blazor에서 typescript 사용하기
변경 전: javascript 기반, 단순 함수를 호출
javascript에 함수로 만들고, 전역변수를 두어 map 객체를 관리한다.
<문제점>
모든 변수는 전역변수로 만든다. (당연히)
map이외에 marker 등 다른 함수와 섞이면서 코드 관리가 어렵다.
변수의 오너십이 없다. 누가 map변수를 바꿔놓을지 모른다.
map을 하나만 만들 수 있다.
map을 여러개 지원하려면
var map;
대신var maps = {}
으로 바꾸고,maps[mapId] = map;
으로 처리한 후,모든 함수에서 mapId를 넘겨받아와서 map을 찾아야 하는 구조로 만들어야 한다.
그렇다고 오너십이 해결되는 건 아니다.
[kakaomap.js]
var map; var dotnetInstance; export function createMap(mapId, instance) { dotnetInstance = instance; var container = document.getElementById(mapId); var options = { center: new kakao.maps.LatLng(33.450701, 126.570667), level: 3 //지도의 레벨(확대, 축소 정도) }; map = new kakao.maps.Map(container, options); } export function setCenter(position) { const center = new kakao.maps.LatLng(position.latitude, position.longitude); map.setCenter(center); } export function getCenter() { map.getCenter(); } function onMapClicked(mouseEvent) { dotnetInstance.invokeMethodAsync('OnMapClicked', mouseEvent); } export function addClickEvent() { kakao.maps.event.addListener(map, 'click', onMapClicked); }
[KakaoMap.cs]
public class KakaoMap : IKakaoMap { private IJSRuntime JS; private DotNetObjectReference<KakaoMap> _kakaoMapRef; private IJSObjectReference _module; public async ValueTask CreateMap(string mapId) { _kakaoMapRef = DotNetObjectReference.Create(this); var jsPath = "./_content/BlazorKakaoMap/js/kakaomap.js"; _module = await JS.InvokeAsync<IJSObjectReference>("import", jsPath); await _module.InvokeVoidAsync("createMap", mapId, _kakaoMapRef); } public async ValueTask SetCenter(LatLng position) { await _module.InvokeVoidAsync("setCenter", position); } public async ValueTask<LatLng> GetCenter() { var center = await _module.InvokeAsync<LatLng>("getCenter"); return center; } private event EventHandler<MouseEvent> _clicked; public event EventHandler<MouseEvent> Clicked { add { // js에 click event를 등록한다. _module.InvokeVoidAsync("addClickEvent"); _clicked += value; } remove { _clicked -= value; } } [JSInvokable] public void OnMapClicked(MouseEvent mouseEvent) { // 지도를 클릭하면 js의 onMapClicked함수를 통해서 불린다. _clicked?.Invoke(this, mouseEvent); } }
변경 후: typescript, 객체 지향으로.
typescript를 적용하였고,
map을 객체 하나로 만들었다.
C# 에서도 map을 하나의 객체로 받아들였다.
IJSObjectReference
를 활용하면 간단하다.js를 import한 module을 받는것이 아니고, map객체를 할당한다.
이렇게 변경하면 여러 map을 만들더라도 객체의 관리를 .net에서 하게 된다.
js에도 전역변수를 없앨 수 있다.
[kakaomap.ts]
declare var kakao: any; export function createMap(mapId, instance) { return new Map(mapId, instance); } class Map { private map: any; private dotnetInstance: any; constructor(mapId: string, instance) { this.dotnetInstance = instance; const container = document.getElementById(mapId); const options = { center: new kakao.maps.LatLng(33.450701, 126.570667), //지도의 중심좌표. level: 3 //지도의 레벨(확대, 축소 정도) }; this.map = new kakao.maps.Map(container, options); } onMapClicked(mouseEvent) { this.dotnetInstance.invokeMethodAsync('OnMapClicked', mouseEvent); } addClickEvent() { kakao.maps.event.addListener(this.map, 'click', this.onMapClicked.bind(this)); } setCenter(position) { const center = new kakao.maps.LatLng(position.latitude, position.longitude); this.map.setCenter(center); } getCenter() { return this.map.getCenter(); } }
[kakaomap.cs]
public class KakaoMap : IKakaoMap { private IJSRuntime JS; private DotNetObjectReference<KakaoMap> _kakaoMapRef; private IJSObjectReference _map; public async ValueTask CreateMap(string mapId) { _kakaoMapRef = DotNetObjectReference.Create(this); var jsPath = "./_content/BlazorKakaoMap/js/kakaomap.js"; var module = await JS.InvokeAsync<IJSObjectReference>("import", jsPath); // kakao map 객체를 가지고 있는다. _map = await module.InvokeAsync<IJSObjectReference>("createMap", mapId, _kakaoMapRef); } public async ValueTask SetCenter(LatLng position) { // map 객체의 함수를 바로 호출한다. // 다른 것을 침범할 수도, 침범당하지도 않는다. await _map.InvokeVoidAsync("setCenter", position); } public async ValueTask<LatLng> GetCenter() { var center = await _map.InvokeAsync<LatLng>("getCenter"); return center; } private event EventHandler<MouseEvent> _clicked; public event EventHandler<MouseEvent> Clicked { add { // js에 click event를 등록한다. _map.InvokeVoidAsync("addClickEvent"); _clicked += value; } remove { _clicked -= value; } } [JSInvokable] public void OnMapClicked(MouseEvent mouseEvent) { // 지도를 클릭하면 js의 onMapClicked함수를 통해서 불린다. _clicked?.Invoke(this, mouseEvent); } }
이 코드가 최종 모습은 아니다.
event 할당도 저렇게 간단하지 않고, 제대로 동작하기 위한 장치가 더 있다.
하지만 전반적인 흐름을 보기 위해서 이 정도로 정리했다.
typescript로 개발하고,
객체화 시켜서 객체 자체를 .net에 할당하는 면 깔끔하게 개발 할 수 있는 것 같다.
여러 js 파일을 가지고 개발할 때는 어떤 이슈가 생길지 모르겠다.
marker를 다른 파일로 생성해서 테스트 해볼 예정.
'HelloJkw 개발' 카테고리의 다른 글
일기장 검색 관련 변화 (0) 2023.06.25 Blazor에서 typescript 디버깅 (0) 2022.03.06 Blazor에서 typescript 사용하기 (0) 2022.03.04 Blazor에 카카오맵 연동하기 (0) 2022.02.28 일기장 검색 기능 만들기 (0) 2022.02.25