diff --git a/Sources/LiveViewNativeCharts/ChartsRegistry.swift b/Sources/LiveViewNativeCharts/ChartsRegistry.swift index a1e4a3f..57e2bc6 100644 --- a/Sources/LiveViewNativeCharts/ChartsRegistry.swift +++ b/Sources/LiveViewNativeCharts/ChartsRegistry.swift @@ -29,7 +29,9 @@ public struct ChartsRegistry: 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" } @@ -44,8 +46,12 @@ public struct ChartsRegistry: CustomRegistry { try ChartOverlayModifier(from: decoder) case .chartXAxis: try ChartXAxisModifier(from: decoder) + case .chartXAxisLabel: + try ChartXAxisLabelModifier(from: decoder) case .chartYAxis: try ChartYAxisModifier(from: decoder) + case .chartYAxisLabel: + try ChartYAxisLabelModifier(from: decoder) case .chartXScale: try ChartXScaleModifier(from: decoder) case .chartYScale: diff --git a/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Extensions/Chart.md b/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Extensions/Chart.md index d663a97..d0981fb 100644 --- a/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Extensions/Chart.md +++ b/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Extensions/Chart.md @@ -12,6 +12,9 @@ ### Axis Scale Modifiers - ``ChartXScaleModifier`` - ``ChartYScaleModifier`` +### Axis Label Modifiers +- ``ChartXAxisLabelModifier`` +- ``ChartYAxisLabelModifier`` ### Symbol Scale Modifiers - ``ChartSymbolScaleModifier`` ### Background Modifiers diff --git a/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Extensions/ChartXAxisLabelModifier.md b/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Extensions/ChartXAxisLabelModifier.md new file mode 100644 index 0000000..98cb06c --- /dev/null +++ b/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Extensions/ChartXAxisLabelModifier.md @@ -0,0 +1,6 @@ +# ``LiveViewNativeCharts/ChartXAxisLabelModifier`` + +@Metadata { + @DocumentationExtension(mergeBehavior: append) + @DisplayName("chart_x_axis_label", style: symbol) +} diff --git a/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Extensions/ChartYAxisLabelModifier.md b/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Extensions/ChartYAxisLabelModifier.md new file mode 100644 index 0000000..a710579 --- /dev/null +++ b/Sources/LiveViewNativeCharts/LiveViewNativeCharts.docc/Extensions/ChartYAxisLabelModifier.md @@ -0,0 +1,6 @@ +# ``LiveViewNativeCharts/ChartYAxisLabelModifier`` + +@Metadata { + @DocumentationExtension(mergeBehavior: append) + @DisplayName("chart_y_axis_label", style: symbol) +} diff --git a/Sources/LiveViewNativeCharts/Modifiers/ChartXAxisLabelModifier.swift b/Sources/LiveViewNativeCharts/Modifiers/ChartXAxisLabelModifier.swift new file mode 100644 index 0000000..3438fa1 --- /dev/null +++ b/Sources/LiveViewNativeCharts/Modifiers/ChartXAxisLabelModifier.swift @@ -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 +/// +/// ... +/// +/// ``` +/// +/// Adds a template as x axis label for charts in the view. +/// ```html +/// +/// ABC +/// ... +/// +/// ``` +/// +/// ## Arguments +/// * ``title`` +/// * ``position`` +/// * ``alignment`` +/// * ``spacing`` +/// * ``content`` +#if swift(>=5.8) +@_documentation(visibility: public) +#endif +struct ChartXAxisLabelModifier: 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 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 + } +} diff --git a/Sources/LiveViewNativeCharts/Modifiers/ChartYAxisLabelModifer.swift b/Sources/LiveViewNativeCharts/Modifiers/ChartYAxisLabelModifer.swift new file mode 100644 index 0000000..01bdc70 --- /dev/null +++ b/Sources/LiveViewNativeCharts/Modifiers/ChartYAxisLabelModifer.swift @@ -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 +/// +/// ... +/// +/// ``` +/// +/// Adds a template as y axis label for charts in the view. +/// ```html +/// +/// ABC +/// ... +/// +/// ``` +/// +/// ## Arguments +/// * ``title`` +/// * ``position`` +/// * ``alignment`` +/// * ``spacing`` +/// * ``content`` +#if swift(>=5.8) +@_documentation(visibility: public) +#endif +struct ChartYAxisLabelModifier: 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 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 + } +} diff --git a/Sources/LiveViewNativeCharts/Types/AnnotationPosition.swift b/Sources/LiveViewNativeCharts/Types/AnnotationPosition.swift new file mode 100644 index 0000000..ae5e713 --- /dev/null +++ b/Sources/LiveViewNativeCharts/Types/AnnotationPosition.swift @@ -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`)`")) + } + } +} diff --git a/lib/live_view_native_swift_ui_charts/modifiers/chart_x_axis_label.ex b/lib/live_view_native_swift_ui_charts/modifiers/chart_x_axis_label.ex new file mode 100644 index 0000000..f84a646 --- /dev/null +++ b/lib/live_view_native_swift_ui_charts/modifiers/chart_x_axis_label.ex @@ -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 diff --git a/lib/live_view_native_swift_ui_charts/modifiers/chart_y_axis_label.ex b/lib/live_view_native_swift_ui_charts/modifiers/chart_y_axis_label.ex new file mode 100644 index 0000000..6b544dd --- /dev/null +++ b/lib/live_view_native_swift_ui_charts/modifiers/chart_y_axis_label.ex @@ -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 diff --git a/lib/live_view_native_swift_ui_charts/types/annotation_position.ex b/lib/live_view_native_swift_ui_charts/types/annotation_position.ex new file mode 100644 index 0000000..558a7bd --- /dev/null +++ b/lib/live_view_native_swift_ui_charts/types/annotation_position.ex @@ -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