أنواع الخرائط

اختيار النظام الأساسي: Android iOS JavaScript

يتناول هذا المستند أنواع الخرائط التي يمكنك عرضها باستخدام واجهة برمجة التطبيقات Maps JavaScript API. تستخدِم واجهة برمجة التطبيقات عنصر MapType لتخزين معلومات عن هذه الخرائط. MapType هي واجهة تحدّد عرض واستخدام مربّعات الخريطة وترجمة أنظمة الإحداثيات من إحداثيات الشاشة إلى إحداثيات العالم (على الخريطة). يجب أن يحتوي كل MapType على بضع طرق لمعالجة استرداد المربّعات وإخلاءها، والخصائص التي تحدّد سلوكها المرئي.

إنّ آلية عمل أنواع الخرائط ضمن واجهة برمجة التطبيقات Maps JavaScript API هي موضوع متقدّم. يمكن لمعظم المطوّرين استخدام أنواع الخرائط الأساسية المذكورة أدناه. ومع ذلك، يمكنك أيضًا تعديل طريقة عرض أنواع الخرائط الحالية باستخدام الخرائط المخصّصة أو تحديد مربّعات الخرائط الخاصة بك باستخدام أنواع الخرائط المخصّصة. عند تقديم أنواع خرائط مخصّصة، عليك معرفة كيفية تعديل سجلّ أنواع الخرائط.

أنواع الخرائط الأساسية

تتوفّر أربعة أنواع من الخرائط في واجهة برمجة التطبيقات Maps JavaScript API. بالإضافة إلى مربّعات خرائط الطرق "المرسومة" المألوفة، تتوافق واجهة برمجة التطبيقات JavaScript لـ "خرائط Google" أيضًا مع أنواع الخرائط الأخرى.

تتوفّر أنواع الخرائط التالية في واجهة برمجة التطبيقات JavaScript لـ "خرائط Google":

  • يعرض roadmap طريقة العرض التلقائية لخريطة الطرق. هذا هو نوع الخريطة التلقائي.
  • satellite لعرض صور الأقمار الصناعية في Google Earth
  • hybrid يعرض مزيجًا من الاطِّلاع العادي واطّلاع القمر الصناعي.
  • terrain تعرِض خريطة طبوغرافية استنادًا إلى معلوماتتضاريس الأرض.

يمكنك تعديل نوع الخريطة المستخدَم في Map من خلال ضبط سمة mapTypeId، إما داخل الدالة الإنشائية من خلال ضبط عنصر Map options، أو من خلال استدعاء setMapTypeId() في الخريطة. تكون القيمة التلقائية لسمة mapTypeID هي roadmap.

ضبط mapTypeId عند إنشاء الحملة:

var myLatlng = new google.maps.LatLng(-34.397, 150.644);
var mapOptions = {
  zoom: 8,
  center: myLatlng,
  mapTypeId: 'satellite'
};
var map = new google.maps.Map(document.getElementById('map'),
    mapOptions);

تعديل mapTypeId ديناميكيًا:

map.setMapTypeId('terrain');

يُرجى العِلم أنّه لا يتمّ ضبط نوع الخريطة مباشرةً، ولكن يتمّ ضبط mapTypeId للإشارة إلى MapType باستخدام معرّف. تستخدِم واجهة برمجة التطبيقات Maps JavaScript API سجلّ أنواع الخرائط، описанًا أدناه، لإدارة هذه الإشارات.

الصور بزاوية 45 درجة

تتيح واجهة برمجة التطبيقات Maps JavaScript API عرض صور بزاوية 45 درجة خاصة لمواقع جغرافية معيّنة. توفّر هذه الصور العالية الدقة عروضًا من منظور مختلف لكل اتجاه أساسي (الشمال والجنوب والشرق والغرب). تتوفّر هذه الصور عند مستويات تكبير أو تصغير أعلى لأنواع الخرائط المتوافقة.

تعرض الصورة التالية منظرًا بزاوية 45 درجة لمدينة نيويورك:

تتيح أنواع الخرائط satellite وhybrid عرض صور بزاوية 45 درجة عند مستويات تكبير عالية (12 أو أكثر) متى توفّرت. إذا كبَّر المستخدم موقعًا جغرافيًا تتوفّر فيه هذه الصور، تغيّر أنواع الخرائط طرق العرض تلقائيًا على النحو التالي:

  • يتم استبدال صور الأقمار الصناعية أو الصور الهجينة بصور تُظهر منظورًا بزاوية 45 درجة وتتمحور حول الموقع الجغرافي الحالي. تكون هذه العروض تلقائيًا موجهة نحو الشمال. إذا كبّر المستخدم الصورة، تظهر صور الأقمار الصناعية أو الصور الهجينة التلقائية مرة أخرى. يختلف السلوك حسب مستوى التكبير وقيمة tilt:
    • بين مستوى التكبير 12 و18، يتم عرض الخريطة الأساسية من الأعلى للأسفل (0 درجة) بشكلٍ تلقائي ما لم يتم ضبط tilt على 45.
    • عند مستويات التكبير التي تبلغ 18 أو أكثر، يتم عرض الخريطة الأساسية بزاوية 45 درجة ما لم يتم ضبط tilt على 0.
  • يصبح عنصر التحكّم في التدوير مرئيًا. يوفّر عنصر التحكّم في التدوير خيارات تتيح للمستخدم تبديل إمالة الشاشة وتدوير العرض بزيادات 90 درجة في أي من الاتجاهين. لإخفاء عنصر التحكّم في التدوير، اضبط rotateControl على false.

يؤدي التصغير من نوع خريطة يعرض صورًا بزاوية 45 درجة إلى التراجع عن كل من هذه التغييرات، ما يؤدي إلى إعادة ضبط أنواع الخرائط الأصلية.

تفعيل صور بزاوية 45 درجة وإيقافها

يمكنك إيقاف الصور بزاوية 45 درجة من خلال طلب setTilt(0) على العنصر Map. لتفعيل الصور بزاوية 45 درجة لأنواع الخرائط المتوافقة، يُرجى الاتصال بالرقم setTilt(45). ستعكس طريقة getTilt() في Map دائمًا tilt الحالي الذي يظهر على الخريطة. إذا ضبطت tilt على خريطة ثم أزلت tilt لاحقًا (من خلال تكبير الخريطة مثلاً)، ستُرجع طريقة getTilt() في الخريطة القيمة 0.

ملاحظة مهمة: لا تتوفّر صور بزاوية 45 درجة إلا في الخرائط المركّبة، ولا يمكن استخدام هذه الصور مع الخرائط المتجهّة.

يعرض المثال التالي عرضًا بزاوية 45 درجة لمدينة نيويورك:

TypeScript

function initMap(): void {
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      center: { lat: 40.76, lng: -73.983 },
      zoom: 15,
      mapTypeId: "satellite",
    }
  );

  map.setTilt(45);
}

declare global {
  interface Window {
    initMap: () => void;
  }
}
window.initMap = initMap;

JavaScript

function initMap() {
  const map = new google.maps.Map(document.getElementById("map"), {
    center: { lat: 40.76, lng: -73.983 },
    zoom: 15,
    mapTypeId: "satellite",
  });

  map.setTilt(45);
}

window.initMap = initMap;
عرض مثال

تجربة عيّنة

الاطّلاع على مثال

تدوير الصور بزاوية 45 درجة

تتألف صور بزاوية 45 درجة من مجموعة من الصور لكل اتجاه أساسي (الشمال والجنوب والشرق والغرب). بعد أن تبدأ الخريطة في عرض صور بزاوية 45 درجة، يمكنك توجيه الصور نحو أحد الاتجاهات الأساسية من خلال استدعاء setHeading() على العنصر Map، مع تمرير قيمة عددية يتم التعبير عنها بالدرجات من الشمال.

يعرض المثال التالي خريطة جوية ويتم تدويرها تلقائيًا كل 3 ثوانٍ عند النقر على الزر:

TypeScript

let map: google.maps.Map;

function initMap(): void {
  map = new google.maps.Map(document.getElementById("map") as HTMLElement, {
    center: { lat: 40.76, lng: -73.983 },
    zoom: 15,
    mapTypeId: "satellite",
    heading: 90,
    tilt: 45,
  });

  // add listener to button
  document.getElementById("rotate")!.addEventListener("click", autoRotate);
}

function rotate90(): void {
  const heading = map.getHeading() || 0;

  map.setHeading(heading + 90);
}

function autoRotate(): void {
  // Determine if we're showing aerial imagery.
  if (map.getTilt() !== 0) {
    window.setInterval(rotate90, 3000);
  }
}

declare global {
  interface Window {
    initMap: () => void;
  }
}
window.initMap = initMap;

JavaScript

let map;

function initMap() {
  map = new google.maps.Map(document.getElementById("map"), {
    center: { lat: 40.76, lng: -73.983 },
    zoom: 15,
    mapTypeId: "satellite",
    heading: 90,
    tilt: 45,
  });
  // add listener to button
  document.getElementById("rotate").addEventListener("click", autoRotate);
}

function rotate90() {
  const heading = map.getHeading() || 0;

  map.setHeading(heading + 90);
}

function autoRotate() {
  // Determine if we're showing aerial imagery.
  if (map.getTilt() !== 0) {
    window.setInterval(rotate90, 3000);
  }
}

window.initMap = initMap;
عرض مثال

تجربة عيّنة

الاطّلاع على مثال

تعديل "قاعدة بيانات أنواع الخرائط"

mapTypeId في الخريطة هو معرّف سلسلة يتم استخدامه لربط MapType بقيمة فريدة. يحتفظ كل عنصر Map بملف شخصي MapTypeRegistry يحتوي على مجموعة من MapType المتاحة لتلك الخريطة. يُستخدَم هذا السجلّ لاختيار أنواع الخرائط المتاحة في عنصر التحكّم MapType في الخريطة، على سبيل المثال.

لا تقرأ البيانات مباشرةً من سجلّ أنواع الخرائط. بدلاً من ذلك، يمكنك تعديل السجلّ من خلال إضافة أنواع خرائط مخصّصة وربطها بمعرّف سلسلة من اختيارك. لا يمكنك تعديل أو تغيير أنواع الخرائط الأساسية (على الرغم من أنّه يمكنك إزالتها من الخريطة من خلال تغيير مظهر mapTypeControlOptions المرتبط بها).

يضبط الرمز البرمجي التالي الخريطة لعرض نوعَي خريطة فقط في mapTypeControlOptions الخريطة، ويُعدِّل السجلّ لإضافة الربط بهذا المعرّف إلى التنفيذ الفعلي لواجهة MapType.

// Modify the control to only display two maptypes, the
// default ROADMAP and the custom 'mymap'.
// Note that because this is an association, we
// don't need to modify the MapTypeRegistry beforehand.

var MY_MAPTYPE_ID = 'mymaps';

var mapOptions = {
  zoom: 12,
  center: brooklyn,
  mapTypeControlOptions: {
     mapTypeIds: ['roadmap', MY_MAPTYPE_ID]
  },
  mapTypeId: MY_MAPTYPE_ID
};

// Create our map. This creation will implicitly create a
// map type registry.
map = new google.maps.Map(document.getElementById('map'),
    mapOptions);

// Create your custom map type using your own code.
// (See below.)
var myMapType = new MyMapType();

// Set the registry to associate 'mymap' with the
// custom map type we created, and set the map to
// show that map type.
map.mapTypes.set(MY_MAPTYPE_ID, myMapType);

خرائط ذات نمط

يتيح لك StyledMapType تخصيص عرض الخرائط الأساسية العادية من Google، وتغيير العرض المرئي لعناصر مثل الطرق والمتنزهات والمناطق المبنية ليعكس نمطًا مختلفًا عن النمط المستخدَم في نوع الخريطة التلقائي.

لمزيد من المعلومات عن StyledMapType، اطّلِع على استخدام ملفّات تعريف StyledMapType المضمّنة في ملف JSON.

أنواع الخرائط المخصّصة

تتيح لك Maps JavaScript API عرض وإدارة أنواع الخرائط المخصّصة، ما يتيح لك تنفيذ صور الخرائط أو التراكبات المربّعة الخاصة بك.

تتوفّر عدة طرق لتنفيذ أنواع الخرائط المحتملة في واجهة برمجة التطبيقات JavaScript لـ "خرائط Google":

  • مجموعات المربّعات العادية التي تتألّف من صورتشكل معًا خرائط تصويرية كاملة وتُعرف مجموعات الوحدات المربّعة هذه أيضًا باسم أنواع الخرائط الأساسية. تعمل أنواع الخرائط هذه بالطريقة نفسها التي تعمل بها أنواع الخرائط التلقائية الحالية: roadmap وsatellite hybrid وterrain. يمكنك إضافة نوع الخريطة المخصّص إلى مصفوفة mapTypes في الخريطة لسماح واجهة المستخدم ضمن واجهة برمجة التطبيقات JavaScript لـ "خرائط Google" بالتعامل مع نوع الخريطة المخصّص كنوع خريطة عادي (عن طريق تضمينه في عنصر التحكّم في نوع الخريطة، على سبيل المثال).
  • تراكبات مربّعات الصور التي تظهر فوق أنواع الخرائط الأساسية الحالية بشكل عام، يتم استخدام أنواع الخرائط هذه لإضافة نوع خريطة حالي لعرض معلومات إضافية، وغالبًا ما تكون مقيّدة بمواقع جغرافية معيّنة و/أو مستويات تكبير معيّنة. يُرجى العِلم أنّ هذه المربّعات قد تكون شفافة، مما يتيح لك إضافة عناصر إلى الخرائط الحالية.
  • أنواع الخرائط غير المستندة إلى الصور، والتي تتيح لك التحكّم في عرض معلومات الخريطة على المستوى الأساسي

يعتمد كل خيار من هذه الخيارات على إنشاء فئة تُنفِّذ واجهة MapType. بالإضافة إلى ذلك، توفّر فئة ImageMapType بعض السلوك المضمّن لتبسيط إنشاء أنواع الخرائط المرئية.

واجهة MapType

قبل إنشاء فئات تنفِّذ MapType، من المهم فهم كيفية تحديد "خرائط Google" للإحداثيات وتحديد أجزاء الخريطة التي سيتم عرضها. عليك تنفيذ منطق مشابه لأي أنواع خرائط أساسية أو مركّبة. اطّلِع على دليل إحداثيات الخريطة والمربّعات.

يجب أن تنفّذ أنواع الخرائط المخصّصة واجهة MapType. تحدّد هذه الواجهة خصائص و methods معيّنة تسمح لواجهة برمجة التطبيقات ببدء طلبات إلى أنواع الخرائط عندما تحدّد واجهة برمجة التطبيقات أنّها بحاجة إلى عرض وحدات ملف تعريف الخريطة ضمن مساحة العرض ومستوى التكبير/التصغير الحاليَين. ويمكنك معالجة هذه الطلبات لتحديد المربّع الذي سيتم تحميله.

ملاحظة: يمكنك إنشاء فئة خاصة بك لتنفيذ هذه الواجهة. بدلاً من ذلك، إذا كانت لديك صور متوافقة، يمكنك استخدام فئة ImageMapType التي تُنفِّذ هذه الواجهة.

تتطلّب الفصول التي تنفِّذ واجهة MapType تحديد السمات التالية وتعبئتها:

  • tileSize (مطلوبة) لتحديد حجم المربّع (من النوع google.maps.Size). يجب أن تكون الأحجام مستطيلة ولكن ليس بالضرورة أن تكون مربّعة.
  • maxZoom (مطلوب) يحدِّد الحد الأقصى لمستوى التكبير الذي يتم عنده عرض أقسام من نوع الخريطة هذا.
  • minZoom (اختياري) لتحديد الحد الأدنى لمستوى التكبير الذي يتم عنده عرض مربّع من نوع الخريطة هذا. تكون هذه القيمة تلقائيًا0، ما يشير إلى عدم توفّر الحد الأدنى لمستوى التكبير/التصغير.
  • name (اختياري) يحدّد اسم نوع هذه الخارطة لا تكون هذه السمة ضرورية إلا إذا أردت أن يكون نوع الخريطة هذا قابلاً للاختيار ضمن عنصر تحكّم من النوع MapType. (اطّلِع على خيارات التحكّم.)
  • alt (اختياري) لتحديد النص البديل لهذا نوع الخريطة، الذي يظهر كنص مركّز. لا تكون هذه السمة ضرورية إلا إذا كنت تريد أن يكون نوع الخريطة هذا قابلاً للاختيار ضمن عنصر تحكّم من النوع MapType. (اطّلِع على خيارات التحكّم.)

بالإضافة إلى ذلك، يجب أن تنفِّذ الصفوف التي تنفِّذ واجهة MapType الأساليب التالية:

  • يتمّ استدعاء getTile() (مطلوب) كلّما حدّدت واجهة برمجة التطبيقات أنّ الخريطة بحاجة إلى عرض شرائح جديدة لمساحة العرض المحدّدة. يجب أن تحتوي طريقة getTile() على التوقيع التالي:

    getTile(tileCoord:Point,zoom:number,ownerDocument:Document):Node

    تحدِّد واجهة برمجة التطبيقات ما إذا كانت بحاجة إلى طلب getTile() استنادًا إلى سمات tileSize minZoom وmaxZoom في MapType ومستوى عرض النافذة الحالي للخريطة ومستوى التكبير/التصغير. يجب أن يعرِض معالِج هذه الطريقة عنصر HTML استنادًا إلى الإحداثيات المرسَلة ومستوى التكبير وعنصر DOM الذي سيتم إلحاق صورة المربّع به.

  • يتمّ استدعاء releaseTile() (اختياري) عندما تحدّد واجهة برمجة التطبيقات أنّ الخريطة بحاجة إلى إزالة مربّع عند خروجه من نطاق العرض. يجب أن تتضمّن هذه الطريقة التوقيع التالي:

    releaseTile(tile:Node)

    عليك عادةً إزالة أي عناصر تم إرفاقها بوحدات الخريطة عند إضافتها إلى الخريطة. على سبيل المثال، إذا أرفقت أدوات معالجة الأحداث بعناصر التراكب في مربّعات الخرائط، عليك إزالتها هنا.

تعمل طريقة getTile() بمثابة وحدة التحكّم الرئيسية في تحديد المربّعات التي يتم تحميلها ضمن إطار عرض معيّن.

أنواع الخرائط الأساسية

يمكن أن تكون أنواع الخرائط التي تنشئها بهذه الطريقة مستقلة أو يمكن دمجها مع أنواع خرائط أخرى كطبقات. تُعرف أنواع الخطط المُستقلة باسم أنواع الخرائط الأساسية. قد تحتاج إلى أن تتعامل واجهة برمجة التطبيقات مع MapType المخصّصة هذه كما تتعامل مع أي نوع آخر من أنواع المخططات الأساسية الحالية (ROADMAP أو TERRAIN أو غير ذلك). لإجراء ذلك، أضِف MapType المخصّص إلى mapTypes في Map. هذا الموقع من النوع MapTypeRegistry.

تنشئ التعليمة البرمجية التالية قاعدة MapType لعرض إحداثيات مربّعات الخريطة وترسم مخطّطًا للمربّعات:

TypeScript

/*
 * This demo demonstrates how to replace default map tiles with custom imagery.
 * In this case, the CoordMapType displays gray tiles annotated with the tile
 * coordinates.
 *
 * Try panning and zooming the map to see how the coordinates change.
 */

class CoordMapType {
  tileSize: google.maps.Size;
  maxZoom = 19;
  name = "Tile #s";
  alt = "Tile Coordinate Map Type";

  constructor(tileSize: google.maps.Size) {
    this.tileSize = tileSize;
  }

  getTile(
    coord: google.maps.Point,
    zoom: number,
    ownerDocument: Document
  ): HTMLElement {
    const div = ownerDocument.createElement("div");

    div.innerHTML = String(coord);
    div.style.width = this.tileSize.width + "px";
    div.style.height = this.tileSize.height + "px";
    div.style.fontSize = "10";
    div.style.borderStyle = "solid";
    div.style.borderWidth = "1px";
    div.style.borderColor = "#AAAAAA";
    div.style.backgroundColor = "#E5E3DF";
    return div;
  }

  releaseTile(tile: HTMLElement): void {}
}

function initMap(): void {
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 10,
      center: { lat: 41.85, lng: -87.65 },
      streetViewControl: false,
      mapTypeId: "coordinate",
      mapTypeControlOptions: {
        mapTypeIds: ["coordinate", "roadmap"],
        style: google.maps.MapTypeControlStyle.DROPDOWN_MENU,
      },
    }
  );

  map.addListener("maptypeid_changed", () => {
    const showStreetViewControl =
      (map.getMapTypeId() as string) !== "coordinate";

    map.setOptions({
      streetViewControl: showStreetViewControl,
    });
  });

  // Now attach the coordinate map type to the map's registry.
  map.mapTypes.set(
    "coordinate",
    new CoordMapType(new google.maps.Size(256, 256))
  );
}

declare global {
  interface Window {
    initMap: () => void;
  }
}
window.initMap = initMap;

JavaScript

/*
 * This demo demonstrates how to replace default map tiles with custom imagery.
 * In this case, the CoordMapType displays gray tiles annotated with the tile
 * coordinates.
 *
 * Try panning and zooming the map to see how the coordinates change.
 */
class CoordMapType {
  tileSize;
  maxZoom = 19;
  name = "Tile #s";
  alt = "Tile Coordinate Map Type";
  constructor(tileSize) {
    this.tileSize = tileSize;
  }
  getTile(coord, zoom, ownerDocument) {
    const div = ownerDocument.createElement("div");

    div.innerHTML = String(coord);
    div.style.width = this.tileSize.width + "px";
    div.style.height = this.tileSize.height + "px";
    div.style.fontSize = "10";
    div.style.borderStyle = "solid";
    div.style.borderWidth = "1px";
    div.style.borderColor = "#AAAAAA";
    div.style.backgroundColor = "#E5E3DF";
    return div;
  }
  releaseTile(tile) {}
}

function initMap() {
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 10,
    center: { lat: 41.85, lng: -87.65 },
    streetViewControl: false,
    mapTypeId: "coordinate",
    mapTypeControlOptions: {
      mapTypeIds: ["coordinate", "roadmap"],
      style: google.maps.MapTypeControlStyle.DROPDOWN_MENU,
    },
  });

  map.addListener("maptypeid_changed", () => {
    const showStreetViewControl = map.getMapTypeId() !== "coordinate";

    map.setOptions({
      streetViewControl: showStreetViewControl,
    });
  });
  // Now attach the coordinate map type to the map's registry.
  map.mapTypes.set(
    "coordinate",
    new CoordMapType(new google.maps.Size(256, 256)),
  );
}

window.initMap = initMap;
عرض مثال

تجربة عيّنة

أنواع الخرائط التي تظهر على سطح الصفحة

تم تصميم بعض أنواع الخرائط للعمل على أنواع الخرائط الحالية. قد تحتوي أنواع الخرائط هذه على طبقات شفافة تشير إلى نقاط الاهتمام، أو تعرض بيانات إضافية للمستخدم.

في هذه الحالات، لا تريد أن يتم التعامل مع نوع الخريطة ككيان منفصل بل كعنصر مركّب. يمكنك إجراء ذلك من خلال إضافة نوع الخريطة إلى MapType حالي مباشرةً باستخدام سمة overlayMapTypes في Map. يحتوي هذا الموقع على MVCArray من MapType. يتم عرض جميع أنواع الخرائط (الأساسية والطبقات الإضافية) ضمن طبقة mapPane. سيتم عرض أنواع الخرائط التي تتداخل فوق الخريطة الأساسية التي تم إرفاقها بها، بالترتيب الذي تظهر به في صفيف Map.overlayMapTypes (يتم عرض التراكبات التي تحتوي على قيم فهرس أعلى أمام التراكبات التي تحتوي على قيم فهرس أقل).

المثال التالي مطابق للمثال السابق باستثناء أنّنا أنشأنا تراكبًا للشرائح MapType فوق نوع الخريطة ROADMAP:

TypeScript

/*
 * This demo illustrates the coordinate system used to display map tiles in the
 * API.
 *
 * Tiles in Google Maps are numbered from the same origin as that for
 * pixels. For Google's implementation of the Mercator projection, the origin
 * tile is always at the northwest corner of the map, with x values increasing
 * from west to east and y values increasing from north to south.
 *
 * Try panning and zooming the map to see how the coordinates change.
 */

class CoordMapType implements google.maps.MapType {
  tileSize: google.maps.Size;
  alt: string|null = null;
  maxZoom: number = 17;
  minZoom: number = 0;
  name: string|null = null;
  projection: google.maps.Projection|null = null;
  radius: number = 6378137;

  constructor(tileSize: google.maps.Size) {
    this.tileSize = tileSize;
  }
  getTile(
    coord: google.maps.Point,
    zoom: number,
    ownerDocument: Document
  ): HTMLElement {
    const div = ownerDocument.createElement("div");

    div.innerHTML = String(coord);
    div.style.width = this.tileSize.width + "px";
    div.style.height = this.tileSize.height + "px";
    div.style.fontSize = "10";
    div.style.borderStyle = "solid";
    div.style.borderWidth = "1px";
    div.style.borderColor = "#AAAAAA";
    return div;
  }
  releaseTile(tile: Element): void {}
}

function initMap(): void {
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 10,
      center: { lat: 41.85, lng: -87.65 },
    }
  );

  // Insert this overlay map type as the first overlay map type at
  // position 0. Note that all overlay map types appear on top of
  // their parent base map.
  const coordMapType = new CoordMapType(new google.maps.Size(256, 256))
  map.overlayMapTypes.insertAt(
    0,
    coordMapType
  );
}

declare global {
  interface Window {
    initMap: () => void;
  }
}
window.initMap = initMap;

JavaScript

/*
 * This demo illustrates the coordinate system used to display map tiles in the
 * API.
 *
 * Tiles in Google Maps are numbered from the same origin as that for
 * pixels. For Google's implementation of the Mercator projection, the origin
 * tile is always at the northwest corner of the map, with x values increasing
 * from west to east and y values increasing from north to south.
 *
 * Try panning and zooming the map to see how the coordinates change.
 */
class CoordMapType {
  tileSize;
  alt = null;
  maxZoom = 17;
  minZoom = 0;
  name = null;
  projection = null;
  radius = 6378137;
  constructor(tileSize) {
    this.tileSize = tileSize;
  }
  getTile(coord, zoom, ownerDocument) {
    const div = ownerDocument.createElement("div");

    div.innerHTML = String(coord);
    div.style.width = this.tileSize.width + "px";
    div.style.height = this.tileSize.height + "px";
    div.style.fontSize = "10";
    div.style.borderStyle = "solid";
    div.style.borderWidth = "1px";
    div.style.borderColor = "#AAAAAA";
    return div;
  }
  releaseTile(tile) {}
}

function initMap() {
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 10,
    center: { lat: 41.85, lng: -87.65 },
  });
  // Insert this overlay map type as the first overlay map type at
  // position 0. Note that all overlay map types appear on top of
  // their parent base map.
  const coordMapType = new CoordMapType(new google.maps.Size(256, 256));

  map.overlayMapTypes.insertAt(0, coordMapType);
}

window.initMap = initMap;
عرض مثال

تجربة عيّنة

أنواع خرائط الصور

يمكن أن يكون تنفيذ MapType ليكون بمثابة نوع خريطة أساسية مهمة تستغرق وقتًا طويلاً وتتطلّب جهدًا كبيرًا. توفّر واجهة برمجة التطبيقات فئة خاصة تنفِّذ واجهة MapType لأنواع الخرائط الأكثر شيوعًا: أنواع الخرائط التي تتألّف من شرائح مكوّنة من ملفات صور فردية.

تم إنشاء هذه الفئة، وهي فئة ImageMapType، باستخدام مواصفات عنصر ImageMapTypeOptions التي تحدّد السمات المطلوبة التالية:

  • tileSize (مطلوبة) لتحديد حجم المربّع (من النوع google.maps.Size). يجب أن تكون الأحجام مستطيلة ولكن ليس بالضرورة أن تكون مربّعة.
  • getTileUrl (سمة مطلوبة) لتحديد الدالة، التي يتم تقديمها عادةً كدالّة حرفية مضمّنة، لمعالجة اختيار مربّع الصورة المناسب استنادًا إلى إحداثيات سطح الأرض ومستوى التكبير المقدَّمين

تنفِّذ التعليمة البرمجية التالية ImageMapType أساسيًا باستخدام مربّعات القمر من Google. يستخدم المثال دالة معالجة طبيعية لضمان تكرار المربّعات على طول محور x، ولكن ليس على طول محور y في خريطتك.

TypeScript

function initMap(): void {
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      center: { lat: 0, lng: 0 },
      zoom: 1,
      streetViewControl: false,
      mapTypeControlOptions: {
        mapTypeIds: ["moon"],
      },
    }
  );

  const moonMapType = new google.maps.ImageMapType({
    getTileUrl: function (coord, zoom): string {
      const normalizedCoord = getNormalizedCoord(coord, zoom);

      if (!normalizedCoord) {
        return "";
      }

      const bound = Math.pow(2, zoom);
      return (
        "https://mw1.google.com/mw-planetary/lunar/lunarmaps_v1/clem_bw" +
        "/" +
        zoom +
        "/" +
        normalizedCoord.x +
        "/" +
        (bound - normalizedCoord.y - 1) +
        ".jpg"
      );
    },
    tileSize: new google.maps.Size(256, 256),
    maxZoom: 9,
    minZoom: 0,
    // @ts-ignore TODO 'radius' does not exist in type 'ImageMapTypeOptions'
    radius: 1738000,
    name: "Moon",
  });

  map.mapTypes.set("moon", moonMapType);
  map.setMapTypeId("moon");
}

// Normalizes the coords that tiles repeat across the x axis (horizontally)
// like the standard Google map tiles.
function getNormalizedCoord(coord, zoom) {
  const y = coord.y;
  let x = coord.x;

  // tile range in one direction range is dependent on zoom level
  // 0 = 1 tile, 1 = 2 tiles, 2 = 4 tiles, 3 = 8 tiles, etc
  const tileRange = 1 << zoom;

  // don't repeat across y-axis (vertically)
  if (y < 0 || y >= tileRange) {
    return null;
  }

  // repeat across x-axis
  if (x < 0 || x >= tileRange) {
    x = ((x % tileRange) + tileRange) % tileRange;
  }

  return { x: x, y: y };
}

declare global {
  interface Window {
    initMap: () => void;
  }
}
window.initMap = initMap;

JavaScript

function initMap() {
  const map = new google.maps.Map(document.getElementById("map"), {
    center: { lat: 0, lng: 0 },
    zoom: 1,
    streetViewControl: false,
    mapTypeControlOptions: {
      mapTypeIds: ["moon"],
    },
  });
  const moonMapType = new google.maps.ImageMapType({
    getTileUrl: function (coord, zoom) {
      const normalizedCoord = getNormalizedCoord(coord, zoom);

      if (!normalizedCoord) {
        return "";
      }

      const bound = Math.pow(2, zoom);
      return (
        "https://mw1.google.com/mw-planetary/lunar/lunarmaps_v1/clem_bw" +
        "/" +
        zoom +
        "/" +
        normalizedCoord.x +
        "/" +
        (bound - normalizedCoord.y - 1) +
        ".jpg"
      );
    },
    tileSize: new google.maps.Size(256, 256),
    maxZoom: 9,
    minZoom: 0,
    // @ts-ignore TODO 'radius' does not exist in type 'ImageMapTypeOptions'
    radius: 1738000,
    name: "Moon",
  });

  map.mapTypes.set("moon", moonMapType);
  map.setMapTypeId("moon");
}

// Normalizes the coords that tiles repeat across the x axis (horizontally)
// like the standard Google map tiles.
function getNormalizedCoord(coord, zoom) {
  const y = coord.y;
  let x = coord.x;
  // tile range in one direction range is dependent on zoom level
  // 0 = 1 tile, 1 = 2 tiles, 2 = 4 tiles, 3 = 8 tiles, etc
  const tileRange = 1 << zoom;

  // don't repeat across y-axis (vertically)
  if (y < 0 || y >= tileRange) {
    return null;
  }

  // repeat across x-axis
  if (x < 0 || x >= tileRange) {
    x = ((x % tileRange) + tileRange) % tileRange;
  }
  return { x: x, y: y };
}

window.initMap = initMap;
عرض مثال

تجربة عيّنة

التوقعات

الأرض هي كرة ثلاثية الأبعاد (تقريبًا)، في حين أنّ الخريطة هي سطح مستوٍ ثنائي الأبعاد. الخريطة التي تظهر لك في واجهة برمجة التطبيقات JavaScript لـ "خرائط Google"، مثل أي خريطة مسطّحة للأرض، هي إسقاط لكوكب الأرض على سطح مستوٍ. في أبسط مصطلحاته، يمكن تعريف الإسقاط على أنّه تعيين قيم خطوط العرض/الطول إلى إحداثيات على خريطة الإسقاط.

يجب أن تنفّذ الإسقاطات في واجهة برمجة التطبيقات Maps JavaScript API واجهة Projection. يجب ألا يقدّم تنفيذ Projection عملية ربط من نظام إحداثيات إلى آخر فقط، بل يجب أن يقدّم عملية ربط ثنائية الاتجاه. وهذا يعني أنّه عليك تحديد كيفية التحويل من إحداثيات الأرض (عناصر LatLng) إلى نظام إحداثيات العالم في فئة Projection، ومن نظام إحداثيات العالم إلى إحداثيات الأرض. تستخدِم "خرائط Google" إسقاط Mercator لإنشاء خرائطها من البيانات الجغرافية وتحويل الأحداث على الخريطة إلى إحداثيات جغرافية. يمكنك الحصول على هذه التوقّعات من خلال الاتصال برقم getProjection() على Map (أو أيّ من أنواع MapType الأساسية العادية). في معظم الاستخدامات، سيكون هذا Projection العادي كافيًا، ولكن يمكنك أيضًا تحديد توقعاتك المخصّصة واستخدامها.

تنفيذ توقّع

عند تنفيذ توقّعات مخصّصة، عليك تحديد بعض العناصر:

  • صِيَغ ربط إحداثيات خط العرض وخط الطول في سطح مستوٍ ديكارتي (كارتيزيتي) وصِيَغ الربط المقابلة من سطح مستوٍ ديكارتي (كارتيزيتي) إلى إحداثيات خط العرض وخط الطول (لا تتيح واجهة Projection سوى عمليات التحويل إلى إحداثيات مستقيمة).
  • حجم المربّع الأساسي يجب أن تكون جميع المربّعات مستطيلة.
  • "حجم العالم" للخريطة باستخدام المربّع الأساسي الذي تم ضبطه على مستوى التكبير 0 يُرجى العِلم أنّه بالنسبة إلى الخرائط التي تتألف من مربّع واحد عند التكبير 0، يكون حجم الخريطة وحجم المربّع الأساسي متطابقَين.

تنسيق عمليات التحويل في التوقّعات

توفّر كل إسقاط طريقتَين للترجمة بين هذين نظامَي الإحداثيات، ما يتيح لك التحويل بين الإحداثيات الجغرافية والإحداثيات العالمية:

  • تحوّل الطريقة Projection.fromLatLngToPoint() قيمة LatLng إلى إحداثي عالمي. تُستخدَم هذه الطريقة لتحديد موضع العناصر التي تظهر على سطح الخريطة (وتحديد موضع الخريطة نفسها).
  • تحوّل الطريقة Projection.fromPointToLatLng() إحداثيًا عالميًا إلى قيمة LatLng. تُستخدَم هذه الطريِق لتحويل الأحداث، مثل النقرات التي تحدث على الخريطة، إلى إحداثيات جغرافية.

تفترض "خرائط Google" أنّ الإسقاطات مستقيمة.

بشكل عام، يمكنك استخدام إسقاط في حالتَين: لإنشاء خريطة للعالم أو لإنشاء خريطة لمنطقة محلية. في الحالة الأولى، يجب التأكّد من أنّ الإسقاط أيضًا مستقيم وعادي في جميع خطوط الطول. قد تكون بعض الإسقاطات (خاصة الإسقاطات المخروطية) "عادية على المستوى المحلي" (أي تشير إلى الشمال) ولكنها تنحرف عن الشمال الحقيقي، على سبيل المثال، كلما زادت المسافة بين الخريطة وخط طول مرجعي معيّن. يمكنك استخدام طريقة إسقاط مماثلة على الجهاز، ولكن يجب أن تكون على دراية بأنّ طريقة الإسقاط هذه غير دقيقة بالضرورة، وسوف تصبح أخطاء التحويل أكثر وضوحًا كلما ابتعدت عن خط الطول المرجعي.

اختيار مربّعات الخريطة في "التوقّعات"

لا تكون الإسقاطات مفيدة فقط لتحديد مواضع المواقع الجغرافية أو التراكبات، بل لتحديد مواضع مربّعات الخريطة نفسها. تعرِض واجهة برمجة التطبيقات Maps JavaScript API الخرائط الأساسية باستخدام واجهة MapType التي يجب أن تحدِّد كلّ من سمة projection لتحديد إسقاط الخريطة وطريقة getTile() لاسترداد شرائح الخريطة استنادًا إلى قيم إحداثيات. تستند إحداثيات المربّع إلى كلّ من حجم المربّع الأساسي (الذي يجب أن يكون مستطيلاً) و "حجم العالم" في خريطتك، وهو حجم البكسل لعالم الخريطة عند مستوى التكبير 0. (بالنسبة إلى الخرائط التي تتألف من مربّع واحد عند التكبير 0، يكون حجم المربّع متطابقًا مع حجم الخريطة.)

يمكنك تحديد حجم مربّع القاعدة ضمن سمة tileSize في MapType. يمكنك تحديد حجم العالم بشكل ضمني ضمن طريقتَي fromLatLngToPoint() وfromPointToLatLng() لإنشاء الخرائط.

بما أنّ اختيار الصور يعتمد على هذه القيم المرسَلة، من المفيد تسمية الصور التي يمكن اختيارها آليًا استنادًا إلى تلك القيم المرسَلة، مثل map_zoom_tileX_tileY.png.

يحدِّد المثال التالي ImageMapType باستخدام إسقاط Gall-Peters:

TypeScript

// This example defines an image map type using the Gall-Peters
// projection.
// https://en.wikipedia.org/wiki/Gall%E2%80%93Peters_projection

function initMap(): void {
  // Create a map. Use the Gall-Peters map type.
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 0,
      center: { lat: 0, lng: 0 },
      mapTypeControl: false,
    }
  );

  initGallPeters();
  map.mapTypes.set("gallPeters", gallPetersMapType);
  map.setMapTypeId("gallPeters");

  // Show the lat and lng under the mouse cursor.
  const coordsDiv = document.getElementById("coords") as HTMLElement;

  map.controls[google.maps.ControlPosition.TOP_CENTER].push(coordsDiv);
  map.addListener("mousemove", (event: google.maps.MapMouseEvent) => {
    coordsDiv.textContent =
      "lat: " +
      Math.round(event.latLng!.lat()) +
      ", " +
      "lng: " +
      Math.round(event.latLng!.lng());
  });

  // Add some markers to the map.
  map.data.setStyle((feature) => {
    return {
      title: feature.getProperty("name") as string,
      optimized: false,
    };
  });
  map.data.addGeoJson(cities);
}

let gallPetersMapType;

function initGallPeters() {
  const GALL_PETERS_RANGE_X = 800;
  const GALL_PETERS_RANGE_Y = 512;

  // Fetch Gall-Peters tiles stored locally on our server.
  gallPetersMapType = new google.maps.ImageMapType({
    getTileUrl: function (coord, zoom) {
      const scale = 1 << zoom;

      // Wrap tiles horizontally.
      const x = ((coord.x % scale) + scale) % scale;

      // Don't wrap tiles vertically.
      const y = coord.y;

      if (y < 0 || y >= scale) return "";

      return (
        "https://developers.google.com/maps/documentation/" +
        "javascript/examples/full/images/gall-peters_" +
        zoom +
        "_" +
        x +
        "_" +
        y +
        ".png"
      );
    },
    tileSize: new google.maps.Size(GALL_PETERS_RANGE_X, GALL_PETERS_RANGE_Y),
    minZoom: 0,
    maxZoom: 1,
    name: "Gall-Peters",
  });

  // Describe the Gall-Peters projection used by these tiles.
  gallPetersMapType.projection = {
    fromLatLngToPoint: function (latLng) {
      const latRadians = (latLng.lat() * Math.PI) / 180;
      return new google.maps.Point(
        GALL_PETERS_RANGE_X * (0.5 + latLng.lng() / 360),
        GALL_PETERS_RANGE_Y * (0.5 - 0.5 * Math.sin(latRadians))
      );
    },
    fromPointToLatLng: function (point, noWrap) {
      const x = point.x / GALL_PETERS_RANGE_X;
      const y = Math.max(0, Math.min(1, point.y / GALL_PETERS_RANGE_Y));

      return new google.maps.LatLng(
        (Math.asin(1 - 2 * y) * 180) / Math.PI,
        -180 + 360 * x,
        noWrap
      );
    },
  };
}

// GeoJSON, describing the locations and names of some cities.
const cities = {
  type: "FeatureCollection",
  features: [
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-87.65, 41.85] },
      properties: { name: "Chicago" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-149.9, 61.218] },
      properties: { name: "Anchorage" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-99.127, 19.427] },
      properties: { name: "Mexico City" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-0.126, 51.5] },
      properties: { name: "London" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [28.045, -26.201] },
      properties: { name: "Johannesburg" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [15.322, -4.325] },
      properties: { name: "Kinshasa" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [151.207, -33.867] },
      properties: { name: "Sydney" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [0, 0] },
      properties: { name: "0°N 0°E" },
    },
  ],
};

declare global {
  interface Window {
    initMap: () => void;
  }
}
window.initMap = initMap;

JavaScript

// This example defines an image map type using the Gall-Peters
// projection.
// https://en.wikipedia.org/wiki/Gall%E2%80%93Peters_projection
function initMap() {
  // Create a map. Use the Gall-Peters map type.
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 0,
    center: { lat: 0, lng: 0 },
    mapTypeControl: false,
  });

  initGallPeters();
  map.mapTypes.set("gallPeters", gallPetersMapType);
  map.setMapTypeId("gallPeters");

  // Show the lat and lng under the mouse cursor.
  const coordsDiv = document.getElementById("coords");

  map.controls[google.maps.ControlPosition.TOP_CENTER].push(coordsDiv);
  map.addListener("mousemove", (event) => {
    coordsDiv.textContent =
      "lat: " +
      Math.round(event.latLng.lat()) +
      ", " +
      "lng: " +
      Math.round(event.latLng.lng());
  });
  // Add some markers to the map.
  map.data.setStyle((feature) => {
    return {
      title: feature.getProperty("name"),
      optimized: false,
    };
  });
  map.data.addGeoJson(cities);
}

let gallPetersMapType;

function initGallPeters() {
  const GALL_PETERS_RANGE_X = 800;
  const GALL_PETERS_RANGE_Y = 512;

  // Fetch Gall-Peters tiles stored locally on our server.
  gallPetersMapType = new google.maps.ImageMapType({
    getTileUrl: function (coord, zoom) {
      const scale = 1 << zoom;
      // Wrap tiles horizontally.
      const x = ((coord.x % scale) + scale) % scale;
      // Don't wrap tiles vertically.
      const y = coord.y;

      if (y < 0 || y >= scale) return "";
      return (
        "https://developers.google.com/maps/documentation/" +
        "javascript/examples/full/images/gall-peters_" +
        zoom +
        "_" +
        x +
        "_" +
        y +
        ".png"
      );
    },
    tileSize: new google.maps.Size(GALL_PETERS_RANGE_X, GALL_PETERS_RANGE_Y),
    minZoom: 0,
    maxZoom: 1,
    name: "Gall-Peters",
  });
  // Describe the Gall-Peters projection used by these tiles.
  gallPetersMapType.projection = {
    fromLatLngToPoint: function (latLng) {
      const latRadians = (latLng.lat() * Math.PI) / 180;
      return new google.maps.Point(
        GALL_PETERS_RANGE_X * (0.5 + latLng.lng() / 360),
        GALL_PETERS_RANGE_Y * (0.5 - 0.5 * Math.sin(latRadians)),
      );
    },
    fromPointToLatLng: function (point, noWrap) {
      const x = point.x / GALL_PETERS_RANGE_X;
      const y = Math.max(0, Math.min(1, point.y / GALL_PETERS_RANGE_Y));
      return new google.maps.LatLng(
        (Math.asin(1 - 2 * y) * 180) / Math.PI,
        -180 + 360 * x,
        noWrap,
      );
    },
  };
}

// GeoJSON, describing the locations and names of some cities.
const cities = {
  type: "FeatureCollection",
  features: [
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-87.65, 41.85] },
      properties: { name: "Chicago" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-149.9, 61.218] },
      properties: { name: "Anchorage" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-99.127, 19.427] },
      properties: { name: "Mexico City" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-0.126, 51.5] },
      properties: { name: "London" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [28.045, -26.201] },
      properties: { name: "Johannesburg" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [15.322, -4.325] },
      properties: { name: "Kinshasa" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [151.207, -33.867] },
      properties: { name: "Sydney" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [0, 0] },
      properties: { name: "0°N 0°E" },
    },
  ],
};

window.initMap = initMap;
عرض مثال

تجربة عيّنة