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

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

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

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

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

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

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

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

هناك العديد من عمليات التنفيذ الممكنة لنوع الخريطة في Maps JavaScript API:

  • مجموعات المربّعات القياسية التي تتكون من صور تشكل مجتمعةً خرائط خرائط كاملة. وتُعرَف مجموعات المربّعات هذه أيضًا باسم أنواع الخرائط الأساسية. تتصرف أنواع الخرائط هذه وتتصرف تمامًا مثل أنواع الخرائط التلقائية الحالية: 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 عملية ربط من نظام إحداثيات إلى آخر فحسب، بل يجب أيضًا توفير عملية ربط ثنائية الاتجاه. وهذا يعني أنّه عليك تحديد كيفية الترجمة من إحداثيات الأرض (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"),
      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;
الاطّلاع على مثال

تجربة العينة