Skip to main content
DrawingManager của Google Maps và các API bị ngừng hỗ trợ: hướng dẫn chuyển đổi 2026
Guides

DrawingManager của Google Maps và các API bị ngừng hỗ trợ: hướng dẫn chuyển đổi 2026

Drawing Library và Heatmap Layer đã bị gỡ khỏi Maps JavaScript API. DirectionsService và DistanceMatrixService ở trạng thái Legacy và đã bị đánh dấu ngừng hỗ trợ. Tình trạng hiện tại, mốc thời gian và giải pháp thay thế.

Brent van der HeidenCập nhật lần cuối 14 min read
#Google Maps API#chuyển đổi API#DrawingManager#DirectionsService#định tuyến#hướng dẫn cho lập trình viên

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áiMốc thời gianThay 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
DirectionsServiceLegacy, 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ắtLớp Route trong thư viện Routes
DistanceMatrixServiceLegacy, 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ắtLớ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 Route thay cho DirectionsService, và lớp RouteMatrix thay 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 trong shape. 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ángGoogle, mỗi 1.000 sau đó (bậc đầu)MapAtlas, miễn phí mỗi thángMapAtlas, mỗi 1.000 sau đó (bậc đầu)
Directions (Legacy) hoặc Compute Routes Essentials10.0005,00 USD100.000 request điều hướng1,53 EUR
Directions Advanced (Legacy) hoặc Compute Routes Pro5.00010,00 USDCùng bậc điều hướng1,53 EUR
Distance Matrix (Legacy) hoặc Compute Route Matrix Essentials10.000 phần tử5,00 USDXem trang giáXem trang giá
Geocoding10.0005,00 USD25.0003,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

  1. 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.
  2. Rà soát mã định tuyến: tìm mọi lời gọi tới DirectionsService, DirectionsRenderer và DistanceMatrixService.
  3. Chọn giải pháp thay thế: các lớp Route và RouteMatrix, Routes API hoặc một nhà cung cấp khác.
  4. 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.
  5. 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.

Thấy hữu ích? Chia sẻ nhé.

Về tác giả

Brent van der Heiden

Viết bởi

Brent van der Heiden

Co-Founder & CEO at MapAtlas

Brent built MapAtlas out of a conviction that developers deserve location APIs with fair pricing and genuine end-user privacy. Before that he co-founded MapMetrics, a community mapping and navigation app. He writes about geospatial infrastructure, map data, AI search visibility, and how location data powers the products people rely on every day.

Xem tất cả bài viết →
Quay lại blog