[Google Maps API] Reverse-Calculating Pixel Coordinates and Why I Intentionally Disabled “Fractional Zoom”

投稿者: | 2026-04-25

日本語版の記事はこちら (Japanese version is here)

While developing the Google Maps Area Editor I recently published, I found myself in a situation where I had to manually reverse-calculate “Latitude and Longitude (LatLng)” from “Pixel Coordinates (X, Y)” on the map.

In doing so, I learned the true mathematical meaning of Google Maps’ zoom levels. I also want to share why I intentionally disabled “Fractional Zoom”—a relatively new feature introduced to the API—as a memorandum.

1. What Does the Zoom Level Value Actually Mean?

When trying to reverse-calculate the LatLng from the mouse cursor’s pixel coordinates, I realized I didn’t actually understand what the zoom level obtained via map.getZoom() (a number like 18 or 19) mathematically meant.

After digging through overseas tech forums, I found out it works like this:

  • At zoom level 0, Google Maps represents the entire world as a single tile of 256 x 256 pixels.
  • Every time the zoom level increases by 1, both the width and height double.
  • In other words, the scale at any given zoom level can be calculated as 2zoom.

Based on this, I wrote a function to reverse-calculate pixel coordinates by combining it with the current map bounds. Since it’s an integer power calculation, you can write it very simply using a JavaScript bitwise shift operator (1 << zoom).

function toLatLng(map, x, y) {
    const projection = map.getProjection();
    const bounds = map.getBounds();
    const ne = projection.fromLatLngToPoint(bounds.getNorthEast());
    const sw = projection.fromLatLngToPoint(bounds.getSouthWest());

    // Calculate the scale ratio from the zoom level (2 to the power of zoom)
    const scale = 1 << map.getZoom();

    // Divide the pixel coordinates by the scale and convert to LatLng
    return projection.fromPointToLatLng(new google.maps.Point(x / scale + sw.x, y / scale + ne.y));
}

2. The Wall of the New “Fractional Zoom” Feature

Now, a problem arises. In a relatively recent update to the Google Maps JavaScript API, a feature called “Fractional Zoom” was introduced.

This feature allows the zoom level to change smoothly in decimals (fractions) like 18.1 or 18.5 when users pinch-to-zoom on a smartphone or use a Mac trackpad.

If the zoom level is a decimal, the bitwise shift operator (1 << zoom) can no longer be used.
Of course, if you change the formula to Math.pow(2, map.getZoom()), you can mathematically handle the reverse calculation of pixel coordinates even with fractional zoom levels.

However, for this Area Editor, I made the decision to intentionally disable fractional zoom (isFractionalZoomEnabled: false).

3. The Real Reason I Disabled It (Performance Issues)

Even if the math works out, enabling fractional zoom hides a major trap: “Continuous event firing.”

The official Google documentation also includes performance warnings about this. If a user performs a pinch gesture while fractional zoom is enabled, the zoom level changes like “18.0 → 18.01 → 18.02…”, causing events (such as zoom_changed and bounds_changed) to fire massively in extremely short intervals.

The Area Editor I created contains the following heavy processing:

  • Real-time recalculation of the coordinates of the four corners (spherical geometry vector operations).
  • DOM repositioning of multiple AdvancedMarkerElements (operation handles).
  • Redrawing of the shape (Polygon).

If these processes are called at a high frequency, the browser’s rendering might not keep up, causing severe lagging or freezing.

Weighing “smooth zooming” UX against “reliable operation and performance as an editor,” I prioritized the latter. This time, I chose an architecture that forces the zoom to integer steps to prevent events from running out of control.

Conclusion

  • The scale calculation of Google Maps is based on 2zoom.
  • Fractional Zoom is smooth, but it causes excessive event firing.
  • When building custom UIs or performing heavy DOM manipulations, intentionally disabling it with isFractionalZoomEnabled: false is a highly effective performance optimization technique.

This development experience reminded me of the importance of not just blindly turning on every new API feature, but rather deciphering the warnings in the official documentation and carefully selecting features that fit the characteristics of your own application.

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です


reCaptcha の認証期間が終了しました。ページを再読み込みしてください。