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

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

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

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

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

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

تتوفّر أنواع الخرائط التالية في Maps JavaScript API:

  • تعرض 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). سيعرض الإجراء MapgetTilt() دائمًا 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 إلا في نوع الخريطة التلقائي roadmap.

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

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

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

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

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

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

MapTypeالواجهة

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

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

ملاحظة: يمكنك إنشاء فئة خاصة بك لتنفيذ هذه الواجهة. بدلاً من ذلك، إذا كانت لديك صور متوافقة، يمكنك استخدام الفئة 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() استنادًا إلى خصائص MapType، وهي tileSize وminZoom وmaxZoom، بالإضافة إلى إطار العرض الحالي وخاصية مستوى التكبير/التصغير للخريطة. يجب أن يعرض معالج هذه الطريقة عنصر 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، ومن نظام الإحداثيات العالمي إلى إحداثيات الأرض. تستخدم &quot;خرائط Google&quot; إسقاط مركاتور لإنشاء خرائطها من البيانات الجغرافية وتحويل الأحداث على الخريطة إلى إحداثيات جغرافية. يمكنك الحصول على هذا الإسقاط من خلال استدعاء 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;
عرض مثال

تجربة عيّنة