خلال الأشهر الثمانية عشر الماضية أعلنت Google إيقاف أربعة أجزاء واسعة الاستخدام في Maps JavaScript API. اثنان منها، Heatmap Layer وDrawing Library، غير متاحين منذ مايو 2026. أما الآخران، DirectionsService وDistanceMatrixService، فهما بحالة Legacy ومُعلن إيقافهما، لكنهما ما زالا يعملان ولا يوجد موعد لإيقافهما.
يعرض هذا الدليل الحالة الحالية لكل منها مع روابط إلى صفحات Google نفسها، ويشرح كيفية استبدالها. وحين يأتي البديل من MapAtlas، تستخدم الشيفرة نقاط النهاية وصيغ الاستجابة الحقيقية لدينا.
ما الذي أُوقف وما الذي ما زال يعمل
| الخدمة | الحالة | التواريخ الرئيسية | البديل من Google |
|---|---|---|---|
| Heatmap Layer | أُزيلت | أُعلن إيقافها في 27 مايو 2025، وأُلغيت في الإصدار 3.65.1c (20 مايو 2026) | مكتبات خارجية مثل deck.gl |
| Drawing Library (DrawingManager) | أُزيلت | أُعلن إيقافها في أغسطس 2025، وغير متاحة منذ مايو 2026 (أكّد ذلك الإصدار 3.65.3b، 4 يونيو 2026) | مكتبات خارجية مثل Terra Draw |
| DirectionsService | Legacy، مُعلن إيقافه | Legacy منذ 1 مارس 2025، ومُعلن إيقافه منذ 25 فبراير 2026 (الإصدار 3.64.2b)، بلا موعد إيقاف | الفئة Route في مكتبة Routes |
| DistanceMatrixService | Legacy، مُعلن إيقافه | Legacy منذ 1 مارس 2025، ومُعلن إيقافه منذ 25 فبراير 2026 (الإصدار 3.64.2b)، بلا موعد إيقاف | الفئة RouteMatrix في مكتبة Routes |
المصادر: صفحة الإيقافات في Google Maps Platform، وملاحظات إصدارات Maps JavaScript API، وصفحة منتجات Legacy.
لحالة Legacy معنى محدد. وفق Google، لا تحصل خدمة Legacy على ميزات جديدة ولا يمكن تفعيلها في مشاريع Cloud الجديدة، لكنها تبقى مدعومة في المشاريع القائمة. وتلتزم Google بإشعار لا يقل عن 12 شهراً قبل إلغاء أي خدمة منها، وتذكر ملاحظة الإصدار التي أعلنت إيقاف DirectionsService وDistanceMatrixService أنه لا يوجد موعد لإيقافهما وأن الأعطال الكبيرة ستظل تُصلح. وشمل التحول نفسه إلى Legacy في 1 مارس 2025 خدمتي الويب Directions API وDistance Matrix API، إضافة إلى 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، فهذا هو السبب. أصلح ذلك أولاً. ثم خطّط لترحيل حساب المسارات قبل أن تعلن Google موعداً.
البدائل التي تقدمها Google
لحساب المسارات تقدم Google طريقين، ولا يُلزمك أي منهما بنقل المنطق إلى خادم:
- في المتصفح: مكتبة Routes في Maps JavaScript API. تحل الفئة
Routeمحل DirectionsService، وتحل الفئةRouteMatrixمحل DistanceMatrixService. - على الخادم: Routes API، وهي خدمة REST فيها الطريقتان Compute Routes وCompute Route Matrix.
أما التصوّر المرئي فلم تعد 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 تُبلغ عن الأخطاء عبر قيمة حالة في دالة callback. أما بدائل REST فتعيد رموز حالة HTTP ونصوص أخطاء، لذا يجب أن تتغير معالجة الأخطاء لديك.
استبدال كل خدمة بخدمات MapAtlas
نقاط نهاية حساب المسارات في MapAtlas خدمات REST على gateway.mapmetrics-atlas.net، وهي موثقة في توثيق MapAtlas API. تستقبل رمزاً (token) معامِلاً في الاستعلام، لذا استدعها من الخادم الخلفي.
من DirectionsService إلى Directions API من MapAtlas
قبل (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);
}
}
);
بعد (Directions API من MapAtlas):
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 إلى Matrix API من MapAtlas
تعيد Matrix API من MapAtlas زمن الرحلة والمسافة لكل زوج من نقطة الانطلاق والوجهة في استدعاء واحد. تحدد نقطة النهاية لدينا كل زوج بمسافة طريق لا تتجاوز 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);
});
});
}
}
);
بعد (Matrix API من MapAtlas):
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");
});
});
الشبكة تقابل rows وelements في Google. تصل المسافات أرقاماً بالوحدة التي تطلبها، والأزمنة بالثواني، فتنسيقها عليك.
بديل 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: HeatmapLayer من deck.gl، التي يقترحها توثيق 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 يتيح للمستخدمين رسم علامات وخطوط ودوائر ومضلعات على الخريطة. توفر Terra Draw، وهي المكتبة التي تذكرها صفحة الإيقافات في Google، الأوضاع نفسها، ولها محوّلات لعدة مكتبات خرائط منها Google Maps وMapLibre GL JS. وتعود الأشكال بصيغة GeoJSON، فيمكنك تخزينها أو إرسالها كما هي إلى خدمة سياج جغرافي أو خدمة خطوط الزمن المتساوي.
مقارنة التكلفة
أسعار Google المعلنة متطابقة لرموز SKU الخاصة بحساب المسارات بحالة Legacy ولرموز Essentials الخاصة ببدائلها. كل الأسعار أدناه من صفحة أسعار Google Maps Platform وصفحة أسعار MapAtlas، وقد رُوجعت في 26 سبتمبر 2026.
| الخدمة | 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
ضع المزوّد خلف flag حتى تتمكن من الرجوع من دون نشر جديد:
const useMapAtlasDirections = process.env.FEATURE_MAPATLAS_DIRECTIONS === "true";
const directions = useMapAtlasDirections
? await fetchMapAtlasDirections(origin, destination)
: await fetchGoogleDirections(origin, destination);
الخطوة 3: راقب معدلات الأخطاء
بعد التحويل، راقب:
- معدلات HTTP 4xx و5xx من الواجهة الجديدة
- تغيّرات زمن الاستجابة
- الحقول المفقودة التي تقرؤها واجهتك
- فروق المسارات في الحالات الحدية مثل العبّارات والطرق ذات الرسوم والمناطق المقيّدة
الخطوة 4: اختبار الحمل قبل الإطلاق
إذا كانت لحركة المرور لديك ذروات، مثل التوزيع الصباحي في منصة لوجستية، فاختبر الواجهة الجديدة بضعف حجم الذروة قبل الاعتماد عليها.
ما الذي تفعله الآن
- إذا كنت ما زلت تحمّل Heatmap Layer أو Drawing Library: استبدلهما أولاً. فهما لم تعودا تعملان في الإصدارات الحالية من Maps JavaScript API.
- افحص شيفرة حساب المسارات: اعثر على كل استدعاء لـDirectionsService وDirectionsRenderer وDistanceMatrixService.
- اختر البديل: الفئتان
RouteوRouteMatrix، أو Routes API، أو مزوّد آخر. - رحّل خدمة واحدة في كل مرة، خلف feature flag، وقارن النتائج قبل التحويل.
- تابع صفحة الإيقافات لدى Google تحسباً لإعلان موعد إيقاف. التزمت Google بإشعار لا يقل عن 12 شهراً لخدمات Legacy.
لتجربة واجهات حساب المسارات من MapAtlas، أنشئ حساباً مجانياً واقرأ توثيق API. وللمساعدة في الترحيل استخدم صفحة التواصل.
الأسئلة الشائعة
هل ما زالت Drawing Library في Google Maps متاحة؟
لا. أعلنت Google إيقاف Drawing Library، بما فيها DrawingManager، في أغسطس 2025، وتذكر صفحة الإيقافات أنها غير متاحة منذ مايو 2026. وتؤكد ملاحظات الإصدار 3.65.3b من Maps JavaScript API (4 يونيو 2026) أن DrawingManager لم يعد متاحاً. وتذكر Google مكتبة Terra Draw بديلاً.
هل ما زالت Heatmap Layer متاحة؟
لا. أعلنت Google إيقاف Heatmap Layer في 27 مايو 2025، ويذكر الإصدار 3.65.1c بتاريخ 20 مايو 2026 أنها أُلغيت نهائياً. وتقترح Google بدلاً منها مكتبات خارجية مثل HeatmapLayer في deck.gl.
متى يتوقف DirectionsService وDistanceMatrixService عن العمل؟
لم تحدد Google موعداً. كلاهما بحالة Legacy منذ 1 مارس 2025 ومُعلن إيقافهما منذ 25 فبراير 2026. ووفق ملاحظات الإصدار من Google، لا يوجد موعد لإيقافهما، وسيستمر إصلاح الأعطال الكبيرة فيهما، وسيسبق انتهاء الدعم إشعار لا يقل عن 12 شهراً. الخدمات بحالة Legacy غير متاحة لمشاريع Cloud الجديدة، لذلك يحتاج أي مشروع جديد إلى الفئتين Route وRouteMatrix أو إلى مزوّد آخر.
هل يمكنني الترحيل تدريجياً أم يجب تغيير كل شيء دفعة واحدة؟
يمكنك ترحيل خدمة واحدة في كل مرة. كل فئة مُعلن إيقافها مستقلة عن غيرها. استبدل أولاً Drawing Library وHeatmap Layer لأنهما لم تعودا تعملان، ثم DirectionsService وDistanceMatrixService وفق جدولك الزمني.
هل يدعم MapAtlas النقاط الوسيطة وأكثر من وسيلة تنقل؟
نعم. تستقبل Directions API من MapAtlas قائمة مرتبة من المواقع، فكل نقطة بين الأولى والأخيرة نقطة وسيطة، وتدعم نماذج التكلفة auto وbicycle وpedestrian وbus وtruck وtaxi وmotor_scooter. وهي نقطة نهاية REST، لذا استدعها من الخادم الخلفي حتى لا يصل مفتاح API إلى المتصفح.

