Skip to content

Commit

Permalink
Allow to assign slots to 2D and 3D Puck (#2107)
Browse files Browse the repository at this point in the history
  • Loading branch information
persidskiy authored Apr 16, 2024
1 parent 40436af commit 70c646b
Show file tree
Hide file tree
Showing 10 changed files with 64 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ struct PuckPlayground: View {
@State private var puckType = PuckType.d2
@State private var bearingType = PuckBearing.heading
@State private var opacity = 1.0
@State private var slot: Slot?
@State private var puck3dSettings = Puck3DSettings()
@State private var puck2dSettings = Puck2DSettings()
@State private var mapStyle = MapStyle.standard(lightPreset: .day)
Expand All @@ -33,11 +34,13 @@ struct PuckPlayground: View {
.showsAccuracyRing(puck2dSettings.accuracyRing)
.opacity(opacity)
.topImage(puck2dSettings.topImage.asPuckTopImage)
.slot(slot)
case .d3:
Puck3D(model: puck3dSettings.modelType.model, bearing: bearingType)
.modelScale(puck3dSettings.modelScale)
.modelOpacity(opacity)
.modelEmissiveStrength(puck3dSettings.emission)
.slot(slot)
}
}
.mapStyle(mapStyle)
Expand Down Expand Up @@ -70,6 +73,14 @@ struct PuckPlayground: View {
RadioButtonSettingView(title: "Puck Type", value: $puckType)
RadioButtonSettingView(title: "Bearing", value: $bearingType)
SliderSettingView(title: "Opacity", value: $opacity, range: 0...1, step: 0.1)
HStack {
Text("Slot")
Picker("Slot", selection: $slot) {
ForEach([Slot.bottom, .middle, .top, nil], id: \.self) { t in
Text(t?.rawValue ?? "nil").tag(t)
}
}.pickerStyle(.segmented)
}

switch puckType {
case .d2:
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
Mapbox welcomes participation and contributions from everyone.

## main
* Allow to assign slot to 2D and 3D location indicators.

## 11.3.0 - 10 April, 2024

Expand Down
4 changes: 3 additions & 1 deletion Sources/MapboxMaps/Foundation/Extensions/Core/Slot.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import Foundation

/// A pre-specified location in the style where layer will be added to
/// (such as on top of existing land layers, but below all labels).
public struct Slot: Equatable, Codable, RawRepresentable, ExpressibleByStringLiteral {
///
/// - SeeAlso: More information about slots in [Mapbox Style Specification](https://docs.mapbox.com/style-spec/reference/slots).
public struct Slot: Hashable, Codable, RawRepresentable, ExpressibleByStringLiteral {
/// Above POI labels and behind Place and Transit labels
public static let top = Slot(rawValue: "top")

Expand Down
6 changes: 5 additions & 1 deletion Sources/MapboxMaps/Location/Puck/Puck2DRenderer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ final class Puck2DRenderer: PuckRenderer {

// MARK: Layer

// swiftlint:disable:next function_body_length
// swiftlint:disable:next function_body_length cyclomatic_complexity
private func updateLayer(newState: PuckRendererState<Puck2DConfiguration>, oldState: PuckRendererState<Puck2DConfiguration>?) throws {
let newConfiguration = newState.configuration
var newLayerLayoutProperties = [LocationIndicatorLayer.LayoutCodingKeys: Any]()
Expand Down Expand Up @@ -235,6 +235,10 @@ final class Puck2DRenderer: PuckRenderer {
// https://github.com/mapbox/mapbox-maps-ios/issues/860
try updateImages(newConfiguration: newConfiguration, oldConfiguration: oldState?.configuration)

if newConfiguration.slot != oldState?.configuration.slot {
allLayerProperties[LocationIndicatorLayer.RootCodingKeys.slot.rawValue] = newConfiguration.slot?.rawValue ?? ""
}

// Update or add the layer
if style.layerExists(withId: Self.layerID) {
try style.setLayerProperties(for: Self.layerID, properties: allLayerProperties)
Expand Down
1 change: 1 addition & 0 deletions Sources/MapboxMaps/Location/Puck/Puck3DRenderer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ final class Puck3DRenderer: PuckRenderer {
modelLayer.modelReceiveShadows = newConfiguration.modelReceiveShadows
modelLayer.modelScaleMode = newConfiguration.modelScaleMode
modelLayer.modelEmissiveStrength = newConfiguration.modelEmissiveStrength
modelLayer.slot = newConfiguration.slot

do {
// create the layer if needed
Expand Down
11 changes: 10 additions & 1 deletion Sources/MapboxMaps/Location/Puck/PuckType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ public struct Puck2DConfiguration: Equatable {
/// The color of the accuracy ring border.
public var accuracyRingBorderColor: UIColor

/// The ``Slot`` where to put puck layers.
///
/// If specified, and a slot with that name exists, it will be placed at that position in the layer order.
public var slot: Slot?

/// Initialize a `Puck2D` object with a top image, bearing image, shadow image, scale, opacity and accuracy ring visibility.
/// - Parameters:
/// - topImage: The image to use as the top layer for the location indicator.
Expand Down Expand Up @@ -171,9 +176,13 @@ public struct Puck3DConfiguration: Equatable {
/// There is no emission for value 0. For value 1.0, only emissive component (no shading) is displayed and values above 1.0 produce light contribution to surrounding area, for some of the parts (e.g. windows).
///
/// Default value is 1.
@_documentation(visibility: public)
public var modelEmissiveStrength: Value<Double>?

/// The ``Slot`` where to put puck layers.
///
/// If specified, and a slot with that name exists, it will be placed at that position in the layer order.
public var slot: Slot?

/// Initialize a `Puck3DConfiguration` with a model, scale and rotation.
/// - Parameters:
/// - model: The `gltf` model to use for the puck.
Expand Down
8 changes: 8 additions & 0 deletions Sources/MapboxMaps/SwiftUI/Builders/Puck2D.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@ public struct Puck2D: PrimitiveMapContent {
copyAssigned(self, \.configuration.accuracyRingBorderColor, accuracyRingBorderColor)
}

/// The ``Slot`` where to put puck layers.
///
/// If specified, and a slot with that name exists, it will be placed at that position in the layer order.
@_documentation(visibility: public)
public func slot(_ slot: Slot?) -> Puck2D {
copyAssigned(self, \.configuration.slot, slot)
}

func _visit(_ visitor: MapContentVisitor) {
visitor.add(locationOptions: LocationOptions(
puckType: .puck2D(configuration),
Expand Down
8 changes: 8 additions & 0 deletions Sources/MapboxMaps/SwiftUI/Builders/Puck3D.swift
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,14 @@ public struct Puck3D: PrimitiveMapContent {
copyAssigned(self, \.configuration.modelEmissiveStrength, .expression(modelEmissiveStrength))
}

/// The ``Slot`` where to put puck layers.
///
/// If specified, and a slot with that name exists, it will be placed at that position in the layer order.
@_documentation(visibility: public)
public func slot(_ slot: Slot?) -> Puck3D {
copyAssigned(self, \.configuration.slot, slot)
}

func _visit(_ visitor: MapContentVisitor) {
visitor.add(locationOptions: LocationOptions(
puckType: .puck3D(configuration),
Expand Down
16 changes: 16 additions & 0 deletions Tests/MapboxMapsTests/Location/Puck/Puck2DRendererTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ final class Puck2DRendererTests: XCTestCase {
expectedProperties["id"] = "puck"
expectedProperties["type"] = "location-indicator"

if let slot = state.configuration.slot?.rawValue {
expectedProperties["slot"] = slot
}

return expectedProperties
}

Expand Down Expand Up @@ -609,4 +613,16 @@ final class Puck2DRendererTests: XCTestCase {
XCTAssertEqual(StyleColor(expectedColor.withAlphaComponent(0)).rawValue, color)
XCTAssertEqual(expectedRadius, radius)
}

func testSlot() throws {
style.layerExistsStub.defaultReturnValue = false

var config = Puck2DConfiguration()
config.slot = "some-slot"
let state = updateState(configuration: config)

let expectedProperties = makeExpectedLayerProperties(with: state)
let actualProperties = try XCTUnwrap(style.addPersistentLayerWithPropertiesStub.invocations.first?.parameters.properties)
XCTAssertEqual(actualProperties as NSDictionary, expectedProperties as NSDictionary)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ final class Puck3DRendererTests: XCTestCase {
XCTAssertEqual(actualLayer.modelCastShadows, configuration.modelCastShadows)
XCTAssertEqual(actualLayer.modelReceiveShadows, configuration.modelReceiveShadows)
XCTAssertEqual(actualLayer.modelEmissiveStrength, configuration.modelEmissiveStrength)
XCTAssertEqual(actualLayer.slot, configuration.slot)
}

private func assertLayerUpdated(configuration: Puck3DConfiguration) throws {
Expand Down

0 comments on commit 70c646b

Please sign in to comment.