Dokumen ini membahas jenis peta yang dapat Anda tampilkan menggunakan
Maps JavaScript API. API tersebut menggunakan objek MapType untuk menyimpan informasi tentang peta ini. MapType adalah antarmuka yang menentukan tampilan dan penggunaan ubin peta serta terjemahan sistem koordinat dari koordinat layar ke koordinat dunia (pada peta). Setiap MapType harus berisi beberapa metode untuk menangani proses pengambilan dan pelepasan ubin, serta properti yang menentukan perilaku visualnya.
Cara kerja internal jenis peta di Maps JavaScript API adalah topik lanjutan. Sebagian besar developer dapat menggunakan jenis peta dasar yang disebutkan di bawah ini. Namun, Anda juga dapat memodifikasi tampilan jenis peta yang ada menggunakan Maps Bergaya atau menentukan ubin peta Anda sendiri menggunakan jenis peta kustom. Saat memberikan jenis peta kustom, Anda perlu memahami cara memodifikasi Registry Jenis Peta.
Jenis Peta Dasar
Ada empat jenis peta yang tersedia dalam Maps JavaScript API. Selain ubin peta jalan "berwarna" yang sudah dikenal, Maps JavaScript API juga mendukung jenis peta lainnya.
Jenis peta berikut ini tersedia di Maps JavaScript API:
roadmapmenampilkan tampilan peta jalan default dengan label peta dasar.satellitemenampilkan peta fotorealistik berdasarkan citra udara.hybridmenampilkan tampilan peta satelit dengan label peta dasar.terrainmenampilkan peta fisik berdasarkan informasi medan.
Anda memodifikasi jenis peta yang digunakan oleh Map dengan
menetapkan properti mapTypeId, baik di dalam konstruktor dengan
menetapkan objek Map options, atau dengan memanggil
metode setMapTypeId(). Secara default, properti mapTypeID
ditetapkan ke roadmap.
Menetapkan mapTypeId saat pembuatan:
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);
Mengubah mapTypeId secara dinamis:
map.setMapTypeId('terrain');
Perhatikan bahwa Anda sebenarnya tidak menetapkan jenis peta untuk peta tersebut secara langsung, tetapi menetapkan mapTypeId untuk mereferensikan MapType menggunakan ID.
Maps JavaScript API menggunakan registry jenis peta, yang dijelaskan di bawah, untuk mengelola referensi ini.
Peta 3D
Maps JavaScript API mendukung gambar 3D. Banyak tindakan dan kemampuan penyesuaian yang tersedia untuk peta 2D juga tersedia untuk peta 3D.
Pelajari lebih lanjut peta 3D di ringkasan peta 3D.
Contoh berikut menampilkan tampilan perspektif 3D San Francisco:
Pelajari lebih lanjut Peta 3D di ringkasan peta 3D.
Gambar 45° (tidak digunakan lagi)
Contoh berikut menunjukkan cara mendapatkan tampilan perspektif 45° di San Francisco menggunakan peta 3D:
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>Memodifikasi Registry Jenis Peta
mapTypeId peta adalah ID string yang digunakan untuk mengaitkan MapType dengan nilai yang unik. Setiap objek Map mempertahankan
MapTypeRegistry yang berisi kumpulan
MapType yang tersedia untuk peta tersebut. Misalnya, registry ini digunakan untuk memilih jenis peta yang tersedia dalam kontrol MapType dari Map tersebut.
Anda tidak membaca langsung dari registry jenis peta. Melainkan, Anda memodifikasi registry dengan menambahkan jenis peta kustom dan mengaitkannya dengan ID string yang dipilih. Anda tidak dapat memodifikasi atau mengubah jenis peta dasar (meskipun Anda dapat menghapusnya dari peta dengan mengubah tampilan mapTypeControlOptions yang terkait dengan peta).
Kode berikut menetapkan peta untuk hanya menampilkan dua jenis peta dalam mapTypeControlOptions peta dan memodifikasi registry untuk menambahkan pengaitan dengan ID ini ke penerapan antarmuka MapType yang sesungguhnya.
// 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);
Peta Bergaya
StyledMapType memungkinkan Anda menyesuaikan penyajian
peta dasar Google standar, mengubah tampilan visual elemen
seperti jalan, taman, dan area padat bangunan untuk mencerminkan gaya yang berbeda daripada yang
digunakan dalam jenis peta default. StyledMapType hanya memengaruhi jenis peta roadmap default.
Untuk mengetahui informasi selengkapnya tentang StyledMapType, lihat
Menggunakan deklarasi gaya JSON
tersemat.
Jenis Peta Kustom
Maps JavaScript API mendukung tampilan dan pengelolaan jenis peta kustom, sehingga Anda dapat menerapkan gambar peta atau overlay ubin Anda sendiri.
Beberapa kemungkinan penerapan jenis peta tersedia dalam Maps JavaScript API:
- Kumpulan ubin standar yang terdiri dari gambar yang secara kolektif membentuk peta kartografi lengkap. Kumpulan ubin ini juga disebut sebagai jenis peta dasar. Jenis peta ini
berfungsi dan berperilaku seperti jenis peta default yang ada:
roadmap,satellite,hybrid, danterrain. Anda dapat menambahkan jenis peta kustom ke arraymapTypesPeta untuk mengizinkan UI dalam Maps JavaScript API memperlakukan jenis peta kustom sebagai jenis peta standar (dengan menyertakannya dalam kontrol MapType, misalnya). - Overlay ubin gambar yang ditampilkan di atas jenis peta dasar yang sudah ada. Biasanya, jenis peta ini digunakan untuk meningkatkan jenis peta yang ada guna menampilkan informasi tambahan dan sering kali dibatasi pada lokasi dan/atau tingkat zoom tertentu. Perhatikan, ubin ini mungkin transparan, yang memungkinkan Anda menambahkan fitur ke peta yang ada.
- Jenis peta bukan-gambar, yang memungkinkan Anda memanipulasi tampilan informasi peta pada tingkat yang paling mendasar.
Setiap opsi ini bergantung pada pembuatan class yang mengimplementasikan antarmuka MapType. Selain itu, class
ImageMapType menyediakan beberapa perilaku bawaan untuk menyederhanakan pembuatan jenis peta gambar.
Antarmuka MapType
Sebelum membuat class yang menerapkan MapType, Anda harus memahami cara Google Maps menentukan koordinat dan memutuskan bagian peta yang akan ditampilkan. Anda perlu menerapkan logika serupa untuk setiap jenis peta dasar atau overlay.
Baca panduan untuk koordinat peta dan ubin.
Jenis peta kustom harus mengimplementasikan antarmuka MapType. Antarmuka ini menetapkan beberapa properti dan metode yang memungkinkan API membuat permintaan ke jenis peta Anda jika API perlu menampilkan ubin peta dalam area tampilan yang terlihat dan tingkat zoom saat ini. Anda menangani permintaan ini untuk memutuskan ubin mana yang dimuat.
Catatan: Anda dapat membuat class sendiri untuk menerapkan antarmuka ini. Atau, jika memiliki gambar yang kompatibel, Anda dapat menggunakan class ImageMapType yang telah mengimplementasikan antarmuka ini.
Class yang mengimplementasikan antarmuka MapType mengharuskan Anda menentukan dan mengisi properti berikut:
tileSize(diperlukan) menentukan ukuran ubin (dengan jenisgoogle.maps.Size). Ukuran harus persegi panjang meskipun tidak perlu berbentuk persegi.maxZoom(diperlukan) menentukan tingkat zoom maksimum untuk menampilkan ubin jenis peta ini.minZoom(opsional) menentukan tingkat zoom minimum untuk menampilkan ubin jenis peta ini. Secara default, nilai ini adalah0yang menunjukkan bahwa tidak ada tingkat zoom minimum.name(opsional) menentukan nama untuk jenis peta ini. Properti ini hanya diperlukan jika Anda ingin jenis peta ini dapat dipilih dalam kontrol MapType. (Lihat Opsi Kontrol.)alt(opsional) menentukan teks alternatif untuk jenis peta ini, yang ditampilkan sebagai teks pengarahan kursor. Properti ini hanya diperlukan jika ingin jenis peta ini dapat dipilih dalam kontrol MapType. (Lihat Opsi Kontrol.)
Selain itu, class yang mengimplementasikan antarmuka MapType
perlu mengimplementasikan metode berikut:
-
getTile()(diperlukan) dipanggil setiap kali API menentukan bahwa peta perlu menampilkan ubin baru untuk area tampilan tertentu. MetodegetTile()ini harus memiliki tanda tangan berikut:getTile(tileCoord:Point,zoom:number,ownerDocument:Document):NodeAPI menentukan apakah perlu memanggil
getTile()berdasarkan propertitileSize,minZoom, danmaxZoomdariMapTypeserta area tampilan dan tingkat zoom saat ini di peta. Pengendali untuk metode ini akan menampilkan elemen HTML dengan memberikan koordinat yang diteruskan, tingkat zoom, dan elemen DOM yang akan ditambahkan gambar ubin. -
releaseTile()(opsional) dipanggil setiap kali API menentukan bahwa peta perlu menghapus ubin karena tidak masuk area tampilan. Metode ini harus memiliki tanda tangan berikut:releaseTile(tile:Node)Anda biasanya harus menangani penghapusan elemen yang terlampir ke ubin peta saat penambahan ke peta. Misalnya, jika Anda melampirkan pemroses peristiwa untuk memetakan overlay ubin peta, Anda harus menghapusnya di sini.
Metode getTile() berfungsi sebagai pengontrol utama untuk menentukan ubin yang akan dimuat dalam area tampilan tertentu.
Jenis Peta Dasar
Jenis peta yang Anda buat dengan cara ini dapat berdiri sendiri atau dikombinasikan dengan jenis peta lain sebagai overlay. Jenis peta mandiri dikenal sebagai jenis peta dasar. Anda mungkin ingin agar API memperlakukan MapType kustom tersebut seperti halnya jenis peta dasar lainnya yang sudah ada (ROADMAP, TERRAIN, dll.). Untuk melakukannya, tambahkan MapType kustom Anda ke properti mapTypes Map. Properti ini berjenis
MapTypeRegistry.
Kode berikut membuat MapType dasar untuk menampilkan koordinat ubin peta dan menggambar garis luar ubin:
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;
Jenis Peta Overlay
Beberapa jenis peta didesain untuk berfungsi sebagai tambahan atas jenis peta yang ada. Jenis peta tersebut mungkin memiliki lapisan transparan yang menunjukkan tempat menarik, atau menampilkan data tambahan kepada pengguna.
Dalam hal ini, Anda tidak ingin jenis peta tersebut diperlakukan sebagai entitas terpisah tetapi sebagai overlay.
Anda dapat melakukannya dengan menambahkan jenis peta ke MapType yang ada secara langsung menggunakan properti overlayMapTypes dari Map. Properti ini berisi
MVCArray dari MapType. Semua jenis peta (dasar dan overlay) dirender dalam lapisan mapPane. Jenis peta overlay akan ditampilkan di atas peta dasar
yang terkait dengannya, sesuai dengan urutan kemunculannya dalam
array Map.overlayMapTypes (overlay dengan nilai indeks yang lebih tinggi
ditampilkan di depan overlay dengan nilai indeks yang lebih rendah).
Contoh berikut identik dengan sebelumnya kecuali jika kami telah membuat overlay ubin MapType sebagai tambahan atas jenis peta 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;
Jenis Peta Gambar
Mengimplementasikan MapType untuk berfungsi sebagai jenis peta dasar bisa menjadi tugas yang memakan waktu dan melelahkan. API ini
menyediakan class khusus yang mengimplementasikan antarmuka MapType
untuk jenis peta paling umum: jenis peta yang terdiri dari ubin yang terdiri
dari file gambar tunggal.
Class ini, class ImageMapType, dibuat menggunakan spesifikasi objek ImageMapTypeOptions yang menentukan properti yang diperlukan berikut ini:
tileSize(diperlukan) menentukan ukuran ubin (dengan jenisgoogle.maps.Size). Ukuran harus persegi panjang meskipun tidak perlu berbentuk persegi.getTileUrl(diperlukan) menetapkan fungsi, biasanya disediakan sebagai literal fungsi segaris, untuk menangani pemilihan ubin gambar yang tepat berdasarkan koordinat dunia dan tingkat zoom yang diberikan.
Kode berikut menerapkan ImageMapType dasar menggunakan ubin bulan Google. Contoh ini menggunakan fungsi normalisasi
untuk memastikan ubin diulang di sepanjang sumbu x, tetapi tidak di sepanjang
sumbu y pada peta Anda.
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;
Proyeksi
Bumi adalah sebuah bola tiga dimensi (kurang-lebih), sedangkan sebuah peta adalah permukaan datar dua dimensi. Peta yang Anda lihat dalam Maps JavaScript API, seperti peta datar Bumi pada umumnya, adalah proyeksi bola bumi pada permukaan datar. Dalam istilah paling sederhana, proyeksi bisa didefinisikan sebagai pemetaan dari nilai garis lintang/garis bujur ke dalam koordinat pada peta proyeksi.
Proyeksi di Maps JavaScript API harus menerapkan
antarmuka Projection. Implementasi Projection
tidak hanya harus memberikan pemetaan dari satu sistem koordinat
ke sistem koordinat lainnya, tetapi juga pemetaan dua arah. Artinya, Anda harus
menentukan cara menerjemahkan dari koordinat Earth (objek LatLng)
ke sistem
koordinat
dunia dari class Projection, dan dari sistem koordinat dunia kembali ke koordinat Earth.
Google Maps menggunakan proyeksi Mercator untuk membuat peta dari data geografis dan mengonversi peristiwa di peta ke dalam koordinat geografis. Anda dapat memperoleh proyeksi ini dengan
memanggil getProjection() pada Map
(atau salah satu jenis MapType dasar standar.) Untuk sebagian besar penggunaan,
Projection standar ini sudah cukup, tetapi Anda juga dapat
menentukan dan menggunakan proyeksi kustom Anda sendiri.
Mengimplementasikan Proyeksi
Saat mengimplementasikan proyeksi khusus, Anda perlu mendefinisikan beberapa hal:
- Rumus untuk memetakan koordinat lintang dan bujur menjadi
bidang Kartesius dan rumus yang sesuai untuk memetakan dari bidang Kartesius ke koordinat lintang
dan bujur. (Antarmuka
Projectionhanya mendukung transformasi menjadi koordinat garis lurus.) - Ukuran ubin dasar. Semua ubin harus persegi panjang.
- "Ukuran dunia" pada peta menggunakan ubin dasar yang ditetapkan pada tingkat zoom 0. Perhatikan, untuk peta yang terdiri dari satu ubin di tingkat zoom 0, ukuran bumi dan ukuran ubin dasar identik.
Transformasi Koordinat dalam Proyeksi
Setiap proyeksi menyediakan dua metode yang menerjemahkan dua sistem koordinat ini, yang memungkinkan Anda mengonversi antara koordinat geografis dan koordinat dunia:
- Metode
Projection.fromLatLngToPoint()mengonversi nilaiLatLngmenjadi koordinat dunia. Metode ini digunakan untuk memosisikan overlay pada peta (dan memosisikan peta itu sendiri). - Metode
Projection.fromPointToLatLng()mengonversi koordinat dunia menjadi nilaiLatLng. Metode ini digunakan untuk mengonversi peristiwa seperti klik yang terjadi di peta menjadi koordinat geografis.
Google Maps beranggapan proyeksi berupa garis lurus.
Biasanya, Anda dapat menggunakan proyeksi untuk dua kasus: untuk membuat peta dunia, atau untuk membuat peta area lokal. Dalam kasus pertama, Anda harus memastikan proyeksi tersebut berupa garis lurus dan normal pada semua garis bujur. Beberapa proyeksi (terutama proyeksi kerucut) mungkin "secara lokal normal" (yaitu titik utara), tetapi menyimpang dari utara sebenarnya, misalnya, makin jauh peta diposisikan sesuai dengan beberapa garis bujur referensi. Anda dapat menggunakan proyeksi tersebut secara lokal, tetapi perhatikan bahwa proyeksi tersebut tentunya tidak akurat dan kesalahan transformasi akan menjadi jelas jika Anda makin jauh menyimpang dari garis bujur referensi.
Pilihan Ubin Peta dalam Proyeksi
Proyeksi tidak hanya berguna untuk menentukan posisi lokasi atau overlay, juga untuk memosisikan ubin peta itu sendiri.
Maps JavaScript API merender peta dasar menggunakan MapType, yang harus mendeklarasikan properti projection untuk mengidentifikasi proyeksi peta dan metode getTile() untuk mengambil ubin peta berdasarkan koordinat ubin. Koordinat ubin berdasarkan pada ukuran ubin dasar Anda (yang harus persegi panjang) dan "ukuran dunia" peta Anda, yang merupakan ukuran piksel dari peta dunia Anda pada tingkat zoom 0. (Untuk peta yang terdiri dari satu ubin pada tingkat zoom 0, ukuran ubin dan ukuran dunia adalah identik.)
Anda menentukan ukuran ubin dasar dalam properti
tileSize MapType. Anda menentukan ukuran dunia secara implisit
dalam metode fromLatLngToPoint()
dan fromPointToLatLng() proyeksi.
Karena pemilihan gambar bergantung pada nilai yang diteruskan ini, sebaiknya
beri nama pada gambar yang dapat dipilih secara terprogram
dengan nilai yang diteruskan tersebut, seperti
map_zoom_tileX_tileY.png.
Contoh berikut menentukan ImageMapType
menggunakan proyeksi
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();