Skip to content

Commit 2a1b55f

Browse files
committed
Adding multiline chartview and straight linechart
1 parent 841bde1 commit 2a1b55f

File tree

6 files changed

+254
-32
lines changed

6 files changed

+254
-32
lines changed

Sources/SwiftUICharts/BarChart/BarChartCell.swift

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,14 @@ public struct BarChartCell : View {
1717
return Double(width)/(Double(numberOfDataPoints) * 1.5)
1818
}
1919
var accentColor: Color
20-
var secondGradientAccentColor: Color?
21-
var gradientColors:[Color] {
22-
if (secondGradientAccentColor != nil) {
23-
return [secondGradientAccentColor!, accentColor]
24-
}
25-
return [accentColor, accentColor]
26-
}
20+
var gradient: GradientColor?
21+
2722
@State var scaleValue: Double = 0
2823
@Binding var touchLocation: CGFloat
2924
public var body: some View {
3025
ZStack {
3126
RoundedRectangle(cornerRadius: 4)
32-
.fill(LinearGradient(gradient: Gradient(colors: gradientColors), startPoint: .bottom, endPoint: .top))
27+
.fill(LinearGradient(gradient: gradient?.getGradient() ?? GradientColor(start: accentColor, end: accentColor).getGradient(), startPoint: .bottom, endPoint: .top))
3328
}
3429
.frame(width: CGFloat(self.cellWidth))
3530
.scaleEffect(CGSize(width: 1, height: self.scaleValue), anchor: .bottom)
@@ -43,7 +38,7 @@ public struct BarChartCell : View {
4338
#if DEBUG
4439
struct ChartCell_Previews : PreviewProvider {
4540
static var previews: some View {
46-
BarChartCell(value: Double(0.75), width: 320, numberOfDataPoints: 12, accentColor: Colors.OrangeStart, secondGradientAccentColor: nil, touchLocation: .constant(-1))
41+
BarChartCell(value: Double(0.75), width: 320, numberOfDataPoints: 12, accentColor: Colors.OrangeStart, gradient: nil, touchLocation: .constant(-1))
4742
}
4843
}
4944
#endif

Sources/SwiftUICharts/BarChart/BarChartRow.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import SwiftUI
1111
public struct BarChartRow : View {
1212
var data: [Double]
1313
var accentColor: Color
14-
var secondGradientAccentColor: Color?
14+
var gradient: GradientColor?
1515
var maxValue: Double {
1616
data.max() ?? 0
1717
}
@@ -20,7 +20,7 @@ public struct BarChartRow : View {
2020
GeometryReader { geometry in
2121
HStack(alignment: .bottom, spacing: (geometry.frame(in: .local).width-22)/CGFloat(self.data.count * 3)){
2222
ForEach(0..<self.data.count) { i in
23-
BarChartCell(value: self.normalizedValue(index: i), index: i, width: Float(geometry.frame(in: .local).width - 22), numberOfDataPoints: self.data.count, accentColor: self.accentColor, secondGradientAccentColor: self.secondGradientAccentColor, touchLocation: self.$touchLocation)
23+
BarChartCell(value: self.normalizedValue(index: i), index: i, width: Float(geometry.frame(in: .local).width - 22), numberOfDataPoints: self.data.count, accentColor: self.accentColor, gradient: self.gradient, touchLocation: self.$touchLocation)
2424
.scaleEffect(self.touchLocation > CGFloat(i)/CGFloat(self.data.count) && self.touchLocation < CGFloat(i+1)/CGFloat(self.data.count) ? CGSize(width: 1.4, height: 1.1) : CGSize(width: 1, height: 1), anchor: .bottom)
2525
.animation(.spring())
2626

Sources/SwiftUICharts/BarChart/BarChartView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public struct BarChartView : View {
1919
public var dropShadow: Bool
2020
public var cornerImage: Image
2121
public var valueSpecifier:String
22-
22+
2323
@State private var touchLocation: CGFloat = -1.0
2424
@State private var showValue: Bool = false
2525
@State private var showLabelValue: Bool = false
@@ -76,7 +76,7 @@ public struct BarChartView : View {
7676
}.padding()
7777
BarChartRow(data: data.points.map{$0.1},
7878
accentColor: self.colorScheme == .dark ? self.darkModeStyle.accentColor : self.style.accentColor,
79-
secondGradientAccentColor: self.colorScheme == .dark ? self.darkModeStyle.secondGradientColor : self.style.secondGradientColor,
79+
gradient: self.colorScheme == .dark ? self.darkModeStyle.gradientColor : self.style.gradientColor,
8080
touchLocation: self.$touchLocation)
8181
if self.legend != nil && self.formSize == ChartForm.medium && !self.showLabelValue{
8282
Text(self.legend!)

Sources/SwiftUICharts/Helpers.swift

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ public struct Colors {
1515
public static let color2Accent:Color = Color(hexString: "#4266E8")
1616
public static let color3:Color = Color(hexString: "#FCECEA")
1717
public static let color3Accent:Color = Color(hexString: "#E1614C")
18-
public static let OrangeStart:Color = Color(hexString: "#FF782C")
19-
public static let OrangeEnd:Color = Color(hexString: "#EC2301")
18+
public static let OrangeEnd:Color = Color(hexString: "#FF782C")
19+
public static let OrangeStart:Color = Color(hexString: "#EC2301")
2020
public static let LegendText:Color = Color(hexString: "#A7A6A8")
2121
public static let LegendColor:Color = Color(hexString: "#E8E7EA")
2222
public static let LegendDarkColor:Color = Color(hexString: "#545454")
@@ -30,6 +30,25 @@ public struct Colors {
3030
public static let BorderBlue:Color = Color(hexString: "#4EBCFF")
3131
}
3232

33+
public struct GradientColor {
34+
public let start: Color
35+
public let end: Color
36+
37+
init(start: Color, end: Color) {
38+
self.start = start
39+
self.end = end
40+
}
41+
42+
public func getGradient() -> Gradient {
43+
return Gradient(colors: [start, end])
44+
}
45+
}
46+
47+
public struct GradientColors {
48+
public static let orange = GradientColor(start: Colors.OrangeStart, end: Colors.OrangeEnd)
49+
public static let blue = GradientColor(start: Colors.GradientPurple, end: Colors.GradientNeonBlue)
50+
}
51+
3352
public struct Styles {
3453
public static let lineChartStyleOne = ChartStyle(
3554
backgroundColor: Color.white,
@@ -82,8 +101,8 @@ public struct Styles {
82101

83102
public static let pieChartStyleOne = ChartStyle(
84103
backgroundColor: Color.white,
85-
accentColor: Colors.OrangeStart,
86-
secondGradientColor: Colors.OrangeEnd,
104+
accentColor: Colors.OrangeEnd,
105+
secondGradientColor: Colors.OrangeStart,
87106
textColor: Color.black,
88107
legendTextColor: Color.gray)
89108

@@ -114,31 +133,40 @@ public struct ChartForm {
114133
public class ChartStyle {
115134
public var backgroundColor: Color
116135
public var accentColor: Color
117-
public var secondGradientColor: Color
136+
public var gradientColor: GradientColor
118137
public var textColor: Color
119138
public var legendTextColor: Color
120139
public weak var darkModeStyle: ChartStyle?
121140

122141
public init(backgroundColor: Color, accentColor: Color, secondGradientColor: Color, textColor: Color, legendTextColor: Color){
123142
self.backgroundColor = backgroundColor
124143
self.accentColor = accentColor
125-
self.secondGradientColor = secondGradientColor
144+
self.gradientColor = GradientColor(start: accentColor, end: secondGradientColor)
145+
self.textColor = textColor
146+
self.legendTextColor = legendTextColor
147+
}
148+
149+
public init(backgroundColor: Color, accentColor: Color, gradientColor: GradientColor, textColor: Color, legendTextColor: Color){
150+
self.backgroundColor = backgroundColor
151+
self.accentColor = accentColor
152+
self.gradientColor = gradientColor
126153
self.textColor = textColor
127154
self.legendTextColor = legendTextColor
128155
}
129156

130157
public init(formSize: CGSize){
131158
self.backgroundColor = Color.white
132159
self.accentColor = Colors.OrangeStart
133-
self.secondGradientColor = Colors.OrangeEnd
160+
self.gradientColor = GradientColors.orange
134161
self.legendTextColor = Color.gray
135162
self.textColor = Color.black
136163
}
137164
}
138165

139-
public class ChartData: ObservableObject {
166+
public class ChartData: ObservableObject, Identifiable {
140167
@Published var points: [(String,Double)]
141168
var valuesGiven: Bool = false
169+
var ID = UUID()
142170

143171
public init<N: BinaryFloatingPoint>(points:[N]) {
144172
self.points = points.map{("", Double($0))}
@@ -165,6 +193,24 @@ public class ChartData: ObservableObject {
165193
}
166194
}
167195

196+
public class MultiLineChartData: ChartData {
197+
var gradient: GradientColor
198+
199+
public init<N: BinaryFloatingPoint>(points:[N], gradient: GradientColor) {
200+
self.gradient = gradient
201+
super.init(points: points)
202+
}
203+
204+
public init<N: BinaryFloatingPoint>(points:[N], color: Color) {
205+
self.gradient = GradientColor(start: color, end: color)
206+
super.init(points: points)
207+
}
208+
209+
public func getGradient() -> GradientColor {
210+
return self.gradient
211+
}
212+
}
213+
168214
public class TestData{
169215
static public var data:ChartData = ChartData(points: [37,72,51,22,39,47,66,85,50])
170216
static public var values:ChartData = ChartData(values: [("2017 Q3",220),

Sources/SwiftUICharts/LineChart/Line.swift

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,13 @@ struct Line: View {
1313
@Binding var frame: CGRect
1414
@Binding var touchLocation: CGPoint
1515
@Binding var showIndicator: Bool
16+
// @Binding var minDataValue: Double?
17+
// @Binding var maxDataValue: Double?
1618
@State private var showFull: Bool = false
1719
@State var showBackground: Bool = true
20+
var gradient: GradientColor = GradientColor(start: Colors.GradientPurple, end: Colors.GradientNeonBlue)
1821
let padding:CGFloat = 30
22+
var curvedLines: Bool = true
1923
var stepWidth: CGFloat {
2024
if data.points.count < 2 {
2125
return 0
@@ -35,11 +39,11 @@ struct Line: View {
3539
}
3640
var path: Path {
3741
let points = self.data.onlyPoints()
38-
return Path.quadCurvedPathWithPoints(points: points, step: CGPoint(x: stepWidth, y: stepHeight))
42+
return curvedLines ? Path.quadCurvedPathWithPoints(points: points, step: CGPoint(x: stepWidth, y: stepHeight)) : Path.linePathWithPoints(points: points, step: CGPoint(x: stepWidth, y: stepHeight))
3943
}
4044
var closedPath: Path {
4145
let points = self.data.onlyPoints()
42-
return Path.quadClosedCurvedPathWithPoints(points: points, step: CGPoint(x: stepWidth, y: stepHeight))
46+
return curvedLines ? Path.quadClosedCurvedPathWithPoints(points: points, step: CGPoint(x: stepWidth, y: stepHeight)) : Path.closedLinePathWithPoints(points: points, step: CGPoint(x: stepWidth, y: stepHeight))
4347
}
4448

4549
var body: some View {
@@ -54,16 +58,16 @@ struct Line: View {
5458
}
5559
self.path
5660
.trim(from: 0, to: self.showFull ? 1:0)
57-
.stroke(LinearGradient(gradient: Gradient(colors: [Colors.GradientPurple, Colors.GradientNeonBlue]), startPoint: .leading, endPoint: .trailing) ,style: StrokeStyle(lineWidth: 3))
61+
.stroke(LinearGradient(gradient: gradient.getGradient(), startPoint: .leading, endPoint: .trailing) ,style: StrokeStyle(lineWidth: 3, lineJoin: .round))
5862
.rotationEffect(.degrees(180), anchor: .center)
5963
.rotation3DEffect(.degrees(180), axis: (x: 0, y: 1, z: 0))
6064
.animation(.easeOut(duration: 1.2))
6165
.onAppear {
6266
self.showFull = true
63-
}
64-
.onDisappear {
65-
self.showFull = false
66-
}
67+
}
68+
.onDisappear {
69+
self.showFull = false
70+
}
6771
.drawingGroup()
6872
if(self.showIndicator) {
6973
IndicatorPoint()
@@ -115,8 +119,7 @@ extension Path {
115119
if (points.count < 2){
116120
return path
117121
}
118-
guard var offset = points.min() else { return path }
119-
// offset -= 3
122+
guard let offset = points.min() else { return path }
120123
var p1 = CGPoint(x: 0, y: CGFloat(points[0]-offset)*step.y)
121124
path.move(to: p1)
122125
for pointIndex in 1..<points.count {
@@ -134,8 +137,7 @@ extension Path {
134137
if (points.count < 2){
135138
return path
136139
}
137-
guard var offset = points.min() else { return path }
138-
// offset -= 3
140+
guard let offset = points.min() else { return path }
139141
path.move(to: .zero)
140142
var p1 = CGPoint(x: 0, y: CGFloat(points[0]-offset)*step.y)
141143
path.addLine(to: p1)
@@ -150,6 +152,39 @@ extension Path {
150152
path.closeSubpath()
151153
return path
152154
}
155+
156+
static func linePathWithPoints(points:[Double], step:CGPoint) -> Path {
157+
var path = Path()
158+
if (points.count < 2){
159+
return path
160+
}
161+
guard let offset = points.min() else { return path }
162+
let p1 = CGPoint(x: 0, y: CGFloat(points[0]-offset)*step.y)
163+
path.move(to: p1)
164+
for pointIndex in 1..<points.count {
165+
let p2 = CGPoint(x: step.x * CGFloat(pointIndex), y: step.y*CGFloat(points[pointIndex]-offset))
166+
path.addLine(to: p2)
167+
}
168+
return path
169+
}
170+
171+
static func closedLinePathWithPoints(points:[Double], step:CGPoint) -> Path {
172+
var path = Path()
173+
if (points.count < 2){
174+
return path
175+
}
176+
guard let offset = points.min() else { return path }
177+
var p1 = CGPoint(x: 0, y: CGFloat(points[0]-offset)*step.y)
178+
path.move(to: p1)
179+
for pointIndex in 1..<points.count {
180+
p1 = CGPoint(x: step.x * CGFloat(pointIndex), y: step.y*CGFloat(points[pointIndex]-offset))
181+
path.addLine(to: p1)
182+
}
183+
path.addLine(to: CGPoint(x: p1.x, y: 0))
184+
path.closeSubpath()
185+
return path
186+
}
187+
153188
}
154189

155190
struct Line_Previews: PreviewProvider {

0 commit comments

Comments
 (0)