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

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

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

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

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

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

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

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

خرائط ثلاثية الأبعاد

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

مزيد من المعلومات حول الخرائط الثلاثية الأبعاد في نظرة عامة على الخرائط الثلاثية الأبعاد

يعرض المثال التالي عرضًا ثلاثي الأبعاد لمدينة سان فرانسيسكو:

مزيد من المعلومات حول "الخرائط الثلاثية الأبعاد" في نظرة عامة على "الخرائط الثلاثية الأبعاد"

صور بزاوية 45 درجة (متوقّفة نهائيًا)

يوضّح النموذج التالي كيفية الحصول على عرض منظور بزاوية 45 درجة لمدينة سان فرانسيسكو باستخدام الخرائط الثلاثية الأبعاد:

TypeScript

async function init() {
    const { Map3DElement } = await google.maps.importLibrary('maps3d');
    const map = new Map3DElement({
        center: {
            lat: 37.789,
            lng: -122.401,
            altitude: 0,
        },
        range: 2200,
        tilt: 45,
        heading: 188,
    });
    map.mode = 'SATELLITE';
    document.body.append(map);
}

void init();

JavaScript

async function init() {
    const { Map3DElement } = await google.maps.importLibrary('maps3d');
    const map = new Map3DElement({
        center: {
            lat: 37.789,
            lng: -122.401,
            altitude: 0,
        },
        range: 2200,
        tilt: 45,
        heading: 188,
    });
    map.mode = 'SATELLITE';
    document.body.append(map);
}

void init();

CSS

/* 
 * Always set the map height explicitly to define the size of the div element
 * that contains the map. 
 */
#gmp-map-3d {
    height: 100%;
}
html,
body {
    height: 100%;
    margin: 0;
    padding: 0;
}

HTML

<html>
    <head>
        <title>3d map 45-degree perspective</title>
        <link rel="stylesheet" type="text/css" href="./style.css" />
        <script type="module" src="./index.js"></script>
        <script>
            // prettier-ignore
            (g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})({
                key: "GOOGLE_MAPS_API_KEY"
            });
        </script>
    </head>
    <body>
        <div id="map"></div>
    </body>
</html>
الاطّلاع على مثال

تعديل سجلّ أنواع الخرائط

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

تتوفّر عدة عمليات تنفيذ محتملة لأنواع الخرائط ضمن Maps JavaScript API:

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

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

واجهة "MapType"

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

يجب أن تنفّذ أنواع الخرائط المخصّصة واجهة 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() استنادًا إلى سمات tileSize وminZoom وmaxZoom في MapType ومساحة العرض الحالية ومستوى التكبير في الخريطة. يجب أن يعرض معالج هذه الطريقة عنصر HTML بناءً على الإحداثيات ومستوى التكبير وعنصر DOM التي تم تمريرها لإلحاق صورة المربّع بها.

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

    releaseTile(tile:Node)

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

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

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

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

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

TypeScript

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

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

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

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

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

  releaseTile(tile: HTMLElement): void {}
}

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

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

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

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

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

JavaScript

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

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

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

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

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

window.initMap = initMap;
الاطّلاع على مثال

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

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

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

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

TypeScript

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

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

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

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

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

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

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

JavaScript

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

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

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

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

window.initMap = initMap;
الاطّلاع على مثال

أنواع مخططات الصور

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

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

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

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

TypeScript

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

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

      if (!normalizedCoord) {
        return "";
      }

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

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

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

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

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

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

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

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

JavaScript

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

      if (!normalizedCoord) {
        return "";
      }

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

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

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

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

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

window.initMap = initMap;
الاطّلاع على مثال

التوقعات

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

يجب أن تنفّذ عمليات الإسقاط في Maps JavaScript API واجهة Projection. يجب أن يوفّر تنفيذ Projection عملية ربط ثنائية الاتجاه، وليس فقط عملية ربط من نظام إحداثيات إلى آخر. وهذا يعني أنّه عليك تحديد كيفية الترجمة من إحداثيات الأرض (كائنات LatLng) إلى نظام الإحداثيات العالمية لفئة Projection، ومن نظام الإحداثيات العالمية إلى إحداثيات الأرض. تستخدم "خرائط Google" إسقاط مركاتور لإنشاء خرائطها من البيانات الجغرافية وتحويل الأحداث على الخريطة إلى إحداثيات جغرافية. يمكنك الحصول على هذا الإسقاط من خلال استدعاء 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 باستخدام إسقاط غال-بيترز:

TypeScript

// This example defines an image map type using the Gall-Peters
// projection.
// https://en.wikipedia.org/wiki/Gall%E2%80%93Peters_projection
const mapElement = document.querySelector('gmp-map')!;
let innerMap: google.maps.Map;

async function init() {
    // Request the needed libraries.
    await google.maps.importLibrary('maps');

    // Create a map.
    innerMap = mapElement.innerMap;
    innerMap.setOptions({
        mapTypeControl: false,
    });

    // Set the Gall-Peters map type.
    const gallPetersMapType = await initGallPeters();
    innerMap.mapTypes.set('gallPeters', gallPetersMapType);
    innerMap.setMapTypeId('gallPeters');

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

    innerMap.addListener('mousemove', (event: google.maps.MapMouseEvent) => {
        coordsDiv.textContent = `lat: ${String(Math.round(event.latLng!.lat()))}, lng: ${String(Math.round(event.latLng!.lng()))}`;
    });

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

async function initGallPeters(): Promise<google.maps.ImageMapType> {
    const [{ ImageMapType }, { Size, Point, LatLng }] = await Promise.all([
        google.maps.importLibrary('maps'),
        google.maps.importLibrary('core'),
    ]);

    const GALL_PETERS_RANGE_X = 800;
    const GALL_PETERS_RANGE_Y = 512;

    // Fetch Gall-Peters tiles stored locally on our server.
    const gallPetersMapType = new ImageMapType({
        getTileUrl(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 `gall-peters_${String(zoom)}_${String(x)}_${String(y)}.png`;
        },
        tileSize: new 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(latLng: google.maps.LatLng) {
            const latRadians = (latLng.lat() * Math.PI) / 180;
            return new Point(
                GALL_PETERS_RANGE_X * (0.5 + latLng.lng() / 360),
                GALL_PETERS_RANGE_Y * (0.5 - 0.5 * Math.sin(latRadians))
            );
        },
        fromPointToLatLng(point: google.maps.Point, noWrap?: boolean) {
            const x = point.x / GALL_PETERS_RANGE_X;
            const y = Math.max(0, Math.min(1, point.y / GALL_PETERS_RANGE_Y));

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

    return gallPetersMapType;
}

// 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' },
        },
    ],
};

void init();

JavaScript

// This example defines an image map type using the Gall-Peters
// projection.
// https://en.wikipedia.org/wiki/Gall%E2%80%93Peters_projection
const mapElement = document.querySelector('gmp-map');
let innerMap;

async function init() {
    // Request the needed libraries.
    await google.maps.importLibrary('maps');

    // Create a map.
    innerMap = mapElement.innerMap;
    innerMap.setOptions({
        mapTypeControl: false,
    });

    // Set the Gall-Peters map type.
    const gallPetersMapType = await initGallPeters();
    innerMap.mapTypes.set('gallPeters', gallPetersMapType);
    innerMap.setMapTypeId('gallPeters');

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

    innerMap.addListener('mousemove', (event) => {
        coordsDiv.textContent = `lat: ${String(Math.round(event.latLng.lat()))}, lng: ${String(Math.round(event.latLng.lng()))}`;
    });

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

async function initGallPeters() {
    const [{ ImageMapType }, { Size, Point, LatLng }] = await Promise.all([
        google.maps.importLibrary('maps'),
        google.maps.importLibrary('core'),
    ]);

    const GALL_PETERS_RANGE_X = 800;
    const GALL_PETERS_RANGE_Y = 512;

    // Fetch Gall-Peters tiles stored locally on our server.
    const gallPetersMapType = new ImageMapType({
        getTileUrl(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 `gall-peters_${String(zoom)}_${String(x)}_${String(y)}.png`;
        },
        tileSize: new 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(latLng) {
            const latRadians = (latLng.lat() * Math.PI) / 180;
            return new Point(
                GALL_PETERS_RANGE_X * (0.5 + latLng.lng() / 360),
                GALL_PETERS_RANGE_Y * (0.5 - 0.5 * Math.sin(latRadians))
            );
        },
        fromPointToLatLng(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 LatLng(
                (Math.asin(1 - 2 * y) * 180) / Math.PI,
                -180 + 360 * x,
                noWrap
            );
        },
    };

    return gallPetersMapType;
}

// 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' },
        },
    ],
};

void init();
الاطّلاع على مثال