این سند انواع نقشههایی را که میتوانید بااستفاده از
Maps JavaScript API نمایش دهید شرح میدهد. این میانای برنامهسازی کاربردی از شیء MapType
برای نگهداری اطلاعات مربوط به این نقشهها استفاده میکند. MapType
میانایی است که نمایش و استفاده از کاشیهای نقشه و
ترجمه سیستمهای مختصات از مختصات صفحه به مختصات
جهانی (روی نقشه) را تعریف میکند. هر MapType باید حاوی چند روش برای مدیریت بازیابی و انتشار کاشیها و ویژگیهایی باشد که رفتار بصری آن را تعریف میکنند.
عملکرد داخلی انواع نقشه در Maps JavaScript API موضوعی پیشرفته است. اکثر توسعهدهندگان میتوانند از انواع نقشه پایه که در زیر ذکر شده است استفاده کنند. بااینحال، میتوانید بااستفاده از نقشههای قابلطراحی، نحوه ارائه انواع نقشههای موجود را نیز تغییر دهید یا بااستفاده از انواع نقشه سفارشی، کاشیهای نقشه خودتان را تعریف کنید. هنگام ارائه انواع نقشه سفارشی، باید نحوه تغییر ثبت نوع نقشه نقشه را درک کنید.
انواع نقشه پایه
چهار نوع نقشه در Maps JavaScript API دردسترس است. علاوهبر کاشیهای نقشه راه «رنگشده» آشنا، 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 از یک دفتر ثبت نوع نقشه،
که در زیر توضیح داده شده است، برای مدیریت این ارجاعها استفاده میکند.
نقشههای سهبعدی
Maps JavaScript API از تصاویر سهبعدی پشتیبانی میکند. بسیاری از کنشها و قابلیتهای سفارشیسازی دردسترس برای نقشههای دوبعدی برای نقشههای سهبعدی نیز دردسترس است.
در نمای کلی نقشههای سهبعدی درباره نقشههای سهبعدی بیشتر بدانید.
مثال زیر نمای ژرفانمای سهبعدی از سانفرانسیسکو را نشان میدهد:
در نمای کلی نقشههای سهبعدی درباره «نقشههای سهبعدی» بیشتر بدانید.
تصاویر ۴۵ درجه (منسوخشده)
نمونه زیر نشان میدهد که چگونه میتوان بااستفاده از نقشههای سهبعدی، نمای پرسپکتیو ۴۵ درجه از سانفرانسیسکو بهدست آورد:
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 مرتبط با نقشه، آنها را از نقشه بردارید).
کد زیر نقشه را طوری تنظیم میکند که فقط دو نوع نقشه را در 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 از نمایش و مدیریت انواع نقشه سفارشی پشتیبانی میکند و به شما امکان میدهد تصاویر نقشه یا همپوشانیهای کاشی خودتان را پیادهسازی کنید.
Several possible map type implementations exist within the Maps JavaScript API:
- مجموعههای کاشی استاندارد شامل تصاویری که
درمجموع نقشههای نقشهنگاری کامل را تشکیل میدهند. این مجموعههای کاشی
بهعنوان انواع نقشه پایه نیز شناخته میشوند. این نوع نقشهها
مانند انواع نقشه پیشفرض موجود عمل میکنند و رفتار میکنند:
roadmap،satellite،hybridوterrain. میتوانید نوع نقشه سفارشیتان را به آرایهmapTypesنقشه اضافه کنید تا به واسط کاربر در Maps JavaScript API اجازه دهید نوع نقشه سفارشیتان را بهعنوان نوع نقشه استاندارد درنظر بگیرد (مثلاً با گنجاندن آن در کنترل MapType). - رونهادهای کاشی تصویر که روی انواع نقشه پایه موجود نمایش داده میشوند. بهطور کلی، این نوع نقشهها برای تقویت نوع نقشه موجود برای نمایش اطلاعات بیشتر استفاده میشوند و اغلب به مکانهای خاص و/یا سطوح بزرگنمایی محدود میشوند. توجه داشته باشید که این کاشیها ممکن است شفاف باشند، که به شما امکان میدهد ویژگیهایی را به نقشههای موجود اضافه کنید.
- انواع نقشه غیرتصویری که به شما امکان میدهد نمایش اطلاعات نقشه را در بنیادیترین سطح آن دستکاری کنید.
هرکدام از این گزینهها به ایجاد کلاسی متکی است که
میانای MapType را
پیادهسازی میکند. علاوهبراین، کلاس
ImageMapType برخی رفتارهای داخلی را برای سادهسازی ایجاد انواع نقشه تصویری ارائه میدهد.
میانای MapType
قبلاز ایجاد کلاسهایی که MapType را پیادهسازی میکنند،
مهم است که بدانید Google Maps چگونه مختصات را تعیین میکند
و تصمیم میگیرد کدام بخشهای نقشه را نشان دهد. باید
منطق مشابهی را برای هر نوع نقشه پایه یا همپوشانی پیادهسازی کنید.
راهنمای مختصات نقشه
و کاشی را بخوانید.
انواع نقشه سفارشی باید میانای MapType را پیادهسازی کنند. این میانجی ویژگیها و روشهای خاصی را مشخص میکند که به API اجازه میدهد درخواستهایی را به نوع(های) نقشه شما ارسال کند، زمانی که API تشخیص میدهد که نیاز به نمایش کاشیهای نقشه در نمای فعلی و سطح بزرگنمایی دارد. شما این درخواستها را مدیریت میکنید تا تصمیم بگیرید کدام کاشی بار شود.
توجه: میتوانید کلاس خودتان را برای پیادهسازی این میانای کاربری ایجاد کنید. یا اگر تصاویر سازگار دارید، میتوانید از کلاس
ImageMapType استفاده کنید که قبلاً این میانای کاربری را پیادهسازی کرده است.
کلاسهایی که میانای MapType را پیادهسازی میکنند
نیاز دارند که ویژگیهای زیر را تعریف و تکمیل کنید:
tileSize(الزامی) اندازه کاشی را مشخص میکند (از نوعgoogle.maps.Size). اندازهها باید مستطیلی باشند هرچند لازم نیست مربع باشند.maxZoom(الزامی) حداکثر سطح بزرگنمایی را که کاشیهای این نوع نقشه در آن نمایش داده میشود مشخص میکند.minZoom(اختیاری) حداقل سطح بزرگنمایی را که در آن کاشی این نوع نقشه نمایش داده میشود مشخص میکند. بهطور پیشفرض، این مقدار0است که نشان میدهد حداقل سطح بزرگنمایی وجود ندارد.name(اختیاری) نام این نوع نقشه را مشخص میکند. این ویژگی فقط درصورتی لازم است که بخواهید این نوع نقشه در کنترل MapType قابلانتخاب باشد. ( گزینههای کنترل را ببینید.)alt(اختیاری) نوشتار جایگزین را برای این نوع نقشه مشخص میکند که بهعنوان نوشتار شناور نمایش داده میشود. این ویژگی فقط زمانی لازم است که بخواهید این نوع نقشه در کنترل MapType قابلانتخاب باشد. (گزینههای کنترل را ببینید.)
بهعلاوه، کلاسهایی که میانای MapType را پیادهسازی میکنند
باید روشهای زیر را پیادهسازی کنند:
-
getTile()(الزامی) هرزمان که API تشخیص دهد نقشه باید کاشیهای جدیدی برای نمای هدف دادهشده نمایش دهد، فراخوانده میشود. روشgetTile()باید امضای زیر را داشته باشد:getTile(tileCoord:Point,zoom:number,ownerDocument:Document):Nodeاین میانای برنامهسازی کاربردی براساس ویژگیهای
tileSize،minZoom، وmaxZoomمربوط بهMapTypeو نمای فعلی و سطح بزرگنمایی نقشه تعیین میکند که آیا لازم استgetTile()را فراخوانی کند یا نه. گرداننده این روش باید عنصر HTML را با مختصات، سطح بزرگنمایی، و عنصر DOM ارائهشده برگرداند تا تصویر کاشی به آن اضافه شود. -
releaseTile()(اختیاری) هرگاه API تشخیص دهد که نقشه باید کاشیای را که از دید خارج شده است بردارد، فراخوانی میشود. این روش باید امضای زیر را داشته باشد:releaseTile(tile:Node)معمولاً باید برداشتن هر عنصری را که هنگام افزودن به نقشه به کاشیهای نقشه متصل شده است مدیریت کنید. برای مثال، اگر شنوندگان رویداد را به همپوشانیهای کاشی نقشه پیوست کردهاید، باید آنها را در اینجا بردارید.
روش 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;
پیشبینیها
زمین (تقریباً) یک کره سهبعدی است، درحالیکه نقشه یک سطح دوبعدی تخت است. نقشهای که در Maps JavaScript API میبینید، مانند هر نقشه مسطح دیگری از زمین، تصویری از آن کره روی یک سطح صاف است. به زبان ساده، تصویر را میتوان بهعنوان نگاشت مقادیر عرض/طول جغرافیایی به مختصات روی نقشه تصویر تعریف کرد.
تصویرها در Maps JavaScript API باید میانای
Projection را پیادهسازی کنند. پیادهسازی Projection
باید نهتنها نگاشتی از یک سیستم مختصات
به سیستم دیگر، بلکه نگاشتی دوطرفه ارائه دهد. یعنی باید
نحوه ترجمه از مختصات Earth (اشیاء LatLng)
به سیستم مختصات
جهانی
کلاس Projection، و از سیستم مختصات جهانی به مختصات Earth را تعریف کنید.
Google Maps از تصویر مرکاتور برای ایجاد نقشههایش
از دادههای جغرافیایی و تبدیل رویدادهای روی نقشه به
مختصات جغرافیایی استفاده میکند. میتوانید این تصویر را با
فراخوانی getProjection() در Map
(یا هریک از انواع پایه استاندارد MapType) بهدست آورید. برای بیشتر کاربردها،
این Projection استاندارد کافی خواهد بود، اما میتوانید
تصویرهای سفارشی خودتان را نیز تعریف و استفاده کنید.
اجرای پیشبینی
هنگام پیادهسازی طرحافکنی سفارشی، باید چند چیز را تعریف کنید:
- فرمولهای نگاشت مختصات عرض جغرافیایی و طول جغرافیایی به
صفحه دکارتی و فرمولهای متناظر برای نگاشت از صفحه دکارتی به مختصات عرض جغرافیایی
و طول جغرافیایی. (میانای
Projectionفقط از تبدیل به مختصات راستخط پشتیبانی میکند.) - اندازه کاشی پایه. همه کاشیها باید مستطیلی باشند.
- «اندازه جهانی» نقشه بااستفاده از مجموعه کاشی پایه در سطح بزرگنمایی ۰. توجه داشته باشید که برای نقشههایی که از یک کاشی در بزرگنمایی ۰ تشکیل شدهاند، اندازه جهان و اندازه کاشی پایه یکسان است.
تبدیل مختصات در تصویرها
هر تصویر دو روش ارائه میدهد که بین این دو سیستم مختصات ترجمه میکند و به شما امکان میدهد بین مختصات جغرافیایی و جهانی تبدیل کنید:
- روش
Projection.fromLatLngToPoint()مقدارLatLngرا به مختصات جهانی تبدیل میکند. از این روش برای جایگذاری همپوشانیها روی نقشه (و جایگذاری خود نقشه) استفاده میشود. - روش
Projection.fromPointToLatLng()مختصات جهانی را به مقدارLatLngتبدیل میکند. این روش برای تبدیل رویدادهایی مانند کلیکهایی که روی نقشه اتفاق میافتد به مختصات جغرافیایی استفاده میشود.
Google Maps فرض میکند که طرحاندازیها راستخطی هستند.
بهطور کلی، ممکن است از تصویر برای دو مورد استفاده کنید: برای ایجاد نقشه جهان، یا برای ایجاد نقشه یک منطقه محلی. در حالت اول، باید مطمئن شوید که تصویر شما در همه طولهای جغرافیایی راستخط و عادی باشد. برخیاز تصویرها (بهویژه تصویرهای مخروطی) ممکن است «بهطور محلی عادی» باشند (یعنی شمال را نشان دهند) اما از شمال واقعی منحرف شوند؛ برای مثال، هرچه نقشه نسبت به برخیاز طولهای جغرافیایی مرجع دورتر قرار گیرد. میتوانید از چنین تصویرسازیای بهصورت محلی استفاده کنید، اما توجه داشته باشید که تصویرسازی لزوماً دقیق نیست و هرچه از طول جغرافیایی مرجع بیشتر منحرف شوید، خطاهای تبدیل بهطور فزایندهای آشکارتر خواهند شد.
انتخاب کاشی نقشه در تصویرها
تصویرها نه تنها برای تعیین موقعیت مکانها یا همپوشانیها، بلکه برای موقعیتیابی کاشیهای نقشه نیز مفید هستند.
Maps JavaScript API نقشههای مبنا را بااستفاده از میانای MapType ارائه میکند که باید هم ویژگی projection را برای شناسایی تصویر نقشه و هم روش getTile() را برای بازیابی کاشیهای نقشه براساس مقادیر مختصات کاشی اعلام کند. مختصات کاشی براساس
اندازه کاشی پایه (که باید مستطیلی باشد) و «اندازه
جهانی» نقشه شما است که اندازه پیکسل جهان نقشه شما
در سطح بزرگنمایی ۰ است. (برای نقشههایی که از یک کاشی در بزرگنمایی ۰ تشکیل شدهاند، اندازه کاشی و اندازه جهان یکسان است.)
اندازه کاشی پایه را در ویژگی tileSize مربوط به MapType تعریف میکنید. اندازه جهان را بهطور ضمنی
در روشهای fromLatLngToPoint()
و fromPointToLatLng() طرحریزیتان تعریف میکنید.
ازآنجاییکه انتخاب تصویر به این مقادیر ارسالشده بستگی دارد، مفید است که تصاویری را نامگذاری کنید که میتوانند بهصورت برنامهنویسیشده با توجه به آن مقادیر ارسالشده انتخاب شوند، مانند map_zoom_tileX_tileY.png.
مثال زیر یک ImageMapType
را بااستفاده از
تصویر گال-پیترز تعریف میکند:
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();