在地圖上重疊顯示並排影像
重要
針對企業用 Bing 地圖服務淘汰
UWP MapControl 和 Windows.Services.Maps 命名空間的地圖服務都是依賴 Bing 地圖服務。 針對企業用 Bing 地圖服務已遭到取代且即將淘汰,屆時 MapControl 及服務將不再接收資料。
如需詳細資訊,請參閱 Bing 地圖服務開發人員中心和 Bing 地圖服務文件。
注意
MapControl 和地圖服務要求地圖驗證金鑰,稱為 MapServiceToken。 如需取得和設定地圖驗證金鑰的詳細資訊,請參閱要求地圖驗證金鑰。
使用磚來源,即可在地圖上重疊顯示協力廠商或自訂的並排影像。 您可以使用磚來源來重疊顯示專業資訊,例如氣象資料、人口資料或地震資料,或是使用磚來源完全取代預設的地圖。
圖格影像概觀
Bing 地圖服務等地圖服務會將地圖切成方形圖格,以便快速擷取和顯示。 這些圖格的大小為 256 x 256 像素,並以多個詳細程度預先轉譯。 許多第三方服務也提供切割成圖格的地圖資料。 使用圖格來源來擷取第三方圖格,或者建立您的自訂圖格,並重疊在 MapControl 顯示的地圖上。
當您使用磚來源時,不需要撰寫程式代碼來要求或放置個別磚。 MapControl 會要求圖格,因為它需要圖格。 每個要求都會指定個別圖格的 X 和 Y 座標和縮放等級。 您只需指定要用來擷取 UriFormatString 屬性中圖格的 Uri 或檔名格式。 也就是說,您會在基底 URI 或檔名中插入可取代的參數,以指出傳遞 X 和 Y 座標的位置,以及每個圖格的縮放等級。
以下是 HttpMapTileDataSource 的 UriFormatString 屬性範例,其中顯示 X 和 Y 座標和縮放等級的可取代參數。
http://www.<web service name>.com/z={zoomlevel}&x={x}&y={y}
X 與 Y 座標表示在指定詳細程度的世界地圖中,各個圖格的位置。圖格編號系統從地圖的左上角 {0, 0} 開始。例如,位於 {1, 2} 的圖格在網格的第三列第二行。
如需對應服務所使用圖格系統的詳細資訊,請參閱 Bing 地圖圖格系統。
從圖格來源重疊圖格
使用 MapTileDataSource 重疊地圖圖格來源的圖格影像。
將繼承自 MapTileDataSource 的三個圖格資料來源類別之一具現化。
將 UriFormatString 設定為要使用的格式,以便在基本 Uri 或檔案名稱中插入可替換的參數以要求圖格。
下列範例會具現化 HttpMapTileDataSource。 此範例會在 HttpMapTileDataSource 的建構函式中指定 UriFormatString 的值。
HttpMapTileDataSource dataSource = new HttpMapTileDataSource( "http://www.<web service name>.com/z={zoomlevel}&x={x}&y={y}");
具現化並設定 MapTileSource。 指定您在上一個步驟中設定為 MapTileSource 的 DataSource 的 MapTileDataSource。
下列範例會在 MapTileSource 的建構函式中指定 DataSource。
MapTileSource tileSource = new MapTileSource(dataSource);
您可以使用 MapTileSource 的屬性來限制顯示圖格的條件。
- 藉由提供 Bounds 屬性的值,只顯示特定地理區域內的圖格。
- 只藉由提供 ZoomLevelRange 屬性的值,以特定詳細程度顯示圖格。
或者,設定 MapTileSource 的其他屬性,以影響載入或顯示圖格,例如 Layer、AllowOverstretch、IsRetryEnabled 和 IsTransparencyEnabled。
將 MapTileSource 新增至 MapControl 的 TileSources 集合。
MapControl1.TileSources.Add(tileSource);
從 Web 服務重疊圖格
使用 HttpMapTileDataSource 從 Web 服務擷取的重疊圖格影像。
指定 Web 服務預期為 UriFormatString 屬性值的 URI 格式。 若要建立此值,請在基底 URI 中插入可取代的參數。 例如,在下列程式碼範例中,UriFormatString 的值是:
http://www.<web service name>.com/z={zoomlevel}&x={x}&y={y}
Web 服務必須支援 URI,其中包含可取代的參數 {x}、{y}和 {zoomlevel}。 大部分的 Web 服務 (例如 Nokia、Bing 和 Google) 都支援此格式的 URI。 如果 Web 服務需要 UriFormatString 屬性無法使用的其他引數,則必須建立自訂 URI。 藉由處理 UriRequested 事件來建立及傳回自訂 URI。 有關詳細資訊,請參閱本主題後面的「提供自訂 URI」一節。
然後,遵循先前在圖格影像概觀中所述的其餘步驟。
下列範例會在北美洲地圖上重疊虛構 Web 服務圖格。 UriFormatString 的值是在 HttpMapTileDataSource 的建構函式中指定。 在此範例中,圖格只會顯示在選擇性 Bounds 屬性所指定的地理界限內。
private void AddHttpMapTileSource()
{
// Create the bounding box in which the tiles are displayed.
// This example represents North America.
BasicGeoposition northWestCorner =
new BasicGeoposition() { Latitude = 48.38544, Longitude = -124.667360 };
BasicGeoposition southEastCorner =
new BasicGeoposition() { Latitude = 25.26954, Longitude = -80.30182 };
GeoboundingBox boundingBox = new GeoboundingBox(northWestCorner, southEastCorner);
// Create an HTTP data source.
// This example retrieves tiles from a fictitious web service.
HttpMapTileDataSource dataSource = new HttpMapTileDataSource(
"http://www.<web service name>.com/z={zoomlevel}&x={x}&y={y}");
// Optionally, add custom HTTP headers if the web service requires them.
dataSource.AdditionalRequestHeaders.Add("header name", "header value");
// Create a tile source and add it to the Map control.
MapTileSource tileSource = new MapTileSource(dataSource);
tileSource.Bounds = boundingBox;
MapControl1.TileSources.Add(tileSource);
}
...
#include <winrt/Windows.Devices.Geolocation.h>
#include <winrt/Windows.UI.Xaml.Controls.Maps.h>
...
void MainPage::AddHttpMapTileSource()
{
Windows::Devices::Geolocation::BasicGeoposition northWest{ 48.38544, -124.667360 };
Windows::Devices::Geolocation::BasicGeoposition southEast{ 25.26954, -80.30182 };
Windows::Devices::Geolocation::GeoboundingBox boundingBox{ northWest, southEast };
Windows::UI::Xaml::Controls::Maps::HttpMapTileDataSource dataSource{
L"http://www.<web service name>.com/z={zoomlevel}&x={x}&y={y}" };
dataSource.AdditionalRequestHeaders().Insert(L"header name", L"header value");
Windows::UI::Xaml::Controls::Maps::MapTileSource tileSource{ dataSource };
tileSource.Bounds(boundingBox);
MapControl1().TileSources().Append(tileSource);
}
...
void MainPage::AddHttpMapTileSource()
{
BasicGeoposition northWest = { 48.38544, -124.667360 };
BasicGeoposition southEast = { 25.26954, -80.30182 };
GeoboundingBox^ boundingBox = ref new GeoboundingBox(northWest, southEast);
auto dataSource = ref new Windows::UI::Xaml::Controls::Maps::HttpMapTileDataSource(
"http://www.<web service name>.com/z={zoomlevel}&x={x}&y={y}");
dataSource->AdditionalRequestHeaders->Insert("header name", "header value");
auto tileSource = ref new Windows::UI::Xaml::Controls::Maps::MapTileSource(dataSource);
tileSource->Bounds = boundingBox;
this->MapControl1->TileSources->Append(tileSource);
}
從本機儲存裝置重疊圖格
使用 LocalMapTileDataSource,重疊儲存在本機的圖格影像檔案。 一般而言,您會將這些檔案隨著應用程式封裝和散發。
將檔名的格式指定為 UriFormatString 屬性的值。 若要建立此值,請在基底檔名中插入可取代的參數。 例如,在下列程式碼範例中,UriFormatString 的值是:
Tile_{zoomlevel}_{x}_{y}.png
如果檔名格式需要 UriFormatString 屬性無法使用的其他引數,則必須建立自訂 URI。 藉由處理 UriRequested 事件來建立及傳回自訂 URI。 有關詳細資訊,請參閱本主題後面的「提供自訂 URI」一節。
然後,遵循先前在圖格影像概觀中所述的其餘步驟。
您可以使用下列通訊協定和位置,從本機儲存裝置載入圖格:
URI | 其他資訊 |
---|---|
ms-appx:/// | 指向應用程式安裝資料夾的根目錄。 |
這是 Package.InstalledLocation 屬性所參考的位置。 | |
ms-appdata:///local | 指向應用程式本機儲存裝置的根目錄。 |
這是 ApplicationData.LocalFolder 屬性所參考的位置。 | |
ms-appdata:///temp | 指向應用程式的暫存資料夾。 |
這是 ApplicationData.TemporaryFolder 屬性所參考的位置。 |
下列範例會使用 ms-appx:///
通訊協定載入儲存為應用程式安裝資料夾中檔案的圖格。 UriFormatString 的值是在 LocalMapTileDataSource 的建構函式中指定。 在此範例中,只有在地圖的縮放等級位於選用 ZoomLevelRange 屬性所指定的範圍內時,才會顯示圖格。
void AddLocalMapTileSource()
{
// Specify the range of zoom levels
// at which the overlaid tiles are displayed.
MapZoomLevelRange range;
range.Min = 11;
range.Max = 20;
// Create a local data source.
LocalMapTileDataSource dataSource = new LocalMapTileDataSource(
"ms-appx:///TileSourceAssets/Tile_{zoomlevel}_{x}_{y}.png");
// Create a tile source and add it to the Map control.
MapTileSource tileSource = new MapTileSource(dataSource);
tileSource.ZoomLevelRange = range;
MapControl1.TileSources.Add(tileSource);
}
提供自訂 URI
如果 HttpMapTileDataSource 的 UriFormatString 屬性或 LocalMapTileDataSource 的 UriFormatString 屬性可用的可取代參數不足以擷取圖格,則您必須建立自訂 URI。 藉由提供 UriRequested 事件的自訂處理常式,建立及傳回自訂 URI。 每個個別圖格都會引發 UriRequested 事件。
- 在 UriRequested 事件的自訂處理常式中,結合必要的自訂引數與 MapTileUriRequestedEventArgs 的 X、Y 和 ZoomLevel 屬性,以建立自訂 Uri。
- 傳回 MapTileUriRequest Uri 屬性中的自訂 URI,該屬性包含在 MapTileUriRequestedEventArgs 的 Request 屬性中。
下列範例示範如何建立 UriRequested 事件的自訂處理常式來提供自訂 URI。 如果您必須以非同步方式執行某些動作來建立自訂 URI,它也會示範如何實作延遲模式。
using Windows.UI.Xaml.Controls.Maps;
using System.Threading.Tasks;
...
var httpTileDataSource = new HttpMapTileDataSource();
// Attach a handler for the UriRequested event.
httpTileDataSource.UriRequested += HandleUriRequestAsync;
MapTileSource httpTileSource = new MapTileSource(httpTileDataSource);
MapControl1.TileSources.Add(httpTileSource);
...
// Handle the UriRequested event.
private async void HandleUriRequestAsync(HttpMapTileDataSource sender,
MapTileUriRequestedEventArgs args)
{
// Get a deferral to do something asynchronously.
// Omit this line if you don't have to do something asynchronously.
var deferral = args.Request.GetDeferral();
// Get the custom Uri.
var uri = await GetCustomUriAsync(args.X, args.Y, args.ZoomLevel);
// Specify the Uri in the Uri property of the MapTileUriRequest.
args.Request.Uri = uri;
// Notify the app that the custom Uri is ready.
// Omit this line also if you don't have to do something asynchronously.
deferral.Complete();
}
// Create the custom Uri.
private async Task<Uri> GetCustomUriAsync(int x, int y, int zoomLevel)
{
// Do something asynchronously to create and return the custom Uri. }
}
從自訂來源重疊圖格
使用 CustomMapTileDataSource 重疊自訂圖格。 即時以程式設計方式在記憶體中建立圖格,或撰寫您自己的程序碼,以從另一個來源載入現有的圖格。
若要建立或載入自訂圖格,請提供 BitmapRequested 事件的自訂處理常式。 每個個別圖格都會引發 BitmapRequested 事件。
- 在 BitmapRequested 事件的自訂處理常式中,結合必要的自訂引數與 MapTileBitmapRequestedEventArgs 的 X、Y 和 ZoomLevel 屬性,以建立或擷取自訂圖格。
- 傳回 MapTileBitmapRequest 的 PixelData 屬性中的自訂圖格,該屬性包含在 MapTileBitmapRequestedEventArgs 的 Request 屬性中。 PixelData 屬性的類型為 IRandomAccessStreamReference。
下列範例示範如何建立 BitmapRequested 事件的自訂處理常式來提供自訂圖格。 此範例會建立部分不透明的相同紅色圖格。 此範例會忽略 MapTileBitmapRequestedEventArgs 的 X、Y 和 ZoomLevel 屬性。 雖然這不是真實世界的範例,但此範例示範如何即時建立記憶體內部自訂圖格。 如果您必須以非同步方式執行某些動作來建立自訂圖格,此範例也會示範如何實作延遲模式。
using Windows.UI.Xaml.Controls.Maps;
using Windows.Storage.Streams;
using System.Threading.Tasks;
...
CustomMapTileDataSource customDataSource = new CustomMapTileDataSource();
// Attach a handler for the BitmapRequested event.
customDataSource.BitmapRequested += customDataSource_BitmapRequestedAsync;
customTileSource = new MapTileSource(customDataSource);
MapControl1.TileSources.Add(customTileSource);
...
// Handle the BitmapRequested event.
private async void customDataSource_BitmapRequestedAsync(
CustomMapTileDataSource sender,
MapTileBitmapRequestedEventArgs args)
{
var deferral = args.Request.GetDeferral();
args.Request.PixelData = await CreateBitmapAsStreamAsync();
deferral.Complete();
}
// Create the custom tiles.
// This example creates red tiles that are partially opaque.
private async Task<RandomAccessStreamReference> CreateBitmapAsStreamAsync()
{
int pixelHeight = 256;
int pixelWidth = 256;
int bpp = 4;
byte[] bytes = new byte[pixelHeight * pixelWidth * bpp];
for (int y = 0; y < pixelHeight; y++)
{
for (int x = 0; x < pixelWidth; x++)
{
int pixelIndex = y * pixelWidth + x;
int byteIndex = pixelIndex * bpp;
// Set the current pixel bytes.
bytes[byteIndex] = 0xff; // Red
bytes[byteIndex + 1] = 0x00; // Green
bytes[byteIndex + 2] = 0x00; // Blue
bytes[byteIndex + 3] = 0x80; // Alpha (0xff = fully opaque)
}
}
// Create RandomAccessStream from byte array.
InMemoryRandomAccessStream randomAccessStream =
new InMemoryRandomAccessStream();
IOutputStream outputStream = randomAccessStream.GetOutputStreamAt(0);
DataWriter writer = new DataWriter(outputStream);
writer.WriteBytes(bytes);
await writer.StoreAsync();
await writer.FlushAsync();
return RandomAccessStreamReference.CreateFromStream(randomAccessStream);
}
...
#include <winrt/Windows.Storage.Streams.h>
...
Windows::Foundation::IAsyncOperation<Windows::Storage::Streams::InMemoryRandomAccessStream> MainPage::CustomRandomAccessStream()
{
constexpr int pixelHeight{ 256 };
constexpr int pixelWidth{ 256 };
constexpr int bpp{ 4 };
std::array<uint8_t, pixelHeight * pixelWidth * bpp> bytes;
for (int y = 0; y < pixelHeight; y++)
{
for (int x = 0; x < pixelWidth; x++)
{
int pixelIndex{ y * pixelWidth + x };
int byteIndex{ pixelIndex * bpp };
// Set the current pixel bytes.
bytes[byteIndex] = (byte)(std::rand() % 256); // Red
bytes[byteIndex + 1] = (byte)(std::rand() % 256); // Green
bytes[byteIndex + 2] = (byte)(std::rand() % 256); // Blue
bytes[byteIndex + 3] = (byte)((std::rand() % 56) + 200); // Alpha (0xff = fully opaque)
}
}
// Create RandomAccessStream from byte array.
Windows::Storage::Streams::InMemoryRandomAccessStream randomAccessStream;
Windows::Storage::Streams::IOutputStream outputStream{ randomAccessStream.GetOutputStreamAt(0) };
Windows::Storage::Streams::DataWriter writer{ outputStream };
writer.WriteBytes(bytes);
co_await writer.StoreAsync();
co_await writer.FlushAsync();
co_return randomAccessStream;
}
...
InMemoryRandomAccessStream^ TileSources::CustomRandomAccessStream::get()
{
int pixelHeight = 256;
int pixelWidth = 256;
int bpp = 4;
Array<byte>^ bytes = ref new Array<byte>(pixelHeight * pixelWidth * bpp);
for (int y = 0; y < pixelHeight; y++)
{
for (int x = 0; x < pixelWidth; x++)
{
int pixelIndex = y * pixelWidth + x;
int byteIndex = pixelIndex * bpp;
// Set the current pixel bytes.
bytes[byteIndex] = (byte)(std::rand() % 256); // Red
bytes[byteIndex + 1] = (byte)(std::rand() % 256); // Green
bytes[byteIndex + 2] = (byte)(std::rand() % 256); // Blue
bytes[byteIndex + 3] = (byte)((std::rand() % 56) + 200); // Alpha (0xff = fully opaque)
}
}
// Create RandomAccessStream from byte array.
InMemoryRandomAccessStream^ randomAccessStream = ref new InMemoryRandomAccessStream();
IOutputStream^ outputStream = randomAccessStream->GetOutputStreamAt(0);
DataWriter^ writer = ref new DataWriter(outputStream);
writer->WriteBytes(bytes);
create_task(writer->StoreAsync()).then([writer](unsigned int)
{
create_task(writer->FlushAsync());
});
return randomAccessStream;
}
取代預設地圖
若要將預設地圖完全取代為第三方或自訂圖格:
- 指定 MapTileLayer。BackgroundReplacement 做為 MapTileSource 的 Layer 屬性值。
- 指定 MapStyle。None 是 MapControl 的 Style 屬性值。