Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 50ab18d047 | |||
| c360f8a685 | |||
| 6acb264fb2 | |||
| a4381e037c | |||
| aecfdc5634 | |||
| 9115a992c9 | |||
| eca6eda179 | |||
| 1f4949a731 | |||
| 92490983c5 | |||
| 5c49a55e68 | |||
| 29700ffd47 | |||
| 5aa8cdf50b | |||
| 08f0053b16 | |||
| 4699847a9a | |||
| 6c768ad47e | |||
| 6c612fae18 | |||
| 812e02815f | |||
| c6610f5679 |
@@ -2,3 +2,4 @@
|
||||
/.build
|
||||
/Packages
|
||||
/*.xcodeproj
|
||||
.swiftpm
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<key>SwiftUICharts.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
<integer>3</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// swift-tools-version:5.1
|
||||
// swift-tools-version:5.3
|
||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||
|
||||
import PackageDescription
|
||||
@@ -6,7 +6,7 @@ import PackageDescription
|
||||
let package = Package(
|
||||
name: "SwiftUICharts",
|
||||
platforms: [
|
||||
.iOS(.v13), .watchOS(.v6), .macOS(.v10_15)
|
||||
.iOS(.v13), .watchOS(.v6), .macOS(.v11)
|
||||
],
|
||||
products: [
|
||||
// Products define the executables and libraries produced by a package, and make them visible to other packages.
|
||||
|
||||
@@ -2,13 +2,27 @@
|
||||
|
||||
Swift package for displaying charts effortlessly.
|
||||
|
||||
**First release of version 2.0 is coming soon! Also iOS 14 WidgetKit support is coming. I will update current charts and possibly extend with some new chart types to provide the best support for building informative and beautiful widgets for the new home screen 🥳 Stay tuned!**
|
||||
## V2 Beta is here 🎉🎉🎉
|
||||
|
||||

|
||||
V2 focuses on providing a strong and easy to use base, on which you can build your beautiful custom charts. It provides basic building blocks, like a chart view (bar, pie, line and ring chart), grid view, card view, interactive label for displaying the curent chart value.
|
||||
So you decide, whether you build a fully fledged interactive view, or just display a bare bone chart
|
||||
|
||||
### Note:
|
||||
**A version 2.0 is coming soon!!! 🎉🎉🎉**, so please hold off your PRs for a while. I'm writing a new code base with more sleek code architecture with an option for easier expansion. I'll make beta releases so you can test betas.
|
||||
**If you'd like to contribute you can find tickets for the new version in the Issues under the `v2` tag, please read more at: [https://github.com/AppPear/ChartView/pull/89](https://github.com/AppPear/ChartView/pull/89)**
|
||||
### It supports interactions and animations
|
||||
<img src="https://user-images.githubusercontent.com/2826764/130787802-9aa619ee-05de-4343-ba3c-1796e4d05e08.gif" width="26%"></img> <img src="https://user-images.githubusercontent.com/2826764/130787814-283f3d26-6c9d-448b-b2c7-879e60a3b05d.gif" width="26%"></img>
|
||||
|
||||
### It is fully customizable, and works together with native SwiftUI elements well
|
||||
<img src="https://user-images.githubusercontent.com/2826764/130785262-010d6791-16cf-485d-b920-29e4086477e2.png" width="45%"></img> <img src="https://user-images.githubusercontent.com/2826764/130785266-94a08622-2963-4177-8777-8bd3ad463809.png" width="45%"></img> <img src="https://user-images.githubusercontent.com/2826764/130785268-284314de-ba96-4fb7-a1e5-8a46578e1f0e.png" width="45%"></img>
|
||||
|
||||
### Installation
|
||||
please check out `2.0.0-beta.2` tag
|
||||
|
||||

|
||||
|
||||
## Original (stable) version:
|
||||
|
||||
<img src="https://user-images.githubusercontent.com/2826764/131211993-5d33312b-09af-44b4-a32e-ffaad739adfe.gif" width="45%"></img> <img src="https://user-images.githubusercontent.com/2826764/131211994-48c9ce4e-2e67-40a0-b727-c88bdbd22cd0.gif" width="45%">
|
||||
|
||||
### Usage
|
||||
|
||||
It supports:
|
||||
* Line charts
|
||||
@@ -18,13 +32,13 @@ It supports:
|
||||
### Slack
|
||||
Join our Slack channel for day to day conversation and more insights:
|
||||
|
||||
[Slack invite link](https://join.slack.com/t/swiftuichartview/shared_invite/zt-el5pnmba-FvyraEsI~EwxqWHNfHZWZg)
|
||||
[Slack invite link](https://join.slack.com/t/swiftuichartview/shared_invite/zt-g6mxioq8-j3iUTF1YKX7D23ML3qcc4g)
|
||||
|
||||
### Installation:
|
||||
|
||||
It requires iOS 13 and Xcode 11!
|
||||
|
||||
In Xcode got to `File -> Swift Packages -> Add Package Dependency` and paste inthe repo's url: `https://github.com/AppPear/ChartView`
|
||||
In Xcode go to `File -> Swift Packages -> Add Package Dependency` and paste in the repo's url: `https://github.com/AppPear/ChartView`
|
||||
|
||||
### Usage:
|
||||
|
||||
@@ -40,7 +54,8 @@ Added an example project, with **iOS, watchOS** target: https://github.com/AppPe
|
||||
|
||||
**LineChartView with multiple lines!**
|
||||
First release of this feature, interaction is disabled for now, I'll figure it out how could be the best to interact with multiple lines with a single touch.
|
||||

|
||||
|
||||
<img src="https://user-images.githubusercontent.com/2826764/131211991-eca64276-cf05-423f-a78a-697c55e44bbc.gif" width="50%"></img>
|
||||
|
||||
Usage:
|
||||
```swift
|
||||
@@ -61,7 +76,6 @@ Available preset gradients:
|
||||
|
||||
**Full screen view called LineView!!!**
|
||||
|
||||

|
||||
|
||||
```swift
|
||||
LineView(data: [8,23,54,32,12,37,7,23,43], title: "Line chart", legend: "Full screen") // legend is optional, use optional .padding()
|
||||
@@ -69,7 +83,7 @@ Available preset gradients:
|
||||
|
||||
Adopts to dark mode automatically
|
||||
|
||||

|
||||
<img src="https://user-images.githubusercontent.com/2826764/131211977-27439357-491d-4872-a6bd-f696edac4c7f.gif" width="45%"></img> <img src="https://user-images.githubusercontent.com/2826764/131211985-f77464d6-7fd8-429d-9e77-9f9bc7424d32.gif" width="45%">
|
||||
|
||||
You can add your custom darkmode style by specifying:
|
||||
|
||||
@@ -91,7 +105,7 @@ You can add a line chart with the following code:
|
||||
|
||||
|
||||
## Bar charts
|
||||

|
||||
<img src="https://user-images.githubusercontent.com/2826764/131211994-48c9ce4e-2e67-40a0-b727-c88bdbd22cd0.gif" width="45%">
|
||||
|
||||
**[New feature] you can display labels also along values and points for each bar to descirbe your data better!**
|
||||
**Bar chart is interactive, so you can drag across to reveal the data points**
|
||||
@@ -169,10 +183,9 @@ You can access built-in styles:
|
||||
* barChartMidnightGreenLight
|
||||
* barChartMidnightGreenDark
|
||||
|
||||

|
||||
|
||||

|
||||
<img src="https://user-images.githubusercontent.com/2826764/131211990-e41cec90-38f4-4965-8bdc-41c30b79acea.gif" width="45%">
|
||||
|
||||
<img src="https://user-images.githubusercontent.com/2826764/131211999-6ec4f13b-0465-4135-b576-76e31b11a2c6.png" width="45%">
|
||||
|
||||
### You can customize the size of the chart with a ChartForm object:
|
||||
|
||||
@@ -186,12 +199,16 @@ You can access built-in styles:
|
||||
BarChartView(data: [8,23,54,32,12,37,7,23,43], title: "Title", form: ChartForm.small)
|
||||
```
|
||||
|
||||
### You can choose whether bar is animated or not after completing your gesture.
|
||||
|
||||
If you want to animate back movement after completing your gesture, you set `animatedToBack` as `true`.
|
||||
|
||||
### WatchOS support for Bar charts:
|
||||
|
||||

|
||||
<img src="https://user-images.githubusercontent.com/2826764/131212000-a058fdd9-af40-4e64-adc3-82201ea2484d.png" width="45%">
|
||||
|
||||
## Pie charts
|
||||

|
||||
<img src="https://user-images.githubusercontent.com/2826764/131211998-e142657d-0ebc-43b7-aeda-07cae4d9e34b.png" width="45%">
|
||||
|
||||
You can add a pie chart with the following code:
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 514 KiB |
|
Before Width: | Height: | Size: 502 KiB |
|
Before Width: | Height: | Size: 222 KiB |
|
Before Width: | Height: | Size: 105 KiB |
|
Before Width: | Height: | Size: 147 KiB |
|
Before Width: | Height: | Size: 343 KiB |
|
Before Width: | Height: | Size: 278 KiB |
|
Before Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 73 KiB |
@@ -17,8 +17,9 @@ public struct BarChartView : View {
|
||||
public var darkModeStyle: ChartStyle
|
||||
public var formSize:CGSize
|
||||
public var dropShadow: Bool
|
||||
public var cornerImage: Image
|
||||
public var cornerImage: Image?
|
||||
public var valueSpecifier:String
|
||||
public var animatedToBack: Bool
|
||||
|
||||
@State private var touchLocation: CGFloat = -1.0
|
||||
@State private var showValue: Bool = false
|
||||
@@ -33,7 +34,7 @@ public struct BarChartView : View {
|
||||
var isFullWidth:Bool {
|
||||
return self.formSize == ChartForm.large
|
||||
}
|
||||
public init(data:ChartData, title: String, legend: String? = nil, style: ChartStyle = Styles.barChartStyleOrangeLight, form: CGSize? = ChartForm.medium, dropShadow: Bool? = true, cornerImage:Image? = Image(systemName: "waveform.path.ecg"), valueSpecifier: String? = "%.1f"){
|
||||
public init(data:ChartData, title: String, legend: String? = nil, style: ChartStyle = Styles.barChartStyleOrangeLight, form: CGSize? = ChartForm.medium, dropShadow: Bool? = true, cornerImage:Image? = Image(systemName: "waveform.path.ecg"), valueSpecifier: String? = "%.1f", animatedToBack: Bool = false){
|
||||
self.data = data
|
||||
self.title = title
|
||||
self.legend = legend
|
||||
@@ -41,8 +42,9 @@ public struct BarChartView : View {
|
||||
self.darkModeStyle = style.darkModeStyle != nil ? style.darkModeStyle! : Styles.barChartStyleOrangeDark
|
||||
self.formSize = form!
|
||||
self.dropShadow = dropShadow!
|
||||
self.cornerImage = cornerImage!
|
||||
self.cornerImage = cornerImage
|
||||
self.valueSpecifier = valueSpecifier!
|
||||
self.animatedToBack = animatedToBack
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
@@ -105,9 +107,19 @@ public struct BarChartView : View {
|
||||
}
|
||||
})
|
||||
.onEnded({ value in
|
||||
self.showValue = false
|
||||
self.showLabelValue = false
|
||||
self.touchLocation = -1
|
||||
if animatedToBack {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||
withAnimation(Animation.easeOut(duration: 1)) {
|
||||
self.showValue = false
|
||||
self.showLabelValue = false
|
||||
self.touchLocation = -1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.showValue = false
|
||||
self.showLabelValue = false
|
||||
self.touchLocation = -1
|
||||
}
|
||||
})
|
||||
)
|
||||
.gesture(TapGesture()
|
||||
|
||||
@@ -268,11 +268,15 @@ class HapticFeedback {
|
||||
static func playSelection() -> Void {
|
||||
WKInterfaceDevice.current().play(.click)
|
||||
}
|
||||
#else
|
||||
#elseif os(iOS)
|
||||
//iOS implementation
|
||||
let selectionFeedbackGenerator = UISelectionFeedbackGenerator()
|
||||
static func playSelection() -> Void {
|
||||
UISelectionFeedbackGenerator().selectionChanged()
|
||||
}
|
||||
#else
|
||||
static func playSelection() -> Void {
|
||||
//No-op
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ struct Legend: View {
|
||||
@Binding var frame: CGRect
|
||||
@Binding var hideHorizontalLines: Bool
|
||||
@Environment(\.colorScheme) var colorScheme: ColorScheme
|
||||
var specifier: String = "%.2f"
|
||||
let padding:CGFloat = 3
|
||||
|
||||
var stepWidth: CGFloat {
|
||||
@@ -42,7 +43,7 @@ struct Legend: View {
|
||||
ZStack(alignment: .topLeading){
|
||||
ForEach((0...4), id: \.self) { height in
|
||||
HStack(alignment: .center){
|
||||
Text("\(self.getYLegendSafe(height: height), specifier: "%.2f")").offset(x: 0, y: self.getYposition(height: height) )
|
||||
Text("\(self.getYLegendSafe(height: height), specifier: specifier)").offset(x: 0, y: self.getYposition(height: height) )
|
||||
.foregroundColor(Colors.LegendText)
|
||||
.font(.caption)
|
||||
self.line(atHeight: self.getYLegendSafe(height: height), width: self.frame.width)
|
||||
|
||||
@@ -80,7 +80,6 @@ public struct Line: View {
|
||||
.onDisappear {
|
||||
self.showFull = false
|
||||
}
|
||||
.drawingGroup()
|
||||
if(self.showIndicator) {
|
||||
IndicatorPoint()
|
||||
.position(self.getClosestPointOnPath(touchLocation: self.touchLocation))
|
||||
|
||||
@@ -38,7 +38,7 @@ public struct LineChartView: View {
|
||||
legend: String? = nil,
|
||||
style: ChartStyle = Styles.lineChartStyleOne,
|
||||
form: CGSize? = ChartForm.medium,
|
||||
rateValue: Int? = 14,
|
||||
rateValue: Int?,
|
||||
dropShadow: Bool? = true,
|
||||
valueSpecifier: String? = "%.1f") {
|
||||
|
||||
@@ -74,14 +74,14 @@ public struct LineChartView: View {
|
||||
}
|
||||
HStack {
|
||||
|
||||
if (self.rateValue ?? 0 != 0)
|
||||
if let rateValue = self.rateValue
|
||||
{
|
||||
if (self.rateValue ?? 0 >= 0){
|
||||
if (rateValue ?? 0 >= 0){
|
||||
Image(systemName: "arrow.up")
|
||||
}else{
|
||||
Image(systemName: "arrow.down")
|
||||
}
|
||||
Text("\(self.rateValue!)%")
|
||||
Text("\(rateValue!)%")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,7 +108,7 @@ public struct LineChartView: View {
|
||||
maxDataValue: .constant(nil)
|
||||
)
|
||||
}
|
||||
.frame(width: frame.width, height: frame.height + 30)
|
||||
.frame(width: frame.width, height: frame.height)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 20))
|
||||
.offset(x: 0, y: 0)
|
||||
}.frame(width: self.formSize.width, height: self.formSize.height)
|
||||
|
||||
@@ -14,7 +14,8 @@ public struct LineView: View {
|
||||
public var legend: String?
|
||||
public var style: ChartStyle
|
||||
public var darkModeStyle: ChartStyle
|
||||
public var valueSpecifier:String
|
||||
public var valueSpecifier: String
|
||||
public var legendSpecifier: String
|
||||
|
||||
@Environment(\.colorScheme) var colorScheme: ColorScheme
|
||||
@State private var showLegend = false
|
||||
@@ -29,13 +30,15 @@ public struct LineView: View {
|
||||
title: String? = nil,
|
||||
legend: String? = nil,
|
||||
style: ChartStyle = Styles.lineChartStyleOne,
|
||||
valueSpecifier: String? = "%.1f") {
|
||||
valueSpecifier: String? = "%.1f",
|
||||
legendSpecifier: String? = "%.2f") {
|
||||
|
||||
self.data = ChartData(points: data)
|
||||
self.title = title
|
||||
self.legend = legend
|
||||
self.style = style
|
||||
self.valueSpecifier = valueSpecifier!
|
||||
self.legendSpecifier = legendSpecifier!
|
||||
self.darkModeStyle = style.darkModeStyle != nil ? style.darkModeStyle! : Styles.lineViewDarkMode
|
||||
}
|
||||
|
||||
@@ -60,12 +63,12 @@ public struct LineView: View {
|
||||
.foregroundColor(self.colorScheme == .dark ? self.darkModeStyle.backgroundColor : self.style.backgroundColor)
|
||||
if(self.showLegend){
|
||||
Legend(data: self.data,
|
||||
frame: .constant(reader.frame(in: .local)), hideHorizontalLines: self.$hideHorizontalLines)
|
||||
frame: .constant(reader.frame(in: .local)), hideHorizontalLines: self.$hideHorizontalLines, specifier: legendSpecifier)
|
||||
.transition(.opacity)
|
||||
.animation(Animation.easeOut(duration: 1).delay(1))
|
||||
}
|
||||
Line(data: self.data,
|
||||
frame: .constant(CGRect(x: 0, y: 0, width: reader.frame(in: .local).width - 30, height: reader.frame(in: .local).height)),
|
||||
frame: .constant(CGRect(x: 0, y: 0, width: reader.frame(in: .local).width - 30, height: reader.frame(in: .local).height + 25)),
|
||||
touchLocation: self.$indicatorLocation,
|
||||
showIndicator: self.$hideHorizontalLines,
|
||||
minDataValue: .constant(nil),
|
||||
@@ -73,7 +76,7 @@ public struct LineView: View {
|
||||
showBackground: false,
|
||||
gradient: self.style.gradientColor
|
||||
)
|
||||
.offset(x: 30, y: -20)
|
||||
.offset(x: 30, y: 0)
|
||||
.onAppear(){
|
||||
self.showLegend = true
|
||||
}
|
||||
|
||||
@@ -29,5 +29,6 @@ public struct MagnifierRect: View {
|
||||
.blendMode(.multiply)
|
||||
}
|
||||
}
|
||||
.offset(x: 0, y: -15)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,15 +85,13 @@ public struct MultiLineChartView: View {
|
||||
.font(.callout)
|
||||
.foregroundColor(self.colorScheme == .dark ? self.darkModeStyle.legendTextColor : self.style.legendTextColor)
|
||||
}
|
||||
if let rateValue = rateValue {
|
||||
HStack {
|
||||
if (rateValue >= 0){
|
||||
Image(systemName: "arrow.up")
|
||||
}else{
|
||||
Image(systemName: "arrow.down")
|
||||
}
|
||||
Text("\(rateValue)%")
|
||||
HStack {
|
||||
if (rateValue ?? 0 >= 0){
|
||||
Image(systemName: "arrow.up")
|
||||
}else{
|
||||
Image(systemName: "arrow.down")
|
||||
}
|
||||
Text("\(rateValue ?? 0)%")
|
||||
}
|
||||
}
|
||||
.transition(.opacity)
|
||||
@@ -112,7 +110,7 @@ public struct MultiLineChartView: View {
|
||||
Spacer()
|
||||
GeometryReader{ geometry in
|
||||
ZStack{
|
||||
ForEach(0..<self.data.count) { i in
|
||||
ForEach(0..<self.data.count, id: \.self) { i in
|
||||
Line(data: self.data[i],
|
||||
frame: .constant(geometry.frame(in: .local)),
|
||||
touchLocation: self.$touchLocation,
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// File.swift
|
||||
//
|
||||
//
|
||||
// Created by 曾文志 on 2020/7/30.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
func isPointInCircle(point: CGPoint, circleRect: CGRect) -> Bool {
|
||||
let r = min(circleRect.width, circleRect.height) / 2
|
||||
let center = CGPoint(x: circleRect.midX, y: circleRect.midY)
|
||||
let dx = point.x - center.x
|
||||
let dy = point.y - center.y
|
||||
let distance = sqrt(dx * dx + dy * dy)
|
||||
return distance <= r
|
||||
}
|
||||
|
||||
func degree(for point: CGPoint, inCircleRect circleRect: CGRect) -> Double {
|
||||
let center = CGPoint(x: circleRect.midX, y: circleRect.midY)
|
||||
let dx = point.x - center.x
|
||||
let dy = point.y - center.y
|
||||
let acuteDegree = Double(atan(dy / dx)) * (180 / .pi)
|
||||
|
||||
let isInBottomRight = dx >= 0 && dy >= 0
|
||||
let isInBottomLeft = dx <= 0 && dy >= 0
|
||||
let isInTopLeft = dx <= 0 && dy <= 0
|
||||
let isInTopRight = dx >= 0 && dy <= 0
|
||||
|
||||
if isInBottomRight {
|
||||
return acuteDegree
|
||||
} else if isInBottomLeft {
|
||||
return 180 - abs(acuteDegree)
|
||||
} else if isInTopLeft {
|
||||
return 180 + abs(acuteDegree)
|
||||
} else if isInTopRight {
|
||||
return 360 - abs(acuteDegree)
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
@@ -25,13 +25,42 @@ public struct PieChartRow : View {
|
||||
}
|
||||
return tempSlices
|
||||
}
|
||||
|
||||
@Binding var showValue: Bool
|
||||
@Binding var currentValue: Double
|
||||
|
||||
@State private var currentTouchedIndex = -1 {
|
||||
didSet {
|
||||
if oldValue != currentTouchedIndex {
|
||||
showValue = currentTouchedIndex != -1
|
||||
currentValue = showValue ? slices[currentTouchedIndex].value : 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
GeometryReader { geometry in
|
||||
ZStack{
|
||||
ForEach(0..<self.slices.count){ i in
|
||||
PieChartCell(rect: geometry.frame(in: .local), startDeg: self.slices[i].startDeg, endDeg: self.slices[i].endDeg, index: i, backgroundColor: self.backgroundColor,accentColor: self.accentColor)
|
||||
.scaleEffect(self.currentTouchedIndex == i ? 1.1 : 1)
|
||||
.animation(Animation.spring())
|
||||
}
|
||||
}
|
||||
.gesture(DragGesture()
|
||||
.onChanged({ value in
|
||||
let rect = geometry.frame(in: .local)
|
||||
let isTouchInPie = isPointInCircle(point: value.location, circleRect: rect)
|
||||
if isTouchInPie {
|
||||
let touchDegree = degree(for: value.location, inCircleRect: rect)
|
||||
self.currentTouchedIndex = self.slices.firstIndex(where: { $0.startDeg < touchDegree && $0.endDeg > touchDegree }) ?? -1
|
||||
} else {
|
||||
self.currentTouchedIndex = -1
|
||||
}
|
||||
})
|
||||
.onEnded({ value in
|
||||
self.currentTouchedIndex = -1
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,10 +69,11 @@ public struct PieChartRow : View {
|
||||
struct PieChartRow_Previews : PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
PieChartRow(data:[8,23,54,32,12,37,7,23,43], backgroundColor: Color(red: 252.0/255.0, green: 236.0/255.0, blue: 234.0/255.0), accentColor: Color(red: 225.0/255.0, green: 97.0/255.0, blue: 76.0/255.0)).frame(width: 100, height: 100)
|
||||
PieChartRow(data:[0], backgroundColor: Color(red: 252.0/255.0, green: 236.0/255.0, blue: 234.0/255.0), accentColor: Color(red: 225.0/255.0, green: 97.0/255.0, blue: 76.0/255.0)).frame(width: 100, height: 100)
|
||||
PieChartRow(data:[8,23,54,32,12,37,7,23,43], backgroundColor: Color(red: 252.0/255.0, green: 236.0/255.0, blue: 234.0/255.0), accentColor: Color(red: 225.0/255.0, green: 97.0/255.0, blue: 76.0/255.0), showValue: Binding.constant(false), currentValue: Binding.constant(0))
|
||||
.frame(width: 100, height: 100)
|
||||
PieChartRow(data:[0], backgroundColor: Color(red: 252.0/255.0, green: 236.0/255.0, blue: 234.0/255.0), accentColor: Color(red: 225.0/255.0, green: 97.0/255.0, blue: 76.0/255.0), showValue: Binding.constant(false), currentValue: Binding.constant(0))
|
||||
.frame(width: 100, height: 100)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -15,8 +15,18 @@ public struct PieChartView : View {
|
||||
public var style: ChartStyle
|
||||
public var formSize:CGSize
|
||||
public var dropShadow: Bool
|
||||
|
||||
public init(data: [Double], title: String, legend: String? = nil, style: ChartStyle = Styles.pieChartStyleOne, form: CGSize? = ChartForm.medium, dropShadow: Bool? = true){
|
||||
public var valueSpecifier:String
|
||||
|
||||
@State private var showValue = false
|
||||
@State private var currentValue: Double = 0 {
|
||||
didSet{
|
||||
if(oldValue != self.currentValue && self.showValue) {
|
||||
HapticFeedback.playSelection()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public init(data: [Double], title: String, legend: String? = nil, style: ChartStyle = Styles.pieChartStyleOne, form: CGSize? = ChartForm.medium, dropShadow: Bool? = true, valueSpecifier: String? = "%.1f"){
|
||||
self.data = data
|
||||
self.title = title
|
||||
self.legend = legend
|
||||
@@ -26,6 +36,7 @@ public struct PieChartView : View {
|
||||
self.formSize = ChartForm.extraLarge
|
||||
}
|
||||
self.dropShadow = dropShadow!
|
||||
self.valueSpecifier = valueSpecifier!
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
@@ -36,15 +47,21 @@ public struct PieChartView : View {
|
||||
.shadow(color: self.style.dropShadowColor, radius: self.dropShadow ? 12 : 0)
|
||||
VStack(alignment: .leading){
|
||||
HStack{
|
||||
Text(self.title)
|
||||
.font(.headline)
|
||||
.foregroundColor(self.style.textColor)
|
||||
if(!showValue){
|
||||
Text(self.title)
|
||||
.font(.headline)
|
||||
.foregroundColor(self.style.textColor)
|
||||
}else{
|
||||
Text("\(self.currentValue, specifier: self.valueSpecifier)")
|
||||
.font(.headline)
|
||||
.foregroundColor(self.style.textColor)
|
||||
}
|
||||
Spacer()
|
||||
Image(systemName: "chart.pie.fill")
|
||||
.imageScale(.large)
|
||||
.foregroundColor(self.style.legendTextColor)
|
||||
}.padding()
|
||||
PieChartRow(data: data, backgroundColor: self.style.backgroundColor, accentColor: self.style.accentColor)
|
||||
PieChartRow(data: data, backgroundColor: self.style.backgroundColor, accentColor: self.style.accentColor, showValue: $showValue, currentValue: $currentValue)
|
||||
.foregroundColor(self.style.accentColor).padding(self.legend != nil ? 0 : 12).offset(y:self.legend != nil ? 0 : -10)
|
||||
if(self.legend != nil) {
|
||||
Text(self.legend!)
|
||||
|
||||