Writing a map library from scratch - Part 3: Panning
If you haven’t read Part 1 and Part 2 yet, I recommend you do so before continuing.
In the previous article, we implemented zooming. Now, we’ll look at panning. How does it work?
Panning
In a nutshell, panning is when you click and drag the map to move it around. It’s pretty straight forward: you just need to calculate the difference between the cursor position when the click/tap starts and when you release it, then move the map center by that amount.
Calculating the difference
Let us have the center at (x0, y0) and the cursor position at (x1, y1), where also the panning starts. The panning ends at (x2, y2). The new center will then be at:
x0 = x0 + (x2 - x1);
y0 = y0 + (y2 - y1);
Example
Let us take the same map from the previous articles:
- The center is:
(13.4, 52.52)
. - The zoom level is
14
. - One tile is
256
pixels wide and high. - The map is inside a container of
400
pixels width and300
pixels height. - The center of the container is at
(200, 150)
.
Using the Web Mercator Projection, these geo-coordinates (on a globe) can be converted
to (2253273.3155555557, 1375543.6427981234)
in
cartesian coordinates (on a flat surface). Let’s say the mouse
cursor is at (100, 150)
inside the container, and we move the cursor while
clicking/tapping to (300, 350)
. Using our formula, the new cartesian center will be:
x0 = 200 + (300 - 100);
x0 = 400;
y0 = 150 + (350 - 150);
y0 = 350
So the cartesian coordinates of the new center are:
x0 = 2253273.3155555557 + (300 - 100);
x0 = 2253473.3155555557;
y0 = 1375543.6427981234 + (350 - 150);
y0 = 1375743.6427981234;
And just like before, we need to use the web mercator projection to convert these cartesian coordinates to geographic coordinates.
axisSize = 4194304 // 256*2^14
lng = 360 * (x0 / axisSize - 0.5);
lng = 13.417166137695329;
lat = 360 * (Math.atan(Math.exp(Math.PI * (1 - (2 * y0) / axisSize))) / Math.PI - 0.25);
lat = 52.50955343022076 ;
If we plug those values back into the algorithm from Part 1, we can pan (click/tap and drag the map):