diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/RCTMGLStyleFactory.java b/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/RCTMGLStyleFactory.java index 763b6af..e03f266 100644 --- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/RCTMGLStyleFactory.java +++ b/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/RCTMGLStyleFactory.java @@ -13,6 +13,8 @@ import com.mapbox.mapboxsdk.style.layers.PropertyValue; import com.mapbox.mapboxsdk.style.layers.RasterLayer; import com.mapbox.mapboxsdk.style.layers.SymbolLayer; import com.mapbox.mapboxsdk.style.layers.TransitionOptions; +import com.mapbox.mapboxsdk.style.light.Light; +import com.mapbox.mapboxsdk.style.light.Position; import java.util.List; @@ -581,6 +583,41 @@ public class RCTMGLStyleFactory { } } } + public static void setLightLayerStyle(Light layer, RCTMGLStyle style) { + List styleKeys = style.getAllStyleKeys(); + + if (styleKeys.size() == 0) { + return; + } + + for (String styleKey : styleKeys) { + RCTMGLStyleValue styleValue = style.getStyleValueForKey(styleKey); + + switch (styleKey) { + case "anchor": + RCTMGLStyleFactory.setAnchor(layer, styleValue); + break; + case "position": + RCTMGLStyleFactory.setPosition(layer, styleValue); + break; + case "positionTransition": + RCTMGLStyleFactory.setPositionTransition(layer, styleValue); + break; + case "color": + RCTMGLStyleFactory.setColor(layer, styleValue); + break; + case "colorTransition": + RCTMGLStyleFactory.setColorTransition(layer, styleValue); + break; + case "intensity": + RCTMGLStyleFactory.setIntensity(layer, styleValue); + break; + case "intensityTransition": + RCTMGLStyleFactory.setIntensityTransition(layer, styleValue); + break; + } + } + } public static void setVisibility(FillLayer layer, RCTMGLStyleValue styleValue) { layer.setProperties(PropertyFactory.visibility(styleValue.getString(VALUE_KEY))); @@ -2930,4 +2967,45 @@ public class RCTMGLStyleFactory { } } + public static void setAnchor(Light layer, RCTMGLStyleValue styleValue) { + layer.setAnchor(styleValue.getString(VALUE_KEY)); + } + + public static void setPosition(Light layer, RCTMGLStyleValue styleValue) { + Float[] values = styleValue.getFloatArray(VALUE_KEY); + layer.setPosition(Position.fromPosition(values[0], values[1], values[2])); + } + + + public static void setPositionTransition(Light layer, RCTMGLStyleValue styleValue) { + TransitionOptions transition = styleValue.getTransition(); + if (transition != null) { + layer.setPositionTransition(transition); + } + } + + public static void setColor(Light layer, RCTMGLStyleValue styleValue) { + layer.setColor(styleValue.getInt(VALUE_KEY)); + } + + + public static void setColorTransition(Light layer, RCTMGLStyleValue styleValue) { + TransitionOptions transition = styleValue.getTransition(); + if (transition != null) { + layer.setColorTransition(transition); + } + } + + public static void setIntensity(Light layer, RCTMGLStyleValue styleValue) { + layer.setIntensity(styleValue.getFloat(VALUE_KEY)); + } + + + public static void setIntensityTransition(Light layer, RCTMGLStyleValue styleValue) { + TransitionOptions transition = styleValue.getTransition(); + if (transition != null) { + layer.setIntensityTransition(transition); + } + } + } diff --git a/ios/RCTMGL/RCTMGLStyle.h b/ios/RCTMGL/RCTMGLStyle.h index d18387f..6ec5791 100644 --- a/ios/RCTMGL/RCTMGLStyle.h +++ b/ios/RCTMGL/RCTMGLStyle.h @@ -21,6 +21,7 @@ - (void)fillExtrusionLayer:(MGLFillExtrusionStyleLayer *)layer withReactStyle:(NSDictionary *)reactStyle; - (void)rasterLayer:(MGLRasterStyleLayer *)layer withReactStyle:(NSDictionary *)reactStyle; - (void)backgroundLayer:(MGLBackgroundStyleLayer *)layer withReactStyle:(NSDictionary *)reactStyle; +- (void)lightLayer:(MGLLight *)layer withReactStyle:(NSDictionary *)reactStyle; - (void)setFillStyleLayerVisibility:(MGLFillStyleLayer *)layer withReactStyleValue:(RCTMGLStyleValue *)styleValue; - (void)setFillAntialias:(MGLFillStyleLayer *)layer withReactStyleValue:(RCTMGLStyleValue *)styleValue; @@ -175,6 +176,13 @@ - (void)setBackgroundPatternTransition:(MGLBackgroundStyleLayer *)layer withReactStyleValue:(RCTMGLStyleValue *)styleValue; - (void)setBackgroundOpacity:(MGLBackgroundStyleLayer *)layer withReactStyleValue:(RCTMGLStyleValue *)styleValue; - (void)setBackgroundOpacityTransition:(MGLBackgroundStyleLayer *)layer withReactStyleValue:(RCTMGLStyleValue *)styleValue; +- (void)setAnchor:(MGLLight *)layer withReactStyleValue:(RCTMGLStyleValue *)styleValue; +- (void)setPosition:(MGLLight *)layer withReactStyleValue:(RCTMGLStyleValue *)styleValue; +- (void)setPositionTransition:(MGLLight *)layer withReactStyleValue:(RCTMGLStyleValue *)styleValue; +- (void)setColor:(MGLLight *)layer withReactStyleValue:(RCTMGLStyleValue *)styleValue; +- (void)setColorTransition:(MGLLight *)layer withReactStyleValue:(RCTMGLStyleValue *)styleValue; +- (void)setIntensity:(MGLLight *)layer withReactStyleValue:(RCTMGLStyleValue *)styleValue; +- (void)setIntensityTransition:(MGLLight *)layer withReactStyleValue:(RCTMGLStyleValue *)styleValue; @end diff --git a/ios/RCTMGL/RCTMGLStyle.m b/ios/RCTMGL/RCTMGLStyle.m index c300331..0f0d4af 100644 --- a/ios/RCTMGL/RCTMGLStyle.m +++ b/ios/RCTMGL/RCTMGLStyle.m @@ -16,6 +16,10 @@ NSArray *styleProps = [reactStyle allKeys]; for (NSString *prop in styleProps) { + if ([prop isEqualToString:@"__MAPBOX_STYLESHEET__"]) { + continue; + } + RCTMGLStyleValue *styleValue = [RCTMGLStyleValue make:reactStyle[prop]]; if ([prop isEqualToString:@"visibility"]) { @@ -64,6 +68,10 @@ NSArray *styleProps = [reactStyle allKeys]; for (NSString *prop in styleProps) { + if ([prop isEqualToString:@"__MAPBOX_STYLESHEET__"]) { + continue; + } + RCTMGLStyleValue *styleValue = [RCTMGLStyleValue make:reactStyle[prop]]; if ([prop isEqualToString:@"lineCap"]) { @@ -134,6 +142,10 @@ NSArray *styleProps = [reactStyle allKeys]; for (NSString *prop in styleProps) { + if ([prop isEqualToString:@"__MAPBOX_STYLESHEET__"]) { + continue; + } + RCTMGLStyleValue *styleValue = [RCTMGLStyleValue make:reactStyle[prop]]; if ([prop isEqualToString:@"symbolPlacement"]) { @@ -278,6 +290,10 @@ NSArray *styleProps = [reactStyle allKeys]; for (NSString *prop in styleProps) { + if ([prop isEqualToString:@"__MAPBOX_STYLESHEET__"]) { + continue; + } + RCTMGLStyleValue *styleValue = [RCTMGLStyleValue make:reactStyle[prop]]; if ([prop isEqualToString:@"visibility"]) { @@ -333,6 +349,10 @@ NSArray *styleProps = [reactStyle allKeys]; for (NSString *prop in styleProps) { + if ([prop isEqualToString:@"__MAPBOX_STYLESHEET__"]) { + continue; + } + RCTMGLStyleValue *styleValue = [RCTMGLStyleValue make:reactStyle[prop]]; if ([prop isEqualToString:@"visibility"]) { @@ -383,6 +403,10 @@ NSArray *styleProps = [reactStyle allKeys]; for (NSString *prop in styleProps) { + if ([prop isEqualToString:@"__MAPBOX_STYLESHEET__"]) { + continue; + } + RCTMGLStyleValue *styleValue = [RCTMGLStyleValue make:reactStyle[prop]]; if ([prop isEqualToString:@"visibility"]) { @@ -430,6 +454,10 @@ NSArray *styleProps = [reactStyle allKeys]; for (NSString *prop in styleProps) { + if ([prop isEqualToString:@"__MAPBOX_STYLESHEET__"]) { + continue; + } + RCTMGLStyleValue *styleValue = [RCTMGLStyleValue make:reactStyle[prop]]; if ([prop isEqualToString:@"visibility"]) { @@ -457,6 +485,41 @@ } } +- (void)lightLayer:(MGLLight *)layer withReactStyle:(NSDictionary *)reactStyle +{ + if (reactStyle == nil) { + // TODO throw exception + return; + } + + NSArray *styleProps = [reactStyle allKeys]; + for (NSString *prop in styleProps) { + if ([prop isEqualToString:@"__MAPBOX_STYLESHEET__"]) { + continue; + } + + RCTMGLStyleValue *styleValue = [RCTMGLStyleValue make:reactStyle[prop]]; + + if ([prop isEqualToString:@"anchor"]) { + [self setAnchor:layer withReactStyleValue:styleValue]; + } else if ([prop isEqualToString:@"position"]) { + [self setPosition:layer withReactStyleValue:styleValue]; + } else if ([prop isEqualToString:@"positionTransition"]) { + [self setPositionTransition:layer withReactStyleValue:styleValue]; + } else if ([prop isEqualToString:@"color"]) { + [self setColor:layer withReactStyleValue:styleValue]; + } else if ([prop isEqualToString:@"colorTransition"]) { + [self setColorTransition:layer withReactStyleValue:styleValue]; + } else if ([prop isEqualToString:@"intensity"]) { + [self setIntensity:layer withReactStyleValue:styleValue]; + } else if ([prop isEqualToString:@"intensityTransition"]) { + [self setIntensityTransition:layer withReactStyleValue:styleValue]; + } else { + // TODO throw exception + } + } +} + @@ -1719,4 +1782,41 @@ +- (void)setAnchor:(MGLLight *)layer withReactStyleValue:(RCTMGLStyleValue *)styleValue +{ + layer.anchor = styleValue.mglStyleValue; +} + +- (void)setPosition:(MGLLight *)layer withReactStyleValue:(RCTMGLStyleValue *)styleValue +{ + layer.position = [styleValue getSphericalPosition]; +} + +- (void)setPositionTransition:(MGLLight *)layer withReactStyleValue:(RCTMGLStyleValue *)styleValue +{ + layer.positionTransition = [styleValue getTransition]; +} + +- (void)setColor:(MGLLight *)layer withReactStyleValue:(RCTMGLStyleValue *)styleValue +{ + layer.color = styleValue.mglStyleValue; +} + +- (void)setColorTransition:(MGLLight *)layer withReactStyleValue:(RCTMGLStyleValue *)styleValue +{ + layer.colorTransition = [styleValue getTransition]; +} + +- (void)setIntensity:(MGLLight *)layer withReactStyleValue:(RCTMGLStyleValue *)styleValue +{ + layer.intensity = styleValue.mglStyleValue; +} + +- (void)setIntensityTransition:(MGLLight *)layer withReactStyleValue:(RCTMGLStyleValue *)styleValue +{ + layer.intensityTransition = [styleValue getTransition]; +} + + + @end diff --git a/javascript/utils/styleMap.js b/javascript/utils/styleMap.js index 74495ef..9b2afce 100644 --- a/javascript/utils/styleMap.js +++ b/javascript/utils/styleMap.js @@ -1221,6 +1221,44 @@ export const BackgroundLayerStyleProp = PropTypes.shape({ backgroundOpacityTransition: TransitionPropType, }); +export const LightLayerStyleProp = PropTypes.shape({ + + /** + * Whether extruded geometries are lit relative to the map or viewport. + */ + anchor: PropTypes.any, + + /** + * Position of the light source relative to lit (extruded) geometries, in [r radial coordinate, a azimuthal angle, p polar angle] where r indicates the distance from the center of the base of an object to its light, a indicates the position of the light relative to 0° (0° when `light.anchor` is set to `viewport` corresponds to the top of the viewport, or 0° when `light.anchor` is set to `map` corresponds to due north, and degrees proceed clockwise), and p indicates the height of the light (from 0°, directly above, to 180°, directly below). + */ + position: PropTypes.arrayOf(PropTypes.number), + + /** + * The transition affecting any changes to this layer’s position property. + */ + positionTransition: TransitionPropType, + + /** + * Color tint for lighting extruded geometries. + */ + color: PropTypes.string, + + /** + * The transition affecting any changes to this layer’s color property. + */ + colorTransition: TransitionPropType, + + /** + * Intensity of lighting (on a scale from 0 to 1). Higher numbers will present as more extreme contrast. + */ + intensity: PropTypes.number, + + /** + * The transition affecting any changes to this layer’s intensity property. + */ + intensityTransition: TransitionPropType, +}); + const styleMap = { fillAntialias: StyleTypes.Constant, @@ -1376,6 +1414,14 @@ const styleMap = { backgroundOpacity: StyleTypes.Constant, backgroundOpacityTransition: StyleTypes.Transition, + anchor: StyleTypes.Constant, + position: StyleTypes.Constant, + positionTransition: StyleTypes.Transition, + color: StyleTypes.Color, + colorTransition: StyleTypes.Transition, + intensity: StyleTypes.Constant, + intensityTransition: StyleTypes.Transition, + visibility: StyleTypes.Constant, }; diff --git a/scripts/autogenHelpers/DocJSONBuilder.js b/scripts/autogenHelpers/DocJSONBuilder.js index 406d198..2fa5209 100644 --- a/scripts/autogenHelpers/DocJSONBuilder.js +++ b/scripts/autogenHelpers/DocJSONBuilder.js @@ -13,7 +13,8 @@ class DocJSONBuilder { this._styledLayers = {}; for (let styleLayer of styledLayers) { - this._styledLayers[pascelCase(styleLayer.name) + 'Layer'] = styleLayer; + const ComponentName = pascelCase(styleLayer.name); + this._styledLayers[ComponentName + (ComponentName === 'Light' ? '' : 'Layer')] = styleLayer; } this._filePath = INPUT_PATH; diff --git a/scripts/autogenHelpers/globals.js b/scripts/autogenHelpers/globals.js index 8e1cf28..b3cb4f4 100644 --- a/scripts/autogenHelpers/globals.js +++ b/scripts/autogenHelpers/globals.js @@ -80,6 +80,8 @@ global.getLayerType = function (layer, platform) { return isIOS ? 'MGLBackgroundStyleLayer' : 'BackgroundLayer'; case 'raster': return isIOS ? 'MGLRasterStyleLayer' : 'RasterLayer'; + case 'light': + return isIOS ? 'MGLLight' : 'Light'; default: throw new Error(`Is ${layer.name} a new layer? We should add support for it!`); } diff --git a/scripts/autogenerate.js b/scripts/autogenerate.js index 9687fa6..70ecb97 100644 --- a/scripts/autogenerate.js +++ b/scripts/autogenerate.js @@ -29,70 +29,73 @@ Object.keys(styleSpecJSON.layer.type.values).forEach((layerName) => { }); }); +// add light as a layer +layers.push({ name: 'light', properties: getPropertiesForLight() }) + +function getPropertiesForLight () { + const lightAttributes = styleSpecJSON.light; + + const lightProps = getSupportedProperties(lightAttributes).map((attrName) => { + return Object.assign({}, buildProperties(lightAttributes, attrName), { + allowedFunctionTypes: [], + }); + }); + + return lightProps; +} + function getPropertiesForLayer (layerName) { const paintAttributes = styleSpecJSON[`paint_${layerName}`]; const layoutAttributes = styleSpecJSON[`layout_${layerName}`]; - const paintProps = Object.keys(paintAttributes) - .filter((attrName) => isAttrSupported(paintAttributes[attrName])) - .map((attrName) => { - let prop = { - name: camelCase(attrName), - doc: { - description: paintAttributes[attrName].doc, - requires: getRequires(paintAttributes[attrName].requires), - disabledBy: getDisables(paintAttributes[attrName].requires), - values: paintAttributes[attrName].values, - }, - type: paintAttributes[attrName].type, - value: paintAttributes[attrName].value, - image: isImage(attrName), - translate: isTranslate(attrName), - transition: paintAttributes[attrName].transition, - support: getAttributeSupport(paintAttributes[attrName]['sdk-support']), - allowedFunctionTypes: getAllowedFunctionTypes(paintAttributes[attrName]), - }; + const paintProps = getSupportedProperties(paintAttributes).map((attrName) => { + let prop = buildProperties(paintAttributes, attrName); - // overrides - if (['line-width'].includes(attrName)) { - prop.allowedFunctionTypes = ['camera']; - } + // overrides + if (['line-width'].includes(attrName)) { + prop.allowedFunctionTypes = ['camera']; + } - return prop; + return prop; }); - const layoutProps = Object.keys(layoutAttributes) - .filter((attrName) => isAttrSupported(layoutAttributes[attrName])) - .map((attrName) => { - let prop = { - name: camelCase(attrName), - doc: { - description: layoutAttributes[attrName].doc, - requires: getRequires(layoutAttributes[attrName].requires), - disabledBy: getDisables(layoutAttributes[attrName].requires), - values: layoutAttributes[attrName].values, - }, - type: layoutAttributes[attrName].type, - value: layoutAttributes[attrName].value, - image: isImage(attrName), - translate: isTranslate(attrName), - support: getAttributeSupport(layoutAttributes[attrName]['sdk-support']), - allowedFunctionTypes: getAllowedFunctionTypes(layoutAttributes[attrName]), - }; - - // overrides - if (['line-join', 'text-max-width', 'text-letter-spacing', 'text-anchor', 'text-justify'].includes(attrName)) { - prop.allowedFunctionTypes = ['camera']; - } - - return prop; - }) + const layoutProps = getSupportedProperties(layoutAttributes).map((attrName) => { + let prop = buildProperties(layoutAttributes, attrName); + // overrides + if (['line-join', 'text-max-width', 'text-letter-spacing', 'text-anchor', 'text-justify'].includes(attrName)) { + prop.allowedFunctionTypes = ['camera']; + } + return prop; + }); return layoutProps.concat(paintProps); } +function getSupportedProperties (attributes) { + return Object.keys(attributes).filter((attrName) => isAttrSupported(attributes[attrName])); +} + +function buildProperties (attributes, attrName) { + return { + name: camelCase(attrName), + doc: { + description: attributes[attrName].doc, + requires: getRequires(attributes[attrName].requires), + disabledBy: getDisables(attributes[attrName].requires), + values: attributes[attrName].values, + }, + type: attributes[attrName].type, + value: attributes[attrName].value, + image: isImage(attrName), + translate: isTranslate(attrName), + transition: attributes[attrName].transition, + support: getAttributeSupport(attributes[attrName]['sdk-support']), + allowedFunctionTypes: getAllowedFunctionTypes(attributes[attrName]), + }; +} + function getRequires (requiredItems) { let items = []; diff --git a/scripts/templates/RCTMGLStyle.m.ejs b/scripts/templates/RCTMGLStyle.m.ejs index 486ef09..b6e5b2b 100644 --- a/scripts/templates/RCTMGLStyle.m.ejs +++ b/scripts/templates/RCTMGLStyle.m.ejs @@ -19,6 +19,10 @@ NSArray *styleProps = [reactStyle allKeys]; for (NSString *prop in styleProps) { + if ([prop isEqualToString:@"__MAPBOX_STYLESHEET__"]) { + continue; + } + RCTMGLStyleValue *styleValue = [RCTMGLStyleValue make:reactStyle[prop]]; <% for (let i = 0; i < layer.properties.length; i++) { -%> @@ -56,7 +60,11 @@ return; } <%_ } _%> + <%_ if (layer.name === 'light' && prop.name === 'position') { _%> + layer.position = [styleValue getSphericalPosition]; + <%_ } else { _%> layer.<%- iosPropName(prop.name) -%> = styleValue.mglStyleValue; + <%_ } _%> } <%_ if (prop.transition) { _%> diff --git a/scripts/templates/RCTMGLStyleFactory.java.ejs b/scripts/templates/RCTMGLStyleFactory.java.ejs index 46c0449..f8fa960 100644 --- a/scripts/templates/RCTMGLStyleFactory.java.ejs +++ b/scripts/templates/RCTMGLStyleFactory.java.ejs @@ -16,6 +16,8 @@ import com.mapbox.mapboxsdk.style.layers.PropertyValue; import com.mapbox.mapboxsdk.style.layers.RasterLayer; import com.mapbox.mapboxsdk.style.layers.SymbolLayer; import com.mapbox.mapboxsdk.style.layers.TransitionOptions; +import com.mapbox.mapboxsdk.style.light.Light; +import com.mapbox.mapboxsdk.style.light.Position; import java.util.List; @@ -78,7 +80,14 @@ public class RCTMGLStyleFactory { layer.setProperties(PropertyFactory.<%= prop.name %>(<%- androidGetConfigType(androidInputType(prop.type, prop.value)) -%>)); } <%_ } else { _%> + <%_ if (layer.name === 'light' && prop.name === 'position') { _%> + Float[] values = styleValue.getFloatArray(VALUE_KEY); + layer.set<%- pascelCase(prop.name) -%>(Position.fromPosition(values[0], values[1], values[2])); + <%_ } else if (layer.name === 'light') { _%> + layer.set<%- pascelCase(prop.name) -%>(<%- androidGetConfigType(androidInputType(prop.type, prop.value)) -%>); + <%_ } else { _%> layer.setProperties(PropertyFactory.<%= prop.name %>(<%- androidGetConfigType(androidInputType(prop.type, prop.value)) -%>)); + <%_ } _%> <%_ } _%> }