-
Notifications
You must be signed in to change notification settings - Fork 653
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: new protocol for chained functions, and added support for expli… (
#252) * feat: new protocol for chained functions, and added support for explicit Y ranges. X coming as well * feat: add new axis interface (#253)
- Loading branch information
Showing
40 changed files
with
730 additions
and
379 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import SwiftUI | ||
|
||
public struct AxisLabels<Content: View>: View { | ||
struct YAxisViewKey: ViewPreferenceKey { } | ||
struct ChartViewKey: ViewPreferenceKey { } | ||
|
||
var axisLabelsData = AxisLabelsData() | ||
var axisLabelsStyle = AxisLabelsStyle() | ||
|
||
@State private var yAxisWidth: CGFloat = 25 | ||
@State private var chartWidth: CGFloat = 0 | ||
@State private var chartHeight: CGFloat = 0 | ||
|
||
let content: () -> Content | ||
|
||
public init(@ViewBuilder content: @escaping () -> Content) { | ||
self.content = content | ||
} | ||
|
||
var yAxis: some View { | ||
VStack(spacing: 0.0) { | ||
ForEach(Array(axisLabelsData.axisYLabels.reversed().enumerated()), id: \.element) { index, axisYData in | ||
Text(axisYData) | ||
.font(axisLabelsStyle.axisFont) | ||
.foregroundColor(axisLabelsStyle.axisFontColor) | ||
.frame(height: getYHeight(index: index, | ||
chartHeight: chartHeight, | ||
count: axisLabelsData.axisYLabels.count), | ||
alignment: getYAlignment(index: index, count: axisLabelsData.axisYLabels.count)) | ||
} | ||
} | ||
.padding([.leading, .trailing], 4.0) | ||
.background(ViewGeometry<YAxisViewKey>()) | ||
.onPreferenceChange(YAxisViewKey.self) { value in | ||
yAxisWidth = value.first?.size.width ?? 0.0 | ||
} | ||
} | ||
|
||
func xAxis(chartWidth: CGFloat) -> some View { | ||
HStack(spacing: 0.0) { | ||
ForEach(Array(axisLabelsData.axisXLabels.enumerated()), id: \.element) { index, axisXData in | ||
Text(axisXData) | ||
.font(axisLabelsStyle.axisFont) | ||
.foregroundColor(axisLabelsStyle.axisFontColor) | ||
.frame(width: chartWidth / CGFloat(axisLabelsData.axisXLabels.count - 1)) | ||
} | ||
} | ||
.frame(height: 24.0, alignment: .top) | ||
} | ||
|
||
var chart: some View { | ||
self.content() | ||
.background(ViewGeometry<ChartViewKey>()) | ||
.onPreferenceChange(ChartViewKey.self) { value in | ||
chartWidth = value.first?.size.width ?? 0.0 | ||
chartHeight = value.first?.size.height ?? 0.0 | ||
} | ||
} | ||
|
||
public var body: some View { | ||
VStack(spacing: 0.0) { | ||
HStack { | ||
if axisLabelsStyle.axisLabelsYPosition == .leading { | ||
yAxis | ||
} else { | ||
Spacer(minLength: yAxisWidth) | ||
} | ||
chart | ||
if axisLabelsStyle.axisLabelsYPosition == .leading { | ||
Spacer(minLength: yAxisWidth) | ||
} else { | ||
yAxis | ||
} | ||
} | ||
xAxis(chartWidth: chartWidth) | ||
} | ||
} | ||
|
||
private func getYHeight(index: Int, chartHeight: CGFloat, count: Int) -> CGFloat { | ||
if index == 0 || index == count - 1 { | ||
return chartHeight / (CGFloat(count - 1) * 2) + 10 | ||
} | ||
|
||
return chartHeight / CGFloat(count - 1) | ||
} | ||
|
||
private func getYAlignment(index: Int, count: Int) -> Alignment { | ||
if index == 0 { | ||
return .top | ||
} | ||
|
||
if index == count - 1 { | ||
return .bottom | ||
} | ||
|
||
return .center | ||
} | ||
} |
57 changes: 57 additions & 0 deletions
57
Sources/SwiftUICharts/Base/Axis/Extension/AxisLabels+Extension.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import SwiftUI | ||
|
||
extension AxisLabels { | ||
public func setAxisYLabels(_ labels: [String], | ||
position: AxisLabelsYPosition = .leading) -> AxisLabels { | ||
self.axisLabelsData.axisYLabels = labels | ||
self.axisLabelsStyle.axisLabelsYPosition = position | ||
return self | ||
} | ||
|
||
public func setAxisXLabels(_ labels: [String]) -> AxisLabels { | ||
self.axisLabelsData.axisXLabels = labels | ||
return self | ||
} | ||
|
||
public func setAxisYLabels(_ labels: [(Double, String)], | ||
range: ClosedRange<Int>, | ||
position: AxisLabelsYPosition = .leading) -> AxisLabels { | ||
let overreach = range.overreach + 1 | ||
var labelArray = [String](repeating: "", count: overreach) | ||
labels.forEach { | ||
let index = Int($0.0) - range.lowerBound | ||
if labelArray[safe: index] != nil { | ||
labelArray[index] = $0.1 | ||
} | ||
} | ||
|
||
self.axisLabelsData.axisYLabels = labelArray | ||
self.axisLabelsStyle.axisLabelsYPosition = position | ||
|
||
return self | ||
} | ||
|
||
public func setAxisXLabels(_ labels: [(Double, String)], range: ClosedRange<Int>) -> AxisLabels { | ||
let overreach = range.overreach + 1 | ||
var labelArray = [String](repeating: "", count: overreach) | ||
labels.forEach { | ||
let index = Int($0.0) - range.lowerBound | ||
if labelArray[safe: index] != nil { | ||
labelArray[index] = $0.1 | ||
} | ||
} | ||
|
||
self.axisLabelsData.axisXLabels = labelArray | ||
return self | ||
} | ||
|
||
public func setColor(_ color: Color) -> AxisLabels { | ||
self.axisLabelsStyle.axisFontColor = color | ||
return self | ||
} | ||
|
||
public func setFont(_ font: Font) -> AxisLabels { | ||
self.axisLabelsStyle.axisFont = font | ||
return self | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
Sources/SwiftUICharts/Base/Axis/Model/AxisLabelsPosition.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import Foundation | ||
|
||
public enum AxisLabelsYPosition { | ||
case leading | ||
case trailing | ||
} | ||
|
||
public enum AxisLabelsXPosition { | ||
case top | ||
case bottom | ||
} |
11 changes: 11 additions & 0 deletions
11
Sources/SwiftUICharts/Base/Axis/Model/AxisLabelsStyle.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import SwiftUI | ||
|
||
public final class AxisLabelsStyle: ObservableObject { | ||
@Published public var axisFont: Font = .callout | ||
@Published public var axisFontColor: Color = .primary | ||
@Published var axisLabelsYPosition: AxisLabelsYPosition = .leading | ||
@Published var axisLabelsXPosition: AxisLabelsXPosition = .bottom | ||
public init() { | ||
// no-op | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
Sources/SwiftUICharts/Base/Axis/Model/AxisLablesData.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import SwiftUI | ||
|
||
public final class AxisLabelsData: ObservableObject { | ||
@Published public var axisYLabels: [String] = [] | ||
@Published public var axisXLabels: [String] = [] | ||
|
||
public init() { | ||
// no-op | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
import SwiftUI | ||
|
||
/// Protocol for any type of chart, to get access to underlying data | ||
public protocol ChartBase { | ||
public protocol ChartBase: View { | ||
var chartData: ChartData { get } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import SwiftUI | ||
|
||
public struct ViewGeometry<T>: View where T: PreferenceKey { | ||
public var body: some View { | ||
GeometryReader { geometry in | ||
Color.clear | ||
.preference(key: T.self, value: [ViewSizeData(size: geometry.size)] as! T.Value) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import SwiftUI | ||
|
||
public protocol ViewPreferenceKey: PreferenceKey { | ||
typealias Value = [ViewSizeData] | ||
} | ||
|
||
public extension ViewPreferenceKey { | ||
static var defaultValue: [ViewSizeData] { | ||
[] | ||
} | ||
|
||
static func reduce(value: inout [ViewSizeData], nextValue: () -> [ViewSizeData]) { | ||
value.append(contentsOf: nextValue()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import SwiftUI | ||
|
||
public struct ViewSizeData: Identifiable, Equatable, Hashable { | ||
public let id: UUID = UUID() | ||
public let size: CGSize | ||
|
||
public static func == (lhs: Self, rhs: Self) -> Bool { | ||
return lhs.id == rhs.id | ||
} | ||
|
||
public func hash(into hasher: inout Hasher) { | ||
hasher.combine(id) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 14 additions & 12 deletions
26
Sources/SwiftUICharts/Base/Extensions/ChartBase+Extension.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,23 @@ | ||
import SwiftUI | ||
|
||
extension View where Self: ChartBase { | ||
|
||
/// Set data for a chart | ||
/// - Parameter data: array of `Double` | ||
/// - Returns: modified `View` with data attached | ||
public func data(_ data: [Double]) -> some View { | ||
chartData.data = data.map { ("", $0) } | ||
extension ChartBase { | ||
public func data(_ data: [Double]) -> some ChartBase { | ||
chartData.data = data.enumerated().map{ (index, value) in (Double(index), value) } | ||
return self | ||
.environmentObject(chartData) | ||
.environmentObject(ChartValue()) | ||
} | ||
|
||
public func data(_ data: [(String, Double)]) -> some View { | ||
public func data(_ data: [(Double, Double)]) -> some ChartBase { | ||
chartData.data = data | ||
return self | ||
.environmentObject(chartData) | ||
.environmentObject(ChartValue()) | ||
} | ||
|
||
public func rangeY(_ range: ClosedRange<FloatLiteralType>) -> some ChartBase{ | ||
chartData.rangeY = range | ||
return self | ||
} | ||
|
||
public func rangeX(_ range: ClosedRange<FloatLiteralType>) -> some ChartBase{ | ||
chartData.rangeX = range | ||
return self | ||
} | ||
} |
Oops, something went wrong.