Skip to content

Add Chart Axis Label modifiers #106

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: chart-scale-modifiers
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Sources/LiveViewNativeCharts/ChartsRegistry.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ public struct ChartsRegistry<Root: RootRegistry>: CustomRegistry {
case chartBackground = "chart_background"
case chartOverlay = "chart_overlay"
case chartXAxis = "chart_x_axis"
case chartXAxisLabel = "chart_x_axis_label"
case chartYAxis = "chart_y_axis"
case chartYAxisLabel = "chart_y_axis_label"
case chartXScale = "chart_x_scale"
case chartYScale = "chart_y_scale"
}
Expand All @@ -44,8 +46,12 @@ public struct ChartsRegistry<Root: RootRegistry>: CustomRegistry {
try ChartOverlayModifier<Root>(from: decoder)
case .chartXAxis:
try ChartXAxisModifier<Root>(from: decoder)
case .chartXAxisLabel:
try ChartXAxisLabelModifier<Root>(from: decoder)
case .chartYAxis:
try ChartYAxisModifier<Root>(from: decoder)
case .chartYAxisLabel:
try ChartYAxisLabelModifier<Root>(from: decoder)
case .chartXScale:
try ChartXScaleModifier(from: decoder)
case .chartYScale:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
### Axis Scale Modifiers
- ``ChartXScaleModifier``
- ``ChartYScaleModifier``
### Axis Label Modifiers
- ``ChartXAxisLabelModifier``
- ``ChartYAxisLabelModifier``
### Symbol Scale Modifiers
- ``ChartSymbolScaleModifier``
### Background Modifiers
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# ``LiveViewNativeCharts/ChartXAxisLabelModifier``

@Metadata {
@DocumentationExtension(mergeBehavior: append)
@DisplayName("chart_x_axis_label", style: symbol)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# ``LiveViewNativeCharts/ChartYAxisLabelModifier``

@Metadata {
@DocumentationExtension(mergeBehavior: append)
@DisplayName("chart_y_axis_label", style: symbol)
}
102 changes: 102 additions & 0 deletions Sources/LiveViewNativeCharts/Modifiers/ChartXAxisLabelModifier.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//
// ChartXAxisLabelModifier.swift
//
//
// Created by murtza on 07/07/2023.
//

import Charts
import SwiftUI
import LiveViewNative

/// Adds a string as x axis label for charts in the view.
/// ```html
/// <Chart modifiers={chart_x_axis_label(@native, title: "ABC")}>
/// ...
/// </Chart>
/// ```
///
/// Adds a template as x axis label for charts in the view.
/// ```html
/// <Chart modifiers={chart_x_axis_label(@native, content: :my_label)}>
/// <Text template={:my_label}>ABC</Text>
/// ...
/// </Chart>
/// ```
///
/// ## Arguments
/// * ``title``
/// * ``position``
/// * ``alignment``
/// * ``spacing``
/// * ``content``
#if swift(>=5.8)
@_documentation(visibility: public)
#endif
struct ChartXAxisLabelModifier<R: RootRegistry>: ViewModifier, Decodable {
/// The label string..
#if swift(>=5.8)
@_documentation(visibility: public)
#endif
private var title: String?

/// The position of the label.
///
/// See ``LiveViewNativeCharts/Charts/AnnotationPosition`` for a list of possible values.
#if swift(>=5.8)
@_documentation(visibility: public)
#endif
private var position: AnnotationPosition

/// The alignment of the label.
///
/// See ``LiveViewNativeCharts/LiveViewNative/SwiftUI/Alignment`` for a list of possible values.
#if swift(>=5.8)
@_documentation(visibility: public)
#endif
private var alignment: Alignment?

/// The spacing of the label from the axis markers.
#if swift(>=5.8)
@_documentation(visibility: public)
#endif
private var spacing: CGFloat?

/// The label content.
#if swift(>=5.8)
@_documentation(visibility: public)
#endif
private var content: String?

@ObservedElement(observeChildren: true) private var element
@LiveContext<R> private var context

init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.title = try container.decodeIfPresent(String.self, forKey: .title)
self.position = try container.decodeIfPresent(AnnotationPosition.self, forKey: .position) ?? .automatic
self.alignment = try container.decodeIfPresent(Alignment.self, forKey: .alignment)
self.spacing = try container.decodeIfPresent(CGFloat.self, forKey: .spacing)
self.content = try container.decodeIfPresent(String.self, forKey: .content)
}

func body(content: Content) -> some View {
if let title {
content.chartXAxisLabel(title, position: position, alignment: alignment, spacing: spacing)
} else if let template = self.content {
content.chartXAxisLabel(position: position, alignment: alignment, spacing: spacing) {
context.buildChildren(of: element, forTemplate: template)
}
} else {
content
}
}

enum CodingKeys: String, CodingKey {
case title
case position
case alignment
case spacing
case content
}
}
102 changes: 102 additions & 0 deletions Sources/LiveViewNativeCharts/Modifiers/ChartYAxisLabelModifer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//
// ChartYAxisLabelModifier.swift
//
//
// Created by murtza on 07/07/2023.
//

import Charts
import SwiftUI
import LiveViewNative

/// Adds a string as y axis label for charts in the view.
/// ```html
/// <Chart modifiers={chart_y_axis_label(@native, title: "ABC")}>
/// ...
/// </Chart>
/// ```
///
/// Adds a template as y axis label for charts in the view.
/// ```html
/// <Chart modifiers={chart_y_axis_label(@native, content: :my_label)}>
/// <Text template={:my_label}>ABC</Text>
/// ...
/// </Chart>
/// ```
///
/// ## Arguments
/// * ``title``
/// * ``position``
/// * ``alignment``
/// * ``spacing``
/// * ``content``
#if swift(>=5.8)
@_documentation(visibility: public)
#endif
struct ChartYAxisLabelModifier<R: RootRegistry>: ViewModifier, Decodable {
/// The label string..
#if swift(>=5.8)
@_documentation(visibility: public)
#endif
private var title: String?

/// The position of the label.
///
/// See ``LiveViewNativeCharts/Charts/AnnotationPosition`` for a list of possible values.
#if swift(>=5.8)
@_documentation(visibility: public)
#endif
private var position: AnnotationPosition

/// The alignment of the label.
///
/// See ``LiveViewNativeCharts/LiveViewNative/SwiftUI/Alignment`` for a list of possible values.
#if swift(>=5.8)
@_documentation(visibility: public)
#endif
private var alignment: Alignment?

/// The spacing of the label from the axis markers.
#if swift(>=5.8)
@_documentation(visibility: public)
#endif
private var spacing: CGFloat?

/// The label content.
#if swift(>=5.8)
@_documentation(visibility: public)
#endif
private var content: String?

@ObservedElement(observeChildren: true) private var element
@LiveContext<R> private var context

init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.title = try container.decodeIfPresent(String.self, forKey: .title)
self.position = try container.decodeIfPresent(AnnotationPosition.self, forKey: .position) ?? .automatic
self.alignment = try container.decodeIfPresent(Alignment.self, forKey: .alignment)
self.spacing = try container.decodeIfPresent(CGFloat.self, forKey: .spacing)
self.content = try container.decodeIfPresent(String.self, forKey: .content)
}

func body(content: Content) -> some View {
if let title {
content.chartYAxisLabel(title, position: position, alignment: alignment, spacing: spacing)
} else if let template = self.content {
content.chartYAxisLabel(position: position, alignment: alignment, spacing: spacing) {
context.buildChildren(of: element, forTemplate: template)
}
} else {
content
}
}

enum CodingKeys: String, CodingKey {
case title
case position
case alignment
case spacing
case content
}
}
43 changes: 43 additions & 0 deletions Sources/LiveViewNativeCharts/Types/AnnotationPosition.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// AnnotationPosition.swift
//
//
// Created by murtza on 07/07/2023.
//

import Charts
import LiveViewNative
import LiveViewNativeCore

/// The position of an annotation.
///
/// Possible values:
/// * `automatic`
/// * `bottom`
/// * `bottom-leading` or `bottom_leading`
/// * `bottom-trailing` or `bottom_trailing`
/// * `leading`
/// * `overlay`
/// * `top`
/// * `top-leading` or `top_leading`
/// * `top-trailing` or `top_trailing`
/// * `trailing`
extension AnnotationPosition: Decodable {
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
switch try container.decode(String.self) {
case "automatic": self = .automatic
case "bottom": self = .bottom
case "bottom-leading", "bottom_leading": self = .bottomLeading
case "bottom-trailing", "bottom_trailing": self = .bottomTrailing
case "leading": self = .leading
case "overlay": self = .overlay
case "top": self = .top
case "top-leading", "top_leading": self = .topLeading
case "top-trailing", "top_trailing": self = .topTrailing
case "trailing": self = .trailing
case let `default`:
throw DecodingError.dataCorrupted(.init(codingPath: container.codingPath, debugDescription: "Unknown Annotation Position `\(`default`)`"))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
defmodule LiveViewNativeSwiftUiCharts.Modifiers.ChartXAxisLabel do
use LiveViewNativePlatform.Modifier

alias LiveViewNativeSwiftUiCharts.Types.AnnotationPosition

modifier_schema "chart_x_axis_label" do
field :title, :string, default: nil
field :position, AnnotationPosition
field :alignment, Ecto.Enum, values: ~w(
bottom
bottom_leading
bottom_trailing
center
leading
leading_last_text_baseline
top
top_leading
top_trailing
trailing
trailing_first_text_baseline
)a
field :spacing, :float, default: nil
field :content, :string, default: nil
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
defmodule LiveViewNativeSwiftUiCharts.Modifiers.ChartYAxisLabel do
use LiveViewNativePlatform.Modifier

alias LiveViewNativeSwiftUiCharts.Types.AnnotationPosition

modifier_schema "chart_y_axis_label" do
field :title, :string, default: nil
field :position, AnnotationPosition
field :alignment, Ecto.Enum, values: ~w(
bottom
bottom_leading
bottom_trailing
center
leading
leading_last_text_baseline
top
top_leading
top_trailing
trailing
trailing_first_text_baseline
)a
field :spacing, :float, default: nil
field :content, :string, default: nil
end
end
34 changes: 34 additions & 0 deletions lib/live_view_native_swift_ui_charts/types/annotation_position.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
defmodule LiveViewNativeSwiftUiCharts.Types.AnnotationPosition do
use LiveViewNativePlatform.Modifier.Type
def type, do: :string

@positions_atom [
:automatic,
:bottom,
:bottom_leading,
:bottom_trailing,
:leading,
:overlay,
:top,
:top_leading,
:top_trailing,
:trailing,
]

@positions_string [
"automatic",
"bottom",
"bottom-leading",
"bottom-trailing",
"leading",
"overlay",
"top",
"top-leading",
"top-trailing",
"trailing",
]

def cast(value) when is_atom(value) and value in @positions_atom, do: {:ok, Atom.to_string(value)}
def cast(value) when is_binary(value) and value in @positions_string, do: {:ok, value}
def cast(_), do: :error
end