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

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

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

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

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

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

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

  • يعرض 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 باستخدام أحد المعرّفات. تستخدم واجهة برمجة تطبيقات JavaScript للخرائط قاعدة بيانات المسجّلين لأنواع الخرائط، كما هو موضّح أدناه، لإدارة هذه المراجع.

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

تتيح واجهة برمجة تطبيقات JavaScript للخرائط استخدام صور خاصة بزاوية 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، يُرجى الاطّلاع على دليل الخرائط ذات الأنماط.

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

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

يتوفّر العديد من عمليات التنفيذ الممكنة لنوع الخريطة في واجهة برمجة تطبيقات JavaScript للخرائط:

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

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

واجهة MapType

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

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

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

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

  • تحدّد السمة tileSize (مطلوبة) حجم المربّع (من النوع google.maps.Size). يجب أن تكون المقاسات مستطيلة رغم أنّها يجب ألا تكون مربّعة.
  • تحدّد السمة maxZoom (مطلوبة) الحد الأقصى لمستوى التكبير أو التصغير الذي يمكن عنده عرض مربّعات من نوع الخريطة هذا.
  • تحدّد السمة minZoom (اختيارية) الحدّ الأدنى لمستوى التكبير/التصغير الذي يمكن عنده عرض مربّع من نوع الخريطة هذا. وتكون هذه القيمة بشكل تلقائي 0، وتشير إلى عدم توفّر حد أدنى لمستوى التكبير/التصغير.
  • تحدّد السمة name (اختيارية) اسم نوع الخريطة هذا. هذه الخاصية ضرورية فقط إذا أردت أن يكون نوع الخريطة هذا قابلاً للاختيار ضمن عنصر تحكم MapType. (يُرجى الاطّلاع على مقالة إضافة عناصر تحكّم MapType أدناه.)
  • تحدّد السمة alt (اختيارية) النص البديل لنوع الخريطة هذا، ويتم عرضه كنص تمرير مؤشر الماوس. هذه الخاصية ضرورية فقط إذا أردت أن يكون نوع الخريطة هذا قابلاً للاختيار ضمن عنصر تحكم MapType. (راجِع إضافة عناصر تحكّم 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. يستخدم المثال دالة تسوية لضمان تكرار المربّعات على طول المحور "س"، ولكن ليس على طول المحور "ص" في الخريطة.

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 للخرائط، مثل أي خريطة مسطّحة للأرض، هي إسقاط لتلك الكرة على سطح مستوٍ. في أبسط مصطلحاته، يمكن تعريف الإسقاط على أنّه عملية ربط قيم خطوط الطول والعرض في إحداثيات على خريطة الإسقاط.

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

تنفيذ توقع

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

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

تنسيق عمليات التحويل من خلال التوقعات

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

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

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

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

اختيار بلاط الخريطة في الإسقاطات

لا تكون الإسقاطات مفيدة فقط في تحديد مواضع المواقع الجغرافية أو تراكبات الصور، بل أيضًا لتحديد أماكن مربّعات الخرائط. تعرض "واجهة برمجة تطبيقات JavaScript للخرائط" الخرائط الأساسية باستخدام واجهة 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;
الاطّلاع على مثال

تجربة "عيّنة"