diff --git a/android/src/main/java/com/rnmapbox/rnmbx/components/mapview/NativeMapViewModule.kt b/android/src/main/java/com/rnmapbox/rnmbx/components/mapview/NativeMapViewModule.kt index 5ff073e3f..7cdd784ea 100644 --- a/android/src/main/java/com/rnmapbox/rnmbx/components/mapview/NativeMapViewModule.kt +++ b/android/src/main/java/com/rnmapbox/rnmbx/components/mapview/NativeMapViewModule.kt @@ -70,6 +70,20 @@ class NativeMapViewModule(context: ReactApplicationContext, val viewTagResolver: promise.resolve(null) } } + + override fun setStyleLayerProperty( + viewRef: ViewRefTag?, + layerId: String, + propertyName: String, + propertyValue: String, + promise: Promise + ) { + withMapViewOnUIThread(viewRef, promise) { + it.setStyleLayerProperty(layerId, propertyName, propertyValue) + + promise.resolve(null) + } + } override fun getCenter(viewRef: ViewRefTag?, promise: Promise) { withMapViewOnUIThread(viewRef, promise) { diff --git a/android/src/main/java/com/rnmapbox/rnmbx/components/mapview/RNMBXMapView.kt b/android/src/main/java/com/rnmapbox/rnmbx/components/mapview/RNMBXMapView.kt index b05cdbe74..485a1dd3b 100644 --- a/android/src/main/java/com/rnmapbox/rnmbx/components/mapview/RNMBXMapView.kt +++ b/android/src/main/java/com/rnmapbox/rnmbx/components/mapview/RNMBXMapView.kt @@ -1173,6 +1173,41 @@ open class RNMBXMapView(private val mContext: Context, var mManager: RNMBXMapVie } } } + + fun setStyleLayerProperty( + layerId: String, + propertyName: String, + propertyValue: String + ): Boolean { + if (mMap == null) { + Logger.e("MapView", "setStyleLayerProperty, map is null") + return false + } + + val style = mMap.getStyle() + if (style == null) { + Logger.e("MapView", "setStyleLayerProperty, style is null") + return false + } + + try { + val result = style.setStyleLayerProperty( + layerId, + propertyName, + Value.valueOf(propertyValue) + ) + + if (result.isError) { + Logger.e("MapView", "setStyleLayerProperty error: ${result.error}") + return false + } + + return true + } catch (e: Exception) { + Logger.e("MapView", "setStyleLayerProperty exception: ${e.message}") + return false + } + } // endregion companion object { diff --git a/docs/MapView.md b/docs/MapView.md index d2ad2d0c8..47335dfe9 100644 --- a/docs/MapView.md +++ b/docs/MapView.md @@ -738,6 +738,23 @@ Sets the visibility of all the layers referencing the specified `sourceLayerId` await this._map.setSourceVisibility(false, 'composite', 'building') ``` +### setStyleLayerProperty(layerId, propertyName, propertyValue) + +Sets the value of a property for a specific layer referencing the specified `layerId` + +#### arguments +| Name | Type | Required | Description | +| ---- | :--: | :------: | :----------: | +| `layerId` | `string` | `Yes` | layerId | +| `propertyName` | `string` | `Yes` | propertyName | +| `propertyValue` | `string` | `Yes` | propertyValue | + + + +```javascript +await this._map.setStyleLayerProperty('my-layer', 'visibility', 'none') +``` + ### setFeatureState(featureId, state, sourceId[, sourceLayerId]) diff --git a/docs/docs.json b/docs/docs.json index 6d6bd98b2..640d45645 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -4646,6 +4646,42 @@ "\nawait this._map.setSourceVisibility(false, 'composite', 'building')\n\n" ] }, + { + "name": "setStyleLayerProperty", + "docblock": "Sets the value of a property for a specific layer referencing the specified `layerId`\n\n@example\nawait this._map.setStyleLayerProperty('my-layer', 'visibility', 'none')\n\n@param {String} layerId - layerId\n@param {String} propertyName - propertyName\n@param {String} propertyValue - propertyValue", + "modifiers": [], + "params": [ + { + "name": "layerId", + "description": "layerId", + "type": { + "name": "string" + }, + "optional": false + }, + { + "name": "propertyName", + "description": "propertyName", + "type": { + "name": "string" + }, + "optional": false + }, + { + "name": "propertyValue", + "description": "propertyValue", + "type": { + "name": "string" + }, + "optional": false + } + ], + "returns": null, + "description": "Sets the value of a property for a specific layer referencing the specified `layerId`", + "examples": [ + "\nawait this._map.setStyleLayerProperty('my-layer', 'visibility', 'none')\n\n" + ] + }, { "name": "setFeatureState", "docblock": "Updates the state map of a feature within a style source.\n\nUpdates entries in the state map of a given feature within a style source.\nOnly entries listed in the `state` will be updated.\nAn entry in the feature state map that is not listed in `state` will retain its previous value.\n\n@param {string} featureId Identifier of the feature whose state should be updated.\n@param {[k: string]: NativeArg} state Map of entries to update with their respective new values.\n@param {string} sourceId Style source identifier.\n@param {string | null} sourceLayerId Style source layer identifier (for multi-layer sources such as vector sources).", diff --git a/docs/examples.json b/docs/examples.json index 77b52e1e0..86bd19487 100644 --- a/docs/examples.json +++ b/docs/examples.json @@ -446,7 +446,7 @@ "metadata": { "title": "Source Layer Visibility", "tags": [ - "MapView#setSoruceVisibility" + "MapView#setSourceVisibility" ], "docs": "\nChanges visibility of layers using a source in the map\n" }, @@ -454,6 +454,18 @@ "relPath": "Map/SourceLayerVisibility.js", "name": "SourceLayerVisibility" }, + { + "metadata": { + "title": "Style Layer Property", + "tags": [ + "MapView#setStyleLayerProperty" + ], + "docs": "\nChanges the property of a layer using the specified layerId\n" + }, + "fullPath": "example/src/examples/Map/StyleLayerProperty.js", + "relPath": "Map/StyleLayerProperty.js", + "name": "StyleLayerProperty" + }, { "metadata": { "title": "Style JSON", diff --git a/example/src/examples/Map/StyleLayerProperty.js b/example/src/examples/Map/StyleLayerProperty.js new file mode 100755 index 000000000..5322e4e91 --- /dev/null +++ b/example/src/examples/Map/StyleLayerProperty.js @@ -0,0 +1,65 @@ +import React from 'react'; +import { Text } from 'react-native'; +import { MapView, Camera } from '@rnmapbox/maps'; + +import Bubble from '../common/Bubble'; + +const defaultCamera = { + centerCoordinate: [-74.005974, 40.712776], + zoomLevel: 13, +}; + +const styles = { + mapView: { flex: 1 }, +}; + +class StyleLayerProperty extends React.Component { + state = { + show: true, + }; + + onPress = () => { + this.setState( + { + show: !this.state.show, + }, + () => { + this._map.setStyleLayerProperty('building', 'visibility', this.state.show ? 'visible' : 'none'); + }, + ); + }; + + render() { + return ( + <> + { + this._map = c; + }} + onPress={this.onPress} + style={styles.mapView} + > + + + + {this.state.show ? 'Hide Buildings' : 'Show Buildings'} + + + ); + } +} + +export default StyleLayerProperty; + +/* end-example-doc */ + +/** + * @typedef {import('../common/ExampleMetadata').ExampleWithMetadata} ExampleWithMetadata + * @type {ExampleWithMetadata['metadata']} + */ +const metadata = { + title: 'Style Layer Property', + tags: ['MapView#setStyleLayerProperty'], + docs: `Changes the property of a layer using the specified layerId`, +}; +StyleLayerProperty.metadata = metadata; diff --git a/example/src/examples/Map/index.js b/example/src/examples/Map/index.js index 36a569a17..e78c34760 100644 --- a/example/src/examples/Map/index.js +++ b/example/src/examples/Map/index.js @@ -10,6 +10,7 @@ export { default as MapFps } from './MapFps'; export { default as ShowMapLocalStyle } from './ShowMapLocalStyle'; export { default as ShowRegionDidChange } from './ShowRegionDidChange'; export { default as SourceLayerVisibility } from './SourceLayerVisibility'; +export { default as StyleLayerProperty } from './StyleLayerProperty'; export { default as StyleJson } from './StyleJson'; export { default as TwoByTwo } from './TwoByTwo'; export { default as MapAndRNNavigation } from './MapAndRNNavigation'; diff --git a/ios/RNMBX/RNMBXMapView.swift b/ios/RNMBX/RNMBXMapView.swift index 817dcb38a..a1ca0f1ee 100644 --- a/ios/RNMBX/RNMBXMapView.swift +++ b/ios/RNMBX/RNMBXMapView.swift @@ -1586,6 +1586,18 @@ extension RNMBXMapView { } } +extension RNMBXMapView { + func setStyleLayerProperty(layerId: String, propertyName: String, propertyValue: Any) -> Void { + let style = self.mapboxMap.style + + do { + try style.setLayerProperty(for: layerId, property: propertyName, value: propertyValue) + } catch { + Logger.log(level: .error, message: "Cannot set property \(propertyName) on layer: \(layerId)") + } + } +} + class RNMBXPointAnnotationManager : AnnotationInteractionDelegate { weak var selected : RNMBXPointAnnotation? = nil private var draggedAnnotation: PointAnnotation? diff --git a/ios/RNMBX/RNMBXMapViewManager.swift b/ios/RNMBX/RNMBXMapViewManager.swift index f5a46de9a..d09f33764 100644 --- a/ios/RNMBX/RNMBXMapViewManager.swift +++ b/ios/RNMBX/RNMBXMapViewManager.swift @@ -68,6 +68,18 @@ extension RNMBXMapViewManager { resolver(nil) } + @objc public static func setStyleLayerProperty( + _ view: RNMBXMapView, + layerId: String, + propertyName: String, + propertyValue: String, + resolver: @escaping RCTPromiseResolveBlock, + rejecter: @escaping RCTPromiseRejectBlock + ) { + view.setStyleLayerProperty(layerId: layerId, propertyName: propertyName, propertyValue: propertyValue) + resolver(nil) + } + @objc public static func getCenter( _ view: RNMBXMapView, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock diff --git a/ios/RNMBX/RNMBXMapViewModule.mm b/ios/RNMBX/RNMBXMapViewModule.mm index 878c4c32e..ba72851af 100644 --- a/ios/RNMBX/RNMBXMapViewModule.mm +++ b/ios/RNMBX/RNMBXMapViewModule.mm @@ -124,6 +124,12 @@ - (void)withMapView:(nonnull NSNumber*)viewRef block:(void (^)(RNMBXMapView *))b } reject:reject methodName:@"setSourceVisibility"]; } +RCT_EXPORT_METHOD(setStyleLayerProperty:(nonnull NSNumber*)viewRef layerId:(NSString *)layerId propertyName:(NSString *)propertyName propertyValue:(id)propertyValue resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { + [self withMapView:viewRef block:^(RNMBXMapView *view) { + [RNMBXMapViewManager setStyleLayerProperty:view layerId:layerId propertyName:propertyName propertyValue:propertyValue resolver:resolve rejecter:reject]; + } reject:reject methodName:@"setStyleLayerProperty"]; +} + RCT_EXPORT_METHOD(setFeatureState:(nonnull NSNumber*)viewRef featureId:(nonnull NSString *)featureId state:(nonnull NSDictionary *)state sourceId:(NSString *)sourceId sourceLayerId:(NSString *)sourceLayerId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { [self withMapView:viewRef block:^(RNMBXMapView *view) { [RNMBXMapViewManager setFeatureState:view featureId:featureId state:state sourceId:sourceId sourceLayerId:sourceLayerId resolver:resolve rejecter:reject]; diff --git a/setup-jest.js b/setup-jest.js index 5a046367e..ef68d4c56 100644 --- a/setup-jest.js +++ b/setup-jest.js @@ -153,6 +153,7 @@ NativeModules.RNMBXMapViewModule = { takeSnap: jest.fn(), queryTerrainElevation: jest.fn(), setSourceVisibility: jest.fn(), + setStyleLayerProperty: jest.fn(), getCenter: jest.fn(), getCoordinateFromView: jest.fn(), getPointInView: jest.fn(), diff --git a/src/components/MapView.tsx b/src/components/MapView.tsx index b458c8517..b2c70bf0c 100644 --- a/src/components/MapView.tsx +++ b/src/components/MapView.tsx @@ -938,6 +938,28 @@ class MapView extends NativeBridgeComponent( ]); } + /** + * Sets the value of a property for a specific layer referencing the specified `layerId` + * + * @example + * await this._map.setStyleLayerProperty('my-layer', 'visibility', 'none') + * + * @param {String} layerId - layerId + * @param {String} propertyName - propertyName + * @param {String} propertyValue - propertyValue + */ + setStyleLayerProperty( + layerId: string, + propertyName: string, + propertyValue: string, + ) { + this._runNative('setStyleLayerProperty', [ + layerId, + propertyName, + propertyValue, + ]); + } + /** * Updates the state map of a feature within a style source. * diff --git a/src/specs/NativeMapViewModule.ts b/src/specs/NativeMapViewModule.ts index c00887666..eddbf6f75 100644 --- a/src/specs/NativeMapViewModule.ts +++ b/src/specs/NativeMapViewModule.ts @@ -15,6 +15,12 @@ export interface Spec extends TurboModule { sourceId: string, sourceLayerId: string, ) => Promise; + setStyleLayerProperty: ( + viewRef: Int32 | null, + layerId: string, + propertyName: string, + propertyValue: string, + ) => Promise; getCenter: (viewRef: Int32 | null) => Promise; getCoordinateFromView: ( viewRef: Int32 | null,