diff --git a/__tests__/interface.test.js b/__tests__/interface.test.js index 693f5d9ee..458d4ed91 100644 --- a/__tests__/interface.test.js +++ b/__tests__/interface.test.js @@ -40,6 +40,7 @@ describe('Public Interface', () => { 'BackgroundLayer', 'RasterLayer', 'RasterParticleLayer', + 'HillshadeLayer', 'SkyLayer', 'Terrain', 'Atmosphere', diff --git a/android/src/main/java/com/rnmapbox/rnmbx/RNMBXPackage.kt b/android/src/main/java/com/rnmapbox/rnmbx/RNMBXPackage.kt index 57c8cc6cf..b86218ce8 100644 --- a/android/src/main/java/com/rnmapbox/rnmbx/RNMBXPackage.kt +++ b/android/src/main/java/com/rnmapbox/rnmbx/RNMBXPackage.kt @@ -31,6 +31,7 @@ import com.rnmapbox.rnmbx.components.styles.layers.RNMBXCircleLayerManager import com.rnmapbox.rnmbx.components.styles.layers.RNMBXFillExtrusionLayerManager import com.rnmapbox.rnmbx.components.styles.layers.RNMBXFillLayerManager import com.rnmapbox.rnmbx.components.styles.layers.RNMBXHeatmapLayerManager +import com.rnmapbox.rnmbx.components.styles.layers.RNMBXHillshadeLayerManager import com.rnmapbox.rnmbx.components.styles.layers.RNMBXLineLayerManager import com.rnmapbox.rnmbx.components.styles.layers.RNMBXModelLayerManager import com.rnmapbox.rnmbx.components.styles.layers.RNMBXRasterLayerManager @@ -161,6 +162,7 @@ class RNMBXPackage : TurboReactPackage() { managers.add(RNMBXCircleLayerManager()) managers.add(RNMBXSymbolLayerManager()) managers.add(RNMBXRasterLayerManager()) + managers.add(RNMBXHillshadeLayerManager()) if (RNMBXRasterParticleLayerManager.isImplemented) { managers.add(RNMBXRasterParticleLayerManager()) } diff --git a/android/src/main/java/com/rnmapbox/rnmbx/components/styles/layers/RNMBXHillshadeLayer.kt b/android/src/main/java/com/rnmapbox/rnmbx/components/styles/layers/RNMBXHillshadeLayer.kt new file mode 100644 index 000000000..7771e7993 --- /dev/null +++ b/android/src/main/java/com/rnmapbox/rnmbx/components/styles/layers/RNMBXHillshadeLayer.kt @@ -0,0 +1,27 @@ +package com.rnmapbox.rnmbx.components.styles.layers + +import android.content.Context +import com.mapbox.maps.extension.style.layers.generated.HillshadeLayer +import com.rnmapbox.rnmbx.components.styles.RNMBXStyle +import com.rnmapbox.rnmbx.components.styles.RNMBXStyleFactory +import com.rnmapbox.rnmbx.utils.Logger + +class RNMBXHillshadeLayer(context: Context?) : RNMBXLayer( + context!! +) { + override fun makeLayer(): HillshadeLayer { + return HillshadeLayer(iD!!, mSourceID!!) + } + + override fun addStyles() { + mLayer?.also { + RNMBXStyleFactory.setHillshadeLayerStyle(it, RNMBXStyle(context, mReactStyle, mMap!!)) + } ?: run { + Logger.e("RNMBXHillshadeLayer", "mLayer is null") + } + } + + fun setSourceLayerID(asString: String?) { + // no-op + } +} diff --git a/android/src/main/java/com/rnmapbox/rnmbx/components/styles/layers/RNMBXHillshadeLayerManager.kt b/android/src/main/java/com/rnmapbox/rnmbx/components/styles/layers/RNMBXHillshadeLayerManager.kt new file mode 100644 index 000000000..fe6fcd1c2 --- /dev/null +++ b/android/src/main/java/com/rnmapbox/rnmbx/components/styles/layers/RNMBXHillshadeLayerManager.kt @@ -0,0 +1,84 @@ +package com.rnmapbox.rnmbx.components.styles.layers + +import com.facebook.react.bridge.Dynamic +import com.facebook.react.uimanager.ThemedReactContext +import com.facebook.react.uimanager.ViewGroupManager +import com.facebook.react.uimanager.annotations.ReactProp +import com.facebook.react.viewmanagers.RNMBXHillshadeLayerManagerInterface + +class RNMBXHillshadeLayerManager : ViewGroupManager(), + RNMBXHillshadeLayerManagerInterface { + override fun getName(): String { + return REACT_CLASS + } + + override fun createViewInstance(reactContext: ThemedReactContext): RNMBXHillshadeLayer { + return RNMBXHillshadeLayer(reactContext) + } + + // @{codepart-replace-start(LayerManagerCommonProps.codepart-kt.ejs,{layerType:"RNMBXHillshadeLayer"})} + @ReactProp(name = "id") + override fun setId(layer: RNMBXHillshadeLayer, id: Dynamic) { + layer.iD = id.asString() + } + + @ReactProp(name = "existing") + override fun setExisting(layer: RNMBXHillshadeLayer, existing: Dynamic) { + layer.setExisting(existing.asBoolean()) + } + + @ReactProp(name = "sourceID") + override fun setSourceID(layer: RNMBXHillshadeLayer, sourceID: Dynamic) { + layer.setSourceID(sourceID.asString()) + } + + @ReactProp(name = "aboveLayerID") + override fun setAboveLayerID(layer: RNMBXHillshadeLayer, aboveLayerID: Dynamic) { + layer.setAboveLayerID(aboveLayerID.asString()) + } + + @ReactProp(name = "belowLayerID") + override fun setBelowLayerID(layer: RNMBXHillshadeLayer, belowLayerID: Dynamic) { + layer.setBelowLayerID(belowLayerID.asString()) + } + + @ReactProp(name = "layerIndex") + override fun setLayerIndex(layer: RNMBXHillshadeLayer, layerIndex: Dynamic) { + layer.setLayerIndex(layerIndex.asInt()) + } + + @ReactProp(name = "minZoomLevel") + override fun setMinZoomLevel(layer: RNMBXHillshadeLayer, minZoomLevel: Dynamic) { + layer.setMinZoomLevel(minZoomLevel.asDouble()) + } + + @ReactProp(name = "maxZoomLevel") + override fun setMaxZoomLevel(layer: RNMBXHillshadeLayer, maxZoomLevel: Dynamic) { + layer.setMaxZoomLevel(maxZoomLevel.asDouble()) + } + + @ReactProp(name = "reactStyle") + override fun setReactStyle(layer: RNMBXHillshadeLayer, style: Dynamic) { + layer.setReactStyle(style.asMap()) + } + + @ReactProp(name = "sourceLayerID") + override fun setSourceLayerID(layer: RNMBXHillshadeLayer, sourceLayerID: Dynamic) { + layer.setSourceLayerID(sourceLayerID.asString()) + } + + @ReactProp(name = "filter") + override fun setFilter(layer: RNMBXHillshadeLayer, filterList: Dynamic) { + layer.setFilter(filterList.asArray()) + } + + @ReactProp(name = "slot") + override fun setSlot(layer: RNMBXHillshadeLayer, slot: Dynamic) { + layer.setSlot(slot.asString()) + } + // @{codepart-replace-end} + + companion object { + const val REACT_CLASS = "RNMBXHillshadeLayer" + } +} diff --git a/docs/HillshadeLayer.md b/docs/HillshadeLayer.md new file mode 100644 index 000000000..2ca0a0e1f --- /dev/null +++ b/docs/HillshadeLayer.md @@ -0,0 +1,383 @@ + + + Mapbox spec: [hillshade](https://docs.mapbox.com/mapbox-gl-js/style-spec/layers/#hillshade) + + +```tsx +import { HillshadeLayer } from '@rnmapbox/maps'; + +HillshadeLayer + +``` + + +## props + + +### id + +```tsx +string +``` +_required_ +A string that uniquely identifies the source in the style to which it is added. + + + +### existing + +```tsx +boolean +``` +The id refers to an existing layer in the style. Does not create a new layer. + + + +### sourceID + +```tsx +string +``` +The source from which to obtain the data to style. +If the source has not yet been added to the current style, the behavior is undefined. +Inferred from parent source only if the layer is a direct child to it. + + _defaults to:_ `Mapbox.StyleSource.DefaultSourceID` + + +### sourceLayerID + +```tsx +string +``` +Identifier of the layer within the source identified by the sourceID property from which the receiver obtains the data to style. + + + +### aboveLayerID + +```tsx +string +``` +Inserts a layer above aboveLayerID. + + + +### belowLayerID + +```tsx +string +``` +Inserts a layer below belowLayerID + + + +### layerIndex + +```tsx +number +``` +Inserts a layer at a specified index + + + +### filter + +```tsx +FilterExpression +``` +Filter only the features in the source layer that satisfy a condition that you define + + + +### minZoomLevel + +```tsx +number +``` +The minimum zoom level at which the layer gets parsed and appears. + + + +### maxZoomLevel + +```tsx +number +``` +The maximum zoom level at which the layer gets parsed and appears. + + + +### slot + +```tsx +'bottom' | 'middle' | 'top' +``` +The slot this layer is assigned to. If specified, and a slot with that name exists, it will be placed at that position in the layer order. + +v11 only + + + +### style + +```tsx +HillshadeLayerStyleProps +``` +_required_ +Customizable style attributes + + + + + + + + + +## styles + +* visibility
+* hillshadeIlluminationDirection
+* hillshadeIlluminationAnchor
+* hillshadeExaggeration
+* hillshadeShadowColor
+* hillshadeHighlightColor
+* hillshadeAccentColor
+ +___ + +### visibility +Name: `visibility` + +Mapbox spec: [visibility](https://docs.mapbox.com/style-spec/reference/layers/#layout-hillshade-visibility) + +#### Description +Whether this layer is displayed. + +#### Type +`enum` +#### Default Value +`visible` + +#### Supported Values +**visible** - The layer is shown.
+**none** - The layer is not shown.
+ + +#### Expression + +Parameters: `` + +___ + +### hillshadeIlluminationDirection +Name: `hillshadeIlluminationDirection` + +Mapbox spec: [hillshade-illumination-direction](https://docs.mapbox.com/style-spec/reference/layers/#paint-hillshade-hillshade-illumination-direction) + +#### Description +The direction of the light source used to generate the hillshading with 0 as the top of the viewport if `hillshadeIlluminationAnchor` is set to `viewport` and due north if `hillshadeIlluminationAnchor` is set to `map` and no 3d lights enabled. If `hillshadeIlluminationAnchor` is set to `map` and 3d lights enabled, the direction from 3d lights is used instead. + +#### Type +`number` +#### Default Value +`335` + +#### Minimum +`0` + + +#### Maximum +`359` + +#### Expression + +Parameters: `zoom` + +___ + +### hillshadeIlluminationAnchor +Name: `hillshadeIlluminationAnchor` + +Mapbox spec: [hillshade-illumination-anchor](https://docs.mapbox.com/style-spec/reference/layers/#paint-hillshade-hillshade-illumination-anchor) + +#### Description +Direction of light source when map is rotated. + +#### Type +`enum` +#### Default Value +`viewport` + +#### Supported Values +**map** - The hillshade illumination is relative to the north direction.
+**viewport** - The hillshade illumination is relative to the top of the viewport.
+ + +#### Expression + +Parameters: `zoom` + +___ + +### hillshadeExaggeration +Name: `hillshadeExaggeration` + +Mapbox spec: [hillshade-exaggeration](https://docs.mapbox.com/style-spec/reference/layers/#paint-hillshade-hillshade-exaggeration) + +#### Description +Intensity of the hillshade + +#### Type +`number` +#### Default Value +`0.5` + +#### Minimum +`0` + + +#### Maximum +`1` + +#### Expression + +Parameters: `zoom` +___ + +### hillshadeExaggerationTransition +Name: `hillshadeExaggerationTransition` + +#### Description + +The transition affecting any changes to this layer’s hillshadeExaggeration property. + +#### Type + +`{ duration, delay }` + +#### Units +`milliseconds` + +#### Default Value +`{duration: 300, delay: 0}` + + +___ + +### hillshadeShadowColor +Name: `hillshadeShadowColor` + +Mapbox spec: [hillshade-shadow-color](https://docs.mapbox.com/style-spec/reference/layers/#paint-hillshade-hillshade-shadow-color) + +#### Description +The shading color of areas that face away from the light source. + +#### Type +`color` +#### Default Value +`#000000` + + +#### Expression + +Parameters: `zoom, measure-light` +___ + +### hillshadeShadowColorTransition +Name: `hillshadeShadowColorTransition` + +#### Description + +The transition affecting any changes to this layer’s hillshadeShadowColor property. + +#### Type + +`{ duration, delay }` + +#### Units +`milliseconds` + +#### Default Value +`{duration: 300, delay: 0}` + + +___ + +### hillshadeHighlightColor +Name: `hillshadeHighlightColor` + +Mapbox spec: [hillshade-highlight-color](https://docs.mapbox.com/style-spec/reference/layers/#paint-hillshade-hillshade-highlight-color) + +#### Description +The shading color of areas that faces towards the light source. + +#### Type +`color` +#### Default Value +`#FFFFFF` + + +#### Expression + +Parameters: `zoom, measure-light` +___ + +### hillshadeHighlightColorTransition +Name: `hillshadeHighlightColorTransition` + +#### Description + +The transition affecting any changes to this layer’s hillshadeHighlightColor property. + +#### Type + +`{ duration, delay }` + +#### Units +`milliseconds` + +#### Default Value +`{duration: 300, delay: 0}` + + +___ + +### hillshadeAccentColor +Name: `hillshadeAccentColor` + +Mapbox spec: [hillshade-accent-color](https://docs.mapbox.com/style-spec/reference/layers/#paint-hillshade-hillshade-accent-color) + +#### Description +The shading color used to accentuate rugged terrain like sharp cliffs and gorges. + +#### Type +`color` +#### Default Value +`#000000` + + +#### Expression + +Parameters: `zoom, measure-light` +___ + +### hillshadeAccentColorTransition +Name: `hillshadeAccentColorTransition` + +#### Description + +The transition affecting any changes to this layer’s hillshadeAccentColor property. + +#### Type + +`{ duration, delay }` + +#### Units +`milliseconds` + +#### Default Value +`{duration: 300, delay: 0}` + + diff --git a/docs/docs.json b/docs/docs.json index 6d6bd98b2..56060783a 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -3038,6 +3038,279 @@ } ] }, + "HillshadeLayer": { + "description": "", + "displayName": "HillshadeLayer", + "methods": [], + "props": [ + { + "name": "id", + "required": true, + "type": "string", + "default": "none", + "description": "A string that uniquely identifies the source in the style to which it is added." + }, + { + "name": "existing", + "required": false, + "type": "boolean", + "default": "none", + "description": "The id refers to an existing layer in the style. Does not create a new layer." + }, + { + "name": "sourceID", + "required": false, + "type": "string", + "default": "Mapbox.StyleSource.DefaultSourceID", + "description": "The source from which to obtain the data to style.\nIf the source has not yet been added to the current style, the behavior is undefined.\nInferred from parent source only if the layer is a direct child to it." + }, + { + "name": "sourceLayerID", + "required": false, + "type": "string", + "default": "none", + "description": "Identifier of the layer within the source identified by the sourceID property from which the receiver obtains the data to style." + }, + { + "name": "aboveLayerID", + "required": false, + "type": "string", + "default": "none", + "description": "Inserts a layer above aboveLayerID." + }, + { + "name": "belowLayerID", + "required": false, + "type": "string", + "default": "none", + "description": "Inserts a layer below belowLayerID" + }, + { + "name": "layerIndex", + "required": false, + "type": "number", + "default": "none", + "description": "Inserts a layer at a specified index" + }, + { + "name": "filter", + "required": false, + "type": "FilterExpression", + "default": "none", + "description": "Filter only the features in the source layer that satisfy a condition that you define" + }, + { + "name": "minZoomLevel", + "required": false, + "type": "number", + "default": "none", + "description": "The minimum zoom level at which the layer gets parsed and appears." + }, + { + "name": "maxZoomLevel", + "required": false, + "type": "number", + "default": "none", + "description": "The maximum zoom level at which the layer gets parsed and appears." + }, + { + "name": "slot", + "required": false, + "type": "'bottom' \\| 'middle' \\| 'top'", + "default": "none", + "description": "The slot this layer is assigned to. If specified, and a slot with that name exists, it will be placed at that position in the layer order.\n\nv11 only" + }, + { + "name": "style", + "required": true, + "type": "HillshadeLayerStyleProps", + "default": "none", + "description": "Customizable style attributes" + } + ], + "fileNameWithExt": "HillshadeLayer.tsx", + "relPath": "src/components/HillshadeLayer.tsx", + "name": "HillshadeLayer", + "mbx": { + "name": "hillshade" + }, + "styles": [ + { + "name": "visibility", + "type": "enum", + "values": [ + { + "value": "visible", + "doc": "The layer is shown." + }, + { + "value": "none", + "doc": "The layer is not shown." + } + ], + "default": "visible", + "description": "Whether this layer is displayed.", + "requires": [], + "disabledBy": [], + "allowedFunctionTypes": [], + "expression": { + "interpolated": false + }, + "mbx": { + "fullName": "layout-hillshade-visibility", + "name": "visibility", + "namespace": "layout" + } + }, + { + "name": "hillshadeIlluminationDirection", + "type": "number", + "values": [], + "minimum": 0, + "maximum": 359, + "default": 335, + "description": "The direction of the light source used to generate the hillshading with 0 as the top of the viewport if `hillshadeIlluminationAnchor` is set to `viewport` and due north if `hillshadeIlluminationAnchor` is set to `map` and no 3d lights enabled. If `hillshadeIlluminationAnchor` is set to `map` and 3d lights enabled, the direction from 3d lights is used instead.", + "requires": [], + "disabledBy": [], + "allowedFunctionTypes": [], + "expression": { + "interpolated": true, + "parameters": [ + "zoom" + ] + }, + "transition": false, + "mbx": { + "fullName": "paint-hillshade-hillshade-illumination-direction", + "name": "hillshade-illumination-direction", + "namespace": "paint" + } + }, + { + "name": "hillshadeIlluminationAnchor", + "type": "enum", + "values": [ + { + "value": "map", + "doc": "The hillshade illumination is relative to the north direction." + }, + { + "value": "viewport", + "doc": "The hillshade illumination is relative to the top of the viewport." + } + ], + "default": "viewport", + "description": "Direction of light source when map is rotated.", + "requires": [], + "disabledBy": [], + "allowedFunctionTypes": [], + "expression": { + "interpolated": false, + "parameters": [ + "zoom" + ] + }, + "mbx": { + "fullName": "paint-hillshade-hillshade-illumination-anchor", + "name": "hillshade-illumination-anchor", + "namespace": "paint" + } + }, + { + "name": "hillshadeExaggeration", + "type": "number", + "values": [], + "minimum": 0, + "maximum": 1, + "default": 0.5, + "description": "Intensity of the hillshade", + "requires": [], + "disabledBy": [], + "allowedFunctionTypes": [], + "expression": { + "interpolated": true, + "parameters": [ + "zoom" + ] + }, + "transition": true, + "mbx": { + "fullName": "paint-hillshade-hillshade-exaggeration", + "name": "hillshade-exaggeration", + "namespace": "paint" + } + }, + { + "name": "hillshadeShadowColor", + "type": "color", + "values": [], + "default": "#000000", + "description": "The shading color of areas that face away from the light source.", + "requires": [], + "disabledBy": [], + "allowedFunctionTypes": [], + "expression": { + "interpolated": true, + "parameters": [ + "zoom", + "measure-light" + ] + }, + "transition": true, + "mbx": { + "fullName": "paint-hillshade-hillshade-shadow-color", + "name": "hillshade-shadow-color", + "namespace": "paint" + } + }, + { + "name": "hillshadeHighlightColor", + "type": "color", + "values": [], + "default": "#FFFFFF", + "description": "The shading color of areas that faces towards the light source.", + "requires": [], + "disabledBy": [], + "allowedFunctionTypes": [], + "expression": { + "interpolated": true, + "parameters": [ + "zoom", + "measure-light" + ] + }, + "transition": true, + "mbx": { + "fullName": "paint-hillshade-hillshade-highlight-color", + "name": "hillshade-highlight-color", + "namespace": "paint" + } + }, + { + "name": "hillshadeAccentColor", + "type": "color", + "values": [], + "default": "#000000", + "description": "The shading color used to accentuate rugged terrain like sharp cliffs and gorges.", + "requires": [], + "disabledBy": [], + "allowedFunctionTypes": [], + "expression": { + "interpolated": true, + "parameters": [ + "zoom", + "measure-light" + ] + }, + "transition": true, + "mbx": { + "fullName": "paint-hillshade-hillshade-accent-color", + "name": "hillshade-accent-color", + "namespace": "paint" + } + } + ] + }, "Image": { "description": "", "displayName": "Image", diff --git a/docs/examples.json b/docs/examples.json index 77b52e1e0..45a02129e 100644 --- a/docs/examples.json +++ b/docs/examples.json @@ -709,6 +709,19 @@ "relPath": "FillRasterLayer/GeoJSONSource.js", "name": "GeoJSONSource" }, + { + "metadata": { + "title": "Hillshade Layer", + "tags": [ + "RasterDemSource", + "HillshadeLayer" + ], + "docs": "Renders terrain hillshading from a raster-dem source." + }, + "fullPath": "example/src/examples/FillRasterLayer/HillshadeSource.tsx", + "relPath": "FillRasterLayer/HillshadeSource.tsx", + "name": "HillshadeSource" + }, { "metadata": { "title": "Image Overlay", diff --git a/example/src/examples/FillRasterLayer/HillshadeSource.tsx b/example/src/examples/FillRasterLayer/HillshadeSource.tsx new file mode 100644 index 000000000..6c70ced40 --- /dev/null +++ b/example/src/examples/FillRasterLayer/HillshadeSource.tsx @@ -0,0 +1,60 @@ +import { useState } from 'react'; +import { Button } from 'react-native'; +import { + MapView, + Camera, + RasterDemSource, + HillshadeLayer, +} from '@rnmapbox/maps'; + +const HillshadeSource = () => { + const [showHillshade, setShowHillshade] = useState(true); + + return ( + <> +