Polyline Encoding
Understand the encoded polyline algorithm and use our interactive playground to encode/decode coordinates
Overview
Polyline encoding is a lossy compression algorithm that stores a series of coordinates as a single ASCII string. The Woosmap Directions API returns route geometries as encoded polylines.
When using the Map JS API with DirectionsRenderer, decoding and display are handled automatically. The DirectionResult object also provides a pre-decoded overview_path property if you need direct access to the coordinates.
Polyline Encoding Algorithm
The encoding process converts coordinates into ASCII characters using a base64-like scheme. Each encoded value is summed with 63 (the ASCII character ?) to ensure printable characters.
Key points:
- Coordinates are multiplied by 1e5 and rounded to integers
- Points store only the offset from the previous point (delta encoding)
- A continuation bit indicates when more data follows for a single value
- Negative values use two’s complement with bit inversion
Note: Backslash characters in encoded strings must be escaped as double-backslashes in string literals.
Encoding Steps
- Take the signed value (e.g.,
-179.9832104) - Multiply by 1e5, round →
-17998321 - Convert to binary using two’s complement for negatives
- Left-shift one bit
- Invert if original was negative
- Break into 5-bit chunks, reverse order
- OR with 0x20 if more chunks follow
- Add 63, convert to ASCII
Example
Encoding three points: (38.5, -120.2), (40.7, -120.95), (43.252, -126.453)
| Latitude | Longitude | Δ Lat | Δ Lng | Encoded Point |
|---|---|---|---|---|
| 38.5 | -120.2 | +3850000 | -12020000 | _p~iF~ps\|U |
| 40.7 | -120.95 | +220000 | -75000 | _ulLnnqC |
| 43.252 | -126.453 | +255200 | -550300 | _mqNvxq\@ |
Result: _p~iF~ps|U_ulLnnqC_mqNvxq@
Using the Map JS API
The simplest way to display a route is with DirectionsRenderer, which handles decoding automatically:
const directionsService = new woosmap.map.DirectionsService();
const directionsRenderer = new woosmap.map.DirectionsRenderer({ map: map });
directionsService.route({
origin: { lat: 48.8566, lng: 2.3522 },
destination: { lat: 45.764, lng: 4.8357 }
}).then((response) => {
directionsRenderer.setDirections(response);
});
If you need the decoded coordinates directly, use the overview_path property:
directionsService.route({
origin: { lat: 48.8566, lng: 2.3522 },
destination: { lat: 45.764, lng: 4.8357 }
}).then((response) => {
const path = response.routes[0].overview_path; // Already decoded!
const routeLine = new woosmap.map.Polyline({
path: path,
strokeColor: "#4285F4",
strokeWeight: 4
});
routeLine.setMap(map);
});
Manual Decoding
If you need to decode polylines outside the Map JS API context (e.g., server-side or with raw API responses):
function decodePolyline(encoded, precision = 5) {
const coordinates = [];
const factor = Math.pow(10, precision);
let index = 0;
let lat = 0;
let lng = 0;
while (index < encoded.length) {
let byte;
let shift = 0;
let result = 0;
do {
byte = encoded.charCodeAt(index++) - 63;
result |= (byte & 0x1f) << shift;
shift += 5;
} while (byte >= 0x20);
const latitudeChange = (result & 1) ? ~(result >> 1) : (result >> 1);
shift = 0;
result = 0;
do {
byte = encoded.charCodeAt(index++) - 63;
result |= (byte & 0x1f) << shift;
shift += 5;
} while (byte >= 0x20);
const longitudeChange = (result & 1) ? ~(result >> 1) : (result >> 1);
lat += latitudeChange;
lng += longitudeChange;
coordinates.push([lat / factor, lng / factor]);
}
return coordinates;
}
type LatLngTuple = [latitude: number, longitude: number];
function decodePolyline(encoded: string, precision: number = 5): LatLngTuple[] {
const coordinates: LatLngTuple[] = [];
const factor = Math.pow(10, precision);
let index = 0;
let lat = 0;
let lng = 0;
while (index < encoded.length) {
let byte: number;
let shift = 0;
let result = 0;
do {
byte = encoded.charCodeAt(index++) - 63;
result |= (byte & 0x1f) << shift;
shift += 5;
} while (byte >= 0x20);
const latitudeChange = (result & 1) ? ~(result >> 1) : (result >> 1);
shift = 0;
result = 0;
do {
byte = encoded.charCodeAt(index++) - 63;
result |= (byte & 0x1f) << shift;
shift += 5;
} while (byte >= 0x20);
const longitudeChange = (result & 1) ? ~(result >> 1) : (result >> 1);
lat += latitudeChange;
lng += longitudeChange;
coordinates.push([lat / factor, lng / factor]);
}
return coordinates;
}
Interactive Playground
Encode coordinates or decode polyline strings and see the results on the map:
Precision
Standard polyline encoding uses 5 decimal places (1e5), giving ~1.1 meter accuracy. Some systems use 6 decimal places (1e6) for ~11 cm accuracy. Ensure encoder and decoder use matching precision.