Translate

2020년 12월 16일 수요일

[IntelliJ] svn: E170013, E230001 - SVN주소 HTTPS 관련 이슈 해결방법

 



증상

IntelliJ 에서 SVN 저장소 추가 시 아래와 같이 보여지며 소스 내용이 보여지지 않았다.



svn: E170013: Unable to connect to a repository at URL 'https://SVN주소'
svn: E230001: Server SSL certificate verification failed: certificate has expired, certificate issued for a different hostname, issuer is not trusted



해결방법

Settings 에서 svn으로 검색 후 아래의 화면과 같이 체크를 한다.



1004lucifer

그리고 SVN저장소 부분을 새로고침 하면 아래와 같은 모습이 나오는데 Accept 를 눌러준다.



SVN계정을 입력 후 OK를 눌러주면 이후에는 정상적으로 이용이 가능하다.



2020년 12월 7일 월요일

[Redis] Failed opening the RDB file root (in server root dir /var/spool/cron) for saving: Read-only file system 에러 (bgsave)

 



Linux 서버에 Redis를 설치 후 정상적으로 작동되는것을 확인하고 나중에 다시 사용하려 하니 정상적으로 사용을 할 수가 없었다.


문제

사용하려 할 시 아래와 같은 에러로그가 보여졌다.


set testkey testValue (error) MISCONF Redis is configured to save RDB snapshots, but it is currently not able to persist on disk. Commands that may modify the data set are disabled, because this instance is configured to report errors during writes if RDB snapshotting fails (stop-writes-on-bgsave-error option). Please check the Redis logs for details about the RDB error.
1004lucifer



서버의 Redis로그를 확인해보니 아래와 같았다.


21982:C 26 Nov 07:55:15.563 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
21982:C 26 Nov 07:55:15.563 # Redis version=4.0.9, bits=64, commit=00000000, modified=0, pid=21982, just started
21982:C 26 Nov 07:55:15.563 # Configuration loaded
                _._     
           _.-``__ ''-._
      _.-``    `.  `_.  ''-._           Redis 4.0.9 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._ 
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 22007
  `-._    `-._  `-./  _.-'    _.-' 
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |           http://redis.io
  `-._    `-._`-.__.-'_.-'    _.-' 
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |
  `-._    `-._`-.__.-'_.-'    _.-' 
      `-._    `-.__.-'    _.-'
          `-._        _.-'    
              `-.__.-'        
1004lucifer
22007:M 26 Nov 07:55:15.568 # Server initialized
22007:M 26 Nov 07:55:15.568 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
22007:M 26 Nov 07:55:15.568 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
22007:M 26 Nov 07:55:15.569 * DB loaded from disk: 0.002 seconds
22007:M 26 Nov 07:55:15.570 * Ready to accept connections
22007:M 26 Nov 09:46:12.033 * DB saved on disk
22007:M 26 Nov 09:46:12.050 * DB saved on disk
22007:M 26 Nov 09:46:12.104 * DB saved on disk
22007:M 26 Nov 09:46:12.123 * DB saved on disk
22007:M 26 Nov 09:46:12.146 * DB saved on disk
22007:M 26 Nov 09:46:12.184 * DB saved on disk
22007:M 26 Nov 09:46:12.197 * DB saved on disk
22007:M 26 Nov 09:46:12.270 * DB saved on disk
22007:M 26 Nov 09:46:12.278 * DB saved on disk
22007:M 26 Nov 09:46:12.312 * DB saved on disk
22007:M 26 Nov 09:46:12.362 * DB saved on disk
22007:M 26 Nov 09:46:12.394 * DB saved on disk
22007:M 26 Nov 09:46:12.402 * DB saved on disk
22007:M 26 Nov 09:46:12.484 * DB saved on disk
22007:M 26 Nov 09:46:12.660 # Failed opening the RDB file root (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:46:12.667 # Failed opening the RDB file root (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:46:12.712 # Failed opening the RDB file root (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:46:12.722 # Failed opening the RDB file backup.db (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:46:12.755 # Failed opening the RDB file backup.db (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:46:12.785 # Failed opening the RDB file backup.db (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:46:12.794 # Failed opening the RDB file backup.db (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:46:12.856 # Failed opening the RDB file backup.db (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:46:12.892 # Failed opening the RDB file root (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:46:12.935 # Failed opening the RDB file backup.db (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:46:13.001 # Failed opening the RDB file backup.db (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:46:13.064 # Failed opening the RDB file backup.db (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:46:13.065 # Failed opening the RDB file backup.db (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:46:13.157 # Failed opening the RDB file backup.db (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:46:13.301 # Failed opening the RDB file root (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:46:13.303 # Failed opening the RDB file root (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:46:13.443 # Failed opening the RDB file root (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:46:13.447 # Failed opening the RDB file root (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:46:13.565 # Failed opening the RDB file root (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:46:13.657 # Failed opening the RDB file root (in server root dir /var/spool/cron) for saving: Read-only file system 1004lucifer
22007:M 26 Nov 09:46:13.745 # Failed opening the RDB file root (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:46:13.839 # Failed opening the RDB file root (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:46:13.839 # Failed opening the RDB file root (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:46:13.917 # Failed opening the RDB file root (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:46:14.046 # Failed opening the RDB file root (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:46:14.141 # Failed opening the RDB file root (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:51:13.079 * 10 changes in 300 seconds. Saving...
22007:M 26 Nov 09:51:13.080 * Background saving started by pid 22345
22345:C 26 Nov 09:51:13.080 # Failed opening the RDB file root (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:51:13.180 # Background saving error
22007:M 26 Nov 09:51:19.090 * 10 changes in 300 seconds. Saving...
22007:M 26 Nov 09:51:19.090 * Background saving started by pid 22346
22346:C 26 Nov 09:51:19.090 # Failed opening the RDB file root (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:51:19.190 # Background saving error
22007:M 26 Nov 09:51:25.100 * 10 changes in 300 seconds. Saving...
22007:M 26 Nov 09:51:25.102 * Background saving started by pid 22347
22347:C 26 Nov 09:51:25.102 # Failed opening the RDB file root (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:51:25.202 # Background saving error
22007:M 26 Nov 09:51:31.012 * 10 changes in 300 seconds. Saving...
22007:M 26 Nov 09:51:31.012 * Background saving started by pid 22350
22350:C 26 Nov 09:51:31.012 # Failed opening the RDB file root (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:51:31.112 # Background saving error
22007:M 26 Nov 09:51:37.021 * 10 changes in 300 seconds. Saving...
22007:M 26 Nov 09:51:37.021 * Background saving started by pid 22351
22351:C 26 Nov 09:51:37.022 # Failed opening the RDB file root (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:51:37.122 # Background saving error
22007:M 26 Nov 09:51:43.031 * 10 changes in 300 seconds. Saving...
22007:M 26 Nov 09:51:43.032 * Background saving started by pid 22352
22352:C 26 Nov 09:51:43.032 # Failed opening the RDB file root (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:51:43.132 # Background saving error
22007:M 26 Nov 09:51:49.041 * 10 changes in 300 seconds. Saving...
22007:M 26 Nov 09:51:49.041 * Background saving started by pid 22353
22353:C 26 Nov 09:51:49.041 # Failed opening the RDB file root (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:51:49.141 # Background saving error
22007:M 26 Nov 09:51:55.050 * 10 changes in 300 seconds. Saving...
22007:M 26 Nov 09:51:55.050 * Background saving started by pid 22354
22354:C 26 Nov 09:51:55.051 # Failed opening the RDB file root (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:51:55.151 # Background saving error
22007:M 26 Nov 09:52:01.061 * 10 changes in 300 seconds. Saving...
22007:M 26 Nov 09:52:01.061 * Background saving started by pid 22357
22357:C 26 Nov 09:52:01.061 # Failed opening the RDB file root (in server root dir /var/spool/cron) for saving: Read-only file system
22007:M 26 Nov 09:52:01.161 # Background saving error

 ... (위 에러가 계속 있음)




원인 및 해결방법

Redis 서버에 패스워드를 지정하지 않았고 기본포트로 되어있다 보니 누구나 접근이 가능했다.

스택오버플로우에서 외부 공격으로 인해 그럴 수 있으니 방화벽 설정을 해두라는 이야기를 듣고 사용할 곳의 IP를 제외하고는 다른곳에서 접속할 수 없게 했더니 더 이상 문제가 발생하지 않았다.



참고
 - https://stackoverflow.com/questions/41887280/redis-config-dir-periodically-modified-to-var-spool-cron-with-failed-opening


2020년 10월 29일 목요일

[Leaflet] Extending Leaflet - Handlers and Controls




 - 이 튜토리얼은 Leaflet의 Class 상속이론을 읽었다고 가정한다.

 - Leaflet에서 Map의 움직이는 모든것은 Layer로 되어있다.
 - Control은 (Map컨테이너에 상대적인) 정적인 상태를 유지하는 HTML요소이다.
 - Handler는 Map의 동작을 변경하는 보이지 않는 코드의 일부이다.


핸들러 (Handlers)

 - Map Handler는 Leaflet 1.0의 새로운 개념으로, 브라우저에서 (클릭, 더블클릭, 마우스휠 같은)DOM 이벤트를 처리하고 Map 상태를 변경하는 기능이다.

 - Handler는 상대적으로 간단하다.
 - Map에서 핸들러가 활성화 될때 수행할 addHooks()메소드와 핸들러가 비활성화 될때 수행할 removeHooks() 메소만 있으면 된다.
 - 핸들러의 골격은 다음과 같다.


 - deviceorientation event를 통해 모바일기기가 기울어졌을 때 지도를 이동하는 간단한 핸들러를 보여줄 수 있다.

 - 핸들러는 map.addHandler('tilt', L.TiltHandler) 를 이용하여 지도에 연결시킬 수 있다.
 - 위 코드는 L.TiltHandler의 인스턴스를 map.tilt로 저장할 것이다.
 - 하지만 addInitHook 문법을 사용하여 모든 Map에 핸들러를 연결시키는게 일반적이다.

 - 이제 핸들러는 map.tilt.enable()이 수행되면 활성화되며, map.tilt.disable()이 수행되면 비활성화 된다.

 - 또한 map에 핸들러와 동일한 이름의 속성이 있는경우 해당 옵션을 true로 설정하면 기본적으로 핸들러가 활성화 된다.

 - 이 예제소스를 확인하려면 deviceorientation event를 지원하는 모바일 브라우저가 필요하다. (테스트 시 완벽하지 않고 불안정하니 감안해야 한다.)

(아래 링크를 클릭하여 새창에서 실행되는 페이지를 모바일에서 확인 시 해당 기기의 기울임에 따라서 지도가 이동하는 것을 확인할 수 있다.)

 - 이벤트 유형에 따라 다르지만, Map핸들러는 이벤트리스너를 document, window, L.Map의 컨테이너에 붙일 수 있다.



컨트롤 (Controls)

 - 왼쪽상단 zoom컨트롤, 왼쪽하단 축척, 오른쪽상단 레이어변경 기능에 대해서 지금까지 봐왔을 것이다.
 - 그것들의 중심에는 Map컨테이너 고정위치에 있는 HTML요소인 L.Control이 있다.

 - control을 만드려면 L.Control을 상속받고 onAdd(), onRemove() 메소드를 구현하면 된다.
 - onAdd()메소드가 control에 해당하는 HTML요소의 인스턴스를 반환하는 것을 제외하면 두개의 메소드는 L.Layer와 비슷하게 작동한다. (control이 map에 추가되거나 제거될 때 수행한다)
 - Map에 HTML요소의 추가/제거는 자동으로 이루어 진다.



플러그인 제작

 - 지금까지 모든것을 이해했다면 Leaflet 플러그인을 만들 준비가 된 것이다.
 - 플러그인 명명규칙 및 제작에 대한 몇가지 팁과 우수사례가 있는 PLUGIN-GUIDE.md 파일을 읽어보길 바란다.




참조: https://leafletjs.com/examples/extending/extending-3-controls.html


2020년 10월 28일 수요일

[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


2020년 10월 26일 월요일

[Leaflet] Extending Leaflet - Class Theory



Leaflet 확장

 - Leaflet에는 수백개의 플러그인이 있다. 이는 Leaflet의 기능을 확장하며 때로는 일반적인 방식으로, 때로는 유스케이스별 방식으로 확장한다.

 - 플러그인이 많은 이유는 Leaflet이 확장하기 쉽기 때문이다.
 - 이 튜토리얼에서는 가장 일반적으로 사용되는 방법을 다룬다.

 - 이 자습서는 다음 사항을 잘 이해하고 있다고 가정한다.
  1) JavaScript
  2) DOM handling
  3) OOP (클래스, 인스턴스, 상속, 메소드 및 프로퍼티와 같은 개념 이해)



Leaflet 아키텍처

 - Leaflet 1.0.0의 단순화된 UML 클래스 다이어그램을 확인해보자.
 - 60개 이상의 JavaScript 클래스가 있어서 다이어그램이 조금 크다.



(마우스 클릭 시 큰 화면으로 확인 가능)


- 기술적 관점에서 Leaflet은 다양한 방법으로 확장 할 수 있다.

 * 가장 일반적인 방법: L.Class.extends()를 활용하여 L.Layer / L.Handler / L.Control 과 같은 서브클래스를 생성

  - map이 이동/확대 될때 Layer가 이동함.
  - Handler는 보이지 않으며 브라우저 이벤트를 해석한다.
  - Control은 고정된 인터페이스 요소이다.

 * L.Class.include() 를 이용하여 기존 클래스에 더 많은 기능을 추가

  - 신규 methods 와 options 추가
  - 특정 methods 변경
  - addInitHook을 사용하여 새로운 (constructor)생성자 코드를 수행

 * L.Class.include() 를 이용하여 기존 클래스의 일부를 변경 (클래스 메소드 작동방법 변경)


 - 이 튜토리얼에서는 Leaflet 1.0.0에서만 사용할 수 있는 일부 클래스와 메소드를 다룬다.
 - 이전 버전용 플러그인을 개발하는 경우 주의해야한다.



L.Class

 - JavaScript는 약간 이상한 언어인데, (Object-Oriented)객체지향 언어가 아니라 (Prototype-Oriented)프로토타입지향 언어이다.
 - 때문에 OOP의미에서 클래스 상속을 사용하기가 어려웠다.

 - Leaflet은 L.Class를 중점적으로 사용하여 클래스 상속을 용이하게 한다.

 - 최근 자바스크립트인 ES6는 클래스를 사용할 수 있지만 Leaflet은 이를 중심으로 설계되지 않았다.


L.Class.extend()

 - Leaflet에서 하위클래스를 만드려면 .extend() 메소드를 사용하면 된다.
 - .extend() 메소드에는 하나의 파라메터를 허용하는데 해당 파라메터는 key-value 쌍으로 되어있는 일반 Object 이다.
 - 해당 Object의 key는 프로퍼티 또는 메소드의 이름이며, value는 프로퍼티값 또는 메소드의 구현체이다.

 - class, method, property 이름을 지정할 때 다음 규칙을 따르는게 좋다.
  1) lowerCamelCase 규칙: Function, method, property, factory 이름
  2) UpperCamelCase 규칙: Class 이름
  3) (접근지정자) private 형식의 property, method 는 밑줄(_)로 시작한다. 이건 private로 만들어 주는것은 아니지만 개발자들에게 직접 사용하지 말라고 권고하는 것이다.


L.Class.include()

 - 클래스가 이미 정의된경우 .include()를 사용하여 기존 property/method 를 재정의 하거나, 새로운 property/method 를 추가할 수 있다. (아래의 코드 참고)


L.Class.initialize()

 - OOP에서 클래스에는 생성자 메소드가 있다.
 - Leaflet 에서 L.Class 생성자 메소드는 항상 initialize 이다.

 - 만약 클래스에 options를 기술한경우 생성자에서 L.setOptions()를 사용해 그것들을 초기화 하는게 좋다.
 - 이 유틸리티 함수는 기술한 options를 클래스의 기본 options 와 병합한다.


 - Leaflet은 특별한 방법으로 options 속성을 처리한다.
 - 부모 클래스의 options는 자식 클래스에 상속된다.


 - 자식클래스가 부모의 생성자를 수행한다음 자신의 생성자를 수행하는게 일반적이다.
 - 이를 위해서 Leaflet 에서는 L.Class.addInitHook() 을 사용할 수 있다.
 - 이 메소드를 이용하여 클래스 initialize() 직후 실행되는 hook 초기화 함수로 사용할 수 있다.

 - 위 코드는 setOptions()를 수행하는 initialize() 이후에 수행된다.
 - 이 뜻은 init hook 이 실행될 때는 this.options 가 이미 생성되어 있다는 의미가 된다.


 - addInitHook은 대체구문이 있으며, 메소드이름과 메소드에 전달할 인수를 채워주면 된다.


부모클래스의 메소드

 - 부모클래스의 메소드를 호출하는 방법은 부모클래스의 prototype에 도달하여 Function.call()을 사용하여 호출할 수 있다.
 - 아래는 L.FeatureGroup의 코드에 대한 샘플이다.

 - 부모의 생성자를 호출하는것도 비슷하지만 다음과 같이 사용이 가능하다.
 - ParentClass.prototype.initialize.call(this, …)


factory

 - 대부분의 Leaflet 클래스는 factory 함수를 가지고 있다.
 - factory 함수는 UpperCamelCase 형식의 클래스명 대신 lowerCamelCase의 클래스명을 사용한다.


명명규칙

 - Leaflet 플러그인의 클래스 이름을 지정할 때 다음의 명명규칙을 따라야 한다.
  1) 플러그인에서 전영변수를 노출시키지 않는다.
  2) 신규 클래스가 있는경우 L 네임스페이스에 직접 추가한다. (ex: L.MyPlugin)
  3) 기존 클래스 중에 하나를 상속하는 경우 하위속성으로 만든다. (ex: L.TileLayer.Banana)



PS. 아래는 해당 튜토리얼에 나와있는 예제



참조: https://leafletjs.com/examples/extending/extending-1-classes.html


2020년 10월 24일 토요일

[Leaflet] Showing video files



웹페이지의 비디오

 - HTML Element의 video 태그를 사용할 수 있을때까지 웹페이지에서 비디오는 어려운 작업이었다.
 - 요즘에는 다음과 같은 HTML 코드를 사용할 수 있다.

 - 이 비디오는 다음과 같이 보여진다.

 - 만약 웹페이지에서 이와같이 보여줄 수 있다면 Leaflet에서 map 안에 보여줄 수 있다.
 - 여기서 비디오를 map과 (fit)크기나 사이즈가 맞게 준비되는 것이 중요하다.
 - 비디오는 지도와 같이 북향 방향으로 되어있어야 하며, 비율은 map과 (fit)맞아야 한다.
 - 그렇지 않으면 이상하게 보일 것이다.



이미지 오버레이의 경계



비디오 오버레이 추가



비디오에 대한 간단한 조작




참고: https://leafletjs.com/examples/video-overlay/


[Leaflet] Working with map panes



What are panes?

 - Leaflet에서 map pane은 개발자가 모르는 사이에 레이어 그룹화를 시킨다.
 - 이 그룹화는 웹 브라우저가 여러 레이어를 개별적으로 작업하는 것보다 더 효율적인 방법으로 작업 할 수 있도록 한다.

 - Map panes는 CSS의 z-index 속성을 이용하여 일부 레이어를 다른레이어 위에 보여준다.
 - 기본 순서는 다음과 같다.
  1) TileLayers and GridLayers
  2) Paths, like lines, polylines, circles, or GeoJSON layers.
  3) Marker shadows
  4) Marker icons
  5) Popups

 - 이 때문에 Leaflet Map에서 팝업이 다른 레이어보다 항상 위에 표시되고 marker는 타일레이어 위에 보여지게된다.

 - (0.7.x에는 없는) Leaflet 1.0.0의 새로운 기능은 이 순서를 사용자 지정할 수 있는 custom map panes 이다.



기본값이 항상 올바른건 아니다.

 - 어떤 특별한 상황에서는 기본 순서가 map에 적합하지 않으며, Cato의 basemaps 과 label 을 통해서 설명을 할 수 있다.


 - Leaflet map에서 basemaps,label 두개의 타일을 이용해서 만들 때, marker나 polygon은 이전의 두개의 타일 위에 나타나겠지만 label타일이 가장 위에 보여지는게 더 나아보일 수 있다.

 - 아래는 기본순서로 보여진 경우(오른쪽)와 기본순서를 custom 한 경우(왼쪽)이다.
   (기본 순서에서는 polygon 이 label 타일보다 위로 올라와 label을 가리게 된다.)



Custom pane



참고: https://leafletjs.com/examples/map-panes/