From dff16e8d2d1c90cbc95e46f23fcd41139f52c80e Mon Sep 17 00:00:00 2001 From: Andras Samu Date: Sun, 21 Jun 2020 18:53:11 +0200 Subject: [PATCH] Creating a data structure which propagets changes in data to the charts (#114) * Creating a data structure which propagets changes in data to the charts * Fixed appearing animation --- .../Base/Chart/AnyChartType.swift | 10 +-- .../SwiftUICharts/Base/Chart/ChartData.swift | 9 +++ .../SwiftUICharts/Base/Chart/ChartType.swift | 4 +- .../Base/Chart/ChartTypeConfiguration.swift | 5 -- Sources/SwiftUICharts/Base/ChartView.swift | 16 ++-- .../Charts/BarChart/BarChart.swift | 10 +-- .../Charts/BarChart/BarChartCell.swift | 64 +++++++++------ .../Charts/BarChart/BarChartRow.swift | 77 ++++++++++--------- .../SwiftUICharts/Charts/LineChart/Line.swift | 13 ++-- .../Charts/LineChart/LineChart.swift | 10 +-- .../Charts/PieChart/PieChart.swift | 18 ++--- .../Charts/PieChart/PieChartRow.swift | 14 ++-- 12 files changed, 140 insertions(+), 110 deletions(-) create mode 100644 Sources/SwiftUICharts/Base/Chart/ChartData.swift delete mode 100644 Sources/SwiftUICharts/Base/Chart/ChartTypeConfiguration.swift diff --git a/Sources/SwiftUICharts/Base/Chart/AnyChartType.swift b/Sources/SwiftUICharts/Base/Chart/AnyChartType.swift index 046dd164..7a758fa4 100644 --- a/Sources/SwiftUICharts/Base/Chart/AnyChartType.swift +++ b/Sources/SwiftUICharts/Base/Chart/AnyChartType.swift @@ -1,19 +1,19 @@ import SwiftUI struct AnyChartType: ChartType { - private let chartMaker: (ChartType.Configuration, ChartType.Style) -> AnyView + private let chartMaker: (ChartType.Data, ChartType.Style) -> AnyView init(_ type: S) { self.chartMaker = type.makeTypeErasedBody } - func makeChart(configuration: ChartType.Configuration, style: ChartType.Style) -> AnyView { - self.chartMaker(configuration, style) + func makeChart(data: ChartType.Data, style: ChartType.Style) -> AnyView { + self.chartMaker(data, style) } } fileprivate extension ChartType { - func makeTypeErasedBody(configuration: ChartType.Configuration, style: ChartType.Style) -> AnyView { - AnyView(makeChart(configuration: configuration, style: style)) + func makeTypeErasedBody(data: ChartType.Data, style: ChartType.Style) -> AnyView { + AnyView(makeChart(data: data, style: style)) } } diff --git a/Sources/SwiftUICharts/Base/Chart/ChartData.swift b/Sources/SwiftUICharts/Base/Chart/ChartData.swift new file mode 100644 index 00000000..9d546de4 --- /dev/null +++ b/Sources/SwiftUICharts/Base/Chart/ChartData.swift @@ -0,0 +1,9 @@ +import SwiftUI + +public class ChartData: ObservableObject { + @Published public var data: [Double] = [] + + public init(_ data: [Double]) { + self.data = data + } +} diff --git a/Sources/SwiftUICharts/Base/Chart/ChartType.swift b/Sources/SwiftUICharts/Base/Chart/ChartType.swift index b7bada4c..de1dc964 100644 --- a/Sources/SwiftUICharts/Base/Chart/ChartType.swift +++ b/Sources/SwiftUICharts/Base/Chart/ChartType.swift @@ -4,8 +4,8 @@ import SwiftUI public protocol ChartType { associatedtype Body: View - func makeChart(configuration: Self.Configuration, style: Self.Style) -> Self.Body + func makeChart(data: Self.Data, style: Self.Style) -> Self.Body - typealias Configuration = ChartTypeConfiguration + typealias Data = ChartData typealias Style = ChartStyle } diff --git a/Sources/SwiftUICharts/Base/Chart/ChartTypeConfiguration.swift b/Sources/SwiftUICharts/Base/Chart/ChartTypeConfiguration.swift deleted file mode 100644 index 0e56a54c..00000000 --- a/Sources/SwiftUICharts/Base/Chart/ChartTypeConfiguration.swift +++ /dev/null @@ -1,5 +0,0 @@ -import SwiftUI - -public struct ChartTypeConfiguration { - public let data: [Double] -} diff --git a/Sources/SwiftUICharts/Base/ChartView.swift b/Sources/SwiftUICharts/Base/ChartView.swift index 5958a711..d13aeba2 100644 --- a/Sources/SwiftUICharts/Base/ChartView.swift +++ b/Sources/SwiftUICharts/Base/ChartView.swift @@ -7,15 +7,21 @@ public struct ChartView: View { @Environment(\.chartType) private var chartType @Environment(\.chartStyle) private var chartStyle - private var configuration: ChartTypeConfiguration + private var data: ChartData + + public init(data: ChartData) { + self.data = data + } public var body: some View { - self.chartType.makeChart(configuration: configuration, style: chartStyle) + self.chartType.makeChart(data: data, style: chartStyle) } } extension ChartView { - public init(data: [Double]) { - self.configuration = ChartTypeConfiguration(data: data) - } +// public init(data: [Double]) { +// self.configuration = ChartTypeConfiguration(data: data) +// } + + } diff --git a/Sources/SwiftUICharts/Charts/BarChart/BarChart.swift b/Sources/SwiftUICharts/Charts/BarChart/BarChart.swift index e655683d..a5e5c73e 100644 --- a/Sources/SwiftUICharts/Charts/BarChart/BarChart.swift +++ b/Sources/SwiftUICharts/Charts/BarChart/BarChart.swift @@ -1,8 +1,8 @@ import SwiftUI public struct BarChart: ChartType { - public func makeChart(configuration: Self.Configuration, style: Self.Style) -> some View { - BarChartRow(data: configuration.data, style: style) + public func makeChart(data: Self.Data, style: Self.Style) -> some View { + BarChartRow(chartData: data, style: style) } public init() {} } @@ -11,17 +11,17 @@ struct BarChart_Previews: PreviewProvider { static var previews: some View { Group { BarChart().makeChart( - configuration: .init(data: [0]), + data: .init([0]), style: .init(backgroundColor: .white, foregroundColor: ColorGradient.redBlack)) Group { BarChart().makeChart( - configuration: .init(data: [1, 2, 3, 5, 1]), + data: .init([1, 2, 3, 5, 1]), style: .init(backgroundColor: .white, foregroundColor: ColorGradient.redBlack)) }.environment(\.colorScheme, .light) Group { BarChart().makeChart( - configuration: .init(data: [1, 2, 3]), + data: .init([1, 2, 3]), style: .init(backgroundColor: .white, foregroundColor: ColorGradient.redBlack)) }.environment(\.colorScheme, .dark) diff --git a/Sources/SwiftUICharts/Charts/BarChart/BarChartCell.swift b/Sources/SwiftUICharts/Charts/BarChart/BarChartCell.swift index 0ab981a9..16936138 100644 --- a/Sources/SwiftUICharts/Charts/BarChart/BarChartCell.swift +++ b/Sources/SwiftUICharts/Charts/BarChart/BarChartCell.swift @@ -1,49 +1,67 @@ import SwiftUI public struct BarChartCell: View { - @State var value: Double - @State var index: Int = 0 - @State var width: Float - @State var numberOfDataPoints: Int + var value: Double + var index: Int = 0 + var width: Float + var numberOfDataPoints: Int var gradientColor: ColorGradient + var touchLocation: CGFloat var cellWidth: Double { return Double(width)/(Double(numberOfDataPoints) * 1.5) } - @State var scaleValue: Double = 0 - @Binding var touchLocation: CGFloat - + @State var firstDisplay: Bool = true + + public init( value: Double, + index: Int = 0, + width: Float, + numberOfDataPoints: Int, + gradientColor: ColorGradient, + touchLocation: CGFloat) { + self.value = value + self.index = index + self.width = width + self.numberOfDataPoints = numberOfDataPoints + self.gradientColor = gradientColor + self.touchLocation = touchLocation + } + public var body: some View { ZStack { RoundedRectangle(cornerRadius: 4) .fill(gradientColor.linearGradient(from: .bottom, to: .top)) - } - .frame(width: CGFloat(self.cellWidth)) - .scaleEffect(CGSize(width: 1, height: self.scaleValue), anchor: .bottom) - .onAppear { - self.scaleValue = self.value - } - .animation(Animation.spring().delay(self.touchLocation < 0 ? Double(self.index) * 0.04 : 0)) + } + .frame(width: CGFloat(self.cellWidth)) + .scaleEffect(CGSize(width: 1, height: self.firstDisplay ? 0.0 : self.value), anchor: .bottom) + .onAppear { + self.firstDisplay = false + } + .onDisappear { + self.firstDisplay = true + } + .transition(.slide) + .animation(Animation.spring().delay(self.touchLocation < 0 || !firstDisplay ? Double(self.index) * 0.04 : 0)) } } struct BarChartCell_Previews: PreviewProvider { static var previews: some View { Group { - BarChartCell(value: 0, width: 50, numberOfDataPoints: 1, gradientColor: ColorGradient.greenRed, touchLocation: .constant(CGFloat())) Group { - BarChartCell(value: 1, width: 50, numberOfDataPoints: 1, gradientColor: ColorGradient.greenRed, touchLocation: .constant(CGFloat())) - BarChartCell(value: 1, width: 50, numberOfDataPoints: 1, gradientColor: ColorGradient.whiteBlack, touchLocation: .constant(CGFloat())) - BarChartCell(value: 1, width: 50, numberOfDataPoints: 1, gradientColor: ColorGradient(.purple), touchLocation: .constant(CGFloat())) + BarChartCell(value: 0, width: 50, numberOfDataPoints: 1, gradientColor: ColorGradient.greenRed, touchLocation: CGFloat()) + + BarChartCell(value: 1, width: 50, numberOfDataPoints: 1, gradientColor: ColorGradient.greenRed, touchLocation: CGFloat()) + BarChartCell(value: 1, width: 50, numberOfDataPoints: 1, gradientColor: ColorGradient.whiteBlack, touchLocation: CGFloat()) + BarChartCell(value: 1, width: 50, numberOfDataPoints: 1, gradientColor: ColorGradient(.purple), touchLocation: CGFloat()) } - + Group { - BarChartCell(value: 1, width: 50, numberOfDataPoints: 1, gradientColor: ColorGradient.greenRed, touchLocation: .constant(CGFloat())) - BarChartCell(value: 1, width: 50, numberOfDataPoints: 1, gradientColor: ColorGradient.whiteBlack, touchLocation: .constant(CGFloat())) - BarChartCell(value: 1, width: 50, numberOfDataPoints: 1, gradientColor: ColorGradient(.purple), touchLocation: .constant(CGFloat())) + BarChartCell(value: 1, width: 50, numberOfDataPoints: 1, gradientColor: ColorGradient.greenRed, touchLocation: CGFloat()) + BarChartCell(value: 1, width: 50, numberOfDataPoints: 1, gradientColor: ColorGradient.whiteBlack, touchLocation: CGFloat()) + BarChartCell(value: 1, width: 50, numberOfDataPoints: 1, gradientColor: ColorGradient(.purple), touchLocation: CGFloat()) }.environment(\.colorScheme, .dark) } - } } diff --git a/Sources/SwiftUICharts/Charts/BarChart/BarChartRow.swift b/Sources/SwiftUICharts/Charts/BarChart/BarChartRow.swift index 5f423e26..21e95af0 100644 --- a/Sources/SwiftUICharts/Charts/BarChart/BarChartRow.swift +++ b/Sources/SwiftUICharts/Charts/BarChart/BarChartRow.swift @@ -1,7 +1,7 @@ import SwiftUI public struct BarChartRow: View { - @State var data: [Double] = [] + @ObservedObject var chartData: ChartData @State var touchLocation: CGFloat = -1.0 enum Constant { @@ -11,7 +11,7 @@ public struct BarChartRow: View { var style: ChartStyle var maxValue: Double { - guard let max = data.max() else { + guard let max = chartData.data.max() else { return 1 } return max != 0 ? max : 1 @@ -20,18 +20,18 @@ public struct BarChartRow: View { public var body: some View { GeometryReader { geometry in HStack(alignment: .bottom, - spacing: (geometry.frame(in: .local).width - Constant.spacing) / CGFloat(self.data.count * 3)) { - ForEach(0.. Double { - return Double(data[index])/Double(maxValue) + print(chartData.data[index]) + return Double(chartData.data[index])/Double(maxValue) } func getScaleSize(touchLocation: CGFloat, index: Int) -> CGSize { - if touchLocation > CGFloat(index)/CGFloat(self.data.count) && - touchLocation < CGFloat(index+1)/CGFloat(self.data.count) { + if touchLocation > CGFloat(index)/CGFloat(chartData.data.count) && + touchLocation < CGFloat(index+1)/CGFloat(chartData.data.count) { return CGSize(width: 1.4, height: 1.1) } return CGSize(width: 1, height: 1) @@ -59,24 +60,24 @@ public struct BarChartRow: View { } -struct BarChartRow_Previews: PreviewProvider { - static var previews: some View { - Group { - BarChartRow(data: [0], style: styleGreenRed) - Group { - BarChartRow(data: [1, 2, 3], style: styleGreenRed) - BarChartRow(data: [1, 2, 3], style: styleGreenRedWhiteBlack) - } - Group { - BarChartRow(data: [1, 2, 3], style: styleGreenRed) - BarChartRow(data: [1, 2, 3], style: styleGreenRedWhiteBlack) - }.environment(\.colorScheme, .dark) - } - } -} - -private let styleGreenRed = ChartStyle(backgroundColor: .white, foregroundColor: .greenRed) - -private let styleGreenRedWhiteBlack = ChartStyle( - backgroundColor: ColorGradient.init(.white), - foregroundColor: [ColorGradient.redBlack, ColorGradient.whiteBlack]) +//struct BarChartRow_Previews: PreviewProvider { +// static var previews: some View { +// Group { +// BarChartRow(data: [0], style: styleGreenRed) +// Group { +// BarChartRow(data: [1, 2, 3], style: styleGreenRed) +// BarChartRow(data: [1, 2, 3], style: styleGreenRedWhiteBlack) +// } +// Group { +// BarChartRow(data: [1, 2, 3], style: styleGreenRed) +// BarChartRow(data: [1, 2, 3], style: styleGreenRedWhiteBlack) +// }.environment(\.colorScheme, .dark) +// } +// } +//} +// +//private let styleGreenRed = ChartStyle(backgroundColor: .white, foregroundColor: .greenRed) +// +//private let styleGreenRedWhiteBlack = ChartStyle( +// backgroundColor: ColorGradient.init(.white), +// foregroundColor: [ColorGradient.redBlack, ColorGradient.whiteBlack]) diff --git a/Sources/SwiftUICharts/Charts/LineChart/Line.swift b/Sources/SwiftUICharts/Charts/LineChart/Line.swift index ce51c420..7eaa484a 100644 --- a/Sources/SwiftUICharts/Charts/LineChart/Line.swift +++ b/Sources/SwiftUICharts/Charts/LineChart/Line.swift @@ -2,7 +2,8 @@ import SwiftUI public struct Line: View { @State var frame: CGRect = .zero - @State var data: [Double] + @ObservedObject var chartData: ChartData + var style: ChartStyle @State var showIndicator: Bool = false @@ -11,11 +12,11 @@ public struct Line: View { @State var showBackground: Bool = true var curvedLines: Bool = true var step: CGPoint { - return CGPoint.getStep(frame: frame, data: data) + return CGPoint.getStep(frame: frame, data: chartData.data) } var path: Path { - let points = data + let points = chartData.data if curvedLines { return Path.quadCurvedPathWithPoints(points: points, @@ -27,7 +28,7 @@ public struct Line: View { } var closedPath: Path { - let points = data + let points = chartData.data if curvedLines { return Path.quadClosedCurvedPathWithPoints(points: points, @@ -109,8 +110,8 @@ extension Line { struct Line_Previews: PreviewProvider { static var previews: some View { Group { - Line(data: [1, 2, 3, 1, 2, 5, 7], style: blackLineStyle) - Line(data: [1, 2, 3, 1, 2, 5, 7], style: redLineStyle) + Line(chartData: ChartData([8, 23, 32, 7, 23, 43]), style: blackLineStyle) + Line(chartData: ChartData([8, 23, 32, 7, 23, 43]), style: redLineStyle) } } } diff --git a/Sources/SwiftUICharts/Charts/LineChart/LineChart.swift b/Sources/SwiftUICharts/Charts/LineChart/LineChart.swift index 2917b4c8..e86579a2 100644 --- a/Sources/SwiftUICharts/Charts/LineChart/LineChart.swift +++ b/Sources/SwiftUICharts/Charts/LineChart/LineChart.swift @@ -1,8 +1,8 @@ import SwiftUI public struct LineChart: ChartType { - public func makeChart(configuration: Self.Configuration, style: Self.Style) -> some View { - Line(data: configuration.data, style: style) + public func makeChart(data: Self.Data, style: Self.Style) -> some View { + Line(chartData: data, style: style) } public init() {} @@ -12,17 +12,17 @@ struct LineChart_Previews: PreviewProvider { static var previews: some View { Group { LineChart().makeChart( - configuration: .init(data: [0]), + data: .init([0]), style: .init(backgroundColor: .white, foregroundColor: ColorGradient(.black))) Group { LineChart().makeChart( - configuration: .init(data: [1, 2, 3, 5, 1]), + data: .init([1, 2, 3, 5, 1]), style: .init(backgroundColor: .white, foregroundColor: ColorGradient(.black))) }.environment(\.colorScheme, .light) Group { LineChart().makeChart( - configuration: .init(data: [1, 2, 3]), + data: .init([1, 2, 3]), style: .init(backgroundColor: .white, foregroundColor: ColorGradient.redBlack)) }.environment(\.colorScheme, .dark) diff --git a/Sources/SwiftUICharts/Charts/PieChart/PieChart.swift b/Sources/SwiftUICharts/Charts/PieChart/PieChart.swift index 721f8ce3..2907a191 100644 --- a/Sources/SwiftUICharts/Charts/PieChart/PieChart.swift +++ b/Sources/SwiftUICharts/Charts/PieChart/PieChart.swift @@ -8,8 +8,8 @@ import SwiftUI public struct PieChart: ChartType { - public func makeChart(configuration: Self.Configuration, style: Self.Style) -> some View { - PieChartRow(data: configuration.data, style: style) + public func makeChart(data: Self.Data, style: Self.Style) -> some View { + PieChartRow(chartData: data, style: style) } public init() {} } @@ -18,30 +18,30 @@ struct PieChart_Previews: PreviewProvider { static var previews: some View { Group { PieChart().makeChart( - configuration: .init(data: [0]), + data: .init([0]), style: styleOneColor) Group { PieChart().makeChart( - configuration: .init(data: [56, 78, 53, 65, 54]), + data: .init([56, 78, 53, 65, 54]), style: styleOneColor) PieChart().makeChart( - configuration: .init(data: [56, 78, 53, 65, 54]), + data: .init([56, 78, 53, 65, 54]), style: styleTwoColor) PieChart().makeChart( - configuration: .init(data: [1, 1, 1, 1, 1, 1]), + data: .init([1, 1, 1, 1, 1, 1]), style: trivialPursuit) }.environment(\.colorScheme, .light) Group { PieChart().makeChart( - configuration: .init(data: [56, 78, 53, 65, 54]), + data: .init([56, 78, 53, 65, 54]), style: styleOneColor) PieChart().makeChart( - configuration: .init(data: [56, 78, 53, 65, 54]), + data: .init([56, 78, 53, 65, 54]), style: styleTwoColor) PieChart().makeChart( - configuration: .init(data: [1, 1, 1, 1, 1, 1]), + data: .init([1, 1, 1, 1, 1, 1]), style: trivialPursuit) }.environment(\.colorScheme, .dark) diff --git a/Sources/SwiftUICharts/Charts/PieChart/PieChartRow.swift b/Sources/SwiftUICharts/Charts/PieChart/PieChartRow.swift index de76cd68..aae06735 100644 --- a/Sources/SwiftUICharts/Charts/PieChart/PieChartRow.swift +++ b/Sources/SwiftUICharts/Charts/PieChart/PieChartRow.swift @@ -8,16 +8,16 @@ import SwiftUI public struct PieChartRow: View { - var data: [Double] - + @ObservedObject var chartData: ChartData + var style: ChartStyle var slices: [PieSlice] { var tempSlices: [PieSlice] = [] var lastEndDeg: Double = 0 - let maxValue: Double = data.reduce(0, +) + let maxValue: Double = chartData.data.reduce(0, +) - for slice in data { + for slice in chartData.data { let normalized: Double = Double(slice) / (maxValue == 0 ? 1 : maxValue) let startDeg = lastEndDeg let endDeg = lastEndDeg + (normalized * 360) @@ -53,17 +53,17 @@ struct PieChartRow_Previews: PreviewProvider { Group { //Empty Array - Default Colors.OrangeStart PieChartRow( - data: [8, 23, 32, 7, 23, 43], + chartData: ChartData([8, 23, 32, 7, 23, 43]), style: defaultMultiColorChartStyle) .frame(width: 100, height: 100) PieChartRow( - data: [8, 23, 32, 7, 23, 43], + chartData: ChartData([8, 23, 32, 7, 23, 43]), style: multiColorChartStyle) .frame(width: 100, height: 100) PieChartRow( - data: [0], + chartData: ChartData([8, 23, 32, 7, 23, 43]), style: multiColorChartStyle) .frame(width: 100, height: 100)