Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 94950db4d5 | |||
| 251a830281 | |||
| b2b0b83b4b |
Generated
BIN
Binary file not shown.
+1
-1
@@ -6,7 +6,7 @@ import PackageDescription
|
||||
let package = Package(
|
||||
name: "SwiftUICharts",
|
||||
platforms: [
|
||||
.iOS(.v13),
|
||||
.iOS(.v13),.watchOS(.v6)
|
||||
],
|
||||
products: [
|
||||
// Products define the executables and libraries produced by a package, and make them visible to other packages.
|
||||
|
||||
@@ -59,7 +59,6 @@ Customizable:
|
||||
* background color
|
||||
* accent color
|
||||
* second gradient color
|
||||
* chart form size
|
||||
* text color
|
||||
* legend text color
|
||||
|
||||
@@ -86,6 +85,22 @@ You can access built-in styles:
|
||||

|
||||
|
||||
|
||||
### You can customize the size of the chart with a Form object:
|
||||
|
||||
**Form**
|
||||
* `.small`
|
||||
* `.medium`
|
||||
* `.large`
|
||||
* `.detail`
|
||||
|
||||
```swift
|
||||
BarChartView(data: [8,23,54,32,12,37,7,23,43], title: "Title", form: Form.small)
|
||||
```
|
||||
|
||||
### WatchOS support for Bar charts:
|
||||
|
||||

|
||||
|
||||
## Pie charts
|
||||

|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ public struct BarChartRow : View {
|
||||
GeometryReader { geometry in
|
||||
HStack(alignment: .bottom, spacing: (geometry.frame(in: .local).width-22)/CGFloat(self.data.count * 3)){
|
||||
ForEach(0..<self.data.count) { i in
|
||||
BarChartCell(value: Double(self.data[i])/Double(self.maxValue), index: i, width: Float(geometry.frame(in: .local).width - 22), numberOfDataPoints: self.data.count, accentColor: self.accentColor, secondGradientAccentColor: self.secondGradientAccentColor, touchLocation: self.$touchLocation)
|
||||
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)
|
||||
.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)
|
||||
|
||||
}
|
||||
@@ -28,6 +28,10 @@ public struct BarChartRow : View {
|
||||
.padding([.top, .leading, .trailing], 10)
|
||||
}
|
||||
}
|
||||
|
||||
func normalizedValue(index: Int) -> Double {
|
||||
return Double(self.data[index])/Double(self.maxValue)
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
|
||||
@@ -13,25 +13,28 @@ public struct BarChartView : View {
|
||||
public var title: String
|
||||
public var legend: String?
|
||||
public var style: ChartStyle
|
||||
let selectionFeedbackGenerator = UISelectionFeedbackGenerator()
|
||||
public var formSize:CGSize
|
||||
// let selectionFeedbackGenerator = UISelectionFeedbackGenerator()
|
||||
|
||||
@State private var touchLocation: CGFloat = -1.0
|
||||
@State private var showValue: Bool = false
|
||||
@State private var currentValue: Int = 0 {
|
||||
didSet{
|
||||
if(oldValue != self.currentValue && self.showValue) {
|
||||
selectionFeedbackGenerator.selectionChanged()
|
||||
// selectionFeedbackGenerator.selectionChanged()
|
||||
HapticFeedback.playSelection()
|
||||
}
|
||||
}
|
||||
}
|
||||
var isFullWidth:Bool {
|
||||
return self.style.chartFormSize == Form.large
|
||||
return self.formSize == Form.large
|
||||
}
|
||||
public init(data: [Int], title: String, legend: String? = nil, style: ChartStyle = Styles.barChartStyleOne ){
|
||||
public init(data: [Int], title: String, legend: String? = nil, style: ChartStyle = Styles.barChartStyleOrangeLight, form: CGSize? = Form.medium){
|
||||
self.data = data
|
||||
self.title = title
|
||||
self.legend = legend
|
||||
self.style = style
|
||||
self.formSize = form!
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
@@ -51,7 +54,7 @@ public struct BarChartView : View {
|
||||
.font(.headline)
|
||||
.foregroundColor(self.style.textColor)
|
||||
}
|
||||
if(self.style.chartFormSize == Form.large && self.legend != nil && !showValue) {
|
||||
if(self.formSize == Form.large && self.legend != nil && !showValue) {
|
||||
Text(self.legend!)
|
||||
.font(.callout)
|
||||
.foregroundColor(self.style.accentColor)
|
||||
@@ -64,7 +67,7 @@ public struct BarChartView : View {
|
||||
.foregroundColor(self.style.legendTextColor)
|
||||
}.padding()
|
||||
BarChartRow(data: data, accentColor: self.style.accentColor, secondGradientAccentColor: self.style.secondGradientColor, touchLocation: self.$touchLocation)
|
||||
if self.legend != nil && self.style.chartFormSize == Form.medium {
|
||||
if self.legend != nil && self.formSize == Form.medium {
|
||||
Text(self.legend!)
|
||||
.font(.headline)
|
||||
.foregroundColor(self.style.legendTextColor)
|
||||
@@ -72,10 +75,10 @@ public struct BarChartView : View {
|
||||
}
|
||||
|
||||
}
|
||||
}.frame(minWidth:self.style.chartFormSize.width, maxWidth: self.isFullWidth ? .infinity : self.style.chartFormSize.width, minHeight:self.style.chartFormSize.height, maxHeight:self.style.chartFormSize.height)
|
||||
}.frame(minWidth:self.formSize.width, maxWidth: self.isFullWidth ? .infinity : self.formSize.width, minHeight:self.formSize.height, maxHeight:self.formSize.height)
|
||||
.gesture(DragGesture()
|
||||
.onChanged({ value in
|
||||
self.touchLocation = value.location.x/self.style.chartFormSize.width
|
||||
self.touchLocation = value.location.x/self.formSize.width
|
||||
self.showValue = true
|
||||
self.currentValue = self.getCurrentValue()
|
||||
})
|
||||
@@ -89,7 +92,7 @@ public struct BarChartView : View {
|
||||
}
|
||||
|
||||
func getCurrentValue()-> Int{
|
||||
let index = max(0,min(self.data.count-1,Int(floor((self.touchLocation*self.style.chartFormSize.width)/(self.style.chartFormSize.width/CGFloat(self.data.count))))))
|
||||
let index = max(0,min(self.data.count-1,Int(floor((self.touchLocation*self.formSize.width)/(self.formSize.width/CGFloat(self.data.count))))))
|
||||
print(index)
|
||||
return self.data[index]
|
||||
}
|
||||
|
||||
@@ -27,8 +27,6 @@ public struct Colors {
|
||||
public static let GradientLowerBlue:Color = Color(hexString: "#F1F9FF")
|
||||
public static let DarkPurple:Color = Color(hexString: "#1B205E")
|
||||
public static let BorderBlue:Color = Color(hexString: "#4EBCFF")
|
||||
|
||||
|
||||
}
|
||||
|
||||
public struct Styles {
|
||||
@@ -36,7 +34,6 @@ public struct Styles {
|
||||
backgroundColor: Color.white,
|
||||
accentColor: Colors.OrangeStart,
|
||||
secondGradientColor: Colors.OrangeEnd,
|
||||
chartFormSize: Form.medium,
|
||||
textColor: Color.black,
|
||||
legendTextColor: Color.gray)
|
||||
|
||||
@@ -44,7 +41,6 @@ public struct Styles {
|
||||
backgroundColor: Color.white,
|
||||
accentColor: Colors.OrangeStart,
|
||||
secondGradientColor: Colors.OrangeEnd,
|
||||
chartFormSize: Form.medium,
|
||||
textColor: Color.black,
|
||||
legendTextColor: Color.gray)
|
||||
|
||||
@@ -52,7 +48,6 @@ public struct Styles {
|
||||
backgroundColor: Color.black,
|
||||
accentColor: Colors.OrangeStart,
|
||||
secondGradientColor: Colors.OrangeEnd,
|
||||
chartFormSize: Form.medium,
|
||||
textColor: Color.white,
|
||||
legendTextColor: Color.gray)
|
||||
|
||||
@@ -60,7 +55,6 @@ public struct Styles {
|
||||
backgroundColor: Color.white,
|
||||
accentColor: Colors.GradientNeonBlue,
|
||||
secondGradientColor: Colors.GradientPurple,
|
||||
chartFormSize: Form.medium,
|
||||
textColor: Color.black,
|
||||
legendTextColor: Color.gray)
|
||||
|
||||
@@ -68,7 +62,6 @@ public struct Styles {
|
||||
backgroundColor: Color.black,
|
||||
accentColor: Colors.GradientNeonBlue,
|
||||
secondGradientColor: Colors.GradientPurple,
|
||||
chartFormSize: Form.medium,
|
||||
textColor: Color.white,
|
||||
legendTextColor: Color.gray)
|
||||
|
||||
@@ -76,7 +69,6 @@ public struct Styles {
|
||||
backgroundColor: Color(hexString: "#36534D"), //3B5147, 313D34
|
||||
accentColor: Color(hexString: "#FFD603"),
|
||||
secondGradientColor: Color(hexString: "#FFCA04"),
|
||||
chartFormSize: Form.medium,
|
||||
textColor: Color.white,
|
||||
legendTextColor: Color(hexString: "#D2E5E1"))
|
||||
|
||||
@@ -84,7 +76,6 @@ public struct Styles {
|
||||
backgroundColor: Color.white,
|
||||
accentColor: Color(hexString: "#84A094"), //84A094 , 698378
|
||||
secondGradientColor: Color(hexString: "#50675D"),
|
||||
chartFormSize: Form.medium,
|
||||
textColor: Color.black,
|
||||
legendTextColor:Color.gray)
|
||||
|
||||
@@ -92,31 +83,37 @@ public struct Styles {
|
||||
backgroundColor: Color.white,
|
||||
accentColor: Colors.OrangeStart,
|
||||
secondGradientColor: Colors.OrangeEnd,
|
||||
chartFormSize: Form.medium,
|
||||
textColor: Color.black,
|
||||
legendTextColor: Color.gray)
|
||||
}
|
||||
|
||||
public struct Form {
|
||||
#if os(watchOS)
|
||||
public static let small = CGSize(width:120, height:90)
|
||||
public static let medium = CGSize(width:120, height:160)
|
||||
public static let large = CGSize(width:180, height:90)
|
||||
public static let detail = CGSize(width:180, height:160)
|
||||
#else
|
||||
public static let small = CGSize(width:180, height:120)
|
||||
public static let medium = CGSize(width:180, height:240)
|
||||
public static let large = CGSize(width:360, height:120)
|
||||
public static let detail = CGSize(width:180, height:120)
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
public struct ChartStyle {
|
||||
public var backgroundColor: Color
|
||||
public var accentColor: Color
|
||||
public var secondGradientColor: Color
|
||||
public var chartFormSize: CGSize
|
||||
public var textColor: Color
|
||||
public var legendTextColor: Color
|
||||
|
||||
public init(backgroundColor: Color, accentColor: Color, secondGradientColor: Color, chartFormSize: CGSize, textColor: Color, legendTextColor: Color){
|
||||
public init(backgroundColor: Color, accentColor: Color, secondGradientColor: Color, textColor: Color, legendTextColor: Color){
|
||||
self.backgroundColor = backgroundColor
|
||||
self.accentColor = accentColor
|
||||
self.secondGradientColor = secondGradientColor
|
||||
self.chartFormSize = chartFormSize
|
||||
self.textColor = textColor
|
||||
self.legendTextColor = legendTextColor
|
||||
}
|
||||
@@ -125,7 +122,6 @@ public struct ChartStyle {
|
||||
self.backgroundColor = Color.white
|
||||
self.accentColor = Colors.OrangeStart
|
||||
self.secondGradientColor = Colors.OrangeEnd
|
||||
self.chartFormSize = formSize
|
||||
self.legendTextColor = Color.gray
|
||||
self.textColor = Color.black
|
||||
}
|
||||
@@ -163,3 +159,18 @@ extension Color {
|
||||
self.init(red: Double(r) / 255, green: Double(g) / 255, blue: Double(b) / 255)
|
||||
}
|
||||
}
|
||||
|
||||
class HapticFeedback {
|
||||
#if os(watchOS)
|
||||
//watchOS implementation
|
||||
static func playSelection() -> Void {
|
||||
WKInterfaceDevice.current().play(.click)
|
||||
}
|
||||
#else
|
||||
//iOS implementation
|
||||
let selectionFeedbackGenerator = UISelectionFeedbackGenerator()
|
||||
static func playSelection() -> Void {
|
||||
UISelectionFeedbackGenerator().selectionChanged()
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -9,28 +9,31 @@
|
||||
import SwiftUI
|
||||
|
||||
public struct LineChartView: View {
|
||||
let selectionFeedbackGenerator = UISelectionFeedbackGenerator()
|
||||
// let selectionFeedbackGenerator = UISelectionFeedbackGenerator()
|
||||
@ObservedObject var data:ChartData
|
||||
public var title: String
|
||||
public var legend: String?
|
||||
public var style: ChartStyle
|
||||
public var formSize:CGSize
|
||||
@State private var touchLocation:CGPoint = .zero
|
||||
@State private var showIndicatorDot: Bool = false
|
||||
@State private var currentValue: Int = 2 {
|
||||
didSet{
|
||||
if (oldValue != self.currentValue && showIndicatorDot) {
|
||||
selectionFeedbackGenerator.selectionChanged()
|
||||
// selectionFeedbackGenerator.selectionChanged()
|
||||
HapticFeedback.playSelection()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
let frame = CGSize(width: 180, height: 120)
|
||||
|
||||
public init(data: [Int], title: String, legend: String? = nil, style: ChartStyle = Styles.lineChartStyleOne ){
|
||||
public init(data: [Int], title: String, legend: String? = nil, style: ChartStyle = Styles.lineChartStyleOne, form: CGSize? = Form.medium){
|
||||
self.data = ChartData(points: data)
|
||||
self.title = title
|
||||
self.legend = legend
|
||||
self.style = style
|
||||
self.formSize = form!
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
@@ -70,7 +73,7 @@ public struct LineChartView: View {
|
||||
.frame(width: frame.width, height: frame.height)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 20))
|
||||
.offset(x: 0, y: 0)
|
||||
}.frame(width: self.style.chartFormSize.width, height: self.style.chartFormSize.height)
|
||||
}.frame(width: self.formSize.width, height: self.formSize.height)
|
||||
}
|
||||
.gesture(DragGesture()
|
||||
.onChanged({ value in
|
||||
|
||||
@@ -13,11 +13,13 @@ public struct PieChartView : View {
|
||||
public var title: String
|
||||
public var legend: String?
|
||||
public var style: ChartStyle
|
||||
public init(data: [Int], title: String, legend: String? = nil, style: ChartStyle = Styles.pieChartStyleOne ){
|
||||
public var formSize:CGSize
|
||||
public init(data: [Int], title: String, legend: String? = nil, style: ChartStyle = Styles.pieChartStyleOne, form: CGSize? = Form.medium ){
|
||||
self.data = data
|
||||
self.title = title
|
||||
self.legend = legend
|
||||
self.style = style
|
||||
self.formSize = form!
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
@@ -46,7 +48,7 @@ public struct PieChartView : View {
|
||||
}
|
||||
|
||||
}
|
||||
}.frame(width: self.style.chartFormSize.width, height: self.style.chartFormSize.height)
|
||||
}.frame(width: self.formSize.width, height: self.formSize.height)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 73 KiB |
Reference in New Issue
Block a user