티스토리 뷰
서론
지금 다니는 회사에서는 위성영상을 인공지능으로 분석해 사용자들에게 정보를 제공해주는 제품을 만드는 일을 한다. 그 중 최근 위성영상을 세그멘테이션하는 툴을 만들게 되었다. 위성영상을 확대/축소하고 이동을 하는 기능이 어려울거라 생각했지만 기존에 한번 비슷한 툴을 만들었기에 코드를 어느정도 가져오면 되겠지 싶었다. 하지만 마음대로 되지 않았고 공식(?)을 정리하고 기록해야 할 필요성을 느껴 작성하게 되었다.
요구사항
먼저 요구사항중에 줌과 이동 기능이 있었다. 다만 줌을 할때에는 마우스 포인터를 기준으로 잡고 줌인 / 아웃을 해야했다.(GIF 참조) 그리고 이동은 여느 프로그램처럼 드래그로 이동을 하면 되었다.
ZOOM
먼저 어려울것 같은 줌부터 해결해보았다. 이걸 어떻게 구현해야하나 고민하고 있을 때 마침 회사분께서 졸업작품으로 비슷한걸 구현하셨다. 그 분께 조언을 구해보니 동차 변환 행렬이란 것을 찾아보라고 알려주셨다. 찾아보니 잘 정리되있는 블로그가 있었다. 행렬을 대수식으로 표현하면 다음과 같은 식이 나온다
$$x\prime = s_xx +p_x(1 - s_x)$$
$$y\prime = s_yy +p_y(1 - s_y)$$
여기에서 S는 확대 비율을 의미한다. X는 기존의 좌표를 P는 기준이 되는 좌표를 의미한다.
(1, 1)을 (2,2)을 기준으로 2배 확대하였을때의 좌표는 다음과 같은 계산결과를 따라 (0,0)이 된다
$$x: 2 * 1 + 2(1 - 2) = 0$$
$$y: 2 * 1 + 2(1 - 2) = 0$$
이걸 코드로 적용해 보았다.
const leftTop = new Point(0, 0)
function zoom(zoomLevel: number) {
const newX = zoomLevel * leftTop.x + relativePoint.x * (1 - zoomLevel)
const newY = zoomLevel * leftTop.y + relativePoint.y * (1 - zoomLevel)
return new Point(newX, newY)
}
PAN
마우스를 잡고 드래그를 하여 위치를 옮기는 것을 Panning이라고 부른다. 패닝된 좌표를 구하는 방법은 굉장히 쉽다. 다들 눈치 챘겠지만 마우스의 무브먼트만큼 기존좌표에 더해주면 된다.
const leftTop = new Point(0, 0)
const panningEventHandler = (e: MouseEvent) => {
return new Point(leftTop.x + e.movementX, leftTop.y + e.movementY)
}
결과물
나는 위 코드와 svg의 transform matrix를 이용하여 Pan, Zoom 요구사항을 구현하였다.
const leftTop = new Point(0, 0)
function zoom(zoomLevel: number) {
const newX = zoomLevel * leftTop.x + relativePoint.x * (1 - zoomLevel)
const newY = zoomLevel * leftTop.y + relativePoint.y * (1 - zoomLevel)
return new Point(newX, newY)
}
const panningEventHandler = (e: MouseEvent) => {
return new Point(leftTop.x + e.movementX, leftTop.y + e.movementY)
}
//matrix 0, 3번째 자리에 줌값을 4번째 자리엔 x값을 5번째 자리엔 y값을 넣어주면 된다.
<svg transform="matrix(1, 0, 0, 1, 0, 0)"></svg>
'Web' 카테고리의 다른 글
CORS(Cross-Origin-Resource-Sharing) (0) | 2019.05.02 |
---|