Sovrapporre immagini in riquadri su una mappa
Importante
Ritiro del servizio Bing Maps for Enterprise
I servizi MapControl della piattaforma UWP e mappa dello spazio dei nomi Windows.Services.Maps si basano su Bing Maps. Bing Maps for Enterprise è deprecato e verrà ritirato, a questo punto MapControl e i servizi non riceveranno più dati.
Per altre informazioni, vedere la documentazione del Centro per sviluppatori di Bing Maps e di Bing Maps.
Nota
MapControl e i servizi per le mappe richiedono una chiave di autenticazione delle mappe denominata MapServiceToken. Per altre informazioni su come ottenere e impostare una chiave di autenticazione delle mappe, vedere Richiedere una chiave di autenticazione per le mappe.
Puoi sovrapporre immagini in riquadri personalizzati o di terze parti su una mappa usando le origini dei riquadri. Queste origini consentono di sovrapporre informazioni speciali, ad esempio dati meteo, dati sulla popolazione o dati sismici oppure, in alternativa, sostituire completamente la mappa predefinita.
Panoramica delle immagini affiancate
I servizi di mapping come Bing Maps tagliano le mappe in riquadri quadrati per recuperare e visualizzare rapidamente. Questi riquadri sono di 256 pixel di 256 pixel e vengono sottoposti a rendering preliminare a più livelli di dettaglio. Molti servizi di terzi forniscono anche dati basati su mappa tagliati in riquadri. Usare le origini dei riquadri per recuperare riquadri di terzi o per creare riquadri personalizzati e sovrapporli alla mappa visualizzata in MapControl.
Quando si usano origini riquadri, non è necessario scrivere codice per richiedere o posizionare singoli riquadri. The MapControl richiede i riquadri in base alle esigenze. Ogni richiesta specifica le coordinate X e Y e il livello di zoom per il singolo riquadro. È sufficiente specificare il formato dell'Uri o del nome file da usare per recuperare i riquadri nella proprietà UriFormatString. Ovvero, si inseriscono parametri sostituibili nell'URI di base o nel nome file per indicare dove passare le coordinate X e Y e il livello di zoom per ogni riquadro.
Ecco un esempio della proprietà UriFormatString per una HttpMapTileDataSource che mostra i parametri sostituibili per le coordinate X e Y e il livello di zoom.
http://www.<web service name>.com/z={zoomlevel}&x={x}&y={y}
Le coordinate X e Y rappresentano la posizione del singolo riquadro all'interno della mappa del mondo a livello di dettaglio specificato. Il sistema di numerazione dei riquadri inizia da {0, 0} nell'angolo superiore sinistro della mappa. Ad esempio, il riquadro in {1, 2} si trova nella seconda colonna della terza riga della griglia dei riquadri.
Per maggiori informazioni sul sistema di riquadri usato dai servizi di mapping, vedere Sistema riquadri di Bing Maps.
Sovrapporre i riquadri da un'origine riquadro
Sovrapporre immagini affiancate da un'origine di riquadri in una mappa usando MapTileDataSource.
Creare un'istanza di una delle tre classi di origine dati dei riquadri che ereditano da MapTileDataSource.
Configurare UriFormatString da usare per richiedere i riquadri inserendo parametri sostituibili nell'Uri di base o nel nome file.
Nell'esempio seguente viene creata un'istanza di HttpMapTileDataSource. In questo esempio viene specificato il valore di UriFormatString nel costruttor di HttpMapTileDataSource.
HttpMapTileDataSource dataSource = new HttpMapTileDataSource( "http://www.<web service name>.com/z={zoomlevel}&x={x}&y={y}");
Creare un'istanza e configurare una MapTileSource. Specificare MapTileDataSource configurato nel passaggio precedente come DataSource di MapTileSource.
Nell'esempio seguente viene specificato DataSource nel costruttore di MapTileSource.
MapTileSource tileSource = new MapTileSource(dataSource);
È possibile limitare le condizioni in cui i riquadri vengono visualizzati usando le proprietà di MapTileSource.
- Visualizzare i riquadri solo all'interno di un'area geografica specifica fornendo un valore per la proprietà Bounds.
- Visualizzare i riquadri solo a determinati livelli di dettaglio fornendo un valore per la proprietà ZoomLevelRange.
Facoltativamente, configurare altre proprietà di MapTileSource che influiscono sul caricamento o sulla visualizzazione dei riquadri, ad esempio Layer, AllowOverstretch, IsRetryEnabled e IsTransparencyEnabled.
Aggiungere MapTileSource alla raccolta TileSources di MapControl.
MapControl1.TileSources.Add(tileSource);
Sovrapporre i riquadri da un servizio Web
Sovrapporre immagini affiancate recuperate da un servizio Web usando HttpMapTileDataSource.
Creare un'istanza di HttpMapTileDataSource.
Specificare il formato dell'URI previsto dal servizio Web come valore della proprietà UriFormatString. Per creare questo valore, inserire parametri sostituibili nell'URI di base. Nell'esempio di codice seguente, ad esempio, il valore di UriFormatString è:
http://www.<web service name>.com/z={zoomlevel}&x={x}&y={y}
Il servizio Web deve supportare un Uri che contiene i parametri sostituibili {x}, {y} e {zoomlevel}. La maggior parte dei servizi Web (ad esempio, Nokia, Bing e Google) supporta gli Uri in questo formato. Se il servizio Web richiede argomenti aggiuntivi che non sono disponibili con la proprietà UriFormatString, è necessario creare un URI personalizzato. Creare e restituire un Uri personalizzato gestendo l'evento UriRequested. Per maggiori informazioni, vedere la sezione Fornire un Uri personalizzato più avanti in questo argomento.
Seguire quindi i passaggi rimanenti descritti in precedenza nella panoramica Immagini affiancate.
L'esempio seguente sovrappone i riquadri da un servizio Web fittizio su una mappa dell'America del Nord. Il valore di UriFormatString viene specificato nel costruttore di HttpMapTileDataSource. In questo esempio, i riquadri vengono visualizzati solo entro i limiti geografici specificati dalla proprietà Bounds opzionale.
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);
}
Sovrapporre riquadri dall'archiviazione locale
Sovrapporre immagini affiancate archiviate come file nella risorsa di archiviazione locale usando LocalMapTileDataSource. In genere, si crea un pacchetto e si distribuiscono questi file con l'app.
Creare un'istanza di LocalMapTileDataSource.
Specificare il formato dei nomi di file come valore della proprietà UriFormatString. Per creare questo valore, inserire parametri sostituibili nel nome del file di base. Nell'esempio di codice seguente, ad esempio, il valore di UriFormatString è:
Tile_{zoomlevel}_{x}_{y}.png
Se il servizio formato dei nomi dei file richiede argomenti aggiuntivi che non sono disponibili con la proprietà UriFormatString, è necessario creare un Uri personalizzato. Creare e restituire un Uri personalizzato gestendo l'evento UriRequested. Per maggiori informazioni, vedere la sezione Fornire un Uri personalizzato più avanti in questo argomento.
Seguire quindi i passaggi rimanenti descritti in precedenza nella panoramica Immagini affiancate.
È possibile usare i protocolli e i percorsi seguenti per caricare i riquadri dall'archiviazione locale:
URI | Altre informazioni |
---|---|
ms-appx:/// | Punta alla radice della cartella di installazione dell'app. |
Si tratta della posizione a cui fa riferimento la proprietà Package.InstalledLocation. | |
ms-appdata:///local | Punta alla radice dell'archiviazione locale dell'app. |
Si tratta della posizione a cui fa riferimento la proprietà AppplicationData.LocalFolder. | |
ms-appdata:///temp | Punta alla cartella temporanea dell'app. |
Si tratta della posizione a cui fa riferimento la proprietà AppplicationData.TemporaryFolder. |
L'esempio seguente carica i riquadri archiviati come file nella cartella di installazione dell'app usando il protocollo ms-appx:///
. Il valore di UriFormatString viene specificato nel costruttore di LocalMapTileDataSource. In questo esempio, i riquadri vengono visualizzati solo quando il livello di zoom della mappa è compreso nell'intervallo specificato dalla proprietà facoltativa 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);
}
Specificare un URI personalizzato
Se i parametri sostituibili disponibili con la proprietà UriFormatString di HttpMapTileDataSource ola proprietà UriFormatString di LocalMapTileDataSource non sono sufficienti per recuperare i riquadri, è necessario creare un Uri personalizzato. Creare e restituire un Uri personalizzato fornendo un gestore personalizzato per l'evento UriRequested. L'evento UriRequested viene generato per ogni singolo riquadro.
- Nel gestore personalizzato per l'evento UriRequested, combinare gli argomenti personalizzati necessari con le proprietà X, Y e ZoomLevel di MapTileUriRequestedEventArgs per creare l'Uri personalizzato.
- Restituisce l'URI personalizzato nella proprietà Uri di MapTileUriRequest, contenuta nella proprietà Richiesta di MapTileUriRequestedEventArgs.
Nell'esempio seguente viene illustrato come fornire un Uri personalizzato creando un gestore personalizzato per l'evento UriRequested. Illustra anche come implementare il modello di differimento se è necessario eseguire un'operazione in modo asincrono per creare l'Uri personalizzato.
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. }
}
Sovrapporre riquadri da un'origine personalizzata
Sovrapporre riquadri personalizzati usando CustomMapTileDataSource. Creare riquadri a livello di codice in memoria in tempo reale o scrivere codice personalizzato per caricare i riquadri esistenti da un'altra origine.
Per creare o caricare riquadri personalizzati, fornire un gestore personalizzato per l'evento BitmapRequested. L'evento BitmapRequested viene generato per ogni singolo riquadro.
- Nel gestore personalizzato per l'evento BitmapRequested combinare gli argomenti personalizzati necessari con le proprietà X, Y e ZoomLevel di MapTileBitmapRequestedEventArgs per creare o recuperare un riquadro personalizzato.
- Restituisce il riquadro personalizzato nella proprietà PixelData di MapTileBitmapRequest, contenuta nella proprietà Richiesta di MapTileBitmapRequestedEventArgs. La proprietà PixelData è di tipo IRandomAccessStreamReference.
Nell'esempio seguente viene illustrato come fornire riquadri personalizzati creando un gestore personalizzato per l'evento BitmapRequested. In questo esempio vengono creati riquadri rossi identici parzialmente opachi. Nell'esempio vengono ignorate le proprietà X, Y e ZoomLevel di MapTileBitmapRequestedEventArgs. Anche se questo non è un esempio reale, l'esempio illustra come creare riquadri personalizzati in memoria in tempo reale. L'esempio mostra anche come implementare il modello di differimento se è necessario eseguire un'operazione in modo asincrono per creare i riquadri personalizzati.
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;
}
Sostituire la mappa predefinita
Per sostituire completamente la mappa predefinita con riquadri personalizzati o di terzi:
- Specificare MapTileLayer.BackgroundReplacement come valore della proprietà Layer di MapTileSource.
- Specificare MapStyle.Nessuno come valore della proprietà Stile di MapControl.