DEV Community

Cover image for How to Calculate Pixel Width and Height of a Bounding Box at Different Map Zoom Levels
Alfiya Tarasenko for Geoapify Maps API

Posted on

How to Calculate Pixel Width and Height of a Bounding Box at Different Map Zoom Levels

When creating print maps or static map images, one of the key challenges is to control the scale: how many pixels wide and tall will my area of interest be?

Imagine you have a bounding box defined by two latitude/longitude corners. Depending on the zoom, its width and height in pixels will change. Sometimes you know the zoom and want to measure the pixel size; other times you know the desired image width (or height) and want to find the zoom that makes the box fit.

This is exactly what you need when working with the Geoapify Static Maps API — for example:

  • printing a map at a specific size,
  • generating static images where labels stay readable,
  • making sure the requested area fits perfectly into the image dimensions.

In this article, we’ll cover three scenarios with simple JavaScript helpers and a live demo:

  1. Calculate bbox width and height at a given zoom.
  2. Calculate width when the height is fixed.
  3. Calculate height when the width is fixed.

Try it out in the demo: https://codepen.io/geoapify/pen/dPYLYpZ


Background: Zoom Levels, Latitude/Longitude, and Pixels

Most modern map libraries — Leaflet, MapLibre GL, Google Maps, OpenLayers — rely on the Web Mercator projection (EPSG:3857). This projection transforms geographic coordinates (latitude/longitude) into a flat, square map that can be tiled and displayed on screens.

Here’s how it works:

  • Longitude maps linearly to the X axis. At zoom level 0, the full range −180° … +180° fits into one 256 px tile.
  • Latitude is projected using the Mercator formula, which stretches distances near the poles. To avoid infinite values, the map is clipped to about ±85.05113° latitude.

A relation between the Mercator projection and the actual relative size of each country. Author: Jakub Nowosad. Source. Licensed under CC BY-SA 4.0:

Animation showing Mercator projection distortion of country sizes

The result is a grid of tiles, each typically 256×256 px:

  • At zoom 0, the world is one tile (256 px wide).
  • At zoom 1, the world is 512 px wide (2 tiles × 256).
  • At zoom 2, 1024 px wide.
  • In general:
worldSizePx = 256 × 2^z
Enter fullscreen mode Exit fullscreen mode

So every zoom step doubles the number of pixels available for both longitude and latitude.

👉 See it live: Zoom collage demo (toggle the grid to view tile boundaries).
👉 Read more: Understanding map zoom levels and XYZ tile coordinates.

This transformation from lat/lon to pixels explains why the pixel width/height of a bounding box depends on zoom. A 1° × 1° area near the equator may span only a few pixels at zoom 2, but thousands at zoom 12 — and at high latitudes, the Mercator projection exaggerates this effect even further.

This foundation prepares us for the three practical scenarios:

  1. Calculate pixel width/height of a bounding box at a given zoom.
  2. Given a fixed image height, find the corresponding width.
  3. Given a fixed image width, find the corresponding height.

Case 1: Width and Height at a Given Zoom

The simplest case: you already know the zoom level and want to measure how many pixels wide and tall a geographic bounding box will be.

This requires converting latitude/longitude to world pixel coordinates in Web Mercator. The math looks like this:

  • Longitude → X (linear):
  x = (lon + 180) / 360 × worldSize
Enter fullscreen mode Exit fullscreen mode
  • Latitude → Y (Mercator projection):
  y = (0.5 - log((1 + sinφ) / (1 - sinφ)) / (4π)) × worldSize
Enter fullscreen mode Exit fullscreen mode

where φ is the latitude expressed in radians (i.e., φ = lat × π / 180).

Here’s a small utility function in JavaScript:

const TILE_SIZE = 256;

// Convert lon/lat to world pixel coordinates at zoom
function lonLatToWorldPixels(lon, lat, zoom, tileSize = TILE_SIZE) {
  const scale = tileSize * Math.pow(2, zoom);
  const x = (lon + 180) / 360 * scale;

  const sin = Math.sin((lat * Math.PI) / 180);
  const y = (0.5 - Math.log((1 + sin) / (1 - sin)) / (4 * Math.PI)) * scale;

  return { x, y };
}

// Calculate bbox width/height in pixels at a given zoom
function bboxSizePx(bbox, zoom, tileSize = TILE_SIZE) {
  const [minLon, minLat, maxLon, maxLat] = bbox;
  const p1 = lonLatToWorldPixels(minLon, minLat, zoom, tileSize);
  const p2 = lonLatToWorldPixels(maxLon, maxLat, zoom, tileSize);
  return {
    width: Math.abs(p2.x - p1.x),
    height: Math.abs(p2.y - p1.y)
  };
}
Enter fullscreen mode Exit fullscreen mode

Example

Let’s measure a box around Paris:

const bboxParis = [2.1, 48.7, 2.5, 49.0]; // [minLon, minLat, maxLon, maxLat]

console.log(bboxSizePx(bboxParis, 5));
// → { width: 9.10 px, height: 10.37 px }

console.log(bboxSizePx(bboxParis, 10));
// → { width: 291.27 px, height: 331.98 px }
Enter fullscreen mode Exit fullscreen mode

At zoom 5, the Paris bbox is just a few pixels across. At zoom 10, it’s already several hundred pixels.

This explains why, when printing or generating static images, choosing the right zoom is crucial: too low and your area looks tiny, too high and it won’t fit into the image dimensions.

Case 2: Width from a Given Height

Sometimes you don’t fix the zoom directly — instead, you know how tall the image should be in pixels. From that height, you can derive the corresponding width of the bounding box (or the zoom that gives you that height).

The math works because in Web Mercator, both width and height scale proportionally with 2^z. If you know one dimension, you can compute the zoom and then derive the other.

JavaScript helper

// Precompute bbox deltas at zoom 0
function bboxDeltaAtZoom0(bbox, tileSize = TILE_SIZE) {
  const [minLon, minLat, maxLon, maxLat] = bbox;

  const x0a = tileSize * (minLon + 180) / 360;
  const x0b = tileSize * (maxLon + 180) / 360;
  const dx0 = Math.abs(x0b - x0a);

  const mercY = (lat) => {
    const s = Math.sin((lat * Math.PI) / 180);
    return (0.5 - Math.log((1 + s) / (1 - s)) / (4 * Math.PI)) * tileSize;
  };
  const dy0 = Math.abs(mercY(maxLat) - mercY(minLat));

  return { dx0, dy0 };
}

// Given a bbox and target height, find zoom
function zoomForHeight(bbox, targetHeightPx, tileSize = TILE_SIZE) {
  const { dy0 } = bboxDeltaAtZoom0(bbox, tileSize);
  return Math.log2(targetHeightPx / dy0);
}

// From that zoom, calculate width
function widthFromHeight(bbox, targetHeightPx, tileSize = TILE_SIZE) {
  const z = zoomForHeight(bbox, targetHeightPx, tileSize);
  const { width } = bboxSizePx(bbox, z, tileSize);
  return { zoom: z, width };
}
Enter fullscreen mode Exit fullscreen mode

Example

const bboxParis = [2.1, 48.7, 2.5, 49.0]; // Paris bbox

const result = widthFromHeight(bboxParis, 600);
console.log(result);
// → { zoom:  10.854, width: 526.42 px }
Enter fullscreen mode Exit fullscreen mode

This tells us:

  • If we want the Paris bbox to be 600 px tall, we need roughly zoom 10.9.
  • At that zoom, its width will be ~526 px.

Why it’s useful

This scenario is handy when you know the image height (e.g., fixed paper size, or a portrait-oriented static map) and want the width to scale accordingly.

Case 3: Height from a Given Width

In many layouts the image width is fixed (website container, print column). From that width, you can solve the zoom first and then derive the height of your bounding box.

JavaScript helpers

// Precompute bbox deltas at zoom 0 (reuse if already defined)
function bboxDeltaAtZoom0(bbox, tileSize = 256) {
  const [minLon, minLat, maxLon, maxLat] = bbox;

  const x0a = tileSize * (minLon + 180) / 360;
  const x0b = tileSize * (maxLon + 180) / 360;
  const dx0 = Math.abs(x0b - x0a);

  const mercY = (lat) => {
    const s = Math.sin((lat * Math.PI) / 180);
    return (0.5 - Math.log((1 + s) / (1 - s)) / (4 * Math.PI)) * tileSize;
  };
  const dy0 = Math.abs(mercY(maxLat) - mercY(minLat));

  return { dx0, dy0 };
}

// Solve zoom for a target pixel width
function zoomForWidth(bbox, targetWidthPx, tileSize = 256) {
  const { dx0 } = bboxDeltaAtZoom0(bbox, tileSize);
  return Math.log2(targetWidthPx / dx0);
}

// From that zoom, calculate height
function heightFromWidth(bbox, targetWidthPx, tileSize = 256) {
  const z = zoomForWidth(bbox, targetWidthPx, tileSize);
  const { height } = bboxSizePx(bbox, z, tileSize); // reuse bboxSizePx from Case 1
  return { zoom: z, height };
}
Enter fullscreen mode Exit fullscreen mode

Example

const bboxParis = [2.1, 48.7, 2.5, 49.0]; // [minLon, minLat, maxLon, maxLat]

const result = heightFromWidth(bboxParis, 800);
console.log(result);
// → { zoom: 11.458, height: 911.81 px }
Enter fullscreen mode Exit fullscreen mode

Interpretation:

  • To make the Paris bbox 800 px wide, you need zoom ≈ 11.5.
  • At that zoom, the bbox will be about 912 px tall.

When this helps

  • Fixed-width web containers (responsive pages where height can grow).
  • Landscape static map images that must match a target width.
  • Print layouts where column width is constrained and height can flow.

Demo walkthrough

To make the math more intuitive, we prepared a live demo you can explore in your browser:

To make the math more intuitive, here’s a live demo you can try directly:

What it shows:

  • Case 1: calculate width and height of a bounding box at a given zoom.
  • Case 2: calculate width when a target height is specified.
  • Case 3: calculate height when a target width is specified.

How to use it:

  1. Enter or adjust the bounding box coordinates.
  2. Select a zoom level or provide a target width/height.
  3. See how the bbox dimensions in pixels update instantly.

This interactive tool helps visualize the link between geographic coordinates, zoom levels, and pixel sizes — the same logic you can reuse in code when preparing static images or print maps.

Conclusion

Working with bounding boxes in Web Mercator isn’t just about coordinates — it’s also about pixels.
In this article we covered three practical scenarios:

  1. Width/height at a given zoom → useful when you already know the zoom and want to measure how large your area will appear.
  2. Width from a given height → handy when your image or print layout has a fixed height.
  3. Height from a given width → perfect for fixed-width web containers or landscape images.

These calculations are especially important when printing maps or generating static images with the Geoapify Static Maps API. They let you:

  • pick the right zoom to make your area fit,
  • avoid cutting off important features,
  • ensure labels and markers stay legible.

And with the demo, you can experiment in real time to see how zoom, width, and height interact.

👉 Explore more mapping tools and APIs at Geoapify.

Top comments (0)