Skip to content

Instantly share code, notes, and snippets.

@kijtra
Last active November 14, 2022 11:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kijtra/7082b44591133b0c0a94 to your computer and use it in GitHub Desktop.
Save kijtra/7082b44591133b0c0a94 to your computer and use it in GitHub Desktop.
[JavaScript] Encode or decode GeoHash
function geohash(lat, lon, len)
{
if (len) {
len = Number(len);
if (len < 1 || len > 12) {
return false;
}
} else {
len = 12;
}
var base32Chars = [
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
];
var latInterval = [-90.0, 90.0];
var lonInterval = [-180.0, 180.0];
var bits = [16, 8, 4, 2, 1];
var bit = 0;
var isEven = true;
// Encode
if (lon && /^[\d\.]+$/.test(lat + '' + lon)) {
var charIndex = 0;
var geohash = '';
while (geohash.length < len) {
if (isEven) {
var middle = (lonInterval[0] + lonInterval[1]) / 2;
if (lon > middle) {
charIndex |= bits[bit];
lonInterval[0] = middle;
} else {
lonInterval[1] = middle;
}
} else {
var middle = (latInterval[0] + latInterval[1]) / 2;
if (lat > middle) {
charIndex |= bits[bit];
latInterval[0] = middle;
} else {
latInterval[1] = middle;
}
}
if (bit < 4) {
bit++;
} else {
geohash += base32Chars[charIndex];
bit = 0;
charIndex = 0;
}
isEven = isEven ? false : true;
}
return geohash;
}
// Decode
else if('string' === typeof lat && lat.length <= 12) {
var geohash = lat;
var base32DecodeMap = {};
for (i = 0, l = base32Chars.length; i < l; i++) {
base32DecodeMap[base32Chars[i]] = i;
}
for (i = 0, l = geohash.length; i < l; i++) {
if (!base32DecodeMap[geohash[i]]) {
// Invalid GeoHash
return false;
}
var currentChar = base32DecodeMap[geohash[i]];
for (j = 0, jl = bits.length; j < jl; j++) {
var mask = bits[j];
if (isEven) {
if ((currentChar & mask) !== 0) {
lonInterval[0] = (lonInterval[0] + lonInterval[1]) / 2;
} else {
lonInterval[1] = (lonInterval[0] + lonInterval[1]) / 2;
}
} else {
if ((currentChar & mask) !== 0) {
latInterval[0] = (latInterval[0] + latInterval[1]) / 2;
} else {
latInterval[1] = (latInterval[0] + latInterval[1]) / 2;
}
}
isEven = isEven ? false : true;
}
}
if (true === lon) {
return {
swlat: latInterval[0],
swlon: lonInterval[0],
nelat: latInterval[1],
nelon: lonInterval[1],
};
} else {
return {
lat: (latInterval[0] + latInterval[1]) / 2,
lon: (lonInterval[0] + lonInterval[1]) / 2
};
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment