เอกสารนี้กล่าวถึงประเภทแผนที่ที่คุณแสดงได้โดยใช้ Maps JavaScript API API จะใช้ออบเจ็กต์ MapType เพื่อเก็บข้อมูลเกี่ยวกับแผนที่เหล่านี้ MapType
คืออินเทอร์เฟซที่กำหนดการแสดงผลและการใช้งานชิ้นส่วนแผนที่และ
การแปลระบบพิกัดจากพิกัดหน้าจอเป็นพิกัดโลก (บนแผนที่) MapType แต่ละรายการต้องมีเมธอด 2-3 รายการเพื่อจัดการการดึงข้อมูลและการปล่อยไทล์ รวมถึงพร็อพเพอร์ตี้ที่กำหนดลักษณะการทำงานด้านภาพ
การทำงานภายในของประเภทแผนที่ภายใน Maps JavaScript API เป็นหัวข้อขั้นสูง นักพัฒนาซอฟต์แวร์ส่วนใหญ่สามารถใช้ ประเภทแผนที่พื้นฐานที่ระบุไว้ด้านล่าง อย่างไรก็ตาม คุณยังสามารถแก้ไขการแสดงผลของประเภทแผนที่ที่มีอยู่โดยใช้แผนที่สไตล์คุณหรือกำหนดชิ้นส่วนแผนที่ของคุณเองโดยใช้ประเภทแผนที่แบบกำหนดเองได้ด้วย เมื่อระบุแผนที่แบบกำหนดเอง คุณจะต้องเข้าใจวิธีแก้ไขรีจิสทรีประเภทแผนที่ของแผนที่
ประเภทแผนที่พื้นฐาน
Maps JavaScript API มีแผนที่ให้เลือก 4 ประเภท นอกจากชิ้นส่วนแผนที่ถนนแบบ "วาด" ที่คุ้นเคยแล้ว Maps JavaScript API ยังรองรับแผนที่ประเภทอื่นๆ ด้วย
Maps JavaScript API มีแผนที่ประเภทต่อไปนี้
roadmapแสดงมุมมองแผนที่ถนนเริ่มต้นพร้อมป้ายกำกับแผนที่ฐานsatelliteแสดงแผนที่ที่สมจริงซึ่งอิงตามภาพถ่ายทางอากาศhybridแสดงมุมมองแผนที่ดาวเทียมพร้อมป้ายกำกับแผนที่ฐานterrainแสดงแผนที่ทางกายภาพตามข้อมูลภูมิประเทศ
คุณแก้ไขประเภทแผนที่ที่ Map ใช้โดยการตั้งค่าพร็อพเพอร์ตี้ mapTypeId ไม่ว่าจะภายในคอนสตรัคเตอร์โดยการตั้งค่าออบเจ็กต์ Map options หรือโดยการเรียกใช้เมธอด setMapTypeId() ของแผนที่ พร็อพเพอร์ตี้ mapTypeID มีค่าเริ่มต้นเป็น roadmap
การตั้งค่า mapTypeId เมื่อสร้าง
var myLatlng = new google.maps.LatLng(-34.397, 150.644); var mapOptions = { zoom: 8, center: myLatlng, mapTypeId: 'satellite' }; var map = new google.maps.Map(document.getElementById('map'), mapOptions);
การแก้ไข mapTypeId แบบไดนามิก:
map.setMapTypeId('terrain');
โปรดทราบว่าคุณไม่ได้ตั้งค่าประเภทแผนที่ของแผนที่โดยตรง แต่ตั้งค่า mapTypeId เพื่ออ้างอิง MapType โดยใช้ตัวระบุแทน
Maps JavaScript API ใช้รีจิสทรีประเภทแผนที่ซึ่งอธิบายไว้ด้านล่างเพื่อจัดการการอ้างอิงเหล่านี้
แผนที่ 3 มิติ
Maps JavaScript API รองรับภาพ 3 มิติ การดำเนินการและความสามารถในการปรับแต่งหลายอย่างที่ใช้ได้กับแผนที่ 2 มิติจะใช้ได้กับแผนที่ 3 มิติด้วย
ดูข้อมูลเพิ่มเติมเกี่ยวกับแผนที่ 3 มิติได้ในภาพรวมแผนที่ 3 มิติ
ตัวอย่างต่อไปนี้แสดงมุมมอง 3 มิติของซานฟรานซิสโก
ดูข้อมูลเพิ่มเติมเกี่ยวกับแผนที่ 3 มิติได้ในภาพรวมแผนที่ 3 มิติ
ภาพ 45° (เลิกใช้งานแล้ว)
ตัวอย่างต่อไปนี้แสดงวิธีดูภาพมุมมอง 45° ของซานฟรานซิสโกโดยใช้แผนที่ 3 มิติ
TypeScript
async function init() { const { Map3DElement } = await google.maps.importLibrary('maps3d'); const map = new Map3DElement({ center: { lat: 37.789, lng: -122.401, altitude: 0, }, range: 2200, tilt: 45, heading: 188, }); map.mode = 'SATELLITE'; document.body.append(map); } void init();
JavaScript
async function init() { const { Map3DElement } = await google.maps.importLibrary('maps3d'); const map = new Map3DElement({ center: { lat: 37.789, lng: -122.401, altitude: 0, }, range: 2200, tilt: 45, heading: 188, }); map.mode = 'SATELLITE'; document.body.append(map); } void init();
CSS
/* * Always set the map height explicitly to define the size of the div element * that contains the map. */ #gmp-map-3d { height: 100%; } html, body { height: 100%; margin: 0; padding: 0; }
HTML
<html>
<head>
<title>3d map 45-degree perspective</title>
<link rel="stylesheet" type="text/css" href="./style.css" />
<script type="module" src="./index.js"></script>
<script>
// prettier-ignore
(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})({
key: "GOOGLE_MAPS_API_KEY"
});
</script>
</head>
<body>
<div id="map"></div>
</body>
</html>แก้ไขรีจิสทรีประเภทแผนที่
mapTypeId ของแผนที่เป็นตัวระบุสตริงที่ใช้เชื่อมโยง MapType กับค่าที่ไม่ซ้ำกัน ออบเจ็กต์ Map แต่ละรายการจะเก็บรักษา MapTypeRegistry ซึ่งมีคอลเล็กชันของ MapType ที่พร้อมใช้งานสำหรับแผนที่นั้น ตัวอย่างเช่น รีจิสทรีนี้ใช้เพื่อเลือกประเภทแผนที่ที่พร้อมใช้งานในการควบคุม MapType ของแผนที่
คุณไม่ได้อ่านจากรีจิสทรีประเภทแผนที่โดยตรง แต่คุณจะแก้ไขรีจิสทรีโดยเพิ่มประเภทแผนที่แบบกำหนดเองและเชื่อมโยงกับตัวระบุสตริงที่คุณเลือก คุณไม่สามารถแก้ไขหรือเปลี่ยนแปลงประเภทแผนที่พื้นฐาน (แต่สามารถนำออกจากแผนที่ได้โดยการเปลี่ยนลักษณะที่ปรากฏของ mapTypeControlOptions ที่เชื่อมโยงกับแผนที่)
โค้ดต่อไปนี้จะตั้งค่าแผนที่ให้แสดงแผนที่เพียง 2 ประเภทใน mapTypeControlOptions ของแผนที่ และแก้ไขรีจิสทรีเพื่อเพิ่มการเชื่อมโยงกับตัวระบุนี้กับการใช้งานจริงของอินเทอร์เฟซ MapType
// Modify the control to only display two maptypes, the // default ROADMAP and the custom 'mymap'. // Note that because this is an association, we // don't need to modify the MapTypeRegistry beforehand. var MY_MAPTYPE_ID = 'mymaps'; var mapOptions = { zoom: 12, center: brooklyn, mapTypeControlOptions: { mapTypeIds: ['roadmap', MY_MAPTYPE_ID] }, mapTypeId: MY_MAPTYPE_ID }; // Create our map. This creation will implicitly create a // map type registry. map = new google.maps.Map(document.getElementById('map'), mapOptions); // Create your custom map type using your own code. // (See below.) var myMapType = new MyMapType(); // Set the registry to associate 'mymap' with the // custom map type we created, and set the map to // show that map type. map.mapTypes.set(MY_MAPTYPE_ID, myMapType);
แผนที่ที่มีการปรับลักษณะ
StyledMapType ช่วยให้คุณปรับแต่งการนำเสนอแผนที่ฐานมาตรฐานของ Google โดยเปลี่ยนการแสดงผลภาพขององค์ประกอบต่างๆ เช่น ถนน สวนสาธารณะ และพื้นที่ที่สร้างขึ้น เพื่อให้แสดงสไตล์ที่แตกต่างจากที่ใช้ในประเภทแผนที่เริ่มต้น StyledMapType จะส่งผลต่อประเภทแผนที่ roadmap เริ่มต้นเท่านั้น
ดูข้อมูลเพิ่มเติมเกี่ยวกับ StyledMapType ได้ที่การใช้การประกาศสไตล์ JSON แบบฝัง
ประเภทแผนที่แบบกำหนดเอง
Maps JavaScript API รองรับการแสดงผลและการจัดการประเภทแผนที่แบบกำหนดเอง ซึ่งช่วยให้คุณใช้ภาพแผนที่หรือการวางซ้อนไทล์ของคุณเองได้
Maps JavaScript API มีการใช้งานประเภทแผนที่ที่เป็นไปได้หลายอย่าง ดังนี้
- ชุดชิ้นส่วนภาพมาตรฐานที่ประกอบด้วยรูปภาพซึ่งรวมกันเป็นแผนที่การทำแผนที่แบบเต็ม ชุดไทล์เหล่านี้เรียกอีกอย่างว่าประเภทแผนที่ฐาน ประเภทแผนที่เหล่านี้ทำงานและทำงานเหมือนกับประเภทแผนที่เริ่มต้นที่มีอยู่ ได้แก่
roadmap,satellite,hybridและterrainคุณสามารถเพิ่มประเภทแผนที่ที่กำหนดเองลงในอาร์เรย์mapTypesของแผนที่เพื่อให้ UI ภายใน Maps JavaScript API ถือว่าประเภทแผนที่ที่กำหนดเองเป็นประเภทแผนที่มาตรฐาน (เช่น โดยรวมไว้ในตัวควบคุม MapType) - การวางซ้อนชิ้นส่วนแผนที่รูปภาพซึ่งแสดงที่ด้านบนของประเภทแผนที่ฐานที่มีอยู่ โดยทั่วไปแล้ว แผนที่ประเภทนี้จะใช้เพื่อเสริมแผนที่ประเภทที่มีอยู่เพื่อแสดงข้อมูลเพิ่มเติม และมักจะจำกัดไว้เฉพาะสถานที่และ/หรือระดับการซูมที่เฉพาะเจาะจง โปรดทราบว่าไทล์เหล่านี้อาจโปร่งใส ซึ่งช่วยให้คุณเพิ่มฟีเจอร์ลงในแผนที่ที่มีอยู่ได้
- ประเภทแผนที่ที่ไม่ใช่แผนที่รูปภาพ ซึ่งช่วยให้คุณจัดการการแสดงข้อมูลแผนที่ในระดับพื้นฐานที่สุดได้
ตัวเลือกแต่ละรายการเหล่านี้อาศัยการสร้างคลาสที่ใช้การติดตั้งใช้งานอินเทอร์เฟซ MapType นอกจากนี้ คลาส
ImageMapType ยังมีลักษณะการทำงานในตัวบางอย่างเพื่อลดความซับซ้อนในการสร้างประเภทแผนที่ภาพ
อินเทอร์เฟซ MapType
ก่อนที่จะสร้างคลาสที่ใช้ MapType คุณควรทำความเข้าใจวิธีที่ Google Maps กำหนดพิกัดและตัดสินใจว่าจะแสดงส่วนใดของแผนที่ คุณต้องใช้ตรรกะที่คล้ายกันสำหรับประเภทแผนที่ฐานหรือแผนที่ซ้อนทับ
อ่านคำแนะนำเกี่ยวกับพิกัดแผนที่และพิกัดแผนที่ย่อย
แผนที่แบบกำหนดเองต้องใช้อินเทอร์เฟซ MapType อินเทอร์เฟซนี้ระบุพร็อพเพอร์ตี้และเมธอดบางอย่างที่ช่วยให้ API เริ่มต้นคำขอไปยังประเภทแผนที่ของคุณได้เมื่อ API พิจารณาแล้วว่าจำเป็นต้องแสดงไทล์แผนที่ภายในวิวพอร์ตและระดับการซูมปัจจุบัน คุณจะจัดการคำขอเหล่านี้เพื่อตัดสินใจว่าจะโหลดการ์ดใด
หมายเหตุ: คุณสามารถสร้างคลาสของคุณเองเพื่อใช้อินเทอร์เฟซนี้ หรือหากมีภาพที่เข้ากันได้ คุณสามารถใช้คลาส
ImageMapType ซึ่งใช้อินเทอร์เฟซนี้อยู่แล้ว
คลาสที่ใช้อินเทอร์เฟซ MapType กำหนดให้คุณต้องกำหนดและป้อนข้อมูลพร็อพเพอร์ตี้ต่อไปนี้
tileSize(ต้องระบุ) ระบุขนาดของหน้าต่าง (ประเภทgoogle.maps.Size) ขนาดต้องเป็นสี่เหลี่ยมผืนผ้า แต่ไม่จำเป็นต้องเป็นสี่เหลี่ยมจัตุรัสmaxZoom(ต้องระบุ) ระบุระดับการซูมสูงสุดที่จะแสดงชิ้นส่วนแผนที่ของแผนที่ประเภทนี้minZoom(ไม่บังคับ) ระบุระดับการซูมขั้นต่ำที่จะแสดงไทล์ของแผนที่ประเภทนี้ โดยค่าเริ่มต้น ค่านี้คือ0ซึ่งหมายความว่าไม่มีระดับการซูมขั้นต่ำname(ไม่บังคับ) ระบุชื่อสำหรับประเภทแผนที่นี้ พร็อพเพอร์ตี้นี้จำเป็นก็ต่อเมื่อคุณต้องการให้เลือกประเภทแผนที่นี้ได้ภายในตัวควบคุม MapType (ดู ตัวเลือกการควบคุม)alt(ไม่บังคับ) ระบุข้อความสำรองสำหรับแผนที่ประเภทนี้ ซึ่งจะแสดงเป็นข้อความเมื่อวางเมาส์เหนือ พร็อพเพอร์ตี้นี้จำเป็นก็ต่อเมื่อคุณต้องการให้เลือกประเภทแผนที่นี้ได้ภายในตัวควบคุม MapType (ดูตัวเลือกการควบคุม)
นอกจากนี้ คลาสที่ใช้การติดตั้งใช้งานอินเทอร์เฟซ MapType จะต้องใช้การติดตั้งใช้งานเมธอดต่อไปนี้ด้วย
-
ระบบจะเรียกใช้
getTile()(จำเป็น) ทุกครั้งที่ API พิจารณาว่าแผนที่ต้องแสดงไทล์ใหม่สำหรับวิวพอร์ตที่ระบุ เมธอดgetTile()ต้องมีซิกเนเจอร์ต่อไปนี้getTile(tileCoord:Point,zoom:number,ownerDocument:Document):NodeAPI จะพิจารณาว่าจำเป็นต้องเรียกใช้
getTile()หรือไม่โดยอิงตามพร็อพเพอร์ตี้tileSize,minZoomและmaxZoomของMapTypeรวมถึงวิวพอร์ตและระดับการซูมปัจจุบันของแผนที่ เครื่องจัดการสำหรับเมธอดนี้ควรแสดงผลองค์ประกอบ HTML ที่มีพิกัด ระดับการซูม และองค์ประกอบ DOM ที่ส่งมาเพื่อเพิ่มรูปภาพไทล์ -
ระบบจะเรียกใช้
releaseTile()(ไม่บังคับ) เมื่อใดก็ตามที่ API พิจารณาว่าแผนที่จำเป็นต้องนำไทล์ออกเนื่องจากอยู่นอกมุมมอง เมธอดนี้ต้องมีลายเซ็นต่อไปนี้releaseTile(tile:Node)โดยปกติแล้ว คุณควรจัดการการนำองค์ประกอบที่แนบมากับไทล์แผนที่ออกเมื่อเพิ่มลงในแผนที่ ตัวอย่างเช่น หากคุณแนบ Listener เหตุการณ์กับภาพซ้อนทับไทล์แผนที่ คุณควรนำ Listener เหตุการณ์ออกที่นี่
เมธอด getTile() ทำหน้าที่เป็นตัวควบคุมหลักในการกำหนดว่าจะโหลดไทล์ใดภายในวิวพอร์ตที่ระบุ
ประเภทแผนที่ฐาน
ประเภทแผนที่ที่คุณสร้างในลักษณะนี้อาจเป็นแบบสแตนด์อโลนหรือรวมกับประเภทแผนที่อื่นๆ เป็นการวางซ้อนก็ได้ ประเภทแผนที่แบบสแตนด์อโลนเรียกว่าประเภทแผนที่ฐาน คุณอาจต้องการให้ API จัดการ MapType ที่กำหนดเองดังกล่าวเหมือนกับประเภทแผนที่ฐานอื่นๆ ที่มีอยู่ (ROADMAP, TERRAIN ฯลฯ) โดยเพิ่ม MapType ที่กำหนดเองลงในพร็อพเพอร์ตี้ mapTypes ของ Map พร็อพเพอร์ตี้นี้เป็นประเภท MapTypeRegistry
โค้ดต่อไปนี้จะสร้าง MapType พื้นฐานเพื่อแสดงพิกัดแผนที่ย่อยของแผนที่และวาดโครงร่างของแผนที่ย่อย
TypeScript
/* * This demo demonstrates how to replace default map tiles with custom imagery. * In this case, the CoordMapType displays gray tiles annotated with the tile * coordinates. * * Try panning and zooming the map to see how the coordinates change. */ class CoordMapType { tileSize: google.maps.Size; maxZoom = 19; name = "Tile #s"; alt = "Tile Coordinate Map Type"; constructor(tileSize: google.maps.Size) { this.tileSize = tileSize; } getTile( coord: google.maps.Point, zoom: number, ownerDocument: Document ): HTMLElement { const div = ownerDocument.createElement("div"); div.innerHTML = String(coord); div.style.width = this.tileSize.width + "px"; div.style.height = this.tileSize.height + "px"; div.style.fontSize = "10"; div.style.borderStyle = "solid"; div.style.borderWidth = "1px"; div.style.borderColor = "#AAAAAA"; div.style.backgroundColor = "#E5E3DF"; return div; } releaseTile(tile: HTMLElement): void {} } function initMap(): void { const map = new google.maps.Map( document.getElementById("map") as HTMLElement, { zoom: 10, center: { lat: 41.85, lng: -87.65 }, streetViewControl: false, mapTypeId: "coordinate", mapTypeControlOptions: { mapTypeIds: ["coordinate", "roadmap"], style: google.maps.MapTypeControlStyle.DROPDOWN_MENU, }, } ); map.addListener("maptypeid_changed", () => { const showStreetViewControl = (map.getMapTypeId() as string) !== "coordinate"; map.setOptions({ streetViewControl: showStreetViewControl, }); }); // Now attach the coordinate map type to the map's registry. map.mapTypes.set( "coordinate", new CoordMapType(new google.maps.Size(256, 256)) ); } declare global { interface Window { initMap: () => void; } } window.initMap = initMap;
JavaScript
/* * This demo demonstrates how to replace default map tiles with custom imagery. * In this case, the CoordMapType displays gray tiles annotated with the tile * coordinates. * * Try panning and zooming the map to see how the coordinates change. */ class CoordMapType { tileSize; maxZoom = 19; name = "Tile #s"; alt = "Tile Coordinate Map Type"; constructor(tileSize) { this.tileSize = tileSize; } getTile(coord, zoom, ownerDocument) { const div = ownerDocument.createElement("div"); div.innerHTML = String(coord); div.style.width = this.tileSize.width + "px"; div.style.height = this.tileSize.height + "px"; div.style.fontSize = "10"; div.style.borderStyle = "solid"; div.style.borderWidth = "1px"; div.style.borderColor = "#AAAAAA"; div.style.backgroundColor = "#E5E3DF"; return div; } releaseTile(tile) {} } function initMap() { const map = new google.maps.Map(document.getElementById("map"), { zoom: 10, center: { lat: 41.85, lng: -87.65 }, streetViewControl: false, mapTypeId: "coordinate", mapTypeControlOptions: { mapTypeIds: ["coordinate", "roadmap"], style: google.maps.MapTypeControlStyle.DROPDOWN_MENU, }, }); map.addListener("maptypeid_changed", () => { const showStreetViewControl = map.getMapTypeId() !== "coordinate"; map.setOptions({ streetViewControl: showStreetViewControl, }); }); // Now attach the coordinate map type to the map's registry. map.mapTypes.set( "coordinate", new CoordMapType(new google.maps.Size(256, 256)), ); } window.initMap = initMap;
ประเภทแผนที่ซ้อนทับ
แผนที่บางประเภทออกแบบมาให้ทำงานร่วมกับแผนที่ประเภทที่มีอยู่ แผนที่ประเภทดังกล่าวอาจมีเลเยอร์โปร่งใสที่ระบุจุดที่น่าสนใจหรือแสดงข้อมูลเพิ่มเติมแก่ผู้ใช้
ในกรณีเหล่านี้ คุณไม่ต้องการให้ระบบถือว่าประเภทแผนที่เป็นเอนทิตีแยกต่างหาก แต่เป็นภาพซ้อนทับ
ซึ่งทำได้โดยเพิ่มประเภทแผนที่ลงใน MapType ที่มีอยู่โดยตรงโดยใช้พร็อพเพอร์ตี้ overlayMapTypes ของ Map พร็อพเพอร์ตี้นี้มี MVCArray ของ MapType แผนที่ทุกประเภท (ฐานและวางซ้อน) จะแสดงผลภายในเลเยอร์ mapPane ประเภทแผนที่ซ้อนทับจะแสดงที่ด้านบนของแผนที่ฐานที่แนบมาด้วย ตามลำดับที่ปรากฏในอาร์เรย์ Map.overlayMapTypes (การซ้อนทับที่มีค่าดัชนีสูงกว่าจะแสดงด้านหน้าการซ้อนทับที่มีค่าดัชนีต่ำกว่า)
ตัวอย่างต่อไปนี้เหมือนกับตัวอย่างก่อนหน้า ยกเว้นว่าเราได้สร้างการวางซ้อนชิ้นส่วนแผนที่ MapType ไว้ด้านบนของประเภทแผนที่ ROADMAP
TypeScript
/* * This demo illustrates the coordinate system used to display map tiles in the * API. * * Tiles in Google Maps are numbered from the same origin as that for * pixels. For Google's implementation of the Mercator projection, the origin * tile is always at the northwest corner of the map, with x values increasing * from west to east and y values increasing from north to south. * * Try panning and zooming the map to see how the coordinates change. */ class CoordMapType implements google.maps.MapType { tileSize: google.maps.Size; alt: string|null = null; maxZoom: number = 17; minZoom: number = 0; name: string|null = null; projection: google.maps.Projection|null = null; radius: number = 6378137; constructor(tileSize: google.maps.Size) { this.tileSize = tileSize; } getTile( coord: google.maps.Point, zoom: number, ownerDocument: Document ): HTMLElement { const div = ownerDocument.createElement("div"); div.innerHTML = String(coord); div.style.width = this.tileSize.width + "px"; div.style.height = this.tileSize.height + "px"; div.style.fontSize = "10"; div.style.borderStyle = "solid"; div.style.borderWidth = "1px"; div.style.borderColor = "#AAAAAA"; return div; } releaseTile(tile: Element): void {} } function initMap(): void { const map = new google.maps.Map( document.getElementById("map") as HTMLElement, { zoom: 10, center: { lat: 41.85, lng: -87.65 }, } ); // Insert this overlay map type as the first overlay map type at // position 0. Note that all overlay map types appear on top of // their parent base map. const coordMapType = new CoordMapType(new google.maps.Size(256, 256)) map.overlayMapTypes.insertAt( 0, coordMapType ); } declare global { interface Window { initMap: () => void; } } window.initMap = initMap;
JavaScript
/* * This demo illustrates the coordinate system used to display map tiles in the * API. * * Tiles in Google Maps are numbered from the same origin as that for * pixels. For Google's implementation of the Mercator projection, the origin * tile is always at the northwest corner of the map, with x values increasing * from west to east and y values increasing from north to south. * * Try panning and zooming the map to see how the coordinates change. */ class CoordMapType { tileSize; alt = null; maxZoom = 17; minZoom = 0; name = null; projection = null; radius = 6378137; constructor(tileSize) { this.tileSize = tileSize; } getTile(coord, zoom, ownerDocument) { const div = ownerDocument.createElement("div"); div.innerHTML = String(coord); div.style.width = this.tileSize.width + "px"; div.style.height = this.tileSize.height + "px"; div.style.fontSize = "10"; div.style.borderStyle = "solid"; div.style.borderWidth = "1px"; div.style.borderColor = "#AAAAAA"; return div; } releaseTile(tile) {} } function initMap() { const map = new google.maps.Map(document.getElementById("map"), { zoom: 10, center: { lat: 41.85, lng: -87.65 }, }); // Insert this overlay map type as the first overlay map type at // position 0. Note that all overlay map types appear on top of // their parent base map. const coordMapType = new CoordMapType(new google.maps.Size(256, 256)); map.overlayMapTypes.insertAt(0, coordMapType); } window.initMap = initMap;
ประเภทแผนที่รูปภาพ
การใช้ MapType เพื่อทำหน้าที่เป็นประเภทแผนที่ฐานอาจเป็นงานที่ใช้เวลานานและต้องใช้แรงงานมาก API มีคลาสพิเศษที่ใช้อินเทอร์เฟซ MapType สำหรับประเภทแผนที่ที่พบบ่อยที่สุด ซึ่งก็คือประเภทแผนที่ที่ประกอบด้วยชิ้นส่วนที่สร้างจากไฟล์ภาพเดียว
คลาสนี้ ซึ่งก็คือคลาส ImageMapType สร้างขึ้นโดยใช้ข้อกำหนดออบเจ็กต์ ImageMapTypeOptions ที่กำหนดพร็อพเพอร์ตี้ที่จำเป็นต่อไปนี้
tileSize(ต้องระบุ) ระบุขนาดของหน้าต่าง (ประเภทgoogle.maps.Size) ขนาดต้องเป็นสี่เหลี่ยมผืนผ้า แต่ไม่จำเป็นต้องเป็นสี่เหลี่ยมจัตุรัสgetTileUrl(ต้องระบุ) ระบุฟังก์ชัน ซึ่งมักจะระบุเป็นลิเทอรัลฟังก์ชันในบรรทัด เพื่อจัดการการเลือกไทล์รูปภาพที่เหมาะสมตามพิกัดโลกและระดับการซูมที่ระบุ
โค้ดต่อไปนี้ใช้ ImageMapType พื้นฐานโดยใช้ไทล์ดวงจันทร์ของ Google ตัวอย่างนี้ใช้ฟังก์ชันการปรับมาตรฐานเพื่อให้แน่ใจว่าไทล์จะซ้ำกันตามแกน x แต่ไม่ซ้ำกันตามแกน y ของแผนที่
TypeScript
function initMap(): void { const map = new google.maps.Map( document.getElementById("map") as HTMLElement, { center: { lat: 0, lng: 0 }, zoom: 1, streetViewControl: false, mapTypeControlOptions: { mapTypeIds: ["moon"], }, } ); const moonMapType = new google.maps.ImageMapType({ getTileUrl: function (coord, zoom): string { const normalizedCoord = getNormalizedCoord(coord, zoom); if (!normalizedCoord) { return ""; } const bound = Math.pow(2, zoom); return ( "https://mw1.google.com/mw-planetary/lunar/lunarmaps_v1/clem_bw" + "/" + zoom + "/" + normalizedCoord.x + "/" + (bound - normalizedCoord.y - 1) + ".jpg" ); }, tileSize: new google.maps.Size(256, 256), maxZoom: 9, minZoom: 0, // @ts-ignore TODO 'radius' does not exist in type 'ImageMapTypeOptions' radius: 1738000, name: "Moon", }); map.mapTypes.set("moon", moonMapType); map.setMapTypeId("moon"); } // Normalizes the coords that tiles repeat across the x axis (horizontally) // like the standard Google map tiles. function getNormalizedCoord(coord, zoom) { const y = coord.y; let x = coord.x; // tile range in one direction range is dependent on zoom level // 0 = 1 tile, 1 = 2 tiles, 2 = 4 tiles, 3 = 8 tiles, etc const tileRange = 1 << zoom; // don't repeat across y-axis (vertically) if (y < 0 || y >= tileRange) { return null; } // repeat across x-axis if (x < 0 || x >= tileRange) { x = ((x % tileRange) + tileRange) % tileRange; } return { x: x, y: y }; } declare global { interface Window { initMap: () => void; } } window.initMap = initMap;
JavaScript
function initMap() { const map = new google.maps.Map(document.getElementById("map"), { center: { lat: 0, lng: 0 }, zoom: 1, streetViewControl: false, mapTypeControlOptions: { mapTypeIds: ["moon"], }, }); const moonMapType = new google.maps.ImageMapType({ getTileUrl: function (coord, zoom) { const normalizedCoord = getNormalizedCoord(coord, zoom); if (!normalizedCoord) { return ""; } const bound = Math.pow(2, zoom); return ( "https://mw1.google.com/mw-planetary/lunar/lunarmaps_v1/clem_bw" + "/" + zoom + "/" + normalizedCoord.x + "/" + (bound - normalizedCoord.y - 1) + ".jpg" ); }, tileSize: new google.maps.Size(256, 256), maxZoom: 9, minZoom: 0, // @ts-ignore TODO 'radius' does not exist in type 'ImageMapTypeOptions' radius: 1738000, name: "Moon", }); map.mapTypes.set("moon", moonMapType); map.setMapTypeId("moon"); } // Normalizes the coords that tiles repeat across the x axis (horizontally) // like the standard Google map tiles. function getNormalizedCoord(coord, zoom) { const y = coord.y; let x = coord.x; // tile range in one direction range is dependent on zoom level // 0 = 1 tile, 1 = 2 tiles, 2 = 4 tiles, 3 = 8 tiles, etc const tileRange = 1 << zoom; // don't repeat across y-axis (vertically) if (y < 0 || y >= tileRange) { return null; } // repeat across x-axis if (x < 0 || x >= tileRange) { x = ((x % tileRange) + tileRange) % tileRange; } return { x: x, y: y }; } window.initMap = initMap;
การคาดการณ์
โลกเป็นทรงกลม 3 มิติ (โดยประมาณ) ในขณะที่แผนที่เป็นพื้นผิว 2 มิติแบบแบนราบ แผนที่ที่คุณเห็นภายใน Maps JavaScript API เช่นเดียวกับแผนที่แบนราบของโลก คือการฉายภาพทรงกลมนั้นลงบนพื้นผิวเรียบ พูดง่ายๆ ก็คือ การฉายภาพแผนที่สามารถกำหนดเป็นการแมปค่าละติจูด/ลองจิจูดเป็นพิกัดบนแผนที่ของการฉายภาพ
การฉายภาพใน Maps JavaScript API ต้องใช้อินเทอร์เฟซ Projection การติดตั้งใช้งาน Projection ต้องไม่เพียงแต่ให้การแมปจากระบบพิกัดหนึ่งไปยังอีกระบบหนึ่งเท่านั้น แต่ยังต้องให้การแมปแบบ 2 ทิศทางด้วย กล่าวคือ คุณต้องกำหนดวิธีแปลจากพิกัดโลก (ออบเจ็กต์ LatLng) เป็นระบบพิกัดโลกของคลาส Projection และจากระบบพิกัดโลกกลับเป็นพิกัดโลก
Google Maps ใช้การฉายภาพแบบเมอร์เคเตอร์เพื่อสร้างแผนที่จากข้อมูลทางภูมิศาสตร์และแปลงเหตุการณ์บนแผนที่เป็นพิกัดทางภูมิศาสตร์ คุณสามารถรับการคาดการณ์นี้ได้โดยเรียกใช้ getProjection() ใน Map (หรือประเภท MapType พื้นฐานมาตรฐานใดก็ได้) สำหรับการใช้งานส่วนใหญ่ Projection มาตรฐานนี้จะเพียงพอ แต่คุณยังสามารถกำหนดและใช้การฉายภาพที่กำหนดเองได้ด้วย
ใช้การฉายภาพ
เมื่อใช้การฉายภาพที่กำหนดเอง คุณจะต้องกำหนดสิ่งต่อไปนี้
- สูตรสำหรับการแมปพิกัดละติจูดและลองจิจูดเป็นระนาบคาร์ทีเซียน และสูตรที่เกี่ยวข้องสำหรับการแมปจากระนาบคาร์ทีเซียนเป็นพิกัดละติจูดและลองจิจูด (อินเทอร์เฟซ
Projectionรองรับเฉพาะการแปลงเป็นพิกัดสี่เหลี่ยมผืนผ้าเท่านั้น) - ขนาดชิ้นส่วนแผนที่ฐาน ไทล์ทั้งหมดต้องเป็นสี่เหลี่ยมผืนผ้า
- "ขนาดโลก" ของแผนที่ที่ใช้ชุดไทล์ฐานที่ระดับการซูม 0 โปรดทราบว่าสำหรับแผนที่ที่ประกอบด้วยไทล์ 1 รายการที่การซูม 0 ขนาดโลกและขนาดไทล์ฐานจะเหมือนกัน
การเปลี่ยนรูปแบบพิกัดในการฉายภาพ
การฉายภาพแต่ละแบบมี 2 วิธีในการแปลระหว่างระบบพิกัดทั้ง 2 ระบบนี้ ซึ่งช่วยให้คุณแปลงระหว่างพิกัดทางภูมิศาสตร์และพิกัดโลกได้ ดังนี้
- เมธอด
Projection.fromLatLngToPoint()จะแปลงค่าLatLngเป็นพิกัดโลก ระบบจะใช้วิธีนี้เพื่อจัดตำแหน่งการวางซ้อนบนแผนที่ (และเพื่อจัดตำแหน่งแผนที่เอง) - เมธอด
Projection.fromPointToLatLng()จะแปลงพิกัดโลกเป็นค่าLatLngวิธีนี้ใช้เพื่อแปลงเหตุการณ์ต่างๆ เช่น การคลิกที่เกิดขึ้นบนแผนที่ให้เป็นพิกัดทางภูมิศาสตร์
Google Maps จะถือว่าการฉายภาพเป็นแบบเส้นตรง
โดยทั่วไป คุณอาจใช้การฉายภาพใน 2 กรณี ได้แก่ เพื่อสร้างแผนที่โลก หรือเพื่อสร้างแผนที่ของพื้นที่ในท้องถิ่น ในกรณีแรก คุณควรตรวจสอบว่าการฉายภาพเป็นแบบเส้นตรงและปกติในลองจิจูดทั้งหมดด้วย การฉายภาพบางแบบ (โดยเฉพาะการฉายภาพทรงกรวย) อาจเป็น "ปกติในพื้นที่" (เช่น ชี้ไปทางทิศเหนือ) แต่เบี่ยงเบนไปจากทิศเหนือจริง เช่น ยิ่งแผนที่อยู่ในตำแหน่งที่สัมพันธ์กับลองจิจูดอ้างอิงบางค่ามากเท่าใด คุณอาจใช้การฉายภาพดังกล่าวในพื้นที่ แต่โปรดทราบว่าการฉายภาพนั้นไม่แม่นยำ และข้อผิดพลาดในการเปลี่ยนรูปแบบจะปรากฏชัดเจนมากขึ้นเมื่อคุณเบี่ยงเบนออกจากลองจิจูดอ้างอิงมากขึ้น
การเลือกไทล์แผนที่ในการฉายภาพ
การฉายภาพไม่เพียงมีประโยชน์ในการกำหนดตำแหน่งของสถานที่หรือการวางซ้อนเท่านั้น แต่ยังใช้ในการจัดตำแหน่งไทล์แผนที่ด้วย
Maps JavaScript API แสดงผลแผนที่ฐานโดยใช้อินเทอร์เฟซ MapType ซึ่งต้องประกาศทั้งพร็อพเพอร์ตี้ projection เพื่อระบุการฉายภาพของแผนที่และเมธอด getTile() เพื่อดึงข้อมูลไทล์แผนที่ตามค่าพิกัดไทล์ พิกัดแผนที่ย่อยจะอิงตามทั้งขนาดแผนที่ย่อยพื้นฐาน (ซึ่งต้องเป็นสี่เหลี่ยมผืนผ้า) และ "ขนาดโลก" ของแผนที่ ซึ่งเป็นขนาดพิกเซลของโลกแผนที่ที่ระดับการซูม 0 (สำหรับแผนที่ที่ประกอบด้วยไทล์เดียวที่การซูม 0 ขนาดไทล์และขนาดโลกจะเหมือนกัน)
คุณกำหนดขนาดการ์ดพื้นฐานภายในพร็อพเพอร์ตี้ tileSize ของ MapType คุณกำหนดขนาดโลกโดยนัยภายในเมธอด fromLatLngToPoint() และ fromPointToLatLng() ของการฉายภาพ
เนื่องจากการเลือกรูปภาพขึ้นอยู่กับค่าที่ส่งมาเหล่านี้ การตั้งชื่อรูปภาพที่เลือกแบบเป็นโปรแกรมได้จึงมีประโยชน์เมื่อพิจารณาจากค่าที่ส่งมา เช่น map_zoom_tileX_tileY.png
ตัวอย่างต่อไปนี้กำหนด ImageMapType โดยใช้การฉายภาพ
Gall-Peters
TypeScript
// This example defines an image map type using the Gall-Peters // projection. // https://en.wikipedia.org/wiki/Gall%E2%80%93Peters_projection const mapElement = document.querySelector('gmp-map')!; let innerMap: google.maps.Map; async function init() { // Request the needed libraries. await google.maps.importLibrary('maps'); // Create a map. innerMap = mapElement.innerMap; innerMap.setOptions({ mapTypeControl: false, }); // Set the Gall-Peters map type. const gallPetersMapType = await initGallPeters(); innerMap.mapTypes.set('gallPeters', gallPetersMapType); innerMap.setMapTypeId('gallPeters'); // Show the lat and lng under the mouse cursor. const coordsDiv = document.getElementById('coords')!; innerMap.addListener('mousemove', (event: google.maps.MapMouseEvent) => { coordsDiv.textContent = `lat: ${String(Math.round(event.latLng!.lat()))}, lng: ${String(Math.round(event.latLng!.lng()))}`; }); // Add some markers to the map. innerMap.data.setStyle((feature) => { return { title: feature.getProperty('name') as string, optimized: false, }; }); innerMap.data.addGeoJson(cities); } async function initGallPeters(): Promise<google.maps.ImageMapType> { const [{ ImageMapType }, { Size, Point, LatLng }] = await Promise.all([ google.maps.importLibrary('maps'), google.maps.importLibrary('core'), ]); const GALL_PETERS_RANGE_X = 800; const GALL_PETERS_RANGE_Y = 512; // Fetch Gall-Peters tiles stored locally on our server. const gallPetersMapType = new ImageMapType({ getTileUrl(coord, zoom) { const scale = 1 << zoom; // Wrap tiles horizontally. const x = ((coord.x % scale) + scale) % scale; // Don't wrap tiles vertically. const y = coord.y; if (y < 0 || y >= scale) return ''; return `gall-peters_${String(zoom)}_${String(x)}_${String(y)}.png`; }, tileSize: new Size(GALL_PETERS_RANGE_X, GALL_PETERS_RANGE_Y), minZoom: 0, maxZoom: 1, name: 'Gall-Peters', }); // Describe the Gall-Peters projection used by these tiles. gallPetersMapType.projection = { fromLatLngToPoint(latLng: google.maps.LatLng) { const latRadians = (latLng.lat() * Math.PI) / 180; return new Point( GALL_PETERS_RANGE_X * (0.5 + latLng.lng() / 360), GALL_PETERS_RANGE_Y * (0.5 - 0.5 * Math.sin(latRadians)) ); }, fromPointToLatLng(point: google.maps.Point, noWrap?: boolean) { const x = point.x / GALL_PETERS_RANGE_X; const y = Math.max(0, Math.min(1, point.y / GALL_PETERS_RANGE_Y)); return new LatLng( (Math.asin(1 - 2 * y) * 180) / Math.PI, -180 + 360 * x, noWrap ); }, }; return gallPetersMapType; } // GeoJSON, describing the locations and names of some cities. const cities = { type: 'FeatureCollection', features: [ { type: 'Feature', geometry: { type: 'Point', coordinates: [-87.65, 41.85] }, properties: { name: 'Chicago' }, }, { type: 'Feature', geometry: { type: 'Point', coordinates: [-149.9, 61.218] }, properties: { name: 'Anchorage' }, }, { type: 'Feature', geometry: { type: 'Point', coordinates: [-99.127, 19.427] }, properties: { name: 'Mexico City' }, }, { type: 'Feature', geometry: { type: 'Point', coordinates: [-0.126, 51.5] }, properties: { name: 'London' }, }, { type: 'Feature', geometry: { type: 'Point', coordinates: [28.045, -26.201] }, properties: { name: 'Johannesburg' }, }, { type: 'Feature', geometry: { type: 'Point', coordinates: [15.322, -4.325] }, properties: { name: 'Kinshasa' }, }, { type: 'Feature', geometry: { type: 'Point', coordinates: [151.207, -33.867] }, properties: { name: 'Sydney' }, }, { type: 'Feature', geometry: { type: 'Point', coordinates: [0, 0] }, properties: { name: '0°N 0°E' }, }, ], }; void init();
JavaScript
// This example defines an image map type using the Gall-Peters // projection. // https://en.wikipedia.org/wiki/Gall%E2%80%93Peters_projection const mapElement = document.querySelector('gmp-map'); let innerMap; async function init() { // Request the needed libraries. await google.maps.importLibrary('maps'); // Create a map. innerMap = mapElement.innerMap; innerMap.setOptions({ mapTypeControl: false, }); // Set the Gall-Peters map type. const gallPetersMapType = await initGallPeters(); innerMap.mapTypes.set('gallPeters', gallPetersMapType); innerMap.setMapTypeId('gallPeters'); // Show the lat and lng under the mouse cursor. const coordsDiv = document.getElementById('coords'); innerMap.addListener('mousemove', (event) => { coordsDiv.textContent = `lat: ${String(Math.round(event.latLng.lat()))}, lng: ${String(Math.round(event.latLng.lng()))}`; }); // Add some markers to the map. innerMap.data.setStyle((feature) => { return { title: feature.getProperty('name'), optimized: false, }; }); innerMap.data.addGeoJson(cities); } async function initGallPeters() { const [{ ImageMapType }, { Size, Point, LatLng }] = await Promise.all([ google.maps.importLibrary('maps'), google.maps.importLibrary('core'), ]); const GALL_PETERS_RANGE_X = 800; const GALL_PETERS_RANGE_Y = 512; // Fetch Gall-Peters tiles stored locally on our server. const gallPetersMapType = new ImageMapType({ getTileUrl(coord, zoom) { const scale = 1 << zoom; // Wrap tiles horizontally. const x = ((coord.x % scale) + scale) % scale; // Don't wrap tiles vertically. const y = coord.y; if (y < 0 || y >= scale) return ''; return `gall-peters_${String(zoom)}_${String(x)}_${String(y)}.png`; }, tileSize: new Size(GALL_PETERS_RANGE_X, GALL_PETERS_RANGE_Y), minZoom: 0, maxZoom: 1, name: 'Gall-Peters', }); // Describe the Gall-Peters projection used by these tiles. gallPetersMapType.projection = { fromLatLngToPoint(latLng) { const latRadians = (latLng.lat() * Math.PI) / 180; return new Point( GALL_PETERS_RANGE_X * (0.5 + latLng.lng() / 360), GALL_PETERS_RANGE_Y * (0.5 - 0.5 * Math.sin(latRadians)) ); }, fromPointToLatLng(point, noWrap) { const x = point.x / GALL_PETERS_RANGE_X; const y = Math.max(0, Math.min(1, point.y / GALL_PETERS_RANGE_Y)); return new LatLng( (Math.asin(1 - 2 * y) * 180) / Math.PI, -180 + 360 * x, noWrap ); }, }; return gallPetersMapType; } // GeoJSON, describing the locations and names of some cities. const cities = { type: 'FeatureCollection', features: [ { type: 'Feature', geometry: { type: 'Point', coordinates: [-87.65, 41.85] }, properties: { name: 'Chicago' }, }, { type: 'Feature', geometry: { type: 'Point', coordinates: [-149.9, 61.218] }, properties: { name: 'Anchorage' }, }, { type: 'Feature', geometry: { type: 'Point', coordinates: [-99.127, 19.427] }, properties: { name: 'Mexico City' }, }, { type: 'Feature', geometry: { type: 'Point', coordinates: [-0.126, 51.5] }, properties: { name: 'London' }, }, { type: 'Feature', geometry: { type: 'Point', coordinates: [28.045, -26.201] }, properties: { name: 'Johannesburg' }, }, { type: 'Feature', geometry: { type: 'Point', coordinates: [15.322, -4.325] }, properties: { name: 'Kinshasa' }, }, { type: 'Feature', geometry: { type: 'Point', coordinates: [151.207, -33.867] }, properties: { name: 'Sydney' }, }, { type: 'Feature', geometry: { type: 'Point', coordinates: [0, 0] }, properties: { name: '0°N 0°E' }, }, ], }; void init();