ประเภทแผนที่

เลือกแพลตฟอร์ม: Android iOS JavaScript

เอกสารนี้กล่าวถึงประเภทแผนที่ที่คุณแสดงได้โดยใช้ Maps JavaScript API API จะใช้ออบเจ็กต์ MapType เพื่อเก็บข้อมูลเกี่ยวกับแผนที่เหล่านี้ MapType คืออินเทอร์เฟซที่กำหนดการแสดงผลและการใช้งานชิ้นส่วนแผนที่และ การแปลระบบพิกัดจากพิกัดหน้าจอเป็นพิกัดโลก (บนแผนที่) MapType แต่ละรายการต้องมีเมธอด 2-3 รายการเพื่อจัดการการดึงข้อมูลและการปล่อยไทล์ รวมถึงพร็อพเพอร์ตี้ที่กำหนดลักษณะการทำงานด้านภาพ

การทำงานภายในของประเภทแผนที่ภายใน Maps JavaScript API เป็นหัวข้อขั้นสูง นักพัฒนาซอฟต์แวร์ส่วนใหญ่สามารถใช้ ประเภทแผนที่พื้นฐานที่ระบุไว้ด้านล่าง อย่างไรก็ตาม คุณยังสามารถแก้ไขการแสดงผลของประเภทแผนที่ที่มีอยู่โดยใช้แผนที่สไตล์คุณหรือกำหนดชิ้นส่วนแผนที่ของคุณเองโดยใช้ประเภทแผนที่แบบกำหนดเองได้ด้วย เมื่อระบุแผนที่แบบกำหนดเอง คุณจะต้องเข้าใจวิธีแก้ไขรีจิสทรีประเภทแผนที่ของแผนที่

ประเภทแผนที่พื้นฐาน

Maps JavaScript API มีแผนที่ให้เลือก 4 ประเภท นอกจากชิ้นส่วนแผนที่ถนนแบบ "วาด" ที่คุ้นเคยแล้ว Maps JavaScript API ยังรองรับแผนที่ประเภทอื่นๆ ด้วย

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 ใช้รีจิสทรีประเภทแผนที่ซึ่งอธิบายไว้ด้านล่างเพื่อจัดการการอ้างอิงเหล่านี้

แผนที่ 3 มิติ

Maps JavaScript API รองรับภาพ 3 มิติ การดำเนินการและความสามารถในการปรับแต่งหลายอย่างที่ใช้ได้กับแผนที่ 2 มิติจะใช้ได้กับแผนที่ 3 มิติด้วย

ดูข้อมูลเพิ่มเติมเกี่ยวกับแผนที่ 3 มิติได้ในภาพรวมแผนที่ 3 มิติ

ตัวอย่างต่อไปนี้แสดงมุมมอง 3 มิติของซานฟรานซิสโก

ดูข้อมูลเพิ่มเติมเกี่ยวกับแผนที่ 3 มิติได้ในภาพรวมแผนที่ 3 มิติ

ภาพ 45° (เลิกใช้งานแล้ว)

ตัวอย่างต่อไปนี้แสดงวิธีดูภาพมุมมอง 45° ของซานฟรานซิสโกโดยใช้แผนที่ 3 มิติ

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 ที่เชื่อมโยงกับแผนที่)

โค้ดต่อไปนี้จะตั้งค่าแผนที่ให้แสดงแผนที่เพียง 2 ประเภทใน 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 ของแผนที่เพื่อให้ UI ภายใน Maps JavaScript API ถือว่าประเภทแผนที่ที่กำหนดเองเป็นประเภทแผนที่มาตรฐาน (เช่น โดยรวมไว้ในตัวควบคุม MapType)
  • การวางซ้อนชิ้นส่วนแผนที่รูปภาพซึ่งแสดงที่ด้านบนของประเภทแผนที่ฐานที่มีอยู่ โดยทั่วไปแล้ว แผนที่ประเภทนี้จะใช้เพื่อเสริมแผนที่ประเภทที่มีอยู่เพื่อแสดงข้อมูลเพิ่มเติม และมักจะจำกัดไว้เฉพาะสถานที่และ/หรือระดับการซูมที่เฉพาะเจาะจง โปรดทราบว่าไทล์เหล่านี้อาจโปร่งใส ซึ่งช่วยให้คุณเพิ่มฟีเจอร์ลงในแผนที่ที่มีอยู่ได้
  • ประเภทแผนที่ที่ไม่ใช่แผนที่รูปภาพ ซึ่งช่วยให้คุณจัดการการแสดงข้อมูลแผนที่ในระดับพื้นฐานที่สุดได้

ตัวเลือกแต่ละรายการเหล่านี้อาศัยการสร้างคลาสที่ใช้การติดตั้งใช้งานอินเทอร์เฟซ MapType นอกจากนี้ คลาส ImageMapType ยังมีลักษณะการทำงานในตัวบางอย่างเพื่อลดความซับซ้อนในการสร้างประเภทแผนที่ภาพ

อินเทอร์เฟซ MapType

ก่อนที่จะสร้างคลาสที่ใช้ MapType คุณควรทำความเข้าใจวิธีที่ Google Maps กำหนดพิกัดและตัดสินใจว่าจะแสดงส่วนใดของแผนที่ คุณต้องใช้ตรรกะที่คล้ายกันสำหรับประเภทแผนที่ฐานหรือแผนที่ซ้อนทับ อ่านคำแนะนำเกี่ยวกับพิกัดแผนที่และพิกัดแผนที่ย่อย

แผนที่แบบกำหนดเองต้องใช้อินเทอร์เฟซ MapType อินเทอร์เฟซนี้ระบุพร็อพเพอร์ตี้และเมธอดบางอย่างที่ช่วยให้ API เริ่มต้นคำขอไปยังประเภทแผนที่ของคุณได้เมื่อ API พิจารณาแล้วว่าจำเป็นต้องแสดงไทล์แผนที่ภายในวิวพอร์ตและระดับการซูมปัจจุบัน คุณจะจัดการคำขอเหล่านี้เพื่อตัดสินใจว่าจะโหลดการ์ดใด

หมายเหตุ: คุณสามารถสร้างคลาสของคุณเองเพื่อใช้อินเทอร์เฟซนี้ หรือหากมีภาพที่เข้ากันได้ คุณสามารถใช้คลาส ImageMapType ซึ่งใช้อินเทอร์เฟซนี้อยู่แล้ว

คลาสที่ใช้อินเทอร์เฟซ MapType กำหนดให้คุณต้องกำหนดและป้อนข้อมูลพร็อพเพอร์ตี้ต่อไปนี้

  • tileSize (ต้องระบุ) ระบุขนาดของหน้าต่าง (ประเภท google.maps.Size) ขนาดต้องเป็นสี่เหลี่ยมผืนผ้า แต่ไม่จำเป็นต้องเป็นสี่เหลี่ยมจัตุรัส
  • maxZoom (ต้องระบุ) ระบุระดับการซูมสูงสุดที่จะแสดงชิ้นส่วนแผนที่ของแผนที่ประเภทนี้
  • minZoom (ไม่บังคับ) ระบุระดับการซูมขั้นต่ำที่จะแสดงไทล์ของแผนที่ประเภทนี้ โดยค่าเริ่มต้น ค่านี้คือ 0 ซึ่งหมายความว่าไม่มีระดับการซูมขั้นต่ำ
  • name (ไม่บังคับ) ระบุชื่อสำหรับประเภทแผนที่นี้ พร็อพเพอร์ตี้นี้จำเป็นก็ต่อเมื่อคุณต้องการให้เลือกประเภทแผนที่นี้ได้ภายในตัวควบคุม MapType (ดู ตัวเลือกการควบคุม)
  • alt (ไม่บังคับ) ระบุข้อความสำรองสำหรับแผนที่ประเภทนี้ ซึ่งจะแสดงเป็นข้อความเมื่อวางเมาส์เหนือ พร็อพเพอร์ตี้นี้จำเป็นก็ต่อเมื่อคุณต้องการให้เลือกประเภทแผนที่นี้ได้ภายในตัวควบคุม MapType (ดูตัวเลือกการควบคุม)

นอกจากนี้ คลาสที่ใช้การติดตั้งใช้งานอินเทอร์เฟซ MapType จะต้องใช้การติดตั้งใช้งานเมธอดต่อไปนี้ด้วย

  • ระบบจะเรียกใช้ getTile() (จำเป็น) ทุกครั้งที่ API พิจารณาว่าแผนที่ต้องแสดงไทล์ใหม่สำหรับวิวพอร์ตที่ระบุ เมธอด getTile() ต้องมีซิกเนเจอร์ต่อไปนี้

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

    API จะพิจารณาว่าจำเป็นต้องเรียกใช้ getTile() หรือไม่โดยอิงตามพร็อพเพอร์ตี้ tileSize, minZoom และ maxZoom ของ MapType รวมถึงวิวพอร์ตและระดับการซูมปัจจุบันของแผนที่ เครื่องจัดการสำหรับเมธอดนี้ควรแสดงผลองค์ประกอบ HTML ที่มีพิกัด ระดับการซูม และองค์ประกอบ DOM ที่ส่งมาเพื่อเพิ่มรูปภาพไทล์

  • ระบบจะเรียกใช้ releaseTile() (ไม่บังคับ) เมื่อใดก็ตามที่ API พิจารณาว่าแผนที่จำเป็นต้องนำไทล์ออกเนื่องจากอยู่นอกมุมมอง เมธอดนี้ต้องมีลายเซ็นต่อไปนี้

    releaseTile(tile:Node)

    โดยปกติแล้ว คุณควรจัดการการนำองค์ประกอบที่แนบมากับไทล์แผนที่ออกเมื่อเพิ่มลงในแผนที่ ตัวอย่างเช่น หากคุณแนบ Listener เหตุการณ์กับภาพซ้อนทับไทล์แผนที่ คุณควรนำ Listener เหตุการณ์ออกที่นี่

เมธอด getTile() ทำหน้าที่เป็นตัวควบคุมหลักในการกำหนดว่าจะโหลดไทล์ใดภายในวิวพอร์ตที่ระบุ

ประเภทแผนที่ฐาน

ประเภทแผนที่ที่คุณสร้างในลักษณะนี้อาจเป็นแบบสแตนด์อโลนหรือรวมกับประเภทแผนที่อื่นๆ เป็นการวางซ้อนก็ได้ ประเภทแผนที่แบบสแตนด์อโลนเรียกว่าประเภทแผนที่ฐาน คุณอาจต้องการให้ API จัดการ 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 เพื่อทำหน้าที่เป็นประเภทแผนที่ฐานอาจเป็นงานที่ใช้เวลานานและต้องใช้แรงงานมาก API มีคลาสพิเศษที่ใช้อินเทอร์เฟซ 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;
ดูตัวอย่าง

การคาดการณ์

โลกเป็นทรงกลม 3 มิติ (โดยประมาณ) ในขณะที่แผนที่เป็นพื้นผิว 2 มิติแบบแบนราบ แผนที่ที่คุณเห็นภายใน Maps JavaScript API เช่นเดียวกับแผนที่แบนราบของโลก คือการฉายภาพทรงกลมนั้นลงบนพื้นผิวเรียบ พูดง่ายๆ ก็คือ การฉายภาพแผนที่สามารถกำหนดเป็นการแมปค่าละติจูด/ลองจิจูดเป็นพิกัดบนแผนที่ของการฉายภาพ

การฉายภาพใน Maps JavaScript API ต้องใช้อินเทอร์เฟซ Projection การติดตั้งใช้งาน Projection ต้องไม่เพียงแต่ให้การแมปจากระบบพิกัดหนึ่งไปยังอีกระบบหนึ่งเท่านั้น แต่ยังต้องให้การแมปแบบ 2 ทิศทางด้วย กล่าวคือ คุณต้องกำหนดวิธีแปลจากพิกัดโลก (ออบเจ็กต์ LatLng) เป็นระบบพิกัดโลกของคลาส Projection และจากระบบพิกัดโลกกลับเป็นพิกัดโลก Google Maps ใช้การฉายภาพแบบเมอร์เคเตอร์เพื่อสร้างแผนที่จากข้อมูลทางภูมิศาสตร์และแปลงเหตุการณ์บนแผนที่เป็นพิกัดทางภูมิศาสตร์ คุณสามารถรับการคาดการณ์นี้ได้โดยเรียกใช้ getProjection() ใน Map (หรือประเภท MapType พื้นฐานมาตรฐานใดก็ได้) สำหรับการใช้งานส่วนใหญ่ Projection มาตรฐานนี้จะเพียงพอ แต่คุณยังสามารถกำหนดและใช้การฉายภาพที่กำหนดเองได้ด้วย

ใช้การฉายภาพ

เมื่อใช้การฉายภาพที่กำหนดเอง คุณจะต้องกำหนดสิ่งต่อไปนี้

  • สูตรสำหรับการแมปพิกัดละติจูดและลองจิจูดเป็นระนาบคาร์ทีเซียน และสูตรที่เกี่ยวข้องสำหรับการแมปจากระนาบคาร์ทีเซียนเป็นพิกัดละติจูดและลองจิจูด (อินเทอร์เฟซ Projection รองรับเฉพาะการแปลงเป็นพิกัดสี่เหลี่ยมผืนผ้าเท่านั้น)
  • ขนาดชิ้นส่วนแผนที่ฐาน ไทล์ทั้งหมดต้องเป็นสี่เหลี่ยมผืนผ้า
  • "ขนาดโลก" ของแผนที่ที่ใช้ชุดไทล์ฐานที่ระดับการซูม 0 โปรดทราบว่าสำหรับแผนที่ที่ประกอบด้วยไทล์ 1 รายการที่การซูม 0 ขนาดโลกและขนาดไทล์ฐานจะเหมือนกัน

การเปลี่ยนรูปแบบพิกัดในการฉายภาพ

การฉายภาพแต่ละแบบมี 2 วิธีในการแปลระหว่างระบบพิกัดทั้ง 2 ระบบนี้ ซึ่งช่วยให้คุณแปลงระหว่างพิกัดทางภูมิศาสตร์และพิกัดโลกได้ ดังนี้

  • เมธอด Projection.fromLatLngToPoint() จะแปลงค่า LatLng เป็นพิกัดโลก ระบบจะใช้วิธีนี้เพื่อจัดตำแหน่งการวางซ้อนบนแผนที่ (และเพื่อจัดตำแหน่งแผนที่เอง)
  • เมธอด Projection.fromPointToLatLng() จะแปลงพิกัดโลกเป็นค่า LatLng วิธีนี้ใช้เพื่อแปลงเหตุการณ์ต่างๆ เช่น การคลิกที่เกิดขึ้นบนแผนที่ให้เป็นพิกัดทางภูมิศาสตร์

Google Maps จะถือว่าการฉายภาพเป็นแบบเส้นตรง

โดยทั่วไป คุณอาจใช้การฉายภาพใน 2 กรณี ได้แก่ เพื่อสร้างแผนที่โลก หรือเพื่อสร้างแผนที่ของพื้นที่ในท้องถิ่น ในกรณีแรก คุณควรตรวจสอบว่าการฉายภาพเป็นแบบเส้นตรงและปกติในลองจิจูดทั้งหมดด้วย การฉายภาพบางแบบ (โดยเฉพาะการฉายภาพทรงกรวย) อาจเป็น "ปกติในพื้นที่" (เช่น ชี้ไปทางทิศเหนือ) แต่เบี่ยงเบนไปจากทิศเหนือจริง เช่น ยิ่งแผนที่อยู่ในตำแหน่งที่สัมพันธ์กับลองจิจูดอ้างอิงบางค่ามากเท่าใด คุณอาจใช้การฉายภาพดังกล่าวในพื้นที่ แต่โปรดทราบว่าการฉายภาพนั้นไม่แม่นยำ และข้อผิดพลาดในการเปลี่ยนรูปแบบจะปรากฏชัดเจนมากขึ้นเมื่อคุณเบี่ยงเบนออกจากลองจิจูดอ้างอิงมากขึ้น

การเลือกไทล์แผนที่ในการฉายภาพ

การฉายภาพไม่เพียงมีประโยชน์ในการกำหนดตำแหน่งของสถานที่หรือการวางซ้อนเท่านั้น แต่ยังใช้ในการจัดตำแหน่งไทล์แผนที่ด้วย 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
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();
ดูตัวอย่าง