# How to Project Geographic Coordinates to Web Mercator in Google Timeline Visualizer

> Learn how the google-timeline-visualizer projects geographic coordinates to Web Mercator using clamping and the Mercator formula for normalized x y values.

- Repository: [mahlernim/google-timeline-visualizer](https://github.com/mahlernim/google-timeline-visualizer)
- Tags: how-to-guide
- Published: 2026-08-22

---

**The google-timeline-visualizer converts latitude/longitude pairs to Web Mercator coordinates by clamping latitude to ±85.05112878° and applying the Mercator projection formula to produce normalized x and y values in the range [0, 1].**

The mahlernim/google-timeline-visualizer project transforms raw location data from Google Timeline into interactive visualizations. To render geographic data onto a flat 2D canvas, the application must project geographic coordinates to Web Mercator, the standard projection used by web mapping services like OpenStreetMap and Google Maps.

## The Core Projection Logic in [`web/src/geo.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/geo.ts)

According to the google-timeline-visualizer source code, the Web Mercator transformation lives in the `project` function within [`web/src/geo.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/geo.ts). This utility accepts latitude and longitude values and returns a `WorldPoint` object containing normalized coordinates suitable for canvas rendering.

## Step-by-Step Coordinate Projection

The implementation follows a precise mathematical sequence to ensure coordinates fit within Web Mercator bounds while maintaining geodetic accuracy.

### Step 1: Clamp Latitude to the Valid Range

Web Mercator cannot represent the poles mathematically, so the `project` function first constrains latitude to approximately ±85.05112878 degrees. This prevents infinite values from occurring in the logarithmic calculation:

```typescript
const lat = Math.max(-85.05112878, Math.min(85.05112878, latitude));

```

### Step 2: Calculate the X Coordinate (Longitude)

The x coordinate uses a linear transformation that maps longitude from the range [-180°, 180°] to [0, 1]. This simple normalization places the Prime Meridian at 0.5 and scales proportionally:

```typescript
const x = (longitude + 180) / 360;

```

### Step 3: Calculate the Y Coordinate (Latitude)

The y coordinate applies the classic Mercator projection formula. The function converts the clamped latitude to radians, computes the sine, then uses the logarithm of the tangent to produce the vertical position:

```typescript
const sinLat = Math.sin((lat * Math.PI) / 180);
const y = Math.max(
  0,
  Math.min(
    1,
    0.5 - Math.log((1 + sinLat) / (1 - sinLat)) / (4 * Math.PI)
  )
);

```

This formula effectively maps the spherical latitude to a cylindrical projection, compressing distances near the poles exponentially.

## Type Safety with `WorldPoint` in [`web/src/types.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/types.ts)

The `project` function returns strictly typed data through the `WorldPoint` interface defined in [`web/src/types.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/types.ts). This type definition ensures that all consuming components receive coordinates with explicit `x` and `y` number properties, preventing type errors throughout the rendering pipeline.

## Practical Implementation Examples

You can import the `project` function from [`web/src/geo.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/geo.ts) to convert real-world geographic coordinates into normalized Web Mercator space:

```typescript
import { project } from './geo';

// Example: San Francisco (37.7749°, -122.4194°)
const sf = project(37.7749, -122.4194);
console.log(sf); // → { x: 0.1289…, y: 0.6473… }

// Example: Tokyo (35.6895°, 139.6917°)
const tokyo = project(35.6895, 139.6917);
console.log(tokyo); // → { x: 0.7777…, y: 0.6039… }

```

## Integration with the Rendering Pipeline

Once normalized, these coordinates feed directly into [`web/src/renderer.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/renderer.ts), which handles the actual canvas drawing. The renderer uses the `WorldPoint` objects to position journey markers and draw path segments, applying additional logic for world-copy handling when journeys cross the antimeridian.

## Summary

- The `project` function in [`web/src/geo.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/geo.ts) implements the standard Web Mercator transformation for the google-timeline-visualizer.
- Latitude values clamp to ±85.05112878° to maintain finite calculations and prevent pole singularities.
- Longitude maps linearly from [-180°, 180°] to [0, 1] via `(longitude + 180) / 360`.
- Latitude transforms via the Mercator logarithmic formula: `0.5 - Math.log((1 + sinLat) / (1 - sinLat)) / (4 * Math.PI)`.
- The `WorldPoint` type in [`web/src/types.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/types.ts) enforces type safety for all projected outputs.
- [`web/src/renderer.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/renderer.ts) consumes normalized coordinates to render geographic paths on HTML5 canvas elements.

## Frequently Asked Questions

### Why does the visualizer clamp latitude to ±85.05112878 degrees?

This value represents the maximum printable latitude in Web Mercator projection. Beyond this threshold, the Mercator formula approaches infinity as it attempts to project the poles onto a flat surface. The clamping in [`web/src/geo.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/geo.ts) ensures all coordinate calculations remain finite and displayable on standard web maps.

### What is the range of output values from the `project` function?

The `project` function guarantees that both x and y coordinates fall within the normalized range [0, 1]. This normalization allows the renderer to scale coordinates to any canvas dimension or tile zoom level using simple multiplication, eliminating the need for additional transformation matrices.

### How does the projection handle coordinates that cross the international date line?

While the `project` function normalizes individual longitude values to [0, 1], the [`web/src/renderer.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/renderer.ts) module implements world-copy handling separately. This architecture allows the visualizer to render continuous journey lines that cross the antimeridian by logically unwrapping coordinate sequences across adjacent world copies.

### Is this projection compatible with standard map tile services?

Yes, the implementation adheres to the Web Mercator (EPSG:3857) specification used by OpenStreetMap, Google Maps, and most web mapping platforms. The normalized [0, 1] output from [`web/src/geo.ts`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/web/src/geo.ts) converts directly to tile coordinates at any zoom level using the formula `tileCoordinate = coordinate * (2 ^ zoomLevel)`.