-
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.
- Loading branch information
Showing
14 changed files
with
235 additions
and
57 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 |
---|---|---|
@@ -1,40 +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 | ||
// font | ||
// foregroundColor | ||
|
||
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 { | ||
HStack { | ||
VStack { | ||
ForEach(Array(axisLabelsData.axisYLabels.reversed().enumerated()), id: \.element) { index, axisYData in | ||
Text(axisYData) | ||
if index != axisLabelsData.axisYLabels.count - 1 { | ||
Spacer() | ||
} | ||
VStack(spacing: 0.0) { | ||
HStack { | ||
if axisLabelsStyle.axisLabelsYPosition == .leading { | ||
yAxis | ||
} else { | ||
Spacer(minLength: yAxisWidth) | ||
} | ||
} | ||
.padding([.trailing], 8.0) | ||
.padding([.bottom], axisLabelsData.axisXLabels.count > 0 ? 28.0 : 0) | ||
.frame(maxHeight: .infinity) | ||
VStack { | ||
self.content() | ||
HStack { | ||
ForEach(Array(axisLabelsData.axisXLabels.enumerated()), id: \.element) { index, axisXData in | ||
Text(axisXData) | ||
if index != axisLabelsData.axisXLabels.count - 1 { | ||
Spacer() | ||
} | ||
} | ||
chart | ||
if axisLabelsStyle.axisLabelsYPosition == .leading { | ||
Spacer(minLength: yAxisWidth) | ||
} else { | ||
yAxis | ||
} | ||
} | ||
.padding([.top, .bottom], 10.0) | ||
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 | ||
} | ||
} |
46 changes: 45 additions & 1 deletion
46
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 |
---|---|---|
@@ -1,13 +1,57 @@ | ||
import SwiftUI | ||
|
||
extension AxisLabels { | ||
public func setAxisYLabels(_ labels: [String]) -> 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 | ||
} | ||
} |
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
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
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
Oops, something went wrong.