过去十八个月里,Google 弃用了 Maps JavaScript API 中四个使用广泛的部分。其中 Heatmap Layer 和 Drawing Library 自 2026 年 5 月起已不可用。另外两个,DirectionsService 和 DistanceMatrixService,处于 Legacy 状态并已弃用,但仍可使用,也没有停用日期。
本指南列出每一项的当前状态,并附上 Google 官方页面链接,同时说明如何替换。凡是使用 MapAtlas 作为替代的地方,代码都采用我们真实的端点和响应格式。
哪些已弃用,哪些仍可使用
| 服务 | 状态 | 关键日期 | Google 的替代方案 |
|---|---|---|---|
| Heatmap Layer | 已移除 | 2025 年 5 月 27 日弃用,3.65.1c 版本(2026 年 5 月 20 日)停用 | deck.gl 等第三方库 |
| Drawing Library(DrawingManager) | 已移除 | 2025 年 8 月弃用,自 2026 年 5 月起不可用(3.65.3b 版本确认,2026 年 6 月 4 日) | Terra Draw 等第三方库 |
| DirectionsService | Legacy,已弃用 | 自 2025 年 3 月 1 日起为 Legacy,自 2026 年 2 月 25 日起弃用(3.64.2b 版本),无停用日期 | Routes 库中的 Route 类 |
| DistanceMatrixService | Legacy,已弃用 | 自 2025 年 3 月 1 日起为 Legacy,自 2026 年 2 月 25 日起弃用(3.64.2b 版本),无停用日期 | Routes 库中的 RouteMatrix 类 |
来源:Google Maps Platform 弃用页面、Maps JavaScript API 发布说明以及 Legacy 产品页面。
Legacy 有明确含义。按照 Google 的说法,Legacy 服务不再增加新功能,也无法在新的 Cloud 项目中启用,但现有项目仍然获得支持。Google 承诺在停用此类服务前至少提前 12 个月通知,而弃用 DirectionsService 和 DistanceMatrixService 的那条发布说明也指出,目前没有停用计划,严重回归问题仍会修复。2025 年 3 月 1 日的同一次 Legacy 调整还涉及 Directions API 和 Distance Matrix API 两个 Web 服务,以及 Places API 和 JavaScript Places Service。
哪些代码会出错
以下代码在当前版本的 Maps JavaScript API 中已经无法运行:
// Removed in 2026: these constructors no longer work
const heatmap = new google.maps.visualization.HeatmapLayer({ data: points });
const drawingManager = new google.maps.drawing.DrawingManager();
以下代码在现有项目中仍可运行,但已被弃用,在新的 Cloud 项目中无法使用:
// Legacy and deprecated, no shutdown date yet
const directionsService = new google.maps.DirectionsService();
const distanceMatrixService = new google.maps.DistanceMatrixService();
如果你网站上的热力图或绘图工具在 2026 年 5 月停止工作,原因就在这里。先修复它们,然后在 Google 公布日期之前规划路径规划的迁移。
Google 提供的替代方案
在路径规划方面,Google 提供两条路径,都不强制把逻辑迁移到服务器:
- 在浏览器中: Maps JavaScript API 中的 Routes 库。
Route类替代 DirectionsService,RouteMatrix类替代 DistanceMatrixService。 - 在服务器上: Routes API,一个提供 Compute Routes 和 Compute Route Matrix 方法的 REST 服务。
在可视化方面,Google 不再提供自有方案。其热力图页面指向 deck.gl,弃用页面则推荐用 Terra Draw 实现绘图。
迁移检查清单
1. 审查代码库
搜索受影响的类:
# Find all files using deprecated Google Maps services
grep -rn "DirectionsService\|DistanceMatrixService\|DirectionsRenderer\|HeatmapLayer\|DrawingManager" \
--include="*.js" --include="*.ts" --include="*.tsx" --include="*.jsx" src/
记录所有使用它们的文件和组件,并注明每次调用运行在浏览器还是服务器上。
2. 记录每个服务的使用方式
针对每处使用,记录:
- 出行方式(驾车、步行、骑行、公共交通)
- 途经点(简单的 A 到 B,或多站点路线)
- 读取的响应字段(距离、时长、折线、步骤、票价)
- 调用量(每日和每月请求数,用于估算成本)
- 延迟要求(面向用户的实时请求,或批处理)
3. 选择目标方案
方案 A:继续使用 Google。 迁移到 Route 和 RouteMatrix 类,或迁移到 Routes API。请对照迁移指南检查你使用的字段,因为响应格式与 Legacy 类不同。
方案 B:更换服务商。 反正都要重写集成代码,可以按照第 2 步的需求比较各家服务商。
4. 新旧实现并行运行
不要原地迁移。让两套实现并行运行一段时间,在正式切换之前,用真实路线比较距离、时长和延迟。
5. 更新错误处理
Legacy 类通过回调中的状态值返回错误。REST 替代方案返回 HTTP 状态码和错误响应体,因此错误处理逻辑需要相应调整。
用 MapAtlas 替换各项服务
MapAtlas 的路径规划端点是部署在 gateway.mapmetrics-atlas.net 上的 REST 服务,文档见 MapAtlas API 文档。它们通过查询参数接收 token,所以请从后端调用。
从 DirectionsService 迁移到 MapAtlas Directions API
迁移前(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);
}
}
);
迁移后(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);
主要区别:
- REST 调用替代 JavaScript 类,由后端发起。
- 途经点是
locations中间的各项。 - 响应结构不同。 总计信息在
trip.summary中,每一段路线在shape中带有编码折线。绘制路线前需要先解码(参见下文的后端示例)。
从 DistanceMatrixService 迁移到 MapAtlas Matrix API
MapAtlas Matrix API 一次调用即可返回每一对起点和终点之间的行程时间和距离。我们的端点将每一对的路线距离限制在 400 公里以内,因此示例使用柏林周边的地点。
迁移前(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);
});
});
}
}
);
迁移后(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");
});
});
这个网格与 Google 的 rows 和 elements 相对应。距离以你请求的单位返回数值,时间以秒为单位,格式化需要自行处理。
替换 Heatmap Layer
方案 1:MapLibre GL JS 热力图图层(开源)
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,
},
});
});
热力图直接由地图库渲染,不需要额外服务。
方案 2:deck.gl 的 HeatmapLayer,这是 Google 文档建议的方案:
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,
});
两种方案都可行。MapLibre GL JS 可以直接读取 MapAtlas 样式,deck.gl 则可以叠加在任何底图之上。
替换 Drawing Library
DrawingManager 允许用户在地图上绘制标记、线、圆和多边形。Google 弃用页面推荐的 Terra Draw 提供相同的绘制模式,并为多个地图库提供适配器,其中包括 Google Maps 和 MapLibre GL JS。绘制的形状以 GeoJSON 返回,可以直接存储,或原样发送给地理围栏或等时线服务。
成本比较
对于路径规划,Google 的 Legacy SKU 与其替代方案的 Essentials SKU 标价相同。以下价格均来自 Google Maps Platform 价格页面和 MapAtlas 价格页面,核对日期为 2026 年 9 月 26 日。
| 服务 | Google 每月免费量 | Google 超出后每 1,000 次(第一档) | MapAtlas 每月免费量 | MapAtlas 超出后每 1,000 次(第一档) |
|---|---|---|---|---|
| Directions(Legacy)或 Compute Routes Essentials | 10,000 | 5.00 美元 | 100,000 次导航请求 | 1.53 欧元 |
| Directions Advanced(Legacy)或 Compute Routes Pro | 5,000 | 10.00 美元 | 同一导航档位 | 1.53 欧元 |
| Distance Matrix(Legacy)或 Compute Route Matrix Essentials | 10,000 个元素 | 5.00 美元 | 见价格页面 | 见价格页面 |
| Geocoding | 10,000 | 5.00 美元 | 25,000 | 3.90 欧元 |
Google 以美元计费,MapAtlas 以欧元计费,比较前请先换算。两者在用量更高时都会降低单价。以每月 500,000 次路线请求为例:
- Google Compute Routes Essentials: 10,000 次免费,90,000 次按 5.00 美元、400,000 次按 4.00 美元计费,合计 2,050 美元。
- MapAtlas 导航: 100,000 次免费,400,000 次按 1.53 欧元计费,合计约 610 欧元。
完整示例:后端路由与地图
这种模式把 API 密钥留在服务器上,只把路线几何数据发送给浏览器。
后端 API 路由(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,
});
}
地图组件(React 与 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" }} />;
}
如何测试迁移
第 1 步:比较两套实现
在测试期间,用相同请求同时调用旧服务和新服务。记录两者返回的距离和时长,检查真实路线上的差异,尤其是轮渡、收费路段和限行道路。
第 2 步:使用功能开关
把服务商选择放在一个 feature flag 后面,这样无需重新部署就能回退:
const useMapAtlasDirections = process.env.FEATURE_MAPATLAS_DIRECTIONS === "true";
const directions = useMapAtlasDirections
? await fetchMapAtlasDirections(origin, destination)
: await fetchGoogleDirections(origin, destination);
第 3 步:监控错误率
切换后重点关注:
- 新 API 的 HTTP 4xx 和 5xx 比例
- 延迟变化
- 界面依赖的缺失字段
- 轮渡、收费道路和限行区域等边界情况下的路线差异
第 4 步:上线前做压力测试
如果你的流量有高峰,例如物流平台早间派单时段,在依赖新 API 之前,请用峰值两倍的流量对其做压力测试。
现在该做什么
- 如果你仍在加载 Heatmap Layer 或 Drawing Library: 先替换它们。它们在当前版本的 Maps JavaScript API 中已无法工作。
- 审查路径规划代码: 找出所有对 DirectionsService、DirectionsRenderer 和 DistanceMatrixService 的调用。
- 选择替代方案:
Route和RouteMatrix类、Routes API,或其他服务商。 - 一次迁移一个服务,放在 feature flag 之后,切换前先比较结果。
- 关注 Google 的弃用页面,以便及时看到停用日期。Google 已承诺对 Legacy 服务至少提前 12 个月通知。
想试用 MapAtlas 的路径规划 API,请创建免费账户并阅读 API 文档。如需迁移方面的帮助,请通过联系页面联系我们。
常见问题
Google Maps Drawing Library 还能用吗?
不能。Google 于 2025 年 8 月弃用了 Drawing Library(包括 DrawingManager),其弃用页面将其列为自 2026 年 5 月起不可用。Maps JavaScript API 3.65.3b 版本(2026 年 6 月 4 日)的发布说明确认 DrawingManager 已不可用。Google 推荐 Terra Draw 作为替代。
Heatmap Layer 还能用吗?
不能。Google 于 2025 年 5 月 27 日弃用了 Heatmap Layer,2026 年 5 月 20 日的 3.65.1c 版本说明它已停用。Google 建议改用第三方库,例如 deck.gl 的 HeatmapLayer。
DirectionsService 和 DistanceMatrixService 什么时候停止工作?
Google 尚未确定日期。两者自 2025 年 3 月 1 日起处于 Legacy 状态,自 2026 年 2 月 25 日起被弃用。根据 Google 的发布说明,目前没有停用计划,严重回归问题仍会修复,并且在停止支持前至少提前 12 个月通知。Legacy 服务不对新的 Cloud 项目开放,因此新项目需要使用 Route 和 RouteMatrix 类或其他服务商。
可以逐步迁移吗,还是必须一次性全部切换?
可以一次迁移一个服务。每个被弃用的类彼此独立。先替换已经失效的 Drawing Library 和 Heatmap Layer,再按自己的计划替换 DirectionsService 和 DistanceMatrixService。
MapAtlas 是否支持途经点和多种出行方式?
支持。MapAtlas Directions API 接收一个有序的位置列表,首尾之间的每个点都是途经点,并支持 auto、bicycle、pedestrian、bus、truck、taxi 和 motor_scooter 等计费模型(costing)。它是一个 REST 端点,请从后端调用,避免 API 密钥暴露在客户端。

