How to Project Geographic Coordinates to Web Mercator in Google Timeline Visualizer
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
According to the google-timeline-visualizer source code, the Web Mercator transformation lives in the project function within 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:
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:
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:
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
The project function returns strictly typed data through the WorldPoint interface defined in 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 to convert real-world geographic coordinates into normalized Web Mercator space:
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, 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
projectfunction inweb/src/geo.tsimplements 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
WorldPointtype inweb/src/types.tsenforces type safety for all projected outputs. web/src/renderer.tsconsumes 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 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 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 converts directly to tile coordinates at any zoom level using the formula tileCoordinate = coordinate * (2 ^ zoomLevel).
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →