Translate

[Leaflet] Extending Leaflet - Layers




 - 이 튜토리얼에서는 Leaflet Class 상속 이론을 읽었다고 가정한다.
 - Leaflet에서 "Layer"는 (map)지도를 이동시킬 때 움직이는 모든것이다.
 - 처음에는 직접 만드는것보다는 간단한 확장 방법을 설명하는게 더 쉽다.


확장 메소드 (Extension methods)

 - 일부 Leaflet 클래스에는 서브클래스의 코드 작성을 위한 진입포인트인 'extension methods'를 가지고 있다.

 - 그중 하나는 L.TileLayer.getTileUrl() 이다.
 - 이 메소드는 L.TileLayer에서 신규 타일이 이미지를 로드해야 할때마다 내부적으로 호출된다.
 - L.TileLayer의 서브클래스를 만들고 getTileUrl() 함수를 다시 작성하여 custom 동작을 만들 수 있다.

 - custom L.TileLayer를 이용하여 PlaceKitten의 랜덤한 고양이 이미지를 노출시켜보자.

 - 일반적으로 getTileUrl()은 타일좌표(coords.x / coords.y / coords.z)를 수신받고 해당 좌표에 대한 타일 (이미지)URL을 생성한다.
 - 이번 예제에서는 좌표를 무시하고 매번 다른 고양이를 얻기위해 난수를 사용한다.



플러그인 코드 분리

 - 이전 예에서는 L.TileLayer.Kitten 과 기본소스와 같은 위치에 정의가 되었다.
 - 플러그인의 경우 플러그인 코드 자체를 파일로 분리하고 해당 플러그인을 사용할 때 import 하는게 좋다.

 - KittenLayer를 L.KittenLayer.js로 분리해주고 사용하는 곳에서 import를 해준다.


L.GridLayer 와 DOM elements

 - 또 다른 확장방법은 L.GridLayer.createTile() 을 이용하는 것이다.
 - L.TailLayer는 (<img> 요소로서) 이미지의 그리드가 있다고 가정하지만, L.GridLayer는 (모든 종류의 HTML Element요소의 그리드를 만들 수 있기에) 그렇게 가정하지 않는다

 - L.GridLayer는 <img>태그의 요소를 생성 가능하지만, <div>/<canvas>/<picture> 등등 다른 모든것들을 생성할 수 있다.
 - createTile()은 전달받은 타일좌표의 HTML Element 인스턴스를 반환하기만 하면 된다.
 - 이때, DOM 요소를 조작하는 방법을 아는것이 중요하다.
 - (Leaflet은 HTML-Element의 인스턴스를 기대하고 있으며, jQuery와 같은 라이브러리의 요소들은 문제가 된다.)

 - custom GridLayer의 예제는 <div>의 타일좌표를 보여주고 있다.
 - 이는 특히 Leaflet 내부를 디버깅하거나 (tile coordinates)타일좌표가 어떻게 작동하는지 이해하는데 유용하다.

 - element가 비동기 초기화를 해야 하는경우 두번째 함수 매개변수인 'done'을 사용하고 (이미지과 완전히 로드된경우)준비되거나 에러가 발생한 경우 해당 함수를 호출한다.


 - custom GridLayer를 사용하면 플러그인은 grid를 만들 때 HTML element를 완전히 컨트롤이 가능하다.
 - 일부 플러그인들은 이미 <canvas>를 사용하여 고급 렌더링을 수행하고 있다.
 - 기본적인 <canvas> GridLayer 사용은 다음과 같다.



픽셀 원점 (The pixel origin)

 - custom L.Layer를 만들 수 있지만, Leaflet이 HTML 요소를 배치하는 것에 대해서 더 깊은 지식이 필요하다.
 - 요약은 아래와 같다.
  1) L.Map 에는 <div>인 (지도 창)'map panes'가 있다.
  2) L.Layer는 'map pane' 안에있는 HTML 요소이다.
  3) map은 모든 LatLng를 지도CRS의 좌표로 변환하고, 그다음 (absolute)절대 '픽셀 좌표'로 변환한다. (CRS의 원점은 픽셀좌표의 원점과 같음)
  4) (중앙 LatLng와 줌레벨을 가지고 있는) L.map이 준비되면 왼쪽 상단의 절대픽셀좌표는 '픽셀원점'이 된다.
  5) 각 L.Layer는 'map pane'에서 픽셀원점과 레이어LatLng의 절대픽셀좌표에 따라 오프셋 된다.
  6) 픽셀원점은 각각 zoomend, viewreset 이벤트가 수행된 이후 리셋되며, (필요한 경우) 모든 L.Layer의 위치는 재계산된다.
  7) map을 주위로 이동 시키는경우 픽셀원점은 리셋되지 않으며, 모든 pane들의 위치가 변경된다.

 - 위 설명은 조금 헷갈릴 수 있으니 다음 지도의 확인이 필요하다.

 - (녹색) CRS원점은 LatLng와 동일하게 유지된다.
 - (빨간색) 픽셀원점은 항상 왼쪽 상단 모서리에서 시작한다.
 - 픽셀원점은 맵이 이동될 때 이리저리 이동하며, ((지도창)map pane이 지도 컨테이너에 따라 재배치됨) 확대/축소 할 시 화면의 동일한 위치에 남아있다. (map pane은 재배치되지 않지만 layer 자체는 다시 그릴 수 있다.)
 - 픽셀원점에 대한 절대픽셀좌표는 확대/축소 할 때 업데이트 되지만 이동중에는 업데이트 되지 않는다.
 - 지도를 확대할 때마다 (녹색 괄호까지의 거리)절대픽셀좌표가 두배가 되는 것을 볼 수 있다.

 - (ex: blue L.Marker)무엇이든 배치하기위해 LatLng는 지도의 L.CRS 안에있는 절대픽셀좌표로 변환된다.
 - 그 다음 픽셀원점의 절대픽셀좌표를 절대픽셀좌표에서 빼고 (연청색)픽셀원점에 대한 오프셋을 제공한다.
 - 픽셀원점은 모든 (지도창)'map pane'의 왼쪽 상단 모서리에 있으므로 이 오프셋을 마커 아이콘의 HTML요소에 적용할 수 있다.
 - (암청색 선)마커의 아이콘앵커는 negative CSS margin을 통해 이루어진다.

 - L.Map.project() 와 L.Map.unproject() 메소드는 절대픽셀좌표에 의해 동작한다.
 - 마찬가지로 L.Map.latLngToLayerPoint() 와 L.Map.layerPointToLatLng() 는 픽셀원점을 기준으로 오프셋으로 작업한다.

 - 다른 레이어들은 이러한 계산을 다른 방식으로 적용한다.
 - L.Marker 는 단순히 아이콘의 위치를 바꾸기만 하면 된다.
 - L.GridLayer는 (절대픽셀좌표의)지도범위를 계산한 다음 요청할 타일좌표 리스트를 계산한다.
 - (polyline, polygon, circle marker 등등)벡터레이어는 각 LatLng를 픽셀로 변환하고, SVG 또는 <canvas>를 사용하여 (기하학적 구조)지오메트리를 그린다.


onAdd 와 onRemove

 - 핵심은 모든 L.Layer는 (지도창)map pane 내부의 HTML 요소이며, 레이어의 코드에 정의된 (position/content)위치와 내용이다.
 - 그러나 레이어가 인스턴스화 되면 HTML요소를 생성할 수 없다.
 - 오히려, 레이어는 지도에 추가되고나서 수행되며, 레이어는 그때까지 map에 대해서 알지 못한다. (심지어 document까지도)

 - 즉, map은 레이어의 onAdd() 메소드를 호출한 후 HTML요소인 레이어를 생성하여 (지도창)map pane에 추가한다.
 - 반대로, 지도에서 레이어가 제거되면 onRemove() 메소드가 호출된다.
 - 레이어는 map에 추가될 때 내용을 업데이트하고 map view가 업데이트 되면 위치를 변경해야한다.
 - 레이어 뼈대는 다음과 같다.

 - 레이어의 HTML요소의 정확한 위치는 (객체를 만들때)레이어의 세부사항에 따라 다르지만, 이 소개는 Leaflet의 레이어코드를 읽고 새로운 레이어를 만드는데 도움이 될 것이다.


부모(클래스)의 onAdd 사용

 - 일부 사용 사례에서는 모든 onAdd 코드를 재생성할 필요는 없지만, (필요시에) 부모의 onAdd를 재사용하는것 대신 일부 세부사항은 초기화 이전 또는 이후에 추가할 수 있다.

 - 예를들어 (옵션을 무시한 ) 항상 빨간색인 L.Polyline의 서브클래스를 가질 수 있다.



참조: https://leafletjs.com/examples/extending/extending-2-layers.html


댓글