گوگل سالهاست Maps Platform خود را سختگیرانهتر میکند، اما موج منسوخسازی مه ۲۰۲۶ مخربترین تا به امروز است. چهار ویژگی پرکاربرد از Maps JavaScript API حذف میشوند: Heatmap Layer، Drawing Library، DirectionsService و DistanceMatrixService. اگر اپلیکیشنت به هر کدام از اینها وابسته است، چند هفتهای بیشتر وقت نداری تا قبل از اینکه کدت از کار بیفتد مهاجرت کنی.
این یک منسوخسازی نرم نیست که endpoint های قدیمی سالها سر جایشان بمانند. گوگل تاریخهای حذف قطعی تعیین کرده و کنسول توسعهدهنده از همین الان هشدار نشان میدهد. این راهنما دقیقاً توضیح میدهد چه چیزی تغییر میکند، چرا گوگل این کار را میکند، و با مثالهای کد کارآمد چطور هر سرویس را منتقل کنی. اگر به جایگزین مستقیم نیاز داری، نشان میدهیم APIهای MapAtlas چطور با هر سرویس منسوخشده گوگل تطبیق دارند.
چه چیزی منسوخ میشود و کی
جدول زمانی کامل سرویسهای آسیبدیده:
| سرویس | منسوخشده | تاریخ حذف | جایگزین (گوگل) |
|---|---|---|---|
| Heatmap Layer (Maps JS API) | اوت ۲۰۲۵ | مه ۲۰۲۶ | Maps Datasets API + deck.gl |
| Drawing Library (Maps JS API) | مه ۲۰۲۵ | مه ۲۰۲۶ | Extended Component Library |
| DirectionsService (Maps JS API) | ۲۵ فوریه ۲۰۲۶ | مه ۲۰۲۶ | Routes API (REST) |
| DistanceMatrixService (Maps JS API) | ۲۵ فوریه ۲۰۲۶ | مه ۲۰۲۶ | Routes API (REST) |
جزئیات مهم: گوگل مسیریابی و محاسبات فاصله را کاملاً حذف نمیکند. چیزی که حذف میشود classهای JavaScript سمت کلاینت است که توسعهدهندگان بیش از یک دهه از آنها استفاده کردهاند، و مهاجرت به Routes API جدیدتر که یک REST endpoint سمت سرور است اجباری میشود. این یک ارتقای نسخه ساده نیست، بلکه تغییر معماری است که منطق مسیریابی را از مرورگر به backend منتقل میکند.
چه چیزی خراب میشود
اگر codebase ات هر کدام از موارد زیر را داشته باشد، بعد از تاریخ حذف از کار میافتد:
// All of these will stop working in May 2026
const directionsService = new google.maps.DirectionsService();
const distanceMatrixService = new google.maps.DistanceMatrixService();
const heatmap = new google.maps.visualization.HeatmapLayer({ data: points });
const drawingManager = new google.maps.drawing.DrawingManager();
بعد از حذف، این constructor ها خطا میاندازند. هیچ رفتار fallback یا degradation تدریجی وجود ندارد. نقشه لود میشود، اما هر قابلیتی که به این classها وابسته باشد کاملاً از کار میافتد.
چرا گوگل این تغییرات را اجباری میکند
دلیل رسمی گوگل عملکرد بهتر و نوسازی است. Routes API که جایگزین DirectionsService و DistanceMatrixService شده، ویژگیهای جدیدتری مثل مسیریابی سازگار با محیط زیست، مسیریابی برای وسایل نقلیه دوچرخ و تخمین هزینه عوارض را پشتیبانی میکند که classهای JavaScript قدیمی از عهدهشان برنمیآمدند.
محرک واقعی کنترل قیمت است. با انتقال مسیریابی به REST API سمت سرور، گوگل صورتحساب دقیقتر و ردیابی استفاده بهتری به دست میآورد. DirectionsService جاوااسکریپتی الگوهای batch سمت کلاینت را ممکن میساخت که برای گوگل سختتر بود دقیقاً اندازهگیری کند. Routes API تضمین میکند که هر درخواست از یک endpoint قابلاندازهگیری عبور کند.
برای Heatmap Layer و Drawing Library، گوگل توسعهدهندگان را به سمت Extended Component Library و ابزارهای تصویرسازی شخص ثالث مثل deck.gl هدایت میکند. این بخشی از الگوی بزرگتری است: گوگل رندرینگ core map tile را در اختیار خودش نگه میدارد و بقیه را به اکوسیستم واگذار میکند.
تأثیر عملی برای توسعهدهندگان: زیرساخت backend بیشتر، کلیدهای API بیشتر برای مدیریت، و در اکثر موارد، هزینه بیشتر به ازای هر درخواست در ردیفهای قیمتگذاری جدید.
چکلیست مهاجرت
قبل از نوشتن هر کد مهاجرتی، این چکلیست را دنبال کن:
۱. Codebase را بررسی کن
در codebase ات به دنبال مراجعه به classهای منسوخشده بگرد:
# Find all files using deprecated Google Maps services
grep -rn "DirectionsService\|DistanceMatrixService\|HeatmapLayer\|visualization.HeatmapLayer\|drawing.DrawingManager\|DrawingManager" \
--include="*.js" --include="*.ts" --include="*.tsx" --include="*.jsx" src/
هر فایل و کامپوننتی که از این سرویسها استفاده میکند مستند کن. یادداشت کن آیا فراخوانیها سمت کلاینت (مرورگر) اتفاق میافتند یا در یک بافت server-rendered مثل API routes در Next.js.
۲. الگوهای استفاده را شناسایی کن
برای هر مورد استفاده مستند کن:
- حالتهای سفر استفادهشده (رانندگی، پیادهروی، دوچرخهسواری، حملونقل عمومی)
- پشتیبانی از waypoint (مسیر ساده A به B، یا مسیرهای چند ایستگاهی)
- فیلدهای response مصرفشده (فاصله، مدت زمان، polyline، مراحل، کرایه)
- حجم (درخواست روزانه/ماهانه برای تخمین هزینه)
- نیازهای تأخیر (real-time برای کاربر، یا پردازش دستهای)
۳. هدف مهاجرت را انتخاب کن
دو گزینه داری:
گزینه A: ماندن با گوگل. از classهای JavaScript منسوخشده به Google Routes API جدید (REST) مهاجرت کن. این نیازمند تغییرات backend، مجوزهای جدید کلید API و بهروزرسانی صورتحساب است.
گزینه B: تغییر provider. به یک routing API شخص ثالث مهاجرت کن. از آنجا که کد یکپارچهسازی را به هر حال باید بازنویسی کنی، این زمان خوبی برای ارزیابی گزینههاست.
۴. یک محیط موازی راهاندازی کن
هرگز در جا مهاجرت نکن. حداقل دو هفته پیادهسازی قدیمی و جدید را کنار هم اجرا کن و قبل از تغییر، نتایج را از نظر دقت و تأخیر مقایسه کن.
۵. Error handling را بهروز کن
سرویسهای منسوخشده خطا را از طریق callback function ها برمیگرداندند. جایگزینهای REST API کدهای وضعیت HTTP برمیگردانند. منطق رسیدگی به خطای تو باید بههمین ترتیب تغییر کند.
راهنمای جایگزینی API به API
از DirectionsService به MapAtlas Directions API
قبل (گوگل، منسوخشده):
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://api.mapatlas.com/v1/directions?" +
new URLSearchParams({
origin: "52.52,13.405",
destination: "48.8566,2.3522",
waypoints: "50.9375,6.9603",
mode: "driving",
key: process.env.MAPATLAS_API_KEY!,
})
);
const data = await response.json();
if (data.status === "OK") {
const leg = data.routes[0].legs[0];
console.log("Distance:", leg.distance.text);
console.log("Duration:", leg.duration.text);
// Polyline for map rendering
const polyline = data.routes[0].overview_polyline;
}
تفاوتهای کلیدی:
- REST endpoint به جای یک JavaScript class. فراخوانیها از backend تو میآیند نه از مرورگر.
- احراز هویت سادهتر. یک کلید API در query string یا header.
- همان ساختار response. Routes، legs، distance، duration و polyline همه حضور دارند.
از DistanceMatrixService به MapAtlas Matrix API
قبل (گوگل، منسوخشده):
const service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix(
{
origins: [
{ lat: 52.52, lng: 13.405 },
{ lat: 48.1351, lng: 11.582 },
],
destinations: [
{ lat: 48.8566, lng: 2.3522 },
{ lat: 51.5074, lng: -0.1278 },
],
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://api.mapatlas.com/v1/matrix", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.MAPATLAS_API_KEY}`,
},
body: JSON.stringify({
origins: [
{ lat: 52.52, lng: 13.405 },
{ lat: 48.1351, lng: 11.582 },
],
destinations: [
{ lat: 48.8566, lng: 2.3522 },
{ lat: 51.5074, lng: -0.1278 },
],
mode: "driving",
}),
});
const data = await response.json();
data.rows.forEach((row: any, i: number) => {
row.elements.forEach((element: any, j: number) => {
console.log(`Origin ${i} -> Dest ${j}:`,
element.distance.text, element.duration.text);
});
});
شکل response تقریباً یکسان است. تغییر اصلی رفتن از API مرورگر مبتنی بر callback به API سرور مبتنی بر Promise است.
جایگزینی Heatmap Layer
برای تصویرسازی heatmap، مسیر مهاجرت به نیازهایت بستگی دارد:
گزینه ۱: MapLibre GL JS با heatmap layer (اپنسورس)
import maplibregl from "maplibre-gl";
const map = new maplibregl.Map({
container: "map",
style: "https://api.mapatlas.com/v1/styles/streets?key=YOUR_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,
},
});
});
این کنترل کامل رندرینگ heatmap را میدهد و به tile server های گوگل وابسته نیست.
گزینه ۲: deck.gl HeatmapLayer (توصیه خود گوگل)
import { Deck } from "@deck.gl/core";
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 با tile style های MapAtlas بهخوبی یکپارچه میشود، در حالی که deck.gl میتواند روی هر نقشه پایهای overlay شود.
مقایسه هزینه: Google Routes API در برابر MapAtlas
مهاجرت به Routes API خود گوگل فقط تغییر کد نیست. با خود قیمتگذاری جدید میآورد:
| سرویس | Google (قدیمی، به ازای ۱,۰۰۰) | Google Routes API (به ازای ۱,۰۰۰) | MapAtlas (به ازای ۱,۰۰۰) |
|---|---|---|---|
| Directions (پایه) | ۵.۰۰$ | ۵.۰۰$ | ۱.۵۰$ |
| Directions (پیشرفته، waypoints/ترافیک) | ۱۰.۰۰$ | ۱۰.۰۰$ | ۲.۵۰$ |
| Distance Matrix (به ازای هر عنصر) | ۵.۰۰$ | ۵.۰۰$ | ۱.۰۰$ |
| Distance Matrix (پیشرفته) | ۱۰.۰۰$ | ۱۰.۰۰$ | ۲.۰۰$ |
| Geocoding | ۵.۰۰$ | ۵.۰۰$ | ۱.۵۰$ |
در ۱۰۰,۰۰۰ درخواست مسیریابی ماهانه:
- Google Routes API: حدود ۵۰۰ تا ۱,۰۰۰ دلار (بسته به ویژگیهای استفادهشده)
- MapAtlas Directions API: حدود ۱۵۰ تا ۲۵۰ دلار
صرفهجویی برای اپلیکیشنهایی که routing را با geocoding و محاسبات فاصله ترکیب میکنند سریع تجمیع میشود. یک پلتفرم لجستیک که ماهانه ۵۰۰,۰۰۰ عنصر ماتریسی پردازش میکند در گوگل حدود ۲,۵۰۰ دلار در مقابل ۵۰۰ دلار در MapAtlas میپردازد.
برای جزئیات کامل قیمتگذاری به قیمتگذاری MapAtlas مراجعه کن.
نمونههای کامل مهاجرت کد: قبل و بعد
اینجا یک نمونه مهاجرت کامل برای یک کامپوننت React است که مسیرهای رانندگی را روی نقشه نشان میدهد.
قبل: Google Maps DirectionsService در React
import { useEffect, useRef } from "react";
function DirectionsMap({ origin, destination }: {
origin: google.maps.LatLngLiteral;
destination: google.maps.LatLngLiteral;
}) {
const mapRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const map = new google.maps.Map(mapRef.current!, {
center: origin,
zoom: 7,
});
const directionsRenderer = new google.maps.DirectionsRenderer();
directionsRenderer.setMap(map);
const directionsService = new google.maps.DirectionsService();
directionsService.route(
{
origin,
destination,
travelMode: google.maps.TravelMode.DRIVING,
},
(result, status) => {
if (status === "OK" && result) {
directionsRenderer.setDirections(result);
}
}
);
}, [origin, destination]);
return <div ref={mapRef} style={{ width: "100%", height: "400px" }} />;
}
بعد: MapAtlas Directions API با 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://api.mapatlas.com/v1/styles/streets?key=YOUR_KEY",
center: [origin.lng, origin.lat],
zoom: 7,
});
map.on("load", async () => {
// Fetch directions from your backend (or directly if CORS allows)
const res = await fetch(
`/api/directions?` +
new URLSearchParams({
origin: `${origin.lat},${origin.lng}`,
destination: `${destination.lat},${destination.lng}`,
mode: "driving",
})
);
const data = await res.json();
if (data.routes?.[0]) {
const coordinates = data.routes[0].geometry.coordinates;
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,
},
});
// Fit map to route bounds
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" }} />;
}
Backend API Route (Next.js)
// app/api/directions/route.ts
import { NextRequest, NextResponse } from "next/server";
export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url);
const origin = searchParams.get("origin");
const destination = searchParams.get("destination");
const mode = searchParams.get("mode") || "driving";
const response = await fetch(
`https://api.mapatlas.com/v1/directions?` +
new URLSearchParams({
origin: origin!,
destination: destination!,
mode,
key: process.env.MAPATLAS_API_KEY!,
})
);
const data = await response.json();
return NextResponse.json(data);
}
این الگو کلید API را روی سرور نگه میدارد و فقط هندسه مسیر را در اختیار کلاینت قرار میدهد.
چطور مهاجرت را قبل از ددلاین تست کنی
مرحله ۱: هر دو API را بهصورت موازی اجرا کن
دو هفته قبل از تغییر، برای هر درخواست هم سرویس قدیمی گوگل و هم جایگزین جدید را صدا بزن. هر دو response را لاگ بگیر و مقایسه کن:
async function getDirectionsWithComparison(
origin: string,
destination: string
) {
const [googleResult, mapatResult] = await Promise.all([
fetchGoogleDirections(origin, destination),
fetchMapAtlasDirections(origin, destination),
]);
// Compare key metrics
const distanceDelta = Math.abs(
googleResult.distance - mapatResult.distance
);
const durationDelta = Math.abs(
googleResult.duration - mapatResult.duration
);
console.log({
route: `${origin} -> ${destination}`,
googleDistance: googleResult.distance,
mapatDistance: mapatResult.distance,
distanceDeltaPercent: ((distanceDelta / googleResult.distance) * 100).toFixed(1),
googleDuration: googleResult.duration,
mapatDuration: mapatResult.duration,
durationDeltaPercent: ((durationDelta / googleResult.duration) * 100).toFixed(1),
});
// Use MapAtlas result in production, Google as validation
return mapatResult;
}
مرحله ۲: Feature flag راهاندازی کن
از یک feature flag برای کنترل اینکه اپلیکیشنت کدام API را صدا میزند استفاده کن. این اجازه میدهد در صورت مشکل فوری rollback کنی:
const useMapAtlasDirections = process.env.FEATURE_MAPATLAS_DIRECTIONS === "true";
const directions = useMapAtlasDirections
? await fetchMapAtlasDirections(origin, destination)
: await fetchGoogleDirections(origin, destination);
مرحله ۳: نرخ خطا را رصد کن
بعد از تغییر رصد کن:
- نرخ خطاهای HTTP 4xx/5xx از API جدید
- افزایش تأخیر (provider جدید ممکن است زمان پاسخ متفاوتی داشته باشد)
- فیلدهای گمشده در response هایی که UI ات به آنها وابسته است
- دقت مسیر برای موارد لبهای (مسیرهای کشتی، جادههای پولی، مناطق محدود)
مرحله ۴: قبل از راهاندازی لود تست بگیر
اگر اپلیکیشنت با spike های ترافیکی کار میکند، مثل یک پلتفرم لجستیک در زمان توزیع صبحگاهی، API جدید را با ۲ برابر حجم اوج تست بار کن. MapAtlas یک محیط sandbox برای تست بار بدون صورتحساب production ارائه میدهد.
جدول زمانی: این هفته چی کار کنیم
اگر هنوز شروع به مهاجرت نکردی، ترتیب اولویت اینجاست:
۱. این هفته: Codebase را بررسی کن. هر مورد استفاده از چهار سرویس منسوخشده را شناسایی کن. ۲. هفته ۲: یک حساب MapAtlas بساز و کلید API بگیر. پلن رایگان ۱۰,۰۰۰ درخواست برای تست را پوشش میدهد. ۳. هفته ۳: جایگزین را برای مهمترین سرویست پیادهسازی کن، معمولاً DirectionsService. ۴. هفته ۴: بقیه سرویسها را منتقل کن و تست موازی اجرا کن. ۵. قبل از ددلاین مه: تغییر نهایی را بده، وابستگیهای Google API را حذف کن، صورتحساب را بهروز کن.
مهاجرت اختیاری نیست. بعد از مه ۲۰۲۶، classهای منسوخشده از Maps JavaScript API حذف میشوند و هر کدی که به آنها ارجاع دهد در زمان اجرا خطا میاندازد. الان شروع کن و وقت خواهی داشت درست تست کنی. تا هفته آخر صبر کن و زیر فشار در production پَچ میزنی.
برای پشتیبانی مهاجرت، MapAtlas کمک مستقیم به توسعهدهندگان ارائه میدهد. از طریق صفحه تماس ارتباط برقرار کن یا با مستندات API شروع کن تا APIهای جایگزین را با توجه به نیازهایت ارزیابی کنی.
سوالات متداول
منسوخ شدنهای Google Maps API دقیقاً کی اجرایی میشوند؟
Heatmap Layer و Drawing Library بهترتیب در اوت و مه ۲۰۲۵ منسوخ شدند و حذف آنها برای مه ۲۰۲۶ برنامهریزی شده. DirectionsService و DistanceMatrixService در ۲۵ فوریه ۲۰۲۶ منسوخ شدند، با همان هدف حذف در مه ۲۰۲۶. بعد از حذف، فراخوانی این سرویسها خطا برمیگرداند.
آیا کلید Google Maps JavaScript API فعلیام بعد از مه ۲۰۲۶ کار میکند؟
کلید API برای سرویسهایی که منسوخ نشدهاند همچنان کار میکند. اما هر کدی که از طریق Maps JavaScript API، DirectionsService، DistanceMatrixService، Heatmap Layer یا Drawing Library را صدا میزند از کار میافتد. باید این فراخوانیهای خاص را قبل از ددلاین به APIهای جایگزین منتقل کنی.
ارزانترین جایگزین Google Maps Directions API کدام است؟
MapAtlas یک Directions API ارائه میدهد که حدوداً ۷۰ درصد ارزانتر از معادل گوگل است. پلن رایگان شامل ۱۰,۰۰۰ درخواست ماهانه است که برای توسعه و تست مهاجرت کافی است. جایگزینهای دیگر شامل Mapbox، HERE و OpenRouteService هستند، اما MapAtlas نزدیکترین فرمت request/response به گوگل را دارد که تلاش مهاجرت را کاهش میدهد.
میتوانم بهتدریج مهاجرت کنم یا باید همه چیز را یکباره تغییر دهم؟
میتوانی بهتدریج مهاجرت کنی. هر سرویس منسوخشده مستقل است، پس میتوانی ابتدا DirectionsService، سپس DistanceMatrixService و بعد کتابخانههای تصویرسازی را جایگزین کنی. این رویکرد توصیهشده است چون قبل از رفتن به مرحله بعد میتوانی هر جایگزین را جداگانه تست کنی.
آیا MapAtlas همان waypoints و travel modes که Google DirectionsService دارد را پشتیبانی میکند؟
بله. MapAtlas Directions API از حالتهای رانندگی، پیادهروی و دوچرخهسواری، بهعلاوه waypoints میانی پشتیبانی میکند. فرمت درخواست کمی متفاوت است (endpoint RESTful در برابر JavaScript class)، اما عملکرد اصلی یعنی مسیریابی چندنقطهای با انتخاب حالت سفر، معادل است.

