매끄러운 지도 프로토타이핑 (Prototyping a Smoother Map)

이 글은 Antin HarasymivPrototyping a Smoother Map글을 번역했습니다. 저의 모든 글은 허가를 받고 진행 하였습니다

Google 지도의 작동 방식을 살펴보기

제가 UX 엔지니어로 구글 지도를 만들 때, 제가 정말 하고 싶었던 일 중 하나는 애니메이션을 줌과 동기화할 수 있는 프로토타입을 만드는 것이었습니다. 그러나 JavaScript Maps API는 확대/축소 제어 기능이 제한되어 있기 때문에 제어 능력을 높이기 위해 HTML5 canvas를 사용하여 완전한 사용자 정의 구현에서 타일을 합성하는 실험을 했습니다.
최신 지도 응용프로그램에서 원활한 확대/축소 작업이 어려운 점을 이해하려면 먼저 지도 제작 방법과 Google 지도(및 다른 대부분의) 클라이언트가 작동하는 방식을 이해하는 데 도움이 됩니다. 굵은 글꼴 제목을 검색하여 바로 사용할 수 있습니다.
  1. 지구를 평평하게 만들기(Making the Earth flat) — 3D 지구를 2D 지도로 바꾸는 과정입니다.
  2. Google Maps - 2005년에 Google이 매핑의 세계를 어떻게 변화시켰는지, 그리고 클라이언트가 어떻게 렌더링했는지에 대해 설명합니다.
  3. 래스터화된 맵을 애니메이션화(Animating the rasterized map) - 부드러운 애니메이션을 활성화하기 위해 사용한 맞춤형 접근 방식입니다.

1. Making the Earth flat (지구를 평평하게 만들기)

저는 그것이 어느 누구에게도 놀라움으로 다가오지 않기를 바라지만, 세상은 둥글어요- 비록 신기하게도, 그것은 실제로 구가 아니라, 오히려 약간 구불구불하고 가운데가 더 넓어졌어요.
대부분 구형의 이 물체를 2D로 표현하는 과정은 지도제작자들이 수 천년 동안 고군분투하고 논쟁해온 것입니다. 실제로 "최선의" 방법은 없습니다. 각 방법에는 트레이드오프가 있습니다.

Latitude and Longitude (위도 및 경도입니다.)

세계를 그 축을 중심으로 회전하는 구로서 상상한다면, 북극은 맨 위에 있고, 남극은 맨 아래에 있으며, 적도는 가운데를 도는 상상의 선입니다.
presentation
Graticule-눈금판
만약 여러분이 적도를 수평으로 앉은 원이라고 생각한다면, 여러분은 각각 적도에 평행한 위아래 수평 원을 더 상상할 수 있습니다. 오른쪽으로 어떤 원을 따라가면 동쪽으로 이동하고, 왼쪽을 따라 서쪽으로 이동합니다. 이러한 상상의 선을 위도의 원(circles of latitude)이라고 합니다. 위도는 아무리 동서로 멀리 여행하더라도 항상 같은 거리입니다.
지구가 축에 기울어져 있기 때문에 태양은 항상 적도 바로 위에 앉아 있는 것이 아니라, 우리의 궤도를 도는 동안 약간 남북으로 떠돌아다니는 것으로 보입니다. 암의 트로픽(Tropic of Cancer)은 태양이 직접 머리 위로 나타날 수 있는 위도의 최북단 원이고, 카프리콘의 트로픽(Tropic of Capricorn)은 남반구(그리고 12월 동지)에 해당합니다. 구글 지도에는 사실 중요한 게 아닙니다. 하지만 이건 재미있습니다.
위도(Latitude)는 여러분이 얼마나 북쪽 또는 남쪽인지 나타냅니다(왜냐하면 여러분이 아무리 동쪽이나 서쪽으로 가더라도 여러분은 북쪽이나 남쪽으로 전혀 이동하지 않았으니까요).
적도에 수직인 다른 방향으로 달리는 것은 meridians 또는 경도선(lines of longitude)입니다. 각각은 북극과 남쪽을 일직선으로 연결합니다. 어느 선이든 북쪽을 따라 내려가면 남쪽을 따라 내려갑니다.
경도(Longitude)는 당신이 얼마나 동쪽이나 서쪽인지 나타냅니다(왜냐하면 아무리 북쪽이나 남쪽으로 가더라도 당신은 동쪽이나 서쪽을 전혀 이동하지 않았기 때문입니다.
위도와 경도의 결정적인 차이는 위도가 항상 구에서 같은 거리인 반면, 경도의 선은 중앙에서 가장 멀리 떨어져 있고 극 근처(적도)에 서로 가까이 있다는 것입니다.
presentation
위도 및 경도를 측정합니다.
위도와 경도는 모두 도(degrees) 단위로 측정됩니다. 구의 중심에서 시작하여 각 원(위도의 평행 원 및 경도의 수직 원)의 각도를 측정합니다
위도는 적도에서 형성된 각도이므로 적도에서 0º이고, 남북에서 90º까지입니다. 북극의 반쪽은 섭씨 45º N입니다.
경도(Longitude)는 Prime Meridian(영국 그리니치(Greenwich)를 통과하는 임의의 선)에서 측정한 각도입니다. 그리니치(Greenwich)에서는 0º이고 최대 180º East or West(세계의 반대쪽)까지입니다.

Global Positioning (글로벌 포지셔닝)

마지막으로, 구글 지도는 별로 중요하지 않습니다. 사람들이 GPS를 사용하기 전에 어떻게 위치를 찾는가 하는 것입니다.
위도(Latitude)는 비교적 간단합니다. 여러분은 지평선과 알려진 별 사이의 각도를 측정한 다음 약간의 계산을 하면 됩니다. 사람들은 수천 년 동안 별들을 기반으로 항해해 왔습니다. 폴라리스(북극성)는 특히 인기가 있습니다. 북극에서는 폴라리스가 바로 머리 위에 있습니다. 적도에서는 폴라리스가 지평선에 앉아 있는 것처럼 보입니다. 이 두 극단 사이에서 폴라리스에 대한 각도는 위도 북쪽의 각도입니다. 여러분은 다른 별들도 사용할 수 있습니다. 그들은 단지 더 많은 수학이 필요합니다.
경도(Longitude)는 매우, 매우, 매우 어렵습니다. 사실 너무 어려워서 1700년대 후반까지는 아무도 잘 할 수 없었습니다(또는 그보다 훨씬 더 늦기 전까지는요. 해결책에는 시간이 필요합니다. 지구는 24시간(또는 시간당 15도)마다 같은 속도로 회전합니다. 따라서 시작 시간과 현재 시간을 알고 있다면 차이에 따라 거리를 계산할 수 있습니다. 정확한 시계를 가지고 오늘날에는 쉽게 할 수 있지만 이전에는 매우 어렵습니다.
원래 그들은 알려진 시간에 천체의 예측된 위치를 이용하여 시간이 얼마인지 계산한 다음, 그것을 현지 시간과 비교했습니다(정오의 태양을 사용하여 "로컬 시계"를 재설정). 가장 널리 사용되는 예측 세트는 영국 그리니치에 있는 왕립 천문대(Royal Observatory)가 발간한 'Nautical Almanac'입니다. 왜 GMT라고 불렸는지, 왜 '프리미엄 메리디안(Prime Meridian)'이 그리니치를 통과하는지 궁금하셨다면, 이는 모든 사람들이 그리니치에 있는 천문대와 비교해서 가장 오랫동안 측정했기 때문입니다.
경도(longitude)를 측정하는 데 있어 가장 큰 돌파구는 더 정확한 시계였기 때문에 천문학(stargazing)을 멈추고 GMT를 확인할 수 있었습니다. 경도는 15º를 곱한 시간 차이입니다. 사실 이것은 우주에 앉아 있는 초정밀 원자 시계들의 집합일 뿐인 지구 위치 확인 시스템(Global Positioning System-GPS)의 발명 전까지 거의 모든 사람들이 경도를 계산한 방식입니다.
만약 여러분이 저만큼 이것에 반쯤 매료되어 있다면, 저는 그것에 관한 이 훌륭한 책을 읽는 것을 정말 추천합니다.

Picking a Projection (투영 선택)

3D 글로브의 점을 2D 평면으로 변환하는 방법을 맵 투영(map projection)이라고 합니다. 여기에는 각각 고유한 강도와 한계를 가진 여러 가지 예측(projections)이 있으며 실제 형상에 어떤 형태의 왜곡이 없는 것은 없습니다.
presentation
위키피디아에서 투영(projection)
Google 지도에서 선택한 투영은 웹 메르카토르(Web Mercator)라는 제목의 Mercator 투영(Mercator projection)을 변형한 버전입니다. [주요 차이점은 이 세상이 평평한 타원체 대신 구라고 가정한다는 것입니다].
메르카토르(Mercator)를 선택하는 데는 몇 가지 이유가 있지만, 가장 좋은 이유는 북쪽과 남쪽이 직선으로 위아래이고, 동쪽과 서쪽이 직선으로 되어 있기 때문입니다. 다른 일부 예측에서는 이 선들이 지도를 가로질러 이동할 때 구부러지거나 이탈할 것입니다. 이는 메르카토르(Mercator)가 항법용으로 널리 채택된 이유와 매우 유사합니다. (즉, 나침반 베어링을 선택하고 고정하는 경우) 항법 라인은 완전히 직선입니다. 측면의 이점은 원통형 투영이기 때문에 수평으로 포장을 하고 지도를 타일링할 수 있다는 것입니다.
메르카토르(Mercator) 투영의 다른 특성은 스케일이 국부화된 지점 주변의 모든 방향에서 동일하며(도시를 확대하면 남북 거리가 동서로 동일합니다) 모든 각도가 정확하게 묘사된다는 것입니다(동부는 북쪽에서 90º).
메르카토르(Mercator) 투영에 대한 가장 큰 비판은 적도에서 멀어질수록 국가의 규모를 크게 왜곡한다는 것입니다.
오렌지 껍질을 벗겼을 때 어떤 일이 일어나는지 생각해보고, 지구에도 똑같이 한다고 상상해보세요. 일련의 세로 선을 따라 자르는 경우, 지구상의 각 세로 선은 직선으로 나타나지만, 두 개의 치수로 포장을 풀면 곡선이 됩니다(경도 선이 극에서 어떻게 서로 가까워졌는지를 기억하십시오).
presentation
Unwrapping the globe
메르카토르(Mercator) 지도가 다시 합쳐지도록 하려면 이 구획들을 수평으로 늘려야 합니다. 적도에서는 이미 접촉하고 있기 때문에 스트레칭이 전혀 필요 없지만 극지방에서는 정말 큰 간격이 있고 많이 뻗어야 합니다. 수평으로 펼쳐질 때 거리와 각도를 양방향으로 보존하기 위해 동일한 양만큼 수직으로 늘어납니다. 극에 가까울수록 더 늘어나야 합니다.
지도의 여러 점에 같은 크기의 원을 그리려고 하면 시각화하기가 조금 더 쉽습니다. 메르카토르 투영의 경우, 원들이 극을 향해 훨씬 더 크게 나타나는 것을 볼 수 있습니다(실제 동일한 크기이긴 하지만). 이것은 우리가 지도를 연결하기 위해서 극지방에서 더 늘려야 했기 때문입니다.
presentation
규모의 변형입니다.
이것은 매우 축소되었을 때만 중요합니다. 왜냐하면 그 규모는 어느 지역에서도 같기 때문입니다. 그래서 주어진 도시나 심지어 국가에서도 모든 것이 비례하기 때문입니다. 그리고 이것은 극지방에 있어서 정말 중요한 문제일 뿐입니다. 하지만 펭귄과 북극곰은 구글 지도를 사용하지 않기 때문에 불평이 별로 없었습니다.
만약 우리가 구를 다시 생각해보면, -- 위도의 선이 서로 평행하고, 항상 같은 거리인 반면, 경도의 선이 극지방에서 서로 더 가까워졌을 때 -- 메르카토르와 함께, 위도는 완벽하게 평행하고, 경도는 완벽하게 수직이 됩니다. 모든 것이 곧습니다.
Grafonaut의 이 환상적인 비디오는 전체적인 변화를 보여줍니다.
3D 글로브를 2D Mercator 투영으로 변환합니다.

2. Google Maps

2005년에 Google 지도는 오늘날에도 여전히 모든 매핑 서비스, 즉 타일 맵을 뒷받침하는 혁신 기술을 사용하여 출시되었습니다. 2013년에는 WebGL을 사용하고 클라이언트 측 렌더링을 추가하기 위한 주요 업데이트가 있었지만, 여전히 타일링 방식입니다.
제가 주목해야 할 것은 구글 지도(Google Maps)는 타일 맵의 개념을 고안해 낸 것이 아니라, 아마도 그것을 사용하는 최초의 주류 애플리케이션일 것입니다. 그리고 그것을 AJAX와 웹과 결합하는 것은 확실히 접근법을 대중화하는 데 도움이 되었습니다.

Tiled Maps

Google은 단일 이미지를 렌더링하는 대신 지도를 더 작은 타일로 분할한 다음 서로 옆에 배치하여 모자이크처럼 하나의 큰 그림을 구성합니다.
presentation
Tiled Map
그 주된 이유는 이미지 크기입니다. Google 지도의 가장 높은 확대/축소 수준에서는 이미지가 5억 화소(HDPI 화면의 두 배) 이상이 될 것이며, 이는 낙관적인 이미지 압축에도 25,000 테라바이트(내 생각에는?) 이상이 될 것입니다. 브라우저에서 해당 이미지를 렌더링할 수 있다고 가정하면 Google Fiber를 사용하여 다운로드하는 데 6년 이상 걸립니다.
두 번째 이유는 서버 부하입니다. 타일을 사용하는 대신, 서버는 정확한 확대/축소 수준, 위도 및 경도 및 창을 채우기 위한 올바른 크기로 각 사용자에 대한 완벽한 크기의 맵을 생성할 수 있습니다. 하지만 이는 각 사용자가 완전히 사용자 지정 맵을 필요로 한다는 것을 의미할 수 있으며, 월 10억 명 이상의 사용자 지정 맵이 매우 많다는 것을 의미합니다. 또한 몇 픽셀이라도 지도를 이동할 때마다 완전히 새로운 지도를 다운로드해야 합니다.
타일은 누구나 공유할 수 있고, 서버는 타일을 캐시할 수 있으며, 사전 생성도 할 수 있으며, 클라이언트가 타일을 쉽게 이동할 수 있습니다. 일부 사용자는 창이 더 크면 몇 개의 추가 타일을 다운로드할 수 있지만 여전히 타일은 한 번만 렌더링하면 됩니다.
참고: 2013 벡터 기반 WebGL 구현의 경우 서버는 이미지 타일을 보내는 대신 벡터 정보(각 경로 및 폴리곤)를 보내고 클라이언트는 이미지를 렌더링합니다. 그러나 이 벡터 정보는 정확히 같은 이유로 "타일"로 분류됩니다(서버 캐슁을 허용하고 클라이언트가 데이터 요청을 세분화할 수 있는 깨끗한 방법을 제공함). 다음 섹션에서는 래스터 구현(Maps JavaScript API에서 여전히 사용됨)에 대해 설명하지만 일반적인 접근 방식은 WebGL 버전에도 적용됩니다.

Zoom Levels

Google 지도는 위치를 기준으로 다양한 확대/축소 수준을 가지지만 대개는 21개 정도 됩니다. 가장 확대/축소된(레벨 0)에서 전체 맵은 단일 256 x 256 픽셀 정사각형 타일로 표시됩니다. 모든 증분 확대/축소 수준에서 맵은 각 방향으로 크기가 두 배로 증가합니다. 확대/축소할 때 각 타일은 4개의 더 상세한 것으로 대체됩니다(2x2). 각 타일은 여전히 256 x 256 픽셀에 불과하며, 조합하면 동일한 맵이 표시됩니다(자세한 내용만 해당).
확대/축소 수준 0에서는 세계 지도가 단일 타일이고, 확대/축소 1에서는 각 방향으로 2개의 타일, 확대/축소 2에서는 4개의 타일, 확대/축소 3에서는 8개의 타일, 기타 등입니다(매 번 2배). 따라서 전체 너비와 높이가 각 레벨의 두 배가 되는 반면 영역은 더 빠르게 증가합니다(타일 1개, 타일 4개, 타일 16개, 타일 64개 등). 확대/축소 수준 21에 도달할 때까지 지도의 폭은 2백만 개의 타일이며, 총 4조 개 이상의 타일이 포함되어 있습니다.
presentation
각 확대/축소 수준에서 타일을 매핑합니다.
각 확대/축소 수준에는 표시할 정보를 결정하는 고유한 스타일 규칙이 있습니다. 세계 지도에 도로 정보를 추가하는 것, 국가 지도 등에 빌딩 정보 등을 추가하는 것은 거의 가치가 없습니다.... 각 수준에서 제시되고 스타일링되는 라벨과 특징의 균형을 끊임없이 맞추는 매우 열심히 일하는 팀이 있습니다.
presentation
일반적으로 첫 몇 가지 수준은 세계 지도에 불과합니다. 확대축소 5에서 대륙과 대륙은 주요한 특징입니다. 10단계에서는 도시의 세부사항이 나타납니다. 레벨 15에서는 거리가 뚜렷하게 보입니다. 줌 20으로 건물들이 모두 렌더링됩니다.
이러한 확대축소에 대한 픽셀 배율을 쉽게 추정할 수 있습니다(더 복잡한 산술로 정밀하게 수행할 수 있지만, 적도(Mercator 투영이 지도를 확장하지 않는 곳)에서는 다음과 같은 간단한 계산입니다).
확대/축소 1은 78km(48마일)이고, 확대/축소 5는 5km(3마일)이며, 확대/축소 10은 150m(164야드), 15m(5.5야드)이며, 확대/축소 20은 15cm(6인치)에 상당합니다.

Positioning

Google 지도에는 위도 및 경도 외에 좌표의 세 가지 개념이 있습니다: 세계 좌표, 픽셀 좌표, 타일 좌표.
월드 좌표(World coordinates)는 확대/축소 수준과 무관하며, 위도와 경도 및 지도의 현재 위치를 변환하는 데 사용됩니다(또는 그 반대). 줌 레벨 0에서 단일 타일을 기준으로 계산됩니다. 위도 및 경도는 해당 단일 타일의 분수 x 및 y 픽셀(0 ~ 256 — 너비와 높이 사이의 숫자)에 매핑됩니다.
비록 제가 수학을 이해한다고 주장할 수는 없지만, 변환은 매우 쉽습니다. 경도 매핑은 직접 번역하기 때문에 이해하기 쉽지만, 위도는 극에 가까워질수록 꼬임 때문에 더 복잡합니다.
픽셀 좌표(Pixel coordinates)는 지정된 확대축소 수준에서 위도와 경도의 정확한 픽셀 위치를 참조합니다. 이 값은 세계 좌표를 가져와서 확대/축소 수준의 총 스케일링 양에 곱하여 계산할 수 있습니다. 축척은 각 확대/축소의 두 배가 되기 때문에 계산하기 쉽습니다.
타일 좌표(Tile coordinates)는 클라이언트가 서버에 이미지를 요청하는 방법입니다.
presentation
Tile coordinates
행과 열에 위치하며, 왼쪽 상단에 0열, 오른쪽으로 행이 증가하며, 아래로 내려갈수록 열이 증가합니다. 픽셀 좌표와 마찬가지로 타일은 확대/축소 수준에 따라 달라지며, 실제로는 픽셀 좌표를 타일 크기로 나누고 정수 숫자를 취하여 픽셀에서 타일로 간단하게 매핑할 수 있습니다.
클라이언트는 화면의 각 모서리에 대한 타일 좌표를 계산하여 필요한 타일을 쉽게 알아낼 수 있습니다. 일반적으로 사용자가 지도를 몇 픽셀 이동시킬 경우에 대비하여 미리 로드하는 방법으로 패딩이 약간 추가됩니다.
클라이언트는 이러한 좌표를 사용하여 타일 URL을 쉽게 생성할 수 있습니다(예: 확대축소 수준 1, 행 0, 열 0, 이 타일은 북아메리카를 포함합니다). Maps API가 사용자를 위해 처리하지만(스타일링 및 기타 이점과 함께) 코드로 구성하는 것은 사소한 일입니다.

Panning

지도와 상호작용하는 것은 타일이 그들의 가치를 증명하는 곳입니다. Google 지도 이전에는 지도 가장자리에 있는 경우, 페이지를 돌려서 더 많은 것을 볼 필요가 있었습니다. 타일의 장점은 사용자가 이동하거나 축소할 때 중단 없이 지도를 자유롭게 탐색할 수 있다는 점입니다.
각 타일은 컨테이너 안에 완전히 배치되고, 모든 타일을 이동하는 대신 맵을 이동하면 컨테이너만 이동하면 됩니다(따라서 타일이 함께 이동). 이렇게 하면 클라이언트가 DOM 변경 횟수를 최소화할 수 있습니다.
presentation
The container moves, not the tiles
타일 좌표를 타일 크기에 곱하기만 하면 각 타일의 위치를 쉽게 계산할 수 있습니다.
마지막 포지셔닝 방법은 브라우저에서 렌더링해야 하는 총 타일 수를 최소화하는 것입니다.
presentation
Maintaining a constant sized DOM
사용자가 맵을 이동하면 클라이언트는 표시할 타일을 확인하고 새 타일을 로드하거나 더 이상 표시되지 않는 타일을 제거합니다.
이 작업은 매우 빠르게 수행되므로 사용자가 거의 알아차리지 못합니다(화면의 하드 한계까지 클리핑하는 대신 양쪽에서 버퍼로 추가 타일을 가져오는 경우가 많습니다). [이 접근 방식은 실제로 Google 포토의 현재 작동 방식과 크게 다르지 않습니다.]

Zooming

상하좌우 이동은 원활하지만, 확대축소는 타일 맵을 사용하는 도전 영역 중 하나입니다.
기술 측면에서는 타일을 배치하는 방법보다는 레벨 간에 전환하는 방법이 더 중요합니다. 각 확대/축소 수준은 배율이 두 배로 증가하며, 도움이 되는 중간 타일은 없습니다.
presentation
Snapping between levels
원래 확대축소는 매우 간단했습니다. 지도를 다음 타일 세트로 대체했을 뿐이죠. 하지만 그것은 약간 거슬렸습니다. 왜냐하면 갑자기 레벨 사이에서 "snap"을 치기 때문입니다.
이를 보상하는 한 가지 방법은 지도의 중심을 확대하지 않고 커서 아래에 있는 모든 위치를 정지 상태로 유지하는 것입니다(커서 아래에 고정됨). 이를 통해 사용자는 관심 있는 기능을 문자 그대로 "점점"하고 집중(기준점 제어)할 수 있습니다.
presentation
Quick scale animation (Maps JavaScript API)
더 최근의 적응은 그것이 더 반응하는 것을 느끼게 했습니다. 확대/축소할 때, 일시적으로 두 확대/축소 수준의 타일(구형 및 신품)을 모두 유지하고 그 사이에 매우 빠른 규모의 애니메이션을 수행합니다. 새 타일은 절반으로 축소되기 시작하고 이전 타일은 두 배 크기로 애니메이션됩니다.
애니메이션이 끝났을 때 여전히 층간에서 "snaps"하지만, 모든 것이 너무 빨리 일어나, 눈이 중간 상태를 상상합니다.
이 스케일 & snap 접근 방식은 Google Maps JavaScript API, Bing Maps, Here Maps, Yahoo Maps, MapQuest, 및 OpenStreetMap (LeafletJS).에서 오늘날에도 여전히 사용되고 있습니다.
presentation
Scale transition during zoom
스케일 및 스냅의 가장 큰 제한은 사용자가 애니메이션을 제어할 수 없으며, 줌을 완료될 때까지 실행하면 속도를 제어하거나 중간 상태에서 일시 중지할 수 없다는 것입니다.

Vector Maps

2013년 Google 지도는 maps.google.com에 PNG 타일 사용을 중지하고 벡터 타일 다운로드를 시작한 주요 업데이트를 발표했습니다. 이러한 벡터 타일은 여전히 타일 좌표로 참조되며 래스터 타일과 매우 유사하게 동작하지만 이미지 대신 모든 레이블, 경로 및 폴리곤을 포함하고 클라이언트에 그려집니다.
벡터 데이터가 이미지보다 더 잘 압축되므로 대역폭을 절약하고 동적 업데이트와 스타일링을 수행할 수 있으며(예: 사용자가 전송 경로를 클릭하는 경우) 상당히 향상된 확대/축소를 가능하게 하는 등 다양한 이유가 있습니다.
presentation
Smooth zooming
래스터라이징된(rasterized) PNG를 사용하면 지도에서 도로(동일한 너비를 그어야 함)나 공원(그리고 더 크게 확장해야 함)을 구분할 수 없습니다. 이는 모든 것이 확장되고 확장된다는 것을 의미합니다. 벡터 정보를 통해 고객은 레이블을 올바르게 배치하고 도로 폭을 유지하면서도 모든 폴리곤의 크기를 조정할 수 있습니다. 따라서 놀랍도록 부드러운 확대 작업이 가능합니다. 또한 응답성이 뛰어나 사용자가 속도를 조절할 수 있고, 심지어 확대/축소 수준에서 정지할 수도 있습니다.
그러나 타일을 매우 원활하게 확장하는 동안 자세히 살펴보거나 직접 사용해 보면 멈출 때까지 새로운 정보가 없습니다. 사용자가 확대/축소를 일시 중지하면 맵은 벡터 타일을 새 확대/축소 수준에서 빠르게 로드하고 스왑 아웃합니다. 정말 매끄럽고 snap합니다.
MapBox는 웹에서 벡터 타일을 사용하는 다른 클라이언트 중 하나이며, 확대/축소 전환 중에 보다 적극적으로 새 타일을 로드하지만 이 매끄럽고 snap하는 접근 방식도 사용합니다.

3. 래스터화된 지도를 애니메이션화합니다.

지도를 부드럽게 애니메이션화할 수 있도록 하기 위해 가장 중요한 요소는 부분 확대/축소 수준(예: 타일이 렌더링하는 두 개의 적분 확대/축소 수준 사이의 중간)을 설정하는 기능입니다. 벡터 타일을 사용하면 클라이언트에서 이를 사용자 지정할 수 있지만 래스터 타일을 사용하면 보다 창의적인 작업을 수행해야 합니다.
이를 지원하기 위해 Maps JavaScript API의 완전한 사용자 정의 버전을 작성했습니다. 이 버전은 Maps Server의 이미지 타일을 재사용하지만 위치시키고 상호 작용을 자체적으로 처리합니다. 이를 통해 각 타일의 스케일링 및 위치 조정과 줌 및 애니메이션에 대한 완전한 제어가 가능해졌습니다. 모두 4,442줄의 코드로 되어있었습니다. 클라이언트가 얼마나 적은 코드를 필요로 하는지는 놀랍지만, 생각해보면, 대부분의 정말 힘든 작업이 서버에서 이루어지고 있습니다(각 타일에 어떤 도로, 호수, 건물 등이 보이는지 알아내고, 스타일과 색상을 결정하고, 그것을 이미지로 렌더링).
이 문서의 나머지 부분은 Google 지도의 일반 버전이 아닌 제 시제품 코드(prototype code)를 참조합니다.

부분 확대/축소 수준을 만듭니다.

Google 포토의 접근 방식과 유사하게 로딩 시 세부 정보를 혼합하기 위해 로우레스와 하이레스의 이미지 간의 불투명성을 교차 분석합니다. 제 이론으로는 여러 확대/축소 수준에서 타일을 혼합하여 중간 상태를 만들 수 있습니다.
더 낮은 확대/축소(zoom) 수준을 취해서 확대하거나, 반대로 축소할 때 더 높은 확대/축소(zoom) 수준을 축소할 수 있습니다. 여러 확대/축소 수준에서 타일을 스케일링하고 오버레이함으로써 적분 확대/축소 간에 원활하게 전환하고 수학적으로 예측 가능한 방식으로 수행할 수 있습니다(애니메이션 동기화에 적합).
Google이 Mercator Projection(Mercator 투영)을 사용하기 때문에 가능합니다. 척도는 국부적으로 균일하므로 타일을 선형적으로 확장하면 모양이 보존됩니다.
교차 페이드(cross-fade)의 불투명도(opacity)를 계산하는 것은 간단하고 선형적(linear)입니다. 두 확대/축소 수준 간에 전환할 때 첫 번째 확대/축소 단계에서는 다음 타일이 완전히 투명(opacity 0)해야 하고, 다음 단계에서는 완전히 불투명(opacity 1)해야 합니다. 불투명도는 지도 확대축소로부터 타일 확대축소 거리를 1 빼는 것입니다(실제로 0과 1 사이의 값으로 클램핑하더라도).
스케일도 그리 복잡하지 않습니다. 각 확대/축소 수준에서 척도가 두 배로 증가하면 2의 파워를 사용하여 중간 수준의 척도 크기를 계산할 수 있습니다.
mapZoom이 타일보다 전체 수준(mapZoom - tyleZoom = 1)인 경우 계산 결과가 2¹ 또는 2가 됩니다. mapZoom이 타일과 동일한 수준(mapZoom - tyleZoom = 0)인 경우 계산은 2⁰ 또는 1이 됩니다. 힘을 계산할 때 가장 좋은 점은 분수와 부정적인 면에 효과가 있다는 것입니다. mapZoom이 tyl(mapZoom - tyleZoom = -1)보다 전체 수준보다 낮으면 2⁻¹ 또는 0.5가 됩니다. 확대/축소 수준(mapZoom - tilZoom = 0.5)을 절반으로 설정하면 2^(0.5) 또는 1.414가 됩니다. 이렇게 하면 각 상태 간에 원활하게 확장할 수 있습니다.
다음 그림에서는 확대 시 이 기능이 어떻게 적용되는지 보여 줍니다. 단색 타일은 시작 확대/축소 수준이고 색상이 지정된 타일은 다음 확대/축소 수준입니다(차이를 관찰할 수 있도록 체크보드에 표시됨). 다음 확대/축소 수준에 가까워질수록 색상이 지정된 타일이 우세해지고 세부 정보(예: 레이블)가 희미해지기 시작하는 것을 볼 수 있습니다.
presentation
Zooming in
여기 반대 방향입니다. 축소합니다. 모노크롬(Monochrome)은 다시 시작 확대/축소 수준으로 이전 확대/축소 수준을 색칠합니다. 이 경우 축소할 때 세부 정보가 손실됩니다.
presentation
Zooming out
이 기능은 매우 효과적이어서 상대적으로 부드러운 확대축소(스케일 & 스냅보다 훨씬 좋음)를 제공하며, 벡터 렌더링(smooth & snap)만큼 부드럽지는 않지만 실제로 스냅 측면이 완전히 제거됩니다.
새 타일이 로드되는 위치를 볼 수 있도록 GIF에 디버그 오버레이를 켰습니다. 실제는 더 부드럽지만(초당 60프레임) GIF를 12fps로 제한했습니다. 여기 비디오가 있습니다. 또는, 여기에 디버그 선이 없습니다.
presentation
12fps
어느 한쪽 극단에서든 지도는 적분 확대/축소와는 거의 다를 수 있지만 중간에 레이블이 서로 경쟁하면서 어색한 상태가 될 수 있습니다. 이는 부분 확대/축소 수준에 머무르는 경우 큰 효과는 없지만 전환 중에 문제가 되지 않으며, 부분 확대/축소를 피하려면 사용자가 확대/축소를 마치면 클라이언트가 다시 적분 확대/축소를 "결정"하여 그 동안 완전한 제어 상태를 유지할 때까지 기다리기 쉽습니다.
presentation
Zooming between integral levels 3 and 4
이걸 효과 척도 & 블렌드라고 할까요? 원활한 확대축소뿐만 아니라 사용자 입력에도 항상 반응합니다.
presentation
Animating zoom at 24fps

HTML5 Canvas

최상의 성능을 얻기 위해 표준 HTML 요소를 사용하는 일반적인 웹 접근 방식을 포기했습니다. 앞 절에서 설명한 대로 맵 API는 DIV와 IMG 요소를 조합하여 맵을 렌더링합니다. 각 이미지는 상위 컨테이너 안에 배치되고 해당 컨테이너는 맵 팬으로 이동합니다. 브라우저가 일반적인 웹 응용 프로그램을 통해 많은 이점을 얻을 수 있는 경우, 브라우저는 화면을 다시 그릴 시기, 요소를 배치 및 배치하는 방법, 상호 작용(예: 스크롤 및 클릭 이벤트)을 간소화하는 방법에 대한 모든 결정을 처리합니다. 이를 위해 브라우저를 활용하는 것이 거의 항상 최선의 방법입니다.
그러나 특히 매우 사용자 지정 도면의 경우 수동으로 수행하는 것이 유리할 수 있습니다. 이를 지원하기 위해 브라우저에서 캔버스 요소를 만들었습니다. 요소를 작성하여 페이지에 추가하는 일반적인 HTML과 달리 캔버스를 사용하여 해당 페이지에 명령어를 그립니다. 선, 호, 원, 직사각형 및 복잡한 곡선을 그릴 수 있습니다. 캔버스는 당신을 위해 어떤 추가적인 것도 하지 않을 것이고, 그 결과를 단지 그림처럼 취급할 것입니다. 캔버스에 이미지를 그리는 경우 정확히 위치와 크기를 알려야 하며, 이미지를 몇 픽셀 이동하려면 캔버스 전체를 지우고(다른 선과 영상 포함) 모든 것을 다시 칠해야 합니다. 일반 웹 사이트를 스크롤하면 브라우저에서 위치를 재계산하고 다시 그립니다. 사용자가 캔버스를 스크롤할 수 있도록 하려면 모든 위치를 수동으로 재계산한 다음 모든 조각을 직접 다시 그려야 합니다.
만약 그것이 많은 일처럼 들린다면, 그것은 정말로 그렇습니다, 그리고 그것이 캔버스가 더 자주 사용되지 않는 많은 이유들 중 하나입니다; 그러나 캔버스가 무언가를 성취하는 가장 좋은 방법이고, 완전히 맞춤화된 지도 렌더러는 그것들 중 하나입니다. (모든 타일의 스케일링과 위치가 어쨌든 어느 정도 복잡성을 더해 주었기 때문에) 오버헤드를 줄였습니다.)
페이지 구성의 차이를 시각화하는 한 가지 방법은 결과적인 HTML을 보는 것입니다. 일반적인 접근방식은 수십 개의 요소를 만들어 페이지에 추가하지만 캔버스 접근방식은 거의 없습니다. 캔버스 접근방식은 모든 것이 캔버스 안에서 그리기 명령어였습니다.
presentation
요소 기반과 캔버스 접근법 사이의 페이지 구조 차이를 나타냅니다.

Fallback tiles

타일을 스케일링 및 블렌딩할 때 처리할 수 있는 한 가지 가장자리 케이스는 혼합할 타일이 없는 경우에 발생합니다. 아래쪽 확대/축소가 아직 로드되지 않은 경우 다음 수준에서 불투명도를 애니메이션화하는 대신 완전히 불투명하게 시작하는 것이 좋습니다. 그렇지 않으면 지도에 패치가 있는 간격이 있을 것입니다.
폴백 타일의 적용 범위를 계산하면 사용자 지정 캔버스 구성이 실제로 빛을 발하는 영역입니다. 각 그리기 작업은 사용자 지정 불투명도를 설정할 수 있습니다. 캔버스는 작은 그리기 작업(예: 지도 타일 크기)에 매우 효율적이기 때문에 각 개별 타일에 대한 사용자 지정 불투명도 수준을 효율적으로 설정할 수 있습니다. 사용자 지정 요소를 사용하여 이 작업을 수행하는 경우 모든 개별 애니메이션이 느려질 수 있습니다.
클라이언트는 항상 전체 불투명도에서 폴백(fallback)-the underlying 타일을 그립니다. 그리고 위에 오버레이되는 기본(대상 확대축소 수준) 타일의 불투명도만 변경합니다. 도색 사이클 전에 기본 타일에 완전한 폴백 커버리지가 있는지, 즉 해당 타일 아래에 모든 것이 그려졌는지 확인합니다.
예를 들어, 확대/축소 0에서 1까지, 색상이 있는 타일은 전체 적용 범위를 가지며, 그 아래에 있는 단일 회색 타일은 완전히 겹칩니다. 이것은 그들이 빈틈없이 안전하게 그들의 불투명함을 애니메이션화 할 수 있다는 것을 의미합니다.
하지만 그 반대는 사실이 아닙니다. 1에서 0까지(색상이 있는 타일이 언더레이가 되는 경우) 축소할 경우, 회색 타일의 불투명도를 애니메이션화할 수 없습니다. 공백이 좀 남기 때문입니다.
presentation
이에 대한 한 가지 가능한 해결책은 커버리지 없이 기본 타일을 완전히 불투명한 기본 계층으로 한 번 칠한 다음, 폴백 타일을 칠한 다음, 기본 타일 불투명도를 안전하게 변경하는 것입니다(최악의 경우 자체와 혼합될 수 있음).
불투명성으로 또 다른 작업을 수행할 수 있습니다. 새로 로드된 타일에서는 빠르게 애니메이션을 생성해야 합니다. 즉, 제자리에 스냅하는 대신, 빠르게 페이드됩니다.

Zoom direction and velocity 방향과 속도를 확대/축소

또한 클라이언트는 사용자가 확대/축소하는 방향과 확대/축소하는 속도를 추적하고 이를 사용하여 새 타일을 로드해야 하는지 여부를 결정합니다.
예를 들어 14에서 15로 확대할 경우 클라이언트는 더 이상 확대/축소 수준 14에서 더 이상 타일을 로드하지 않고 15에서 필요한 새 타일을 가져오는 우선 순위를 지정합니다. 반대로 15에서 14로 축소되는 경우 클라이언트는 14의 새 타일만 로드하려고 합니다.
또한 확대/축소 속도를 사용하여 타일을 로드할 수 있는 지점이 있는지 또는 이미지를 로드하기 전에 레이어가 확대/축소될 가능성이 있는지 여부를 결정합니다. 예를 들어, 빠르게 확대하면 사용자가 1초 만에 확대/축소 4에서 15까지 경주를 할 수 있습니다. 5, 6, 7, 8... 왜냐하면 타일 낭비일 뿐이기 때문입니다. 다행히도, 확대/축소를 위해 몇 개의 타일(줌 0에서 타일은 전 세계를 나타냄)만 축척하여 색상/형상을 모호하게 나타낼 수 있습니다.

Avoiding downscaling 다운스케일링 방지

더 높은 확대/축소 수준에서 맵이 점점 더 상세해지고 있기 때문에, 저는 순진하게도 확대/축소할 때 더 높은 수준을 사용하고 축소하는 것이 바람직하다고 생각했습니다.
presentation
Downscaling too many tiles - 너무 많은 타일을 축소
그러나 실제로 이것은 잘 작동하지 않았습니다. 모든 폴리곤(예: 물이나 공원)의 스케일이 잘 보존되어 있는 반면, 모든 라벨과 아이콘의 스케일이 조정되어, 특히 중간에 매우 복잡하게 보이는 지도가 만들어집니다. 퍼포먼스도 큰 성공을 거두었습니다. 왜냐하면 수십 개의 타일을 그리는 대신 갑자기 수백 개의 타일을 그릴 수 있게 되었기 때문입니다.
이를 방지하기 위해 다운스케일링을 1개 이상의 확대/축소 차이만큼 비활성화했습니다. Ie 14s의 부분 수준(예: 14.2)을 확대하면 확대/축소 15의 타일을 사용할 수 있지만 16개 이상의 타일은 사용할 수 없습니다.

Animations

프로젝트를 시작할 때 제가 언급한 의도는 애니메이션과 줌을 프로그래밍 방식으로 동기화할 수 있도록 하는 것이었는데, 이는 사용자 입력에 더 부드럽고 반응하는 단점이기도 합니다. 적분 확대/축소 수준에서 일반적인 구현과 동일하게 작동합니다. 하지만 저는 이것이 애니메이션을 하는데 꽤 효과적이라고 생각합니다. 스스로 판단할 수 있습니다.
다음은 샌프란시스코에서 호주까지 가능한 비행 경로를 시각화한 예입니다. [전체 비디오 또는 디버그 오버레이가 있는 비디오]를 선택합니다.
presentation
샌프란시스코에서 호주까지(그리고 매끄럽게) 비행하세요.
물론 애니메이션을 확대축소하는 데 제한을 받을 필요는 없습니다. 모든 것을 캔버스에 칠하는 것의 또 다른 이점은 우리가 원한다면 정말로 창의적인 것들을 할 수 있게 해준다는 것입니다.
presentation
destination-out globalCompositeOperation
표시된 것은 캔버스의 대상 출력 구성 모드를 사용하여 지도에서 도형을 "잘라내기(destination-out)"하는 예입니다. 여기서는 색칠된 지도 위에 흑백 지도를 덧씌운 다음 도면을 애니메이션화합니다. [전체 비디오]입니다.

Future usage 향후 사용량

Google과 MapBox는 모두 이러한 스케일과 혼합 방식을 뛰어넘는 벡터 렌더링을 가지고 있습니다. 벡터 타일로 업그레이드하지 않은 다른 모든 사람들에게 비슷한 것을 구현하는 것을 고려하도록 기꺼이 권하고 싶습니다. 이 기술은 매우 단순한 기술입니다. 즉, 벡터 렌더링에 비해 훨씬 복잡하지는 않지만 훨씬 부드럽고 응답성이 뛰어난 환경을 지원합니다.

이 글은 번역 글입니다. 원본 링크입니다.


안녕하세요! Early adopter입니다.
페이스북 [DTF] 디자인 번역 공장 - Design Translation Factory 그룹도 많이 가입해주시길 바랍니다.
"보버"에서 "디자인 번역 공장" 연재를 저와 함께 해주실 분을 찾습니다. 하단 "리뷰" 또는 "페이스북"으로 편하게 메시지 주세요!
PS. 제가 사용하는 블로그 "보버"에 "함께 쓰는 블로그"라는 기능이 요번에 추가됐네요 ㅋ (미디엄에 퍼블리케이션 같은 기능..)
하단 링크 글을 보시면 "디자인 번역 공장"에 어떻게 함께 연재할 수 있는지 자세히 설명되어있습니다. 또는 쉽게 FB 메시지 주세요!
https://bit.ly/2LxR0Bz