Maps bestehen in der Regel aus Basemap Layers zur Orientierung und Operational Layers für das Visualisieren, Abfragen, Bearbeiten und Analysieren von Geo-Informationen. In ArcGIS werden zwei Typen von Basemaps unterschieden: Raster Tile Services (gecachte Map Services und Image Services) und die noch recht jungen Vector Tile Services.

Link zur Live Map
Für die Offline-Nutzung von Basemaps in
ArcGIS Runtime können schon seit langer Zeit Tile Packages (.tpk) direkt aus Raster Tile Services exportiert werden. Brandneu ist nun die Möglichkeit, Bereiche von Vector Tile Services zu exportieren und lokal als Vector Tile Packages (.vtpk) nutzen zu können:
Vector Tile Services für den Export
Der große Vorteil von Vector Tile Services ist das clientseitige dynamische Rendering von Tiles. Somit ist die Basemap in jedem Maßstab der Map und bei jeder Auflösung des Displays immer gestochen scharf. Weiterhin werden die Daten und der Style der Basemap getrennt behandelt. Das ermöglicht dynamisches Anzeigen von Labels und das Erstellen von Basemaps mit unterschiedlichen Themen basierend auf immer denselben Datensatz. Und letztendlich werden Vektoren übertragen, also keine Bilder wie bei Raster Tile Services. Das sorgt für hohe Performanz und deutlich kleinere Datenmengen.
In
ArcGIS Online werden schon eine Reihe von exportierbaren Vector Tile Basemaps bereitgestellt. Die
hier verlinkten Services basieren alle auf denselben World Basemap Daten, aber immer jeweils mit anderem Style. Falls mehrere dieser Basemaps offline genutzt werden sollen, muss nur von
einem der Services das vtpk (Daten + „Root Style“) und von allen Services jeweils nur der Style exportiert werden. Dazu später mehr.
Es können auch eigene Vector Tile Services auf ArcGIS Online erstellt und für den Export freigeschaltet werden. Dazu wird in den allgemeinen Einstellungen des Vector Tile Service Portal Items in der Registerkarte Einstellungen der Offline-Modus aktiviert:
Wie eigene Vector Tile Services erzeugt und dafür verschiedene Styles erstellt werden können, wird in diesen zwei Esri UK - Blogs sehr gut beschrieben:
Export von Vector Tile Packages und Styles in ArcGIS Runtime
Für den Export von Vector Tile Services und Styles werden die PortalItem IDs der Services, eine Identität (Named User oder ArcGIS Online Developer Account) und mindestens die ArcGIS Runtime Version 100.2 benötigt. Hier ist die exemplarische Vorgehensweise anhand des ArcGIS Runtime SDK for .NET:

Online Map mit dem zu exportierenden Gebiet (AreaOfInterest im ExportVectorTilesParameters)
1. Authentifizieren
Der anonyme Export ist nicht erlaubt, es ist eine Authentifizierung erforderlich. Dafür gibt es mehrere Möglichkeiten, z.B in diesem Sample.
2. Vector Tile Service PortalItem erzeugen
Wir nutzen in unserem Code-Beispiel die World Topographic Map (for Export). Hiervon wird die Portal ID benötigt.
<SPAN class="keyword token">var</SPAN> portal <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">await</SPAN> ArcGISPortal<SPAN class="punctuation token">.</SPAN><SPAN class="token function">CreateAsync</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="keyword token">var</SPAN> portalItem <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">await</SPAN> PortalItem<SPAN class="punctuation token">.</SPAN><SPAN class="token function">CreateAsync</SPAN><SPAN class="punctuation token">(</SPAN>portal<SPAN class="punctuation token">,</SPAN><SPAN class="string token">"df541726b3df4c0caf99255bb1be4c86"</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="line-numbers-rows"><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN></SPAN>
TIP:
Es ist leider nicht möglich, von einem Vector Tile Service equivalente Services mit anderen Styles abzufragen. Um das trotzdem zu automatisieren kann in ArcGIS Runtime nach PortalItems-Typen und Tags gesucht werden.
Z.B ist in den hier beschriebenen ArcGIS Online Basemaps der spezifischer Tag "World_Basemap_Export_v2".
Bei eigenen Services muss dementsprechend ein eigener spezifischer Tag gewählt werden.
So wird gesucht:
<SPAN class="keyword token">var</SPAN> queryExpression <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">string</SPAN><SPAN class="punctuation token">.</SPAN><SPAN class="token function">Format</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="string token">"tags:\"{0}\"type: \"Vector Tile Service\""</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="string token">"World_Basemap_Export_v2"</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN>
PortalQueryParameters queryParams <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">new</SPAN> <SPAN class="token class-name">PortalQueryParameters</SPAN><SPAN class="punctuation token">(</SPAN>queryExpression<SPAN class="punctuation token">,</SPAN> <SPAN class="number token">100</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="comment token">// Search the portal using the query parameters and await the results</SPAN>
PortalQueryResultSet<SPAN class="operator token"><</SPAN>PortalItem<SPAN class="operator token">></SPAN> findResult <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">await</SPAN> portal<SPAN class="punctuation token">.</SPAN><SPAN class="token function">FindItemsAsync</SPAN><SPAN class="punctuation token">(</SPAN>queryParams<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="comment token">// Get the items from the query results</SPAN>
<SPAN class="keyword token">var</SPAN> tileServicePortalItems <SPAN class="operator token">=</SPAN> findResult<SPAN class="punctuation token">.</SPAN>Results<SPAN class="punctuation token">;</SPAN><SPAN class="line-numbers-rows"><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN></SPAN>3. Task, Parameter und Job erzeugen und ausführen
Im folgenden Code werden nur die Daten (.vtpk) und nicht der Style exportiert.
<SPAN class="comment token">// Create the task</SPAN>
<SPAN class="keyword token">var</SPAN> exportTask <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">await</SPAN> ExportVectorTilesTask<SPAN class="punctuation token">.</SPAN><SPAN class="token function">CreateAsync</SPAN><SPAN class="punctuation token">(</SPAN>portalItem<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="comment token">// Create a new parameters instance</SPAN>
<SPAN class="keyword token">var</SPAN> parameters <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">new</SPAN> <SPAN class="token class-name">ExportVectorTilesParameters</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN>
<SPAN class="punctuation token">{</SPAN>
AreaOfInterest <SPAN class="operator token">=</SPAN> exportArea<SPAN class="punctuation token">.</SPAN>Geometry<SPAN class="punctuation token">,</SPAN> <SPAN class="comment token">//area to export</SPAN>
MaxLevel <SPAN class="operator token">=</SPAN> exportTask<SPAN class="punctuation token">.</SPAN>VectorTileSourceInfo<SPAN class="punctuation token">.</SPAN>LevelsOfDetail<SPAN class="punctuation token">.</SPAN>Count <SPAN class="operator token">-</SPAN> <SPAN class="number token">1</SPAN> <SPAN class="comment token">//levels to export</SPAN>
<SPAN class="punctuation token">}</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="comment token">// Create the export job</SPAN>
<SPAN class="keyword token">var</SPAN> job <SPAN class="operator token">=</SPAN> exportTask<SPAN class="punctuation token">.</SPAN><SPAN class="token function">ExportVectorTiles</SPAN><SPAN class="punctuation token">(</SPAN>parameters<SPAN class="punctuation token">,</SPAN> Path<SPAN class="punctuation token">.</SPAN><SPAN class="token function">Combine</SPAN><SPAN class="punctuation token">(</SPAN>_vectorTileCachePath<SPAN class="punctuation token">,</SPAN> <SPAN class="string token">"name.vtpk"</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="comment token">// Subscribe to notifications for status updates</SPAN>
job<SPAN class="punctuation token">.</SPAN>JobChanged <SPAN class="operator token">+</SPAN><SPAN class="operator token">=</SPAN> <SPAN class="punctuation token">(</SPAN>sender<SPAN class="punctuation token">,</SPAN> e<SPAN class="punctuation token">)</SPAN> <SPAN class="operator token">=</SPAN><SPAN class="operator token">></SPAN>
<SPAN class="punctuation token">{</SPAN>
<SPAN class="keyword token">if</SPAN> <SPAN class="punctuation token">(</SPAN>job<SPAN class="punctuation token">.</SPAN>Status <SPAN class="operator token">==</SPAN> Esri<SPAN class="punctuation token">.</SPAN>ArcGISRuntime<SPAN class="punctuation token">.</SPAN>Tasks<SPAN class="punctuation token">.</SPAN>JobStatus<SPAN class="punctuation token">.</SPAN>Succeeded<SPAN class="punctuation token">)</SPAN>
<SPAN class="punctuation token">{</SPAN>
<SPAN class="comment token">//do something</SPAN>
<SPAN class="punctuation token">}</SPAN>
<SPAN class="keyword token">else</SPAN> <SPAN class="keyword token">if</SPAN> <SPAN class="punctuation token">(</SPAN>job<SPAN class="punctuation token">.</SPAN>Status <SPAN class="operator token">==</SPAN> Esri<SPAN class="punctuation token">.</SPAN>ArcGISRuntime<SPAN class="punctuation token">.</SPAN>Tasks<SPAN class="punctuation token">.</SPAN>JobStatus<SPAN class="punctuation token">.</SPAN>Failed<SPAN class="punctuation token">)</SPAN>
<SPAN class="punctuation token">{</SPAN>
<SPAN class="comment token">// Notify the user</SPAN>
<SPAN class="token function">ShowStatusMessage</SPAN><SPAN class="punctuation token">(</SPAN>job<SPAN class="punctuation token">.</SPAN>Error<SPAN class="punctuation token">.</SPAN>Message<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="punctuation token">}</SPAN>
<SPAN class="punctuation token">}</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="comment token">// Start the export job</SPAN>
job<SPAN class="punctuation token">.</SPAN><SPAN class="token function">Start</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN><SPAN class="line-numbers-rows"><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN></SPAN>Es kann auch das vtpk und der Style (falls vorhanden) in einem Rutsch exportiert werden . Dazu muss dem ExportVectorTilesJob nur zusätzlich der Speicherpfad für einen Ordner für den Style mitgegeben werden.
ExportVectorTilesJob job<SPAN class="punctuation token">;</SPAN>
<SPAN class="keyword token">if</SPAN> <SPAN class="punctuation token">(</SPAN>exportTask<SPAN class="punctuation token">.</SPAN>HasStyleResources<SPAN class="punctuation token">)</SPAN>
<SPAN class="punctuation token">{</SPAN>
job <SPAN class="operator token">=</SPAN> exportTask<SPAN class="punctuation token">.</SPAN><SPAN class="token function">ExportVectorTiles</SPAN><SPAN class="punctuation token">(</SPAN>parameters<SPAN class="punctuation token">,</SPAN> Path<SPAN class="punctuation token">.</SPAN><SPAN class="token function">Combine</SPAN><SPAN class="punctuation token">(</SPAN>_vectorTileCachePath<SPAN class="punctuation token">,</SPAN> <SPAN class="string token">"name.vtpk"</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">,</SPAN> _styleResourcePath<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="punctuation token">}</SPAN>
<SPAN class="keyword token">else</SPAN>
<SPAN class="punctuation token">{</SPAN>
job <SPAN class="operator token">=</SPAN> exportTask<SPAN class="punctuation token">.</SPAN><SPAN class="token function">ExportVectorTiles</SPAN><SPAN class="punctuation token">(</SPAN>parameters<SPAN class="punctuation token">,</SPAN> Path<SPAN class="punctuation token">.</SPAN><SPAN class="token function">Combine</SPAN><SPAN class="punctuation token">(</SPAN>_vectorTileCachePath<SPAN class="punctuation token">,</SPAN> <SPAN class="string token">"name.vtpk"</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="punctuation token">}</SPAN><SPAN class="line-numbers-rows"><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN></SPAN>Und wenn nur der Style exportiert werden soll sieht es so aus:
<SPAN class="keyword token">var</SPAN> exportTask <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">await</SPAN> ExportVectorTilesTask<SPAN class="punctuation token">.</SPAN><SPAN class="token function">CreateAsync</SPAN><SPAN class="punctuation token">(</SPAN>portalItem<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="keyword token">if</SPAN> <SPAN class="punctuation token">(</SPAN>exportTask<SPAN class="punctuation token">.</SPAN>HasStyleResources<SPAN class="punctuation token">)</SPAN>
<SPAN class="punctuation token">{</SPAN>
<SPAN class="keyword token">var</SPAN> exportStyleJob <SPAN class="operator token">=</SPAN> exportTask<SPAN class="punctuation token">.</SPAN><SPAN class="token function">ExportStyleResourceCache</SPAN><SPAN class="punctuation token">(</SPAN>_styleResourcePath<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="keyword token">var</SPAN> result <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">await</SPAN> exportStyleJob<SPAN class="punctuation token">.</SPAN><SPAN class="token function">GetResultAsync</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="comment token">//do something</SPAN>
<SPAN class="punctuation token">}</SPAN><SPAN class="line-numbers-rows"><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN></SPAN>Wenn zum Beispiel alle die weiter oben beschriebenen exportierbaren ArcGIS Online Vector Tile Services lokal als Basemaps verfügbar sein sollen, muss von einem Service das vtpk und von allen Services nur die Styles exportiert werden. In einem StyleResource Ordner befinden sich nur JSON-Dateien mit der Beschreibung des Styles, diese sind sehr klein.

Nutzen von lokalen Vector Tile Packages und Styles in ArcGIS Runtime
Das lokale vtpk und ein vorhandener Style können dann so in die Map eingebunden werden:
<SPAN class="comment token">//Load a style</SPAN>
<SPAN class="keyword token">var</SPAN> itemResourceCache <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">new</SPAN> <SPAN class="token class-name">ItemResourceCache</SPAN><SPAN class="punctuation token">(</SPAN>_styleResourcePath<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="comment token">//Load the vtpk</SPAN>
<SPAN class="keyword token">var</SPAN> offlineVectorTileCache <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">new</SPAN> <SPAN class="token class-name">VectorTileCache</SPAN><SPAN class="punctuation token">(</SPAN>Path<SPAN class="punctuation token">.</SPAN><SPAN class="token function">Combine</SPAN><SPAN class="punctuation token">(</SPAN>_vectorTileCachePath<SPAN class="punctuation token">,</SPAN> <SPAN class="string token">"name.vtpk"</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="comment token">// Create a tile layer with the cache and the style</SPAN>
<SPAN class="keyword token">var</SPAN> layer <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">new</SPAN> <SPAN class="token class-name">ArcGISVectorTiledLayer</SPAN><SPAN class="punctuation token">(</SPAN>offlineVectorTileCache<SPAN class="punctuation token">,</SPAN> itemResourceCache<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="comment token">// Create a tile layer only with the cache</SPAN>
<SPAN class="comment token">//var layer = new ArcGISVectorTiledLayer(offlineVectorTileCache);</SPAN>
<SPAN class="comment token">// Create a new map with the layer as basemap</SPAN>
<SPAN class="keyword token">var</SPAN> map <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">new</SPAN> <SPAN class="token class-name">Map</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="keyword token">new</SPAN> <SPAN class="token class-name">Basemap</SPAN><SPAN class="punctuation token">(</SPAN>layer<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="comment token">// Apply the map to the mapview</SPAN>
MyMapView<SPAN class="punctuation token">.</SPAN>Map <SPAN class="operator token">=</SPAN> map<SPAN class="punctuation token">;</SPAN><SPAN class="line-numbers-rows"><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN></SPAN>
Wenn der Entwickler alles beschriebene schön kombiniert, können so in der ArcGIS Runtime App lokal mehrer Basemaps auf Basis von nur einem vtpk genutzt werden. Um den Speicherplatz der Daten auf dem Gerät muss sich meistens auch keine Sorgen mehr gemacht werden. In einem Test mit dem Gebiet grob Bayern in der gesamten Detailtiefe ist die Größe des vtpks + Styles nur ca.230 MB groß und der Export hat knapp 7 min gedauert. Wichtig ist noch die Information, dass es eine maximale Begrenzung ("maxExportTilesCount":10000) für einen Export gibt.

Offline Vector Tile Basemap ohne extra Style (nur das .vtpk geladen)

Offline Vector Tile Basemap mit Style

Offline Vector Tile Basemap mit Style

Offline Vector Tile Basemap mit Style

Offline Vector Tile Basemap mit Style