diff --git a/android/src/main/java/com/rnmapbox/rnmbx/components/styles/sources/RNMBXRasterSource.kt b/android/src/main/java/com/rnmapbox/rnmbx/components/styles/sources/RNMBXRasterSource.kt index cbb90de1f..345cda994 100644 --- a/android/src/main/java/com/rnmapbox/rnmbx/components/styles/sources/RNMBXRasterSource.kt +++ b/android/src/main/java/com/rnmapbox/rnmbx/components/styles/sources/RNMBXRasterSource.kt @@ -5,20 +5,35 @@ import com.mapbox.maps.extension.style.sources.generated.RasterSource class RNMBXRasterSource(context: Context?) : RNMBXTileSource(context) { private var mTileSize: Int? = null + private var mPrefetchZoomDelta: Long? = null + private var mTileNetworkRequestsDelay: Double? = null override fun makeSource(): RasterSource { val id = iD!! val configurationUrl = uRL val tileSize = if (mTileSize == null) DEFAULT_TILE_SIZE else mTileSize!! - return if (configurationUrl != null) { - RasterSource.Builder(id).url(configurationUrl).tileSize(tileSize.toLong()).build() - } else RasterSource.Builder(id).tileSet(buildTileset()) - .tileSize(tileSize.toLong()).build() + val builder = if (configurationUrl != null) { + RasterSource.Builder(id).url(configurationUrl) + } else { + RasterSource.Builder(id).tileSet(buildTileset()) + } + builder.tileSize(tileSize.toLong()) + mPrefetchZoomDelta?.let { builder.prefetchZoomDelta(it) } + mTileNetworkRequestsDelay?.let { builder.tileNetworkRequestsDelay(it) } + return builder.build() } fun setTileSize(tileSize: Int) { mTileSize = tileSize } + fun setPrefetchZoomDelta(value: Long?) { + mPrefetchZoomDelta = value + } + + fun setTileNetworkRequestsDelay(value: Double?) { + mTileNetworkRequestsDelay = value + } + override fun hasPressListener(): Boolean { return false } diff --git a/android/src/main/java/com/rnmapbox/rnmbx/components/styles/sources/RNMBXRasterSourceManager.kt b/android/src/main/java/com/rnmapbox/rnmbx/components/styles/sources/RNMBXRasterSourceManager.kt index aa625b3c6..11dd35395 100644 --- a/android/src/main/java/com/rnmapbox/rnmbx/components/styles/sources/RNMBXRasterSourceManager.kt +++ b/android/src/main/java/com/rnmapbox/rnmbx/components/styles/sources/RNMBXRasterSourceManager.kt @@ -35,6 +35,16 @@ class RNMBXRasterSourceManager(reactApplicationContext: ReactApplicationContext) source.setTileSize(tileSize.asInt()) } + @ReactProp(name = "prefetchZoomDelta") + override fun setPrefetchZoomDelta(source: RNMBXRasterSource, value: Dynamic) { + source.setPrefetchZoomDelta(if (value.isNull) null else value.asInt().toLong()) + } + + @ReactProp(name = "tileNetworkRequestsDelay") + override fun setTileNetworkRequestsDelay(source: RNMBXRasterSource, value: Dynamic) { + source.setTileNetworkRequestsDelay(if (value.isNull) null else value.asDouble()) + } + override fun customEvents(): Map? { return eventMapOf( EventKeys.RASTER_SOURCE_LAYER_CLICK to "onMapboxRasterSourcePress", diff --git a/docs/RasterSource.md b/docs/RasterSource.md index ae7a2f539..cf490b6c6 100644 --- a/docs/RasterSource.md +++ b/docs/RasterSource.md @@ -85,6 +85,30 @@ Mapbox urls default to 256, all others default to 512. +### prefetchZoomDelta + +```tsx +number +``` +When greater than 0, the map first requests a tile at a zoom level below +`zoom - prefetchZoomDelta`, rounded to a multiple of the delta, so it can show a +low-resolution map quickly. 0 disables this. The default value for this option is 4. +Only read when the source is created. + +[Raster Source tile requests](../examples/FillRasterLayer/RasterSourceTileRequests) + +### tileNetworkRequestsDelay + +```tsx +number +``` +Delay in milliseconds before a tile's network request is sent while a gesture or a camera +animation is in progress. Tiles that leave the viewport before the delay elapses are never +requested. Has no effect on an idle map. The default value for this option is 0. +Only read when the source is created. + +[Raster Source tile requests](../examples/FillRasterLayer/RasterSourceTileRequests) + ### tms ```tsx diff --git a/docs/docs.json b/docs/docs.json index 5dff1c0f7..6d0649a76 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -7735,6 +7735,20 @@ "default": "none", "description": "Size of the map tiles.\nMapbox urls default to 256, all others default to 512." }, + { + "name": "prefetchZoomDelta", + "required": false, + "type": "number", + "default": "none", + "description": "When greater than 0, the map first requests a tile at a zoom level below\n`zoom - prefetchZoomDelta`, rounded to a multiple of the delta, so it can show a\nlow-resolution map quickly. 0 disables this. The default value for this option is 4.\nOnly read when the source is created." + }, + { + "name": "tileNetworkRequestsDelay", + "required": false, + "type": "number", + "default": "none", + "description": "Delay in milliseconds before a tile's network request is sent while a gesture or a camera\nanimation is in progress. Tiles that leave the viewport before the delay elapses are never\nrequested. Has no effect on an idle map. The default value for this option is 0.\nOnly read when the source is created." + }, { "name": "tms", "required": false, diff --git a/docs/examples.json b/docs/examples.json index a2bfbc54e..4cfd6d59a 100644 --- a/docs/examples.json +++ b/docs/examples.json @@ -988,6 +988,20 @@ "relPath": "FillRasterLayer/RasterSource.js", "name": "RasterSource" }, + { + "metadata": { + "title": "Raster Source tile requests", + "tags": [ + "RasterSource", + "RasterSource#prefetchZoomDelta", + "RasterSource#tileNetworkRequestsDelay" + ], + "docs": "\nFetches only the tiles of the current zoom level (no parent tiles as a placeholder) and waits 200 ms\nbefore requesting tiles while the map pans, so tiles that leave the screen during a fast pan are\nnever requested. Watch the network log while panning to compare with the Raster Source example.\n" + }, + "fullPath": "example/src/examples/FillRasterLayer/RasterSourceTileRequests.js", + "relPath": "FillRasterLayer/RasterSourceTileRequests.js", + "name": "RasterSourceTileRequests" + }, { "metadata": { "title": "Watercolor Raster Tiles", diff --git a/example/src/examples/FillRasterLayer/RasterSourceTileRequests.js b/example/src/examples/FillRasterLayer/RasterSourceTileRequests.js new file mode 100644 index 000000000..202c3f9ea --- /dev/null +++ b/example/src/examples/FillRasterLayer/RasterSourceTileRequests.js @@ -0,0 +1,53 @@ +import React from 'react'; +import { MapView, RasterLayer, RasterSource, Camera } from '@rnmapbox/maps'; + +const styles = { + matchParent: { flex: 1 }, +}; + +export default function RasterSourceTileRequestsExample() { + return ( + + + + + + ); +} + +/* end-example-doc */ + +/** + * @typedef {import('../common/ExampleMetadata').ExampleWithMetadata} ExampleWithMetadata + * @type {ExampleWithMetadata['metadata']} + */ +const metadata = { + title: 'Raster Source tile requests', + tags: [ + 'RasterSource', + 'RasterSource#prefetchZoomDelta', + 'RasterSource#tileNetworkRequestsDelay', + ], + docs: ` +Fetches only the tiles of the current zoom level (no parent tiles as a placeholder) and waits 200 ms +before requesting tiles while the map pans, so tiles that leave the screen during a fast pan are +never requested. Watch the network log while panning to compare with the Raster Source example. +`, +}; +RasterSourceTileRequestsExample.metadata = metadata; diff --git a/example/src/examples/FillRasterLayer/index.js b/example/src/examples/FillRasterLayer/index.js index f9f81e4af..28926e796 100644 --- a/example/src/examples/FillRasterLayer/index.js +++ b/example/src/examples/FillRasterLayer/index.js @@ -7,6 +7,7 @@ export { default as QueryAtPoint } from './QueryAtPoint'; export { default as QuerySourceFeatures } from './QuerySourceFeatures'; export { default as QueryWithRect } from './QueryWithRect'; export { default as RasterSource } from './RasterSource'; +export { default as RasterSourceTileRequests } from './RasterSourceTileRequests'; export { default as WatercolorRasterTiles } from './WatercolorRasterTiles'; export { default as HillshadeSource } from './HillshadeSource'; diff --git a/ios/RNMBX/RNMBXRasterSource.swift b/ios/RNMBX/RNMBXRasterSource.swift index b88395241..0d2b5c1d0 100644 --- a/ios/RNMBX/RNMBXRasterSource.swift +++ b/ios/RNMBX/RNMBXRasterSource.swift @@ -11,6 +11,8 @@ public class RNMBXRasterSource : RNMBXSource { @objc public var minZoomLevel: NSNumber? @objc public var maxZoomLevel: NSNumber? @objc public var tileSize: NSNumber? + @objc public var prefetchZoomDelta: NSNumber? + @objc public var tileNetworkRequestsDelay: NSNumber? @objc public var tms: Bool = false @@ -31,6 +33,14 @@ public class RNMBXRasterSource : RNMBXSource { result.tileSize = tileSize.doubleValue } + if let prefetchZoomDelta = prefetchZoomDelta { + result.prefetchZoomDelta = prefetchZoomDelta.doubleValue + } + + if let tileNetworkRequestsDelay = tileNetworkRequestsDelay { + result.tileNetworkRequestsDelay = tileNetworkRequestsDelay.doubleValue + } + if let minZoomLevel = minZoomLevel { result.minzoom = minZoomLevel.doubleValue } diff --git a/ios/RNMBX/RNMBXRasterSourceComponentView.mm b/ios/RNMBX/RNMBXRasterSourceComponentView.mm index d007a56f6..dbfc5de90 100644 --- a/ios/RNMBX/RNMBXRasterSourceComponentView.mm +++ b/ios/RNMBX/RNMBXRasterSourceComponentView.mm @@ -104,6 +104,14 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared & if (tileSize != nil) { _view.tileSize = tileSize; } + id prefetchZoomDelta = RNMBXConvertFollyDynamicToId(newProps.prefetchZoomDelta); + if (prefetchZoomDelta != nil) { + _view.prefetchZoomDelta = prefetchZoomDelta; + } + id tileNetworkRequestsDelay = RNMBXConvertFollyDynamicToId(newProps.tileNetworkRequestsDelay); + if (tileNetworkRequestsDelay != nil) { + _view.tileNetworkRequestsDelay = tileNetworkRequestsDelay; + } id tms = RNMBXConvertFollyDynamicToId(newProps.tms); if (tms != nil) { _view.tms = tms; diff --git a/src/components/RasterSource.tsx b/src/components/RasterSource.tsx index 7811f0c72..03acb08f1 100644 --- a/src/components/RasterSource.tsx +++ b/src/components/RasterSource.tsx @@ -55,6 +55,22 @@ type Props = BaseProps & { */ tileSize?: number; + /** + * When greater than 0, the map first requests a tile at a zoom level below + * `zoom - prefetchZoomDelta`, rounded to a multiple of the delta, so it can show a + * low-resolution map quickly. 0 disables this. The default value for this option is 4. + * Only read when the source is created. + */ + prefetchZoomDelta?: number; + + /** + * Delay in milliseconds before a tile's network request is sent while a gesture or a camera + * animation is in progress. Tiles that leave the viewport before the delay elapses are never + * requested. Has no effect on an idle map. The default value for this option is 0. + * Only read when the source is created. + */ + tileNetworkRequestsDelay?: number; + /** * Influences the y direction of the tile coordinates. (tms inverts y axis) */ @@ -116,6 +132,8 @@ class RasterSource extends AbstractSource { minZoomLevel: this.props.minZoomLevel, maxZoomLevel: this.props.maxZoomLevel, tileSize: this.props.tileSize, + prefetchZoomDelta: this.props.prefetchZoomDelta, + tileNetworkRequestsDelay: this.props.tileNetworkRequestsDelay, tms: this.props.tms, attribution: this.props.attribution, }; diff --git a/src/specs/RNMBXRasterSourceNativeComponent.ts b/src/specs/RNMBXRasterSourceNativeComponent.ts index 8c22fea06..e5f4a5bf9 100644 --- a/src/specs/RNMBXRasterSourceNativeComponent.ts +++ b/src/specs/RNMBXRasterSourceNativeComponent.ts @@ -13,6 +13,8 @@ export interface NativeProps extends ViewProps { minZoomLevel: UnsafeMixed; maxZoomLevel: UnsafeMixed; tileSize: UnsafeMixed; + prefetchZoomDelta: UnsafeMixed; + tileNetworkRequestsDelay: UnsafeMixed; tms: UnsafeMixed; attribution: UnsafeMixed; sourceBounds: UnsafeMixed>;