カスタムのラスタータイル
SDK for iOS を使用すると、カスタムのラスタタイル API NMAMapTileLayer
を使用してマップを拡張できます。
カスタムのラスタタイルは、地図に追加できるタイル画像です。この画像を使用すると、地理的に広い範囲の追加情報で地図を拡張できます。 カスタムのラスタタイルを表示するようにアプリケーションが設定されている場合、ユーザーは、指定されたズーム レベルまたは一定範囲のズームレベルで指定された地理的領域を表示するたびに、それらのタイルを表示できます。
- カスタムのラスタタイルイメージをリモートサーバーに保存
NMAMapTileLayerDataSource mapTileLayer:urlForTileAtX:y:zoomLevel:
し、プロトコルメソッドを使用して URL を返します。 NMAMapTileLayerDataSource mapTileLayer:requestDataForTileAtX:y:zoomLevel:tileRequest:
プロトコルメソッドを使用して、生のビットマップデータを提供します。
GitHub でラスタタイルの例をマップします
この機能を示す例について は、 https://github.com/heremaps/ (Obj-C) および https://github.com/heremaps/ (Swift) を参照してください。
地図を分割し、タイル座標を使用します
NMAMapTileLayer
ワールドマップを、 x 、 y 、およびズーム レベル座標で指定されたタイルに分割するスキームを使用します。 NMAMapTileLayerDataSource
この座標系は、タイルを要求するときにプロトコルによって使用されます。
- レベル 0 の場合 : 1 x 1 = 1 タイル
- レベル 1 の場合 : 2 x 2 = 4 タイル
- レベル 2 の場合 : 4 x 4 = 16 タイル
- レベル 3 の場合 : 8 x 8 = 64 タイル
- レベル 4 の場合 : 16 x 16 = 256 タイル
- ズーム レベル 20 まで続行します
たとえば、ズーム レベル 2 では、ワールドマップは次のように分割されます。

x および y パラメータは、指定されたズーム レベルに要求されているタイルを示します。
地理的領域内でサポートしているすべてのズームレベルをカバーするのに十分なタイルイメージを提供する必要があります。 NMAMapTileLayer
の boundingBox
プロパティを使用して、カスタムタイルレンダリングを特定の NMAGeoBoundingBox
に制限できます。 および showAtZoomLevel:
関連するメソッドを使用して、ズーム レベルを制限できます。
Web サーバーからタイルを提供しています
- サーバー上の適切な数のタイルをズームレベルに従ってホスト
NMAGeoBoundingBox
し、サポートしている必要があります。 タイルは PNG または JPG 形式で、 256 x 256 ピクセルのサイズにする必要があります ( これは既定のサイズですが、変更できます ) 。 - サーバー上の指定したタイルを参照する URL を返すように、派生元
NMAMapTileLayerDataSource
のオブジェクトを作成してmapTileLayer:urlForTileAtX:y:zoomLevel:method
インプリメントします。 -
NMAMapTileLayer
オブジェクトを作成し、そのプロパティをタイルデータソースサーバーに対応するように設定します。 少なくとも、サーバーでホストされているタイルを反映するようにboundingBox
およびzoomLevel
のプロパティを設定してください。dataSource
プロパティを設定します。 - オプション
fadingEnabled
で、などのプロパティを設定して、マップ ビュー内のタイルの外観をカスタマイズします。 addMapTileLayer:
メソッドを呼び出して、NMAMapTileLayer
オブジェクトをNMAMapView
に追加します。
次のコード スニペットは、ロンドンのクイーンエリザベスオリンピックパークをレンダリングするクラスを示しています。 パークは、NMAMapView
に追加されたタイルレイヤーとして表示 され、ラスタタイルは HERE サーバーから提供されます。 このクラスを使用するには、を呼び出し [OlympicParkTileLayer addOlympicParkTileLayerToMapView:myMapView]
ます。
@interface OlympicParkTileLayer : NMAMapTileLayer <NMAMapTileLayerDataSource>
@end
@implementation OlympicParkTileLayer
+(void)addOlympicParkTileLayerToMapView:(NMAMapView*)mapView
{
OlympicParkTileLayer *tileLayer = [OlympicParkTileLayer new];
[mapView addMapTileLayer:tileLayer];
[mapView setGeoCenter:tileLayer.boundingBox.center
zoomLevel:14.0
orientation:NMAMapViewPreserveValue
tilt:NMAMapViewPreserveValue
withAnimation:NMAMapAnimationNone ];
}
-(id)init
{
if (self = [super init]) {
// Set the data source
self.dataSource = self;
// Set the bitmap format properties (must be compatible with pngs hosted on the
// server)
self.pixelFormat = NMAPixelFormatRGBA;
self.transparent = NO;
// Limit the tiles to the bounding box supported by the server
NMAGeoBoundingBox *olympicParkBoundingBox =
[NMAGeoBoundingBox geoBoundingBoxWithTopLeft:
[NMAGeoCoordinates geoCoordinatesWithLatitude:51.557000 longitude:-0.042772]
bottomRight:
[NMAGeoCoordinates geoCoordinatesWithLatitude:51.525941 longitude: 0.028296]];
self.boundingBox = olympicParkBoundingBox;
// Customize the tile layer
self.fadingEnabled = YES;
// covers everything else on the map
self.mapLayerType = NMAMapLayerTypeForeground;
// Enable caching
self.cacheTimeToLive = 60 * 60 * 24; // 24 hours
self.cacheSizeLimit = 1024 * 1024 * 64; // 64MB
[self setCacheEnabled:YES withIdentifier:@"OlympicParkTileLayer"];
}
return self;
}
-(NSString *)mapTileLayer:(NMAMapTileLayer *)mapTileLayer
urlForTileAtX:(NSUInteger)x
y:(NSUInteger)y
zoomLevel:(NSUInteger)zoomLevel
{
// Return a URL for the specified tile
// This tile source is hosted by HERE Global B.V. and may be removed at any time
return [NSString stringWithFormat:
@"http://api.maps.example.org/maptiles/olympic_park/normal.day/%d/%d/%d.png",
zoomLevel,
y,
x ];
}
@end
タイルをビットマップとして指定します
アプリでバンドルされた静的タイル、動的に生成されたタイル、またはタイルイメージに使用しているサーバーで認証が必要な場合は、タイルをビットマップとして提供することを選択できます。 3 つ目のケースでは NMAMapTileLayer
、単純な HTTP GET 要求を使用してタイルイメージを取得するだけであるため、認証を処理してタイルをダウンロードするコードを提供するかどうかはユーザーの責任になります。 タイルがダウンロードされたら NMAMapTileLayer
、クラスのローカルビットマップとして使用できます。
-
NMAMapTileLayerDataSource
メソッドから派生し、mapTileLayer:requestDataForTileAtX:y:zoomLevel:tileRequest:
メソッドを実装するオブジェクトを作成します。NMAMapTileRequest
パラメーターを保持して使用し、要求されたビットマップデータを提供します。 -
NMAMapTileLayer
オブジェクトを作成し、そのプロパティをタイルデータソースに対応するように設定します。dataSource
プロパティを設定します。 - オプション
fadingEnabled
で、などのプロパティを設定して、マップ ビュー内のタイルの外観をカスタマイズします。 addMapTileLayer:
メソッドを呼び出して、NMAMapTileLayer
オブジェクトをNMAMapView
に追加します。
NMAMapView
タイルレイヤーを使用して上で赤と緑のタイルをレンダリングするクラスの例を次に示します。 を呼び出すことで使用 [SimpleBitmapTileLayer addSimpleBitmapTileLayerToMapView]
できます。
@interface SimpleBitmapTileLayer : NMAMapTileLayer <NMAMapTileLayerDataSource>
{
char *_redBitmap;
char *_greenBitmap;
}
@end
@implementation SimpleBitmapTileLayer
+(void)addSimpleBitmapTileLayerToMapView:(NMAMapView*)mapView
{
[mapView addMapTileLayer:[SimpleBitmapTileLayer new]];
}
-(id)init
{
if (self = [super init]) {
// Set the data source
self.dataSource = self;
// Set the bitmap properties (must match what is returned in
// requestDataForTileAtX:)
self.pixelFormat = NMAPixelFormatRGBA;
self.transparent = NO;
// The tiles will replace the map background
self.mapLayerType = NMAMapLayerTypeArea;
// We want the tiles to span the globe so don't limit with a bounding box or
// zoom level.
// We don't want to cache these tiles to disk, as in this simple case
// it's more efficient to keep bitmaps in memory.
// Create a red bitmap
_redBitmap = (char *)malloc(256*256*4);
for (int i=0; i<256*256*4; i+=4) {
_redBitmap[i] = 0xFF;
_redBitmap[i+1] = 0x00;
_redBitmap[i+2] = 0x00;
_redBitmap[i+3] = 0xFF;
}
// Create a green bitmap
_greenBitmap = (char *)malloc(256*256*4);
for (int i=0; i<256*256*4; i+=4) {
_greenBitmap[i] = 0x00;
_greenBitmap[i+1] = 0xFF;
_greenBitmap[i+2] = 0x00;
_greenBitmap[i+3] = 0xFF;
}
}
return self;
}
-(void)dealloc
{
free(_redBitmap);
free(_greenBitmap);
}
-(void) mapTileLayer:(NMAMapTileLayer *)mapTileLayer
requestDataForTileAtX:(NSUInteger)x
y:(NSUInteger)y
zoomLevel:(NSUInteger)zoomLevel
tileRequest:(NMAMapTileRequest *)tileRequest
{
// Dispatch to a global queue to demonstrate retaining the tile request and
// completing asynchronously. In this case it is not necessary but if obtaining
// the bitmap data was a lengthy operation we would not want to block the current
// (map rendering) thread.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Use alternating red and green bitmaps to create checkerboard effect
void *bitmap = ( (x%2==0 && y%2==1) || (x%2 ==1 && y%2==0) ) ? _redBitmap :
_greenBitmap;
// Copy the bitmap into the bitmap buffer supplied by the tile request
// Copy exactly tileRequest.bytesLength
memcpy(tileRequest.bytesPtr, bitmap, tileRequest.bytesLength);
// Complete the tile request AFTER the copy has completed
tileRequest.status = NMAMapTileRequestStatusComplete;
});
}
@end
NMAMapTileRequest
このオブジェクトを使用する際に考慮すべき重要な点がいくつかあります。 - ビットマップデータは
NMAMapTileLayer pixelFormat
、プロパティで指定された形式にする必要があります。 デフォルトはですNMAPixelFormatRGBA
。 - 要求を完了する前にビットマップバイトをコピーし、
bytesLength
で指定されたバイト数のみをコピーして、メモリの破損を防ぎます。 - リクエストは
NMAMapTileRequestStatusComplete
、必ずまたはのいずれかを使用して正確に 1 回完了NMAMapTileRequestStatusFailed
してください。 未完了のリクエストは、完了するまでメモリを占有します。 mapTileLayer:requestDataForTileAtX:y:zoomLevel:tileRequest:
レンダリングのパフォーマンスに影響を与えるため、長期間ブロックしないでください。
オーバーレイのレンダリング順序を変更しています
プロパティを使用 mapLayerType
して、ラスタタイルがレンダリングされるマップ レイヤーをカスタマイズできます。 たとえば、作成した NMAMapObjects
と共にタイルを NMAMapLayerTypeForeground
レイヤーに配置する場合、 zIndex
を使用して、タイルの上または下にオブジェクトをレンダリングするかどうかを制御できます。
その他のタイルのカスタマイズ
NMAMapTileLayer
では、次のようなタイルの外観をさらにカスタマイズするためのプロパティがサポートされています。 - タイルサイズ
- RGB や BGRA などのピクセル形式 ( メモリ使用量を削減するため )
- タイルが描画されるときにフェードインするかどうかを指定します
- 欠落しているタイルの代わりに、別のズーム レベルからのタイルをレンダリングするかどうかを指定します
- タイルが透明度をサポートするかどうかを示します
タイルのキャッシュ
タイルをディスクにキャッシュして、 URL フェッチケースのパフォーマンスを改善し、データトラフィックを削減できます。
キャッシュを有効にする場合は、キャッシュ識別子を指定する必要があります。 この識別子は NMAMapTileLayer
、アプリケーション内で使用されている各識別子で一意である必要があります。 キャッシュはアプリセッション間で保持されるため、(定数を定義するなどして)セッション間で同じ識別子を使用することが重要です。
オプションで、キャッシュされた各タイルのキャッシュサイズと存続時間を制限できます。 を呼び出すと、いつでもキャッシュを消去 [NMAMapTileLayer clearCache]
できます。 キャッシュが完全に消去されたことを確認するには、 [NMAMapTileLayer clearCache]
を呼び出す前に、まずマップ ビューから NMAMapTileLayer
を削除します。
次のコードでは、最大 128 MB のディスクキャッシュと、 7 日間のタイル有効期間を有効にします。
NMAMapTileLayer *tileLayer = [[NMAMapTileLayer alloc]init];
tileLayer.dataSource = self; // Assuming self is a valid data source
[tileLayer setCacheEnabled:YES withIdentifier:@"MyUniqueTileCacheIdenfifier"];
tileLayer.cacheTimeToLive = 60 * 60 * 24 * 7; // 7 days
tileLayer.cacheSizeLimit = 1024 * 1024 * 128; // 128 MB
[mapView addMapTileLayer:tileLayer]; // NOTE: add to map view after setting tile properties
パフォーマンスのヒント
- 重要 :
NMAMapTileLayer
タイルレイヤーをマップ ビューに追加する前に、プロパティを設定します。 ほとんどのプロパティでは、ビューに追加された後での設定は無視されます。 - 1
NMAMapTileLayer
つのインスタンスを複数のマップに追加しないでください。 - タイルレイヤーで設定したプロパティが
NMAMapTileLayerDataSource
、プロトコル経由で提供しているデータと一致することを確認してください。 たとえば、タイルデータが透明機能をサポートしていない場合は、透明機能を有効にしないでください。 NMAMapTileLayerDataSource
メソッドを長期間ブロックしないでください。 たとえば、その場でタイルを生成するのに時間がかかる場合は、処理を別の GCD キューに移動します。NMAMapTileRequest
メモリmapTileLayer:requestDataForTileAtX:y:zoomLevel:tileRequest:
リークを避けるため、経由で受信したすべてのオブジェクトが完了していることを確認します。NMAMapTileRequest bytesPtr
メモリのコピーを避けるために、プロパティに直接書き込みます。- 特定のタイルの要求が頻繁に失敗する場合は、
NO
RETURNINGmapTileLayer:hasTileAtX:y:zoomLevel:
の実装を検討してください。 - 提供されているディスクキャッシュメカニズムを使用します。