Để lấy tọa độ (latitude, longitude) từ địa chỉ hoặc vị trí hiện tại, có 2 hướng tiếp cận:
1. HTML5 Geolocation API - Vị trí hiện tại của USER
Chỉ lấy vị trí của người dùng (device), không geocode địa chỉ văn bản.
function getCurrentLocation() {
return new Promise((resolve, reject) => {
if (!navigator.geolocation) {
reject(new Error('Trình duyệt không hỗ trợ Geolocation'));
return;
}
navigator.geolocation.getCurrentPosition(
position => resolve({
lat: position.coords.latitude,
lng: position.coords.longitude,
accuracy: position.coords.accuracy
}),
error => reject(error),
{ enableHighAccuracy: true, timeout: 10000, maximumAge: 0 }
);
});
}
// Sử dụng
getCurrentLocation()
.then(pos => console.log('Vị trí:', pos.lat, pos.lng))
.catch(err => console.error('Lỗi:', err.message));
2. Google Maps Geocoding API - Địa chỉ → Tọa độ (Forward Geocoding)
Cần API Key (Google Cloud Console, enable Geocoding API, billing).
async function geocodeAddress(address, apiKey) {
const url = `https://maps.googleapis.com/maps/api/geocode/json?address=${encodeURIComponent(address)}&key=${apiKey}`;
const response = await fetch(url);
const data = await response.json();
if (data.status === 'OK' && data.results.length > 0) {
const loc = data.results[0].geometry.location;
return { lat: loc.lat, lng: loc.lng, formatted: data.results[0].formatted_address };
}
throw new Error('Geocoding failed: ' + data.status);
}
// Sử dụng
geocodeAddress('1600 Amphitheatre Parkway, Mountain View, CA', 'YOUR_API_KEY')
.then(loc => console.log(loc.lat, loc.lng))
.catch(console.error);
3. Reverse Geocoding - Tọa độ → Địa chỉ
async function reverseGeocode(lat, lng, apiKey) {
const url = `https://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${lng}&key=${apiKey}`;
const response = await fetch(url);
const data = await response.json();
return data.results[0]?.formatted_address || 'Không tìm thấy';
}
4. Alternatives miễn phí (No API Key / Generous free tier)
| Dịch vụ | Free Tier | Đặc điểm |
|---|---|---|
| Nominatim (OpenStreetMap) | Unlimited (rate limit 1/s) | Open source, self-hostable, policy: attribution required |
| LocationIQ | 10,000 req/day | Dễ dùng, có SDK |
| OpenCage | 2,500 req/day | Hỗ trợ forward/reverse, multilingual |
| Mapbox | 100,000 req/month | Đẹp, tích hợp map |
// Nominatim example (free, no key)
async function nominatimGeocode(address) {
const url = `https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(address)}`;
const response = await fetch(url, { headers: { 'User-Agent': 'MyApp/1.0' } });
const data = await response.json();
if (data.length) return { lat: parseFloat(data[0].lat), lng: parseFloat(data[0].lon) };
throw new Error('Not found');
}
So sánh
| Tiêu chí | HTML5 Geolocation | Geocoding API |
|---|---|---|
| Input | Vị trí device (GPS/WiFi/IP) | Địa chỉ văn bản / Tọa độ |
| Output | Lat/Lng của user | Lat/Lng của địa chỉ / Địa chỉ của lat/lng |
| Yêu cầu HTTPS | Bắt buộc | Bắt buộc (Google) |
| Quyền user | Cần cho phép (prompt) | Không cần (server-side) |
| Độ chính xác | Cao (GPS: ~10m) | Tùy data (building level - city level) |
Best Practice
- Luôn handle error: permission denied, timeout, unavailable.
- Cache kết quả geocoding (localStorage/IndexedDB) để giảm API call.
- Debounce input tìm kiếm địa chỉ (300ms).
- Respect rate limits & terms of service.