Loại bản đồ

Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.
Chọn nền tảng: Android iOS JavaScript

Tài liệu này thảo luận về các loại bản đồ mà bạn có thể hiển thị bằng API Maps JavaScript. API sử dụng một đối tượng MapType để lưu giữ thông tin về các bản đồ này. MapType là một giao diện xác định cách hiển thị và sử dụng ô bản đồ cũng như bản dịch hệ toạ độ từ toạ độ màn hình đến toạ độ thế giới (trên bản đồ). Mỗi MapType phải chứa một vài phương thức để xử lý việc truy xuất và hủy bỏ các thẻ thông tin cũng như các thuộc tính xác định hành vi hình ảnh của tệp đó.

Hoạt động nội bộ của các loại bản đồ trong API JavaScript cho Maps là một chủ đề nâng cao. Hầu hết các nhà phát triển đều có thể sử dụng các loại bản đồ cơ bản được nêu dưới đây. Tuy nhiên, bạn cũng có thể sửa đổi bản trình bày của các loại bản đồ hiện có bằng cách sử dụng Bản đồ được tạo kiểu hoặc xác định ô bản đồ của riêng mình bằng cách sử dụng các loại bản đồ tùy chỉnh. Khi cung cấp các loại bản đồ tuỳ chỉnh, bạn sẽ cần hiểu cách sửa đổi Tổ chức quản lý loại bản đồ.

Các loại bản đồ cơ bản

Có bốn loại bản đồ trong API JavaScript cho Maps. Ngoài các ô bản đồ đường "vẽ" quen thuộc, Maps JavaScript API còn hỗ trợ các loại bản đồ khác.

Các loại bản đồ sau có sẵn trong API JavaScript cho Maps:

  • roadmap hiển thị chế độ xem bản đồ đường mặc định. Đây là loại bản đồ mặc định.
  • satellite hiển thị hình ảnh vệ tinh của Google Earth.
  • hybrid hiển thị kết hợp giữa các chế độ xem thông thường và chế độ xem vệ tinh.
  • terrain hiển thị bản đồ thực dựa trên thông tin địa hình.

Bạn có thể sửa đổi loại bản đồ mà Map đang sử dụng bằng cách đặt thuộc tính mapTypeId, trong hàm khởi tạo thông qua việc đặt đối tượng Map options hoặc bằng cách gọi phương thức setMapTypeId() của bản đồ. Thuộc tính mapTypeID mặc định là roadmap.

Thiết lập mapTypeId khi đang xây dựng:

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);

Sửa đổi mapTypeId một cách linh động:

map.setMapTypeId('terrain');

Hãy lưu ý rằng bạn không thực sự trực tiếp đặt loại bản đồ của bản đồ mà nên đặt mapTypeId để tham chiếu đến MapType bằng giá trị nhận dạng. API Maps JavaScript sử dụng sổ đăng ký loại bản đồ, được giải thích bên dưới, để quản lý các tệp tham chiếu này.

Hình ảnh 45°

API JavaScript của Maps hỗ trợ hình ảnh 45° đặc biệt cho một số vị trí nhất định. Hình ảnh có độ phân giải cao này cung cấp góc nhìn theo từng hướng chính (Bắc, Nam, Đông, Tây). Những hình ảnh này có sẵn ở mức thu phóng cao hơn cho các loại bản đồ được hỗ trợ.

Hình ảnh sau đây cho thấy góc nhìn 45° của Thành phố New York:

Loại bản đồ satellitehybrid hỗ trợ hình ảnh 45° ở mức thu phóng cao (12 trở lên), nếu có. Nếu người dùng phóng to một vị trí nơi hình ảnh như vậy tồn tại, thì các loại bản đồ này sẽ tự động thay đổi chế độ xem theo cách sau:

  • Hình ảnh vệ tinh hoặc kết hợp được thay thế bằng hình ảnh cung cấp góc nhìn 45°, căn giữa tại vị trí hiện tại. Theo mặc định, các chế độ xem này được hướng về phía bắc. Nếu người dùng thu nhỏ, vệ tinh mặc định hoặc hình ảnh kết hợp sẽ xuất hiện lại. Hành vi này sẽ khác nhau tuỳ thuộc vào mức thu phóng và giá trị của tilt:
    • Theo mặc định, giữa mức thu phóng 12 và 18, bản đồ cơ sở từ trên xuống (0°) sẽ hiển thị trừ khi bạn đặt tilt thành 45.
    • Ở mức thu phóng 18 trở lên, bản đồ cơ sở 45° sẽ hiển thị trừ khi tilt được đặt thành 0.
  • Chế độ điều khiển xoay sẽ xuất hiện. Chế độ điều khiển xoay cung cấp các tuỳ chọn cho phép người dùng bật/tắt chế độ nghiêng và xoay chế độ xem theo mức tăng 90° theo một trong hai hướng. Để ẩn nút điều khiển xoay, hãy đặt rotateControl thành false.

Việc thu nhỏ từ một loại bản đồ hiển thị hình ảnh 45° sẽ huỷ bỏ từng thay đổi trong số này, thiết lập lại các loại bản đồ ban đầu.

Bật và tắt hình ảnh 45°

Bạn có thể tắt hình ảnh 45° bằng cách gọi setTilt(0) trên đối tượng Map. Để bật hình ảnh 45° cho các loại bản đồ được hỗ trợ, hãy gọi setTilt(45). Phương thức getTilt() của Map sẽ luôn phản ánh tilt hiện tại đang hiển thị trên bản đồ; nếu bạn đặt tilt trên bản đồ và sau đó xóa tilt đó (ví dụ: thu nhỏ bản đồ), phương thức getTilt() của bản đồ sẽ trả về 0.

Lưu ý quan trọng: Hình ảnh 45° chỉ được hỗ trợ trên bản đồ đường quét; không thể sử dụng hình ảnh này với bản đồ vectơ.

Ví dụ sau đây cho thấy chế độ xem 45° của Thành phố New York:

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;
Xem ví dụ

Thử mẫu

Xem ví dụ.

Xoay hình ảnh 45°

Hình ảnh 45° thực ra bao gồm một tập hợp hình ảnh cho mỗi hướng chính (Bắc, Nam, Đông, Tây). Khi bản đồ của bạn đang hiển thị hình ảnh 45°, bạn có thể định hướng hình ảnh theo một trong các hướng chính bằng cách gọi setHeading() trên đối tượng Map, truyền một giá trị số được biểu thị dưới dạng độ từ phía Bắc.

Ví dụ sau đây cho thấy một bản đồ trên không và tự động xoay bản đồ 3 giây một lần khi người dùng nhấp vào nút:

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;
Xem ví dụ

Thử mẫu

Xem ví dụ.

Sửa đổi Sổ đăng ký loại bản đồ

mapTypeId của bản đồ là một giá trị nhận dạng chuỗi được dùng để liên kết MapType với một giá trị duy nhất. Mỗi đối tượng Map duy trì một MapTypeRegistry chứa bộ sưu tập MapType có sẵn cho bản đồ đó. Ví dụ: sổ đăng ký này dùng để chọn các loại bản đồ có trong tùy chọn kiểm soát MapType của Maps.

Bạn không đọc trực tiếp từ sổ đăng ký loại bản đồ. Thay vào đó, bạn sẽ sửa đổi sổ đăng ký bằng cách thêm các loại bản đồ tùy chỉnh và liên kết chúng với giá trị nhận dạng chuỗi mà bạn chọn. Bạn không thể sửa đổi hoặc thay đổi các loại bản đồ cơ bản (mặc dù bạn có thể xoá chúng khỏi bản đồ bằng cách thay đổi giao diện của mapTypeControlOptions được liên kết của bản đồ).

Mã sau đây đặt bản đồ để chỉ hiển thị hai loại bản đồ trong mapTypeControlOptions của bản đồ và sửa đổi sổ đăng ký để thêm liên kết với giá trị nhận dạng này vào việc triển khai giao diện 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);

Bản đồ được tạo mẫu

StyledMapType cho phép bạn tuỳ chỉnh cách trình bày các bản đồ cơ sở tiêu chuẩn của Google, thay đổi cách hiển thị trực quan của các phần tử như đường, công viên và khu vực tích hợp để phản ánh phong cách khác với kiểu được sử dụng trong loại bản đồ mặc định.

Để biết thêm thông tin về StyledMapType, hãy xem hướng dẫn để tạo kiểu cho bản đồ.

Các loại bản đồ tùy chỉnh

API JavaScript của Maps hỗ trợ hiển thị và quản lý loại bản đồ tùy chỉnh, cho phép bạn triển khai hình ảnh bản đồ hoặc lớp phủ ô của riêng mình.

Hiện có một số cách triển khai loại bản đồ trong API JavaScript cho Maps:

  • Bộ thẻ thông tin chuẩn bao gồm các hình ảnh chung tạo thành bản đồ bản đồ đầy đủ. Những tập hợp ô này còn được gọi là loại bản đồ cơ sở. Các loại bản đồ này hoạt động và hoạt động giống như các loại bản đồ mặc định hiện có: roadmap, satellite, hybridterrain. Bạn có thể thêm loại bản đồ tùy chỉnh của mình vào một mảng mapTypes của Map để cho phép giao diện người dùng trong API Maps JavaScript xem đây là loại bản đồ tùy chỉnh (ví dụ: bằng cách đưa loại bản đồ đó vào việc kiểm soát MapType).
  • Lớp phủ hình ảnh hiển thị trên các loại bản đồ cơ sở hiện có. Nhìn chung, các loại bản đồ này được dùng để hỗ trợ một loại bản đồ hiện có nhằm hiển thị thông tin bổ sung, và thường bị giới hạn ở các vị trí và/hoặc mức thu phóng cụ thể. Lưu ý rằng những ô này có thể trong suốt, cho phép bạn thêm các đối tượng vào bản đồ hiện có.
  • Các loại bản đồ không phải hình ảnh, cho phép bạn thao tác với việc hiển thị thông tin bản đồ ở cấp cơ bản nhất.

Mỗi tuỳ chọn này dựa trên việc tạo một lớp triển khai giao diện MapType. Ngoài ra, lớp ImageMapType cũng cung cấp một số hành vi tích hợp sẵn để đơn giản hoá quá trình tạo các loại bản đồ hình ảnh.

Giao diện MapType

Trước khi tạo các lớp triển khai MapType, bạn cần hiểu cách Google Maps xác định toạ độ và quyết định phần nào của bản đồ sẽ hiển thị. Bạn cần triển khai logic tương tự cho mọi loại bản đồ cơ sở hoặc lớp phủ. Hãy đọc hướng dẫn về bản đồ bản đồ và toạ độ.

Các loại bản đồ tuỳ chỉnh phải triển khai giao diện MapType. Giao diện này chỉ định một số thuộc tính và phương thức cho phép API khởi tạo yêu cầu đến(các) loại bản đồ của bạn khi API xác định rằng cần phải hiển thị ô bản đồ trong khung nhìn và mức thu phóng hiện tại. Bạn xử lý các yêu cầu này để quyết định thẻ thông tin cần tải.

Lưu ý: Bạn có thể tạo lớp của riêng mình để triển khai giao diện này. Ngoài ra, nếu có hình ảnh tương thích, bạn có thể sử dụng lớp ImageMapType đã triển khai giao diện này.

Các lớp triển khai giao diện MapType yêu cầu bạn phải xác định và điền sẵn các thuộc tính sau:

  • tileSize (bắt buộc) chỉ định kích thước của ô (thuộc loại google.maps.Size). Kích thước phải là hình chữ nhật mặc dù không cần là hình vuông.
  • maxZoom (bắt buộc) chỉ định mức thu phóng tối đa để hiển thị thẻ thông tin thuộc loại bản đồ này.
  • minZoom (không bắt buộc) chỉ định mức thu phóng tối thiểu để hiển thị ô của loại bản đồ này. Theo mặc định, giá trị này là 0, cho biết không có mức thu phóng tối thiểu nào.
  • name (không bắt buộc) chỉ định tên cho loại bản đồ này. Bạn chỉ cần thuộc tính này nếu bạn muốn chọn loại bản đồ này trong phần điều khiển MapType. (Xem phần Thêm các tùy chọn điều khiển MapType bên dưới.)
  • alt (không bắt buộc) chỉ định văn bản thay thế cho loại bản đồ này, được hiển thị dưới dạng văn bản di chuột. Thuộc tính này chỉ cần thiết nếu bạn muốn chọn loại bản đồ này trong điều khiển MapType. (Xem Thêm các chế độ điều khiển MapType ở bên dưới.)

Ngoài ra, các lớp triển khai giao diện MapType cần triển khai các phương thức sau:

  • getTile() (bắt buộc) được gọi bất cứ khi nào API xác định rằng bản đồ cần hiển thị các ô mới cho khung nhìn cụ thể. Phương thức getTile() phải có chữ ký sau:

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

    API xác định xem có cần gọi getTile() hay không dựa trên thuộc tính tileSize, minZoommaxZoom của MapType, cũng như khung nhìn hiện tại và mức thu phóng của bản đồ. Trình xử lý cho phương thức này sẽ trả về một phần tử HTML dựa trên toạ độ được truyền, mức thu phóng và phần tử DOM để thêm hình ảnh thẻ thông tin.

  • releaseTile() (không bắt buộc) được gọi bất cứ khi nào API xác định rằng bản đồ cần xoá một thẻ thông tin khi nó bị chuyển ra khỏi chế độ xem. Phương thức này phải có chữ ký sau:

    releaseTile(tile:Node)

    Thông thường, bạn nên xử lý việc xóa mọi phần tử được đính kèm vào các ô bản đồ đó khi thêm vào bản đồ. Ví dụ: nếu đã đính kèm trình nghe sự kiện để liên kết các lớp phủ xếp kề, bạn nên xóa các lớp phủ đó tại đây.

Phương thức getTile() đóng vai trò là bộ điều khiển chính để xác định thẻ thông tin cần tải trong một khung nhìn nhất định.

Loại bản đồ cơ sở

Các loại bản đồ mà bạn tạo theo cách này có thể đứng độc lập hoặc được kết hợp với các loại bản đồ khác dưới dạng lớp phủ. Các loại bản đồ độc lập được gọi là loại bản đồ cơ sở. Bạn nên yêu cầu API xử lý các MapType tuỳ chỉnh giống như mọi loại bản đồ cơ sở hiện có khác (ROADMAP, TERRAIN, v.v.). Để làm việc này, hãy thêm MapType của bạn vào thuộc tính mapTypes của Map. Thuộc tính này thuộc loại MapTypeRegistry.

Mã sau đây tạo ra một MapType cơ sở để hiển thị toạ độ ô của bản đồ và vẽ đường viền cho các ô:

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;
Xem ví dụ

Thử mẫu

Các loại bản đồ lớp phủ

Một số loại bản đồ được thiết kế để hoạt động dựa trên các loại bản đồ hiện có. Những loại bản đồ như vậy có thể có các lớp trong suốt cho biết địa điểm yêu thích hoặc hiển thị thêm dữ liệu cho người dùng.

Trong những trường hợp này, bạn không muốn loại bản đồ được xem như một thực thể riêng biệt mà là một lớp phủ. Bạn có thể thực hiện việc này bằng cách thêm trực tiếp loại bản đồ vào MapType hiện có bằng cách sử dụng thuộc tính overlayMapTypes của Map. Thuộc tính này chứa MVCArray của MapType. Tất cả các loại bản đồ (cơ sở và lớp phủ) đều được hiển thị trong lớp mapPane. Các loại bản đồ lớp phủ sẽ xuất hiện ở đầu bản đồ cơ sở mà các mục đó được đính kèm, theo thứ tự xuất hiện trong mảng Map.overlayMapTypes (các lớp phủ có giá trị chỉ mục cao hơn sẽ xuất hiện trước lớp phủ có giá trị chỉ mục thấp hơn).

Ví dụ sau giống với ví dụ trước ngoại trừ việc chúng tôi đã tạo một lớp phủ thẻ thông tin MapType ở đầu loại bản đồ 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;
Xem ví dụ

Thử mẫu

Loại bản đồ hình ảnh

Việc triển khai MapType để hoạt động như một loại bản đồ cơ sở có thể là một công việc tốn thời gian và công sức. API này cung cấp một lớp đặc biệt triển khai giao diện MapType cho các loại bản đồ phổ biến nhất: loại bản đồ bao gồm các thẻ tạo thành từ các tệp hình ảnh đơn lẻ.

Lớp này, lớp ImageMapType, được xây dựng bằng cách sử dụng quy cách đối tượng ImageMapTypeOptions xác định các thuộc tính bắt buộc sau:

  • tileSize (bắt buộc) chỉ định kích thước của ô (thuộc loại google.maps.Size). Kích thước phải là hình chữ nhật mặc dù không cần là hình vuông.
  • getTileUrl (bắt buộc) chỉ định hàm, thường được cung cấp dưới dạng một giá trị cố định của hàm cùng dòng để xử lý việc chọn ô hình ảnh phù hợp dựa trên toạ độ thế giới và mức thu phóng đã cung cấp.

Mã sau đây triển khai một ImageMapType cơ bản bằng cách sử dụng thẻ thông tin trên mặt trăng của Google. Ví dụ này sử dụng hàm chuẩn hoá để đảm bảo rằng các thẻ thông tin lặp lại dọc theo trục x, nhưng không dọc theo trục y của bản đồ.

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;
Xem ví dụ

Thử mẫu

Dự đoán

Trái đất là một hình cầu ba chiều (khoảng), trong khi bản đồ là một bề mặt phẳng hai chiều. Bản đồ mà bạn thấy trong API Maps JavaScript, giống như mọi bản đồ phẳng của Trái đất, là một sự chiếu của hình cầu đó lên một bề mặt phẳng. Nói một cách đơn giản, phép chiếu có thể được định nghĩa là mối liên kết giữa các giá trị vĩ độ/kinh độ với các toạ độ trên bản đồ của phép chiếu.

Các phép chiếu trong API JavaScript cho Maps phải triển khai giao diện Projection. Quá trình triển khai Projection không chỉ phải cung cấp mối liên kết từ một hệ thống toạ độ đến một hệ thống toạ độ khác, mà còn liên kết hai chiều. Tức là bạn phải xác định cách dịch từ toạ độ Earth (đối tượng LatLng) sang hệ thống toạ độ thế giới của lớp Projection và ngược lại. Google Maps sử dụng phép chiếu TCF để tạo bản đồ từ dữ liệu địa lý và chuyển đổi các sự kiện trên bản đồ thành các toạ độ địa lý. Bạn có thể có được phép chiếu này bằng cách gọi getProjection() trên Map (hoặc bất kỳ loại MapType cơ sở chuẩn nào.) Đối với hầu hết mục đích sử dụng, bạn chỉ nên sử dụng Projection tiêu chuẩn này, nhưng bạn cũng có thể xác định và sử dụng phép chiếu tùy chỉnh của riêng mình.

Triển khai phép chiếu

Khi triển khai phép chiếu tuỳ chỉnh, bạn cần xác định một số điều sau:

  • Công thức để ánh xạ toạ độ vĩ độ và kinh độ thành mặt phẳng Cartesian và ngược lại. (Giao diện Projection chỉ hỗ trợ chuyển đổi thành các toạ độ trực tuyến.)
  • Kích thước ô cơ bản. Tất cả các ô phải có hình chữ nhật.
  • "Kích thước thế giới" của bản đồ bằng cách sử dụng ô cơ sở được đặt ở mức thu phóng 0. Lưu ý rằng đối với bản đồ bao gồm một thẻ thông tin ở mức thu phóng 0, kích thước thế giới và kích thước thẻ thông tin cơ bản là giống nhau.

Chuyển đổi toạ độ trong phép chiếu

Mỗi phép chiếu cung cấp hai phương thức dịch giữa hai hệ toạ độ này, cho phép bạn chuyển đổi giữa toạ độ địa lý và toạ độ thế giới:

  • Phương thức Projection.fromLatLngToPoint() chuyển đổi giá trị LatLng thành một toạ độ thế giới. Phương thức này dùng để định vị các lớp phủ trên bản đồ (và để xác định vị trí của bản đồ).
  • Phương thức Projection.fromPointToLatLng() chuyển đổi một toạ độ thế giới thành một giá trị LatLng. Phương thức này được dùng để chuyển đổi các sự kiện như lượt nhấp xảy ra trên bản đồ vào toạ độ địa lý.

Google Maps giả định rằng các phép chiếu có dạng thẳng đứng.

Nói chung, bạn có thể sử dụng phép chiếu cho hai trường hợp: để tạo bản đồ thế giới hoặc tạo bản đồ của một khu vực địa phương. Trong trường hợp trước, bạn nên đảm bảo rằng phép chiếu của bạn cũng quay toàn bộ và bình thường ở tất cả các kinh độ. Một số phép chiếu (đặc biệt là phép chiếu hình nón) có thể "bình thường tại địa phương" (tức là trỏ về phía Bắc) nhưng sai lệch so với hướng Bắc thực; ví dụ: bản đồ càng nằm ở vị trí tương đối so với một số kinh độ tham chiếu. Bạn có thể sử dụng phép chiếu như vậy cục bộ, nhưng hãy lưu ý rằng phép chiếu đó nhất thiết không chính xác và các lỗi biến đổi sẽ ngày càng rõ ràng hơn so với kinh độ tham chiếu mà bạn sai lệch.

Lựa chọn ô bản đồ trong phép chiếu

Phép chiếu không chỉ hữu ích cho việc xác định vị trí của các vị trí hoặc lớp phủ, mà còn để định vị các ô bản đồ. API JavaScript của Maps kết xuất bản đồ cơ sở bằng giao diện MapType. Giao diện này phải khai báo cả thuộc tính projection để xác định phép chiếu của bản đồ và phương thức getTile() để truy xuất ô bản đồ dựa trên giá trị toạ độ ô. Toạ độ ô dựa trên cả kích thước ô cơ bản của bạn (phải là hình chữ nhật) và "kích thước thế giới" của bản đồ (kích thước pixel của thế giới bản đồ) ở mức thu phóng 0. (Đối với bản đồ bao gồm một ô ở mức thu phóng 0, kích thước ô và kích thước thế giới giống nhau.)

Bạn xác định kích thước ô cơ sở trong thuộc tính tileSize của MapType. Bạn xác định ngầm kích thước thế giới trong các phương thức fromLatLngToPoint()fromPointToLatLng() của phép chiếu.

Vì lựa chọn hình ảnh phụ thuộc vào các giá trị được chuyển này, nên việc đặt tên cho hình ảnh có thể được chọn theo phương thức lập trình dựa trên các giá trị đã truyền đó, chẳng hạn như map_zoom_tileX_tileY.png.

Ví dụ sau đây xác định ImageMapType bằng cách sử dụng phép chiếu Gll- 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;
Xem ví dụ

Thử mẫu