Trong mười tám tháng qua, Google đã đánh dấu ngừng hỗ trợ bốn phần được dùng rộng rãi của Maps JavaScript API. Hai trong số đó, Heatmap Layer và Drawing Library, không còn khả dụng từ tháng 5 năm 2026. Hai phần còn lại, DirectionsService và DistanceMatrixService, ở trạng thái Legacy và bị ngừng hỗ trợ, nhưng vẫn chạy và chưa có ngày tắt.
Hướng dẫn này tổng hợp tình trạng hiện tại của từng phần, kèm liên kết tới chính các trang của Google, và cách thay thế. Khi giải pháp thay thế đến từ MapAtlas, mã dùng endpoint và định dạng phản hồi thật của chúng tôi.
Những gì đã ngừng hỗ trợ và những gì vẫn chạy
| Dịch vụ | Trạng thái | Mốc thời gian | Thay thế của Google |
|---|---|---|---|
| Heatmap Layer | Đã gỡ bỏ | Ngừng hỗ trợ ngày 27/5/2025, gỡ bỏ ở phiên bản 3.65.1c (20/5/2026) | Thư viện bên thứ ba như deck.gl |
| Drawing Library (DrawingManager) | Đã gỡ bỏ | Ngừng hỗ trợ tháng 8/2025, không khả dụng từ tháng 5/2026 (được xác nhận ở phiên bản 3.65.3b, 4/6/2026) | Thư viện bên thứ ba như Terra Draw |
| DirectionsService | Legacy, ngừng hỗ trợ | Legacy từ 1/3/2025, ngừng hỗ trợ từ 25/2/2026 (phiên bản 3.64.2b), chưa có ngày tắt | Lớp Route trong thư viện Routes |
| DistanceMatrixService | Legacy, ngừng hỗ trợ | Legacy từ 1/3/2025, ngừng hỗ trợ từ 25/2/2026 (phiên bản 3.64.2b), chưa có ngày tắt | Lớp RouteMatrix trong thư viện Routes |
Nguồn: trang deprecation của Google Maps Platform, ghi chú phát hành Maps JavaScript API và trang sản phẩm Legacy.
Legacy có ý nghĩa cụ thể. Theo Google, dịch vụ Legacy không được bổ sung tính năng mới và không thể bật trong dự án Cloud mới, nhưng vẫn được hỗ trợ trong các dự án hiện có. Google cam kết thông báo trước ít nhất 12 tháng trước khi gỡ bỏ một dịch vụ như vậy, và ghi chú phát hành đánh dấu ngừng hỗ trợ DirectionsService và DistanceMatrixService cho biết chưa có kế hoạch tắt và các lỗi hồi quy nghiêm trọng vẫn sẽ được sửa. Cùng đợt chuyển sang Legacy ngày 1/3/2025 còn có các dịch vụ web Directions API và Distance Matrix API, cùng Places API và JavaScript Places Service.
Những gì bị hỏng
Đoạn mã này đã lỗi trên các phiên bản Maps JavaScript API hiện tại:
// Removed in 2026: these constructors no longer work
const heatmap = new google.maps.visualization.HeatmapLayer({ data: points });
const drawingManager = new google.maps.drawing.DrawingManager();
Đoạn mã này vẫn chạy trong dự án hiện có, nhưng đã bị ngừng hỗ trợ và không chạy trong dự án Cloud mới:
// Legacy and deprecated, no shutdown date yet
const directionsService = new google.maps.DirectionsService();
const distanceMatrixService = new google.maps.DistanceMatrixService();
Nếu bản đồ nhiệt hoặc công cụ vẽ trên trang của bạn ngừng hoạt động từ tháng 5 năm 2026, đây là nguyên nhân. Hãy sửa phần đó trước. Sau đó lên kế hoạch chuyển đổi phần định tuyến trước khi Google công bố ngày tắt.
Giải pháp thay thế của Google
Với định tuyến, Google đưa ra hai hướng, và không hướng nào bắt bạn chuyển logic lên máy chủ:
- Trên trình duyệt: thư viện Routes trong Maps JavaScript API. Lớp
Routethay cho DirectionsService, và lớpRouteMatrixthay cho DistanceMatrixService. - Trên máy chủ: Routes API, một dịch vụ REST với các phương thức Compute Routes và Compute Route Matrix.
Về trực quan hóa, Google không còn giải pháp riêng. Trang bản đồ nhiệt hướng tới deck.gl, còn trang deprecation nêu Terra Draw cho việc vẽ.
Danh sách kiểm tra khi chuyển đổi
1. Rà soát mã nguồn
Tìm các lớp bị ảnh hưởng:
# Find all files using deprecated Google Maps services
grep -rn "DirectionsService\|DistanceMatrixService\|DirectionsRenderer\|HeatmapLayer\|DrawingManager" \
--include="*.js" --include="*.ts" --include="*.tsx" --include="*.jsx" src/
Ghi lại mọi file và component đang dùng chúng, và mỗi lời gọi chạy trên trình duyệt hay trên máy chủ.
2. Ghi lại cách bạn dùng từng dịch vụ
Với mỗi chỗ sử dụng, hãy ghi:
- Phương tiện di chuyển (ô tô, đi bộ, xe đạp, phương tiện công cộng)
- Điểm dừng trung gian (đơn giản từ A tới B, hay tuyến nhiều điểm dừng)
- Các trường phản hồi bạn đọc (khoảng cách, thời gian, polyline, các bước, giá vé)
- Lưu lượng (số request mỗi ngày và mỗi tháng, để ước tính chi phí)
- Yêu cầu độ trễ (thời gian thực cho người dùng, hay xử lý theo lô)
3. Chọn đích đến
Phương án A: tiếp tục với Google. Chuyển sang các lớp Route và RouteMatrix hoặc Routes API. Đối chiếu các trường bạn dùng với hướng dẫn chuyển đổi, vì định dạng phản hồi khác với các lớp Legacy.
Phương án B: đổi nhà cung cấp. Dù sao bạn cũng phải viết lại phần tích hợp, nên hãy so sánh các nhà cung cấp theo yêu cầu ở bước 2.
4. Chạy song song cũ và mới
Đừng chuyển đổi tại chỗ. Chạy cả hai cách triển khai song song trong một thời gian và so sánh khoảng cách, thời gian và độ trễ trên các tuyến thật trước khi chuyển hẳn.
5. Cập nhật xử lý lỗi
Các lớp Legacy báo lỗi qua giá trị trạng thái trong callback. Các giải pháp REST trả về mã trạng thái HTTP và nội dung lỗi, vì vậy phần xử lý lỗi của bạn cần thay đổi.
Thay thế từng dịch vụ bằng MapAtlas
Các endpoint định tuyến của MapAtlas là dịch vụ REST trên gateway.mapmetrics-atlas.net, được mô tả trong tài liệu API của MapAtlas. Chúng nhận token qua tham số query, nên hãy gọi từ backend.
Từ DirectionsService sang MapAtlas Directions API
Trước (Google, Legacy):
const directionsService = new google.maps.DirectionsService();
directionsService.route(
{
origin: { lat: 52.52, lng: 13.405 },
destination: { lat: 48.8566, lng: 2.3522 },
travelMode: google.maps.TravelMode.DRIVING,
waypoints: [
{ location: { lat: 50.9375, lng: 6.9603 }, stopover: true }
],
},
(result, status) => {
if (status === "OK") {
const route = result.routes[0];
console.log("Distance:", route.legs[0].distance.text);
console.log("Duration:", route.legs[0].duration.text);
}
}
);
Sau (MapAtlas Directions API):
const response = await fetch(
`https://gateway.mapmetrics-atlas.net/directions/?token=${process.env.MAPATLAS_API_KEY}`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
// Ordered stops: origin, waypoints, destination
locations: [
{ lat: 52.52, lon: 13.405 },
{ lat: 50.9375, lon: 6.9603 },
{ lat: 48.8566, lon: 2.3522 },
],
costing: "auto", // auto, bicycle, pedestrian, bus, truck, taxi, motor_scooter
units: "kilometers",
}),
}
);
const { trip } = await response.json();
console.log("Distance (km):", trip.summary.length);
console.log("Duration (s):", trip.summary.time);
// Each leg carries its geometry as an encoded polyline (precision 6)
const shapes = trip.legs.map((leg) => leg.shape);
Khác biệt chính:
- Lời gọi REST thay cho lớp JavaScript, thực hiện từ backend.
- Điểm dừng trung gian là các phần tử ở giữa
locations. - Cấu trúc phản hồi khác. Tổng số nằm trong
trip.summary, và mỗi chặng có một polyline đã mã hóa trongshape. Hãy giải mã trước khi vẽ tuyến (xem ví dụ backend bên dưới).
Từ DistanceMatrixService sang MapAtlas Matrix API
MapAtlas Matrix API trả về thời gian di chuyển và khoảng cách cho mọi cặp điểm đi và điểm đến trong một lần gọi. Endpoint của chúng tôi giới hạn mỗi cặp ở 400 km quãng đường, vì vậy ví dụ dùng các địa điểm quanh Berlin.
Trước (Google, Legacy):
const service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix(
{
origins: [
{ lat: 52.52, lng: 13.405 },
{ lat: 52.3906, lng: 13.0645 },
],
destinations: [
{ lat: 51.3397, lng: 12.3731 },
{ lat: 51.0504, lng: 13.7373 },
],
travelMode: google.maps.TravelMode.DRIVING,
},
(response, status) => {
if (status === "OK") {
response.rows.forEach((row, i) => {
row.elements.forEach((element, j) => {
console.log(`Origin ${i} -> Dest ${j}:`,
element.distance.text, element.duration.text);
});
});
}
}
);
Sau (MapAtlas Matrix API):
const response = await fetch(
`https://gateway.mapmetrics-atlas.net/matrix/?token=${process.env.MAPATLAS_API_KEY}`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
sources: [
{ lat: 52.52, lon: 13.405 },
{ lat: 52.3906, lon: 13.0645 },
],
targets: [
{ lat: 51.3397, lon: 12.3731 },
{ lat: 51.0504, lon: 13.7373 },
],
costing: "auto",
units: "kilometers",
}),
}
);
const data = await response.json();
// One row per source, one cell per target
data.sources_to_targets.forEach((row: any[], i: number) => {
row.forEach((cell, j) => {
console.log(`Origin ${i} -> Dest ${j}:`, cell.distance, "km", cell.time, "s");
});
});
Lưới này tương ứng với rows và elements của Google. Khoảng cách trả về dạng số theo đơn vị bạn yêu cầu và thời gian tính bằng giây, nên bạn tự định dạng khi hiển thị.
Thay thế Heatmap Layer
Phương án 1: lớp bản đồ nhiệt trong MapLibre GL JS (mã nguồn mở)
import maplibregl from "maplibre-gl";
const map = new maplibregl.Map({
container: "map",
style: "https://gateway.mapmetrics-atlas.net/styles/?fileName=YOUR_ACCOUNT_ID/mapstyle.json&token=YOUR_API_KEY",
center: [13.405, 52.52],
zoom: 10,
});
map.on("load", () => {
map.addSource("heat-data", {
type: "geojson",
data: {
type: "FeatureCollection",
features: heatmapPoints.map((point) => ({
type: "Feature",
geometry: { type: "Point", coordinates: [point.lng, point.lat] },
properties: { weight: point.weight },
})),
},
});
map.addLayer({
id: "heatmap-layer",
type: "heatmap",
source: "heat-data",
paint: {
"heatmap-weight": ["get", "weight"],
"heatmap-intensity": 1,
"heatmap-radius": 20,
"heatmap-opacity": 0.7,
},
});
});
Bản đồ nhiệt được vẽ ngay trong thư viện bản đồ, không cần dịch vụ bổ sung.
Phương án 2: HeatmapLayer của deck.gl, được tài liệu của Google gợi ý:
import { HeatmapLayer } from "@deck.gl/aggregation-layers";
const heatmapLayer = new HeatmapLayer({
data: heatmapPoints,
getPosition: (d) => [d.lng, d.lat],
getWeight: (d) => d.weight,
radiusPixels: 30,
});
Cả hai đều dùng được. MapLibre GL JS đọc trực tiếp style của MapAtlas, còn deck.gl có thể đặt lên bất kỳ bản đồ nền nào.
Thay thế Drawing Library
DrawingManager cho phép người dùng vẽ marker, đường, hình tròn và đa giác lên bản đồ. Terra Draw, thư viện được trang deprecation của Google nêu tên, cung cấp các chế độ vẽ tương tự và có adapter cho nhiều thư viện bản đồ, trong đó có Google Maps và MapLibre GL JS. Các hình vẽ được trả về dưới dạng GeoJSON, bạn có thể lưu hoặc gửi nguyên vẹn tới dịch vụ geofencing hay isochrone.
So sánh chi phí
Giá niêm yết của Google giống nhau cho các SKU định tuyến Legacy và các SKU Essentials thay thế. Mọi mức giá dưới đây lấy từ trang giá của Google Maps Platform và trang giá của MapAtlas, đều được kiểm tra ngày 26/9/2026.
| Dịch vụ | Google, miễn phí mỗi tháng | Google, mỗi 1.000 sau đó (bậc đầu) | MapAtlas, miễn phí mỗi tháng | MapAtlas, mỗi 1.000 sau đó (bậc đầu) |
|---|---|---|---|---|
| Directions (Legacy) hoặc Compute Routes Essentials | 10.000 | 5,00 USD | 100.000 request điều hướng | 1,53 EUR |
| Directions Advanced (Legacy) hoặc Compute Routes Pro | 5.000 | 10,00 USD | Cùng bậc điều hướng | 1,53 EUR |
| Distance Matrix (Legacy) hoặc Compute Route Matrix Essentials | 10.000 phần tử | 5,00 USD | Xem trang giá | Xem trang giá |
| Geocoding | 10.000 | 5,00 USD | 25.000 | 3,90 EUR |
Google tính tiền bằng đô la Mỹ còn MapAtlas bằng euro, nên hãy quy đổi trước khi so sánh. Cả hai đều giảm giá khi lưu lượng cao hơn. Ví dụ với 500.000 request tuyến đường mỗi tháng:
- Google Compute Routes Essentials: 10.000 miễn phí, 90.000 với giá 5,00 USD và 400.000 với giá 4,00 USD, tổng cộng 2.050 USD.
- Điều hướng MapAtlas: 100.000 miễn phí và 400.000 với giá 1,53 EUR, tổng cộng khoảng 610 EUR.
Ví dụ đầy đủ: route backend và bản đồ
Cách làm này giữ API key trên máy chủ và chỉ gửi hình học tuyến đường tới trình duyệt.
Route API backend (Next.js)
// app/api/directions/route.ts
import { NextRequest, NextResponse } from "next/server";
// Decode an encoded polyline with precision 6 into [lon, lat] pairs
function decodePolyline6(str: string): [number, number][] {
const coords: [number, number][] = [];
let index = 0, lat = 0, lng = 0;
while (index < str.length) {
for (const axis of [0, 1]) {
let result = 0, shift = 0, byte: number;
do {
byte = str.charCodeAt(index++) - 63;
result |= (byte & 0x1f) << shift;
shift += 5;
} while (byte >= 0x20);
const delta = result & 1 ? ~(result >> 1) : result >> 1;
if (axis === 0) lat += delta; else lng += delta;
}
coords.push([lng / 1e6, lat / 1e6]);
}
return coords;
}
export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url);
const [oLat, oLon] = searchParams.get("origin")!.split(",").map(Number);
const [dLat, dLon] = searchParams.get("destination")!.split(",").map(Number);
const response = await fetch(
`https://gateway.mapmetrics-atlas.net/directions/?token=${process.env.MAPATLAS_API_KEY}`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
locations: [{ lat: oLat, lon: oLon }, { lat: dLat, lon: dLon }],
costing: "auto",
units: "kilometers",
}),
}
);
if (!response.ok) {
return NextResponse.json({ error: "routing failed" }, { status: 502 });
}
const { trip } = await response.json();
const coordinates = trip.legs.flatMap((leg: { shape: string }) => decodePolyline6(leg.shape));
return NextResponse.json({
coordinates,
distanceKm: trip.summary.length,
durationS: trip.summary.time,
});
}
Component bản đồ (React và MapLibre GL JS)
import { useEffect, useRef } from "react";
import maplibregl from "maplibre-gl";
function DirectionsMap({ origin, destination }: {
origin: { lat: number; lng: number };
destination: { lat: number; lng: number };
}) {
const mapRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const map = new maplibregl.Map({
container: mapRef.current!,
style: "https://gateway.mapmetrics-atlas.net/styles/?fileName=YOUR_ACCOUNT_ID/mapstyle.json&token=YOUR_API_KEY",
center: [origin.lng, origin.lat],
zoom: 7,
});
map.on("load", async () => {
const res = await fetch(
"/api/directions?" +
new URLSearchParams({
origin: `${origin.lat},${origin.lng}`,
destination: `${destination.lat},${destination.lng}`,
})
);
if (!res.ok) return;
const { coordinates } = await res.json();
map.addSource("route", {
type: "geojson",
data: {
type: "Feature",
geometry: { type: "LineString", coordinates },
properties: {},
},
});
map.addLayer({
id: "route-line",
type: "line",
source: "route",
paint: { "line-color": "#4A90D9", "line-width": 5 },
});
const bounds = coordinates.reduce(
(b: maplibregl.LngLatBounds, coord: [number, number]) => b.extend(coord),
new maplibregl.LngLatBounds(coordinates[0], coordinates[0])
);
map.fitBounds(bounds, { padding: 50 });
});
return () => map.remove();
}, [origin, destination]);
return <div ref={mapRef} style={{ width: "100%", height: "400px" }} />;
}
Cách kiểm thử quá trình chuyển đổi
Bước 1: so sánh hai cách triển khai
Trong thời gian thử nghiệm, gọi cả dịch vụ cũ và mới với cùng request. Ghi lại khoảng cách và thời gian từ cả hai và xem xét chênh lệch trên các tuyến thật, nhất là phà, đường thu phí và đường hạn chế lưu thông.
Bước 2: dùng feature flag
Đặt nhà cung cấp sau một flag để có thể quay lại mà không cần deploy:
const useMapAtlasDirections = process.env.FEATURE_MAPATLAS_DIRECTIONS === "true";
const directions = useMapAtlasDirections
? await fetchMapAtlasDirections(origin, destination)
: await fetchGoogleDirections(origin, destination);
Bước 3: theo dõi tỷ lệ lỗi
Sau khi chuyển, theo dõi:
- Tỷ lệ HTTP 4xx và 5xx từ API mới
- Thay đổi về độ trễ
- Các trường bị thiếu mà giao diện của bạn đọc
- Khác biệt tuyến đường ở các trường hợp biên như phà, đường thu phí và khu vực hạn chế
Bước 4: kiểm thử tải trước khi chạy thật
Nếu lưu lượng của bạn có đỉnh, chẳng hạn giờ điều phối buổi sáng trên một nền tảng logistics, hãy kiểm thử tải API mới ở mức gấp đôi lưu lượng đỉnh trước khi phụ thuộc vào nó.
Việc cần làm ngay
- Nếu bạn vẫn tải Heatmap Layer hoặc Drawing Library: hãy thay chúng trước. Chúng không còn chạy trên các phiên bản Maps JavaScript API hiện tại.
- Rà soát mã định tuyến: tìm mọi lời gọi tới DirectionsService, DirectionsRenderer và DistanceMatrixService.
- Chọn giải pháp thay thế: các lớp
RoutevàRouteMatrix, Routes API hoặc một nhà cung cấp khác. - Chuyển từng dịch vụ một, sau feature flag, và so sánh kết quả trước khi chuyển hẳn.
- Theo dõi trang deprecation của Google phòng khi có ngày tắt. Google đã cam kết thông báo trước ít nhất 12 tháng với các dịch vụ Legacy.
Để thử API định tuyến của MapAtlas, hãy tạo tài khoản miễn phí và đọc tài liệu API. Nếu cần hỗ trợ chuyển đổi, hãy dùng trang liên hệ.
Câu hỏi thường gặp
Drawing Library của Google Maps còn dùng được không?
Không. Google đánh dấu ngừng hỗ trợ Drawing Library, gồm cả DrawingManager, vào tháng 8 năm 2025, và trang deprecation ghi rằng thư viện này không còn khả dụng từ tháng 5 năm 2026. Ghi chú phát hành phiên bản 3.65.3b của Maps JavaScript API (ngày 4 tháng 6 năm 2026) xác nhận DrawingManager không còn khả dụng. Google gợi ý Terra Draw làm phương án thay thế.
Heatmap Layer còn dùng được không?
Không. Google đánh dấu ngừng hỗ trợ Heatmap Layer ngày 27 tháng 5 năm 2025, và phiên bản 3.65.1c ngày 20 tháng 5 năm 2026 cho biết tính năng này đã bị gỡ bỏ. Google khuyên dùng thư viện bên thứ ba như HeatmapLayer của deck.gl thay thế.
Khi nào DirectionsService và DistanceMatrixService ngừng hoạt động?
Google chưa đưa ra ngày cụ thể. Cả hai ở trạng thái Legacy từ ngày 1 tháng 3 năm 2025 và bị đánh dấu ngừng hỗ trợ từ ngày 25 tháng 2 năm 2026. Theo ghi chú phát hành của Google, chưa có kế hoạch ngừng, các lỗi hồi quy nghiêm trọng vẫn được sửa, và sẽ có thông báo trước ít nhất 12 tháng trước khi kết thúc hỗ trợ. Dịch vụ Legacy không dùng được trong dự án Cloud mới, nên dự án mới cần các lớp Route và RouteMatrix hoặc một nhà cung cấp khác.
Có thể chuyển đổi từng phần hay phải đổi tất cả cùng lúc?
Bạn có thể chuyển từng dịch vụ một. Mỗi lớp bị ngừng hỗ trợ độc lập với nhau. Hãy thay Drawing Library và Heatmap Layer trước vì chúng đã không còn chạy, sau đó thay DirectionsService và DistanceMatrixService theo lịch của bạn.
MapAtlas có hỗ trợ điểm dừng trung gian và nhiều phương tiện di chuyển không?
Có. MapAtlas Directions API nhận một danh sách vị trí có thứ tự, nên mọi điểm nằm giữa điểm đầu và điểm cuối đều là điểm dừng trung gian. API hỗ trợ các mô hình chi phí auto, bicycle, pedestrian, bus, truck, taxi và motor_scooter. Đây là endpoint REST, vì vậy hãy gọi từ backend để API key không lộ ra phía client.

