지도 유형

플랫폼 선택: Android iOS JavaScript

이 문서에서는 Maps JavaScript API를 사용하여 표시할 수 있는 지도 유형을 설명합니다. API는 MapType 객체를 사용하여 이러한 지도에 대한 정보를 저장합니다. MapType은 지도 타일의 표시 및 사용, 화면 좌표에서 (지도상의) 세계 좌표로의 좌표계 변환을 정의하는 인터페이스입니다. 각 MapType에는 타일 가져오기 및 배치를 처리하기 위한 메서드와 시각적 동작을 정의하는 속성을 포함해야 합니다.

Maps JavaScript API 내 지도 유형의 내부 작동은 고급 주제에 해당합니다. 대부분의 개발자는 아래에 설명되어 있는 기본 지도 유형을 사용할 수 있습니다. 하지만 스타일 지도를 사용하여 기존 지도 유형의 표시를 수정하거나 맞춤 지도 유형을 사용하여 나만의 지도 타일을 정의할 수도 있습니다. 맞춤 지도 유형을 제공할 때는 지도의 지도 유형 레지스트리를 수정하는 방법을 알아야 합니다.

기본 지도 유형

Maps JavaScript API 내에서는 네 가지 유형의 지도를 사용할 수 있습니다. Maps JavaScript API는 익숙한 '채색된' 도로 지도 타일 외에 다른 지도 유형도 지원합니다.

Maps JavaScript API에서 사용할 수 있는 지도 유형은 다음과 같습니다.

  • roadmap은 기본 도로 지도 뷰를 표시합니다. 이 유형은 기본 지도 유형입니다.
  • satellite는 Google 어스 위성 이미지를 표시합니다.
  • hybrid는 일반 뷰와 위성 뷰를 혼합하여 표시합니다.
  • terrain은 지형 정보를 기반으로 실제 지도를 표시합니다.

Map에서 사용 중인 지도 유형은 생성자 내에서 Map options 객체를 설정하거나 지도의 setMapTypeId() 메서드를 호출하여 mapTypeId 속성을 설정하는 방법으로 수정할 수 있습니다. 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');

실제로 지도의 지도 유형은 직접 설정하는 것이 아니라 식별자를 사용하여 MapType을 참조하도록 mapTypeId를 설정합니다. Maps JavaScript API는 아래 설명된 지도 유형 레지스트리를 사용하여 이러한 참조를 관리합니다.

45° 이미지

Maps JavaScript API는 특정 위치에 대해 특별한 45° 이미지를 지원합니다. 이 고해상도 이미지는 각 기본 방향(동, 서, 남, 북)을 향한 원근 뷰를 제공합니다. 지원되는 지도 유형의 경우 더 높은 확대/축소 수준에서 이러한 이미지를 사용할 수 있습니다.

다음 이미지는 뉴욕시의 45° 원근 뷰를 보여줍니다.

satellitehybrid 지도 유형은 가능한 경우 높은 확대/축소 수준(12 이상)에서 45° 이미지를 지원합니다. 사용자가 이러한 이미지가 있는 위치를 확대하면, 이 지도 유형이 다음과 같은 방식으로 뷰를 자동으로 변경합니다.

  • 위성 또는 하이브리드 이미지는 현재 위치를 중심으로 45° 원근 뷰를 제공하는 이미지로 교체됩니다. 기본적으로 이러한 뷰는 북쪽을 향합니다. 사용자가 축소하면 기본 위성 또는 하이브리드 이미지가 다시 표시됩니다. 동작은 확대/축소 수준과 tilt의 값에 따라 달라집니다.
    • 12~18 확대/축소 수준에서는 tilt가 45로 설정되지 않은 한 기본적으로 하향식 기본 지도(0°)가 표시됩니다.
    • 18 이상의 확대/축소 수준에서는 tilt가 0으로 설정되지 않은 한 45° 기본 지도가 표시됩니다.
  • 회전 컨트롤이 표시됩니다. 회전 컨트롤은 사용자가 기울기를 전환하고 어느 방향으로든 뷰를 90° 단위로 회전할 수 있는 옵션을 제공합니다. 회전 컨트롤을 숨기려면 rotateControlfalse로 설정하세요.

45° 이미지를 표시하는 지도 유형에서 축소하면 각 변경사항을 되돌리고 원래의 지도 유형으로 다시 설정됩니다.

45도 이미지 사용 설정 및 중지

Map 객체에서 setTilt(0)을 호출하여 45° 이미지를 사용 중지할 수 있습니다. 지원되는 지도 유형에 대해 45° 이미지를 사용 설정하려면 setTilt(45)를 호출하세요. MapgetTilt() 메서드는 항상 지도에 표시된 현재 tilt를 반영합니다. 지도에 tilt를 설정한 다음 나중에 (예를 들어 지도를 축소하여) 해당 tilt를 삭제하면 지도의 getTilt() 메서드가 0을 반환합니다.

중요: 45° 이미지는 래스터 지도에서만 지원됩니다. 이 이미지는 벡터 지도와 함께 사용할 수 없습니다.

다음 예는 뉴욕시의 45° 뷰를 표시합니다.

TypeScript

function initMap(): void {
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      center: { lat: 40.76, lng: -73.983 },
      zoom: 15,
      mapTypeId: "satellite",
    }
  );

  map.setTilt(45);
}

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

JavaScript

function initMap() {
  const map = new google.maps.Map(document.getElementById("map"), {
    center: { lat: 40.76, lng: -73.983 },
    zoom: 15,
    mapTypeId: "satellite",
  });

  map.setTilt(45);
}

window.initMap = initMap;
예 보기

샘플 사용해 보기

예시 보기

45° 이미지 회전

45° 이미지는 실제로 각 기본 방향(동, 서, 남, 북)의 이미지 모음으로 구성됩니다. 지도에 45° 이미지가 표시되면 Map 객체에서 setHeading()을 호출하고 북쪽을 기준으로 도 단위로 표현된 숫자 값을 전달하여 이미지가 기본 방향 중 하나를 향하도록 할 수 있습니다.

다음 예는 항공 지도를 보여주며 버튼이 클릭되면 지도가 3초마다 자동으로 회전합니다.

TypeScript

let map: google.maps.Map;

function initMap(): void {
  map = new google.maps.Map(document.getElementById("map") as HTMLElement, {
    center: { lat: 40.76, lng: -73.983 },
    zoom: 15,
    mapTypeId: "satellite",
    heading: 90,
    tilt: 45,
  });

  // add listener to button
  document.getElementById("rotate")!.addEventListener("click", autoRotate);
}

function rotate90(): void {
  const heading = map.getHeading() || 0;

  map.setHeading(heading + 90);
}

function autoRotate(): void {
  // Determine if we're showing aerial imagery.
  if (map.getTilt() !== 0) {
    window.setInterval(rotate90, 3000);
  }
}

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

JavaScript

let map;

function initMap() {
  map = new google.maps.Map(document.getElementById("map"), {
    center: { lat: 40.76, lng: -73.983 },
    zoom: 15,
    mapTypeId: "satellite",
    heading: 90,
    tilt: 45,
  });
  // add listener to button
  document.getElementById("rotate").addEventListener("click", autoRotate);
}

function rotate90() {
  const heading = map.getHeading() || 0;

  map.setHeading(heading + 90);
}

function autoRotate() {
  // Determine if we're showing aerial imagery.
  if (map.getTilt() !== 0) {
    window.setInterval(rotate90, 3000);
  }
}

window.initMap = initMap;
예 보기

샘플 사용해 보기

예시 보기

지도 유형 레지스트리 수정

지도의 mapTypeIdMapType을 고유한 값과 연결하는 데 사용되는 문자열 식별자입니다. 각 Map 객체는 해당 지도에 사용할 수 있는 MapType 모음이 포함된 MapTypeRegistry를 유지관리합니다. 이 레지스트리는 예를 들어 지도의 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에 관한 자세한 내용은 삽입된 JSON 스타일 선언 사용을 참고하세요.

맞춤 지도 유형

Maps JavaScript API는 맞춤 지도 유형의 표시 및 관리를 지원하므로 자체 지도 이미지 또는 타일 오버레이를 구현할 수 있습니다.

Maps JavaScript API 내에서 여러 가지 지도 유형을 구현할 수 있습니다.

  • 전체 지도 제작용 지도를 공통으로 구성하는 이미지로 구성된 표준 타일 집합. 이러한 타일 집합을 기본 지도 유형이라고도 합니다. 이러한 지도 유형의 작동 방식은 기존 기본 지도 유형(roadmap, satellite, hybridterrain)과 같습니다. 지도의 mapTypes 배열에 맞춤 지도 유형을 추가하여 Maps JavaScript API 내의 UI에서 맞춤 지도 유형을 (예를 들어 MapType 컨트롤에 포함하여) 표준 지도 유형으로 간주하도록 할 수 있습니다.
  • 기존 기본 지도 유형 위에 표시되는 이미지 타일 오버레이. 일반적으로 이러한 지도 유형은 기존 지도 유형을 보강하여 추가 정보를 표시하는 데 사용되며 대개 특정 위치 또는 확대/축소 수준으로 제한됩니다. 이 타일은 투명하여 기존 지도에 지형지물을 추가하도록 해줍니다.
  • 가장 기초적인 수준에서 지도 정보 표시를 조작할 수 있는 비이미지 지도 유형

각 옵션을 사용하려면 MapType 인터페이스를 구현하는 클래스를 만들어야 합니다. 또한 ImageMapType 클래스는 이미지 지도 유형을 간단하게 만들 수 있도록 기본 동작을 제공합니다.

MapType 인터페이스

MapType을 구현하는 클래스를 만들기 전에 Google 지도가 좌표를 확인하고 지도에 표시할 부분을 결정하는 방식을 이해하는 것이 중요합니다. 기본 또는 오버레이 지도 유형에 대해 유사한 로직을 구현해야 합니다. 지도 및 타일 좌표 가이드를 읽어보세요.

맞춤 지도 유형은 MapType 인터페이스를 구현해야 합니다. 이 인터페이스는 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는 MapTypetileSize, minZoom, maxZoom 속성과 지도의 현재 표시 영역 및 확대/축소 수준을 기반으로 getTile()을 호출해야 하는지를 결정합니다. 이 메서드의 핸들러는 전달된 좌표, 확대/축소 수준, 타일 이미지를 연결할 DOM 요소를 고려하여 HTML 요소를 반환해야 합니다.

  • releaseTile()(선택사항)은 API가 타일이 뷰를 벗어나 지도에서 타일을 삭제해야 한다고 판단할 때마다 호출됩니다. 이 메서드에는 다음과 같은 서명이 있어야 합니다.

    releaseTile(tile:Node)

    일반적으로 지도에 지도 타일을 추가할 때 지도 타일에 연결된 요소를 삭제해야 합니다. 예를 들어 이벤트 리스너를 지도 타일 오버레이에 연결한 경우 여기에서 삭제해야 합니다.

getTile() 메서드는 지정된 표시 영역 내에서 로드할 타일을 결정하는 기본 컨트롤러 역할을 합니다.

기본 지도 유형

이 방식으로 생성하는 지도 유형은 독립형이거나 오버레이로 다른 지도 유형과 결합할 수 있습니다. 독립형 지도 유형을 기본 지도 유형이라고 합니다. API에서 이러한 맞춤 MapTypeROADMAP, TERRAIN 등 다른 기존 기본 지도 유형처럼 처리하도록 할 수도 있습니다. 그렇게 하려면 맞춤 MapTypeMapmapTypes 속성에 추가하세요. 이 속성은 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;
예 보기

샘플 사용해 보기

오버레이 지도 유형

어떤 지도 유형은 기존 지도 유형 위에서 작동하도록 디자인됩니다. 이러한 지도 유형에는 관심 장소를 나타내거나 사용자에게 추가 데이터를 보여주는 투명 레이어가 있을 수도 있습니다.

이러한 경우 지도 유형을 별도의 항목으로 처리하지 않고 오버레이로 처리해야 합니다. MapoverlayMapTypes 속성을 사용하여 지도 유형을 기존 MapType에 직접 추가하면 됩니다. 이 속성에는 MapTypeMVCArray가 포함됩니다. 모든 지도 유형(기본 및 오버레이)은 mapPane 레이어 내에서 렌더링됩니다. 오버레이 지도 유형은 연결된 기본 지도 위에 Map.overlayMapTypes 배열에 표시된 순서대로 표시됩니다(색인 값이 더 큰 오버레이가 색인 값이 더 작은 오버레이 앞에 표시됩니다).

다음 예는 ROADMAP 지도 유형 위에 타일 오버레이 MapType을 만들었다는 점을 제외하고 이전 예와 동일합니다.

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(필수)은 제공된 세계 좌표와 확대/축소 수준을 기반으로 적절한 이미지 타일을 선택할 수 있도록, 대개 인라인 함수 리터럴로 제공되는 함수를 지정합니다.

다음 코드는 Google의 달 타일을 사용하여 기본 ImageMapType을 구현합니다. 이 예에서는 정규화 함수를 사용하여 타일이 지도의 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;
예 보기

샘플 사용해 보기

투영

지구는 대략적으로 3D 구체이지만 지도는 평평한 2D 표면입니다. Maps JavaScript API 내에 표시되는 지도는 지구의 모든 평평한 지도와 같이 구를 평평한 표면에 투영한 것입니다. 간단히 말해 투영은 위도/경도 값을 투영된 지도의 좌표로 매핑한 것이라고 정의할 수 있습니다.

Maps JavaScript API의 투영에서는 Projection 인터페이스를 구현해야 합니다. Projection을 구현하려면 한 좌표계에서 다른 좌표계로의 매핑뿐 아니라 양방향 매핑을 제공해야 합니다. 즉 지구 좌표 (LatLng 객체)를 Projection 클래스의 세계 좌표계 또는 그 반대로 변환하는 방법을 정의해야 합니다. Google 지도는 메르카토르 도법을 사용하여 지리 데이터로부터 지도를 만들고 지도 위의 이벤트를 지리적 좌표로 변환합니다. Map(또는 표준 기본 MapType 유형)에서 getProjection()을 호출하여 이 투영을 얻을 수 있습니다. 대부분의 경우 이 표준 Projection으로 충분하지만 자체 맞춤 투영을 정의하여 사용할 수도 있습니다.

투영 구현

맞춤 투영을 구현할 때 다음 사항을 정의해야 합니다.

  • 위도와 경도 좌표를 데카르트 평면으로 매핑하는 공식과 데카르트 평면에서 위도 및 경도 좌표로 매핑하는 상응하는 공식 Projection 인터페이스는 직선 좌표로의 변환만 지원합니다.
  • 기본 타일 크기. 모든 타일은 직사각형이어야 합니다.
  • 확대/축소 수준 0에서 설정된 기본 타일을 사용하는 지도의 '세계 크기'. 확대/축소 수준 0에서 타일 한 개로 구성된 지도의 경우 세계 크기와 기본 타일 크기가 동일합니다.

투영의 좌표 변환

각 투영은 이러한 두 좌표계 간에 변환하는 두 가지 메서드를 제공하므로 지리적 좌표와 세계 좌표 간에 변환할 수 있습니다.

  • Projection.fromLatLngToPoint() 메서드는 LatLng 값을 세계 좌표로 변환합니다. 이 메서드는 지도에 오버레이를 배치하고 지도 자체를 배치하는 데 사용됩니다.
  • Projection.fromPointToLatLng() 메서드는 세계 좌표를 LatLng 값으로 변환합니다. 이 메서드는 지도에서 발생하는 클릭과 같은 이벤트를 지리적 좌표로 변환하는 데 사용됩니다.

Google 지도에서는 투영이 직선이라고 가정합니다.

일반적으로 세계 지도를 만들거나 지역의 지도를 만들기 위해 투영을 사용할 수 있습니다. 세계 지도를 만드는 경우 모든 경도에서 투영이 직선이고 정상이어야 합니다. 일부 투영(특히 원뿔 투영)의 경우 '지역적으로 정상'이지만(예: 북쪽을 가리키지만) 진북에서 벗어날 수 있습니다. 예를 들어 일부 참조 경도에 비해 지도가 더 멀리 배치됩니다. 이러한 투영은 지역적으로 사용할 수 있지만, 참조 경도에서 멀어질수록 투영이 부정확하고 변환 오류가 점점 더 분명해집니다.

투영의 지도 타일 선택

투영은 장소나 오버레이의 위치를 결정할 때뿐 아니라 지도 타일 자체를 배치할 때도 유용합니다. Maps JavaScript API는 MapType 인터페이스를 사용하여 기본 지도를 렌더링합니다. 이 인터페이스는 지도의 투영을 식별하기 위한 projection 속성과 타일 좌표 값을 기반으로 지도 타일을 검색하기 위한 getTile() 메서드를 모두 선언해야 합니다. 타일 좌표는 기본 타일 크기(직사각형이어야 함) 및 지도의 '세계 크기'(확대/축소 수준 0에서 지도 세계의 픽셀 크기)를 기반으로 합니다. 확대/축소 수준 0에서 타일 한 개로 구성된 지도의 경우 타일 크기와 세계 크기가 동일합니다.

MapTypetileSize 속성 내에 기본 타일 크기를 정의합니다. 세계 크기는 투영의 fromLatLngToPoint()fromPointToLatLng() 메서드 내에 암시적으로 정의합니다.

이렇게 전달된 값에 따라 이미지가 선택되므로 이미지에 이러한 전달된 값을 프로그래매틱 방식으로 선택할 수 있는 이름(예: map_zoom_tileX_tileY.png)을 지정하는 것이 유용합니다.

다음 예에서는 Gall-Peters 투영을 사용하여 ImageMapType을 정의합니다.

TypeScript

// This example defines an image map type using the Gall-Peters
// projection.
// https://en.wikipedia.org/wiki/Gall%E2%80%93Peters_projection

function initMap(): void {
  // Create a map. Use the Gall-Peters map type.
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 0,
      center: { lat: 0, lng: 0 },
      mapTypeControl: false,
    }
  );

  initGallPeters();
  map.mapTypes.set("gallPeters", gallPetersMapType);
  map.setMapTypeId("gallPeters");

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

  map.controls[google.maps.ControlPosition.TOP_CENTER].push(coordsDiv);
  map.addListener("mousemove", (event: google.maps.MapMouseEvent) => {
    coordsDiv.textContent =
      "lat: " +
      Math.round(event.latLng!.lat()) +
      ", " +
      "lng: " +
      Math.round(event.latLng!.lng());
  });

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

let gallPetersMapType;

function initGallPeters() {
  const GALL_PETERS_RANGE_X = 800;
  const GALL_PETERS_RANGE_Y = 512;

  // Fetch Gall-Peters tiles stored locally on our server.
  gallPetersMapType = new google.maps.ImageMapType({
    getTileUrl: function (coord, zoom) {
      const scale = 1 << zoom;

      // Wrap tiles horizontally.
      const x = ((coord.x % scale) + scale) % scale;

      // Don't wrap tiles vertically.
      const y = coord.y;

      if (y < 0 || y >= scale) return "";

      return (
        "https://developers.google.com/maps/documentation/" +
        "javascript/examples/full/images/gall-peters_" +
        zoom +
        "_" +
        x +
        "_" +
        y +
        ".png"
      );
    },
    tileSize: new google.maps.Size(GALL_PETERS_RANGE_X, GALL_PETERS_RANGE_Y),
    minZoom: 0,
    maxZoom: 1,
    name: "Gall-Peters",
  });

  // Describe the Gall-Peters projection used by these tiles.
  gallPetersMapType.projection = {
    fromLatLngToPoint: function (latLng) {
      const latRadians = (latLng.lat() * Math.PI) / 180;
      return new google.maps.Point(
        GALL_PETERS_RANGE_X * (0.5 + latLng.lng() / 360),
        GALL_PETERS_RANGE_Y * (0.5 - 0.5 * Math.sin(latRadians))
      );
    },
    fromPointToLatLng: function (point, noWrap) {
      const x = point.x / GALL_PETERS_RANGE_X;
      const y = Math.max(0, Math.min(1, point.y / GALL_PETERS_RANGE_Y));

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

// GeoJSON, describing the locations and names of some cities.
const cities = {
  type: "FeatureCollection",
  features: [
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-87.65, 41.85] },
      properties: { name: "Chicago" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-149.9, 61.218] },
      properties: { name: "Anchorage" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-99.127, 19.427] },
      properties: { name: "Mexico City" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-0.126, 51.5] },
      properties: { name: "London" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [28.045, -26.201] },
      properties: { name: "Johannesburg" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [15.322, -4.325] },
      properties: { name: "Kinshasa" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [151.207, -33.867] },
      properties: { name: "Sydney" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [0, 0] },
      properties: { name: "0°N 0°E" },
    },
  ],
};

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

JavaScript

// This example defines an image map type using the Gall-Peters
// projection.
// https://en.wikipedia.org/wiki/Gall%E2%80%93Peters_projection
function initMap() {
  // Create a map. Use the Gall-Peters map type.
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 0,
    center: { lat: 0, lng: 0 },
    mapTypeControl: false,
  });

  initGallPeters();
  map.mapTypes.set("gallPeters", gallPetersMapType);
  map.setMapTypeId("gallPeters");

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

  map.controls[google.maps.ControlPosition.TOP_CENTER].push(coordsDiv);
  map.addListener("mousemove", (event) => {
    coordsDiv.textContent =
      "lat: " +
      Math.round(event.latLng.lat()) +
      ", " +
      "lng: " +
      Math.round(event.latLng.lng());
  });
  // Add some markers to the map.
  map.data.setStyle((feature) => {
    return {
      title: feature.getProperty("name"),
      optimized: false,
    };
  });
  map.data.addGeoJson(cities);
}

let gallPetersMapType;

function initGallPeters() {
  const GALL_PETERS_RANGE_X = 800;
  const GALL_PETERS_RANGE_Y = 512;

  // Fetch Gall-Peters tiles stored locally on our server.
  gallPetersMapType = new google.maps.ImageMapType({
    getTileUrl: function (coord, zoom) {
      const scale = 1 << zoom;
      // Wrap tiles horizontally.
      const x = ((coord.x % scale) + scale) % scale;
      // Don't wrap tiles vertically.
      const y = coord.y;

      if (y < 0 || y >= scale) return "";
      return (
        "https://developers.google.com/maps/documentation/" +
        "javascript/examples/full/images/gall-peters_" +
        zoom +
        "_" +
        x +
        "_" +
        y +
        ".png"
      );
    },
    tileSize: new google.maps.Size(GALL_PETERS_RANGE_X, GALL_PETERS_RANGE_Y),
    minZoom: 0,
    maxZoom: 1,
    name: "Gall-Peters",
  });
  // Describe the Gall-Peters projection used by these tiles.
  gallPetersMapType.projection = {
    fromLatLngToPoint: function (latLng) {
      const latRadians = (latLng.lat() * Math.PI) / 180;
      return new google.maps.Point(
        GALL_PETERS_RANGE_X * (0.5 + latLng.lng() / 360),
        GALL_PETERS_RANGE_Y * (0.5 - 0.5 * Math.sin(latRadians)),
      );
    },
    fromPointToLatLng: function (point, noWrap) {
      const x = point.x / GALL_PETERS_RANGE_X;
      const y = Math.max(0, Math.min(1, point.y / GALL_PETERS_RANGE_Y));
      return new google.maps.LatLng(
        (Math.asin(1 - 2 * y) * 180) / Math.PI,
        -180 + 360 * x,
        noWrap,
      );
    },
  };
}

// GeoJSON, describing the locations and names of some cities.
const cities = {
  type: "FeatureCollection",
  features: [
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-87.65, 41.85] },
      properties: { name: "Chicago" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-149.9, 61.218] },
      properties: { name: "Anchorage" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-99.127, 19.427] },
      properties: { name: "Mexico City" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-0.126, 51.5] },
      properties: { name: "London" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [28.045, -26.201] },
      properties: { name: "Johannesburg" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [15.322, -4.325] },
      properties: { name: "Kinshasa" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [151.207, -33.867] },
      properties: { name: "Sydney" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [0, 0] },
      properties: { name: "0°N 0°E" },
    },
  ],
};

window.initMap = initMap;
예 보기

샘플 사용해 보기