Compare commits

...

41 Commits

Author SHA1 Message Date
Samu Andras 102b51bff6 feat: added wiki article links to readme 2021-08-28 12:02:24 +02:00
Andras Samu 13ab3af479 feat: move images from resource folder to cloud (#208) 2021-08-28 11:03:43 +02:00
Andras Samu c360f8a685 Update README.md 2021-08-25 14:37:35 +02:00
Andras Samu 6acb264fb2 Update README.md 2021-08-25 14:35:35 +02:00
Suyeong Pi a4381e037c modify LineChartView rateValue set code (#200) 2021-08-11 22:06:11 +02:00
Szczepan Wiśniowski aecfdc5634 Add id in ForEach in MultiLineChartView for dynamic content (#203) 2021-08-11 22:05:30 +02:00
Cljak10 9115a992c9 Add legend format specifier option in LineView (#186)
Co-authored-by: ClaesCJ <claes@airwallet.net>
2021-03-26 19:36:05 +01:00
Will Dale eca6eda179 Bugfix: Line height in LineView (#175)
* Make the line reach the top and bottom of the chart.

* Put the Magnifier's bottom edge on the 0 line.
2021-03-26 19:32:04 +01:00
Mike Koene 1f4949a731 Bugfix: Draw Lines (#173)
Remove .drawingGroup() to draw Lines again.
2021-03-26 19:31:20 +01:00
Fumiya Tanaka 92490983c5 [WIP]Add an option to animate to back position (BarChart). (#171)
* add `keepTouchLocation` to let us choose whether touchLocation is back to -1 after label has been dragged.

* keep showing value if `keepTouchLocation` is true.

* Update README.md

* feat: when `keepTouchLocation` is true,  bar is automatically deselect in a second after a gesture.

* fix: (BarChart) add animation when back to initial position after completing your gesture. and rename keepTouchLocation to animatedToBack.
2021-03-26 19:30:51 +01:00
Andras Samu 5c49a55e68 fix(LineChartView): fixed linechart shifting down 2021-03-26 19:22:18 +01:00
josephwalden13 29700ffd47 made cornerImage optional (#76) 2021-03-26 18:56:51 +01:00
willtemperley 5aa8cdf50b macOS support: v11 only. Swift tools bumped to 5.3 (#183) 2021-03-24 15:31:12 +01:00
Andras Samu 08f0053b16 update slack link 2020-09-23 14:20:22 +02:00
Andras Samu 4699847a9a Fixed missing self in piechartrow 2020-08-01 11:50:22 +02:00
Lebron 6c768ad47e created interaction for PieChart (#147) 2020-08-01 11:32:52 +02:00
Abdullah Alhaider 6c612fae18 Fix typo (#144) 2020-07-26 09:21:03 +02:00
Andras Samu 812e02815f Update README.md 2020-07-25 20:07:09 +02:00
Andras Samu c6610f5679 Fixed control flow error 2020-07-05 11:02:56 +02:00
Andras Samu 47052674f5 Builded with xcode 12 2020-06-28 14:52:46 +02:00
Andras Samu a36c1db2f8 Update README.md 2020-06-27 14:50:41 +02:00
Roderic Campbell ca19dd578c Cleanup the explicitly unwrapped parameters which had a default value… (#123)
* Cleanup the explicitly unwrapped parameters which had a default value anyway

* Remove print statement
2020-06-27 09:27:55 +02:00
nicolas 27e7e0dd1d Bigger scale (#113) 2020-06-16 19:43:09 +02:00
nicolas 74140af7a7 Add extra large size (#108) 2020-05-31 20:06:17 +02:00
nicolas 7568c5d40c Bug Fix - only 0 data (#109) 2020-05-30 17:18:31 +02:00
nicolas 24cf9eacb8 Update README.md (#106) 2020-05-28 18:58:06 +02:00
Andras Samu c89b1e1480 Update Package.swift 2020-05-28 18:55:26 +02:00
Andras Samu 82e8f249cc Create swift.yml 2020-05-28 18:52:44 +02:00
Andras Samu 22a38a1d40 Update README.md 2020-05-24 21:21:56 +02:00
Andras Samu b5b7c62645 Update v2Ticket.md 2020-05-24 20:50:01 +02:00
Andras Samu 3447d5c9bb Rename v2Ticket to v2Ticket.md 2020-05-24 20:47:47 +02:00
Andras Samu 640ddeb4d2 Create v2Ticket 2020-05-24 20:44:24 +02:00
Lucas Desouza ebd09f438e Fix issue templates (#92)
* fixes name of template files

* adds missing front matter
2020-05-24 17:37:35 +02:00
Andras Samu 0303c3c14d Update README.md 2020-05-24 16:40:02 +02:00
Lucas Desouza 068ea84ddf adds pr template (#90) 2020-05-22 22:15:32 +02:00
Lucas Desouza fa8e015794 adds issue templates (#88) 2020-05-22 17:52:57 +02:00
Daniel dd7a1fc9bd Line view custom gradient (#67)
* feat: Added gradient to Line init from LineView

* Making GradientColor's init method as public
2020-05-18 12:23:21 +02:00
josephwalden13 fada162030 change rateValue to optional to fix crash from force unwraps and set it to show in the chart only for non zero values (#71) 2020-05-07 11:55:35 +02:00
Pierluigi Dell'Acqua a242bd3c94 Making GradientColor's init method as public (#63)
Making the method as public, application is allowed to define custom GradientColor.
2020-04-26 16:22:29 +02:00
Andras Samu c12c773af0 fixed unwrap error 2020-03-17 10:38:45 +01:00
Andras Samu 75804f470a Customisable drop shadow color (#53)
* Customisable drop shadow color

* Drop shadow color parameter in ChartStyle

* Fixed BarChartView
2020-03-05 11:57:38 +01:00
33 changed files with 381 additions and 88 deletions
+34
View File
@@ -0,0 +1,34 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
<!--- Provide a general summary of the issue in the Title above -->
## Description
<!--- Provide a more detailed introduction to the issue itself, and why you consider it to be a bug -->
## Expected Behavior
<!--- Tell us what should happen -->
## Actual Behavior
<!--- Tell us what happens instead -->
## Possible Fix
<!--- Not obligatory, but suggest a fix or reason for the bug -->
## Steps to Reproduce
<!--- Provide a link to a live example, or an unambiguous set of steps to -->
<!--- reproduce this bug. Include code to reproduce, if relevant -->
## Your Environment
<!--- Include as many relevant details about the environment -->
* Version of this package used:
* Device/Simulator:
* Operating System and version:
* Link to your project:
+20
View File
@@ -0,0 +1,20 @@
---
name: Feature request
about: Ask for a new feature
title: ''
labels: ''
assignees: ''
---
<!--- Provide a general summary of the issue in the Title above -->
## Detailed Description
<!--- Provide a detailed description of the change or addition you are proposing -->
## Context
<!--- Why is this change important to you? How would you use it? -->
<!--- How can it benefit other users? -->
## Possible Implementation
<!--- Not obligatory, but suggest an idea for implementing addition or change -->
+11
View File
@@ -0,0 +1,11 @@
---
name: v2 ticket
about: Create tasks for the upcoming new version
title: ''
labels: v2
assignees: ''
---
# v2 ticket
## Ticket description:
+29
View File
@@ -0,0 +1,29 @@
<!--- Provide a general summary of your changes in the Title above -->
## Description
<!--- Describe your changes in detail -->
## Motivation and Context
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->
## How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->
## Screenshots (if appropriate):
## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
- [ ] Non-functional change (Updating Documentation, CI automation, etc..)
## Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] My code follows the code style of this project.
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
+22
View File
@@ -0,0 +1,22 @@
name: Swift
on:
push:
branches:
- master
- new-version
pull_request:
branches:
- master
- new-version
jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: Build
run: swift build -v
- name: Run tests
run: swift test -v
+1
View File
@@ -2,3 +2,4 @@
/.build
/Packages
/*.xcodeproj
.swiftpm
@@ -7,7 +7,7 @@
<key>SwiftUICharts.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>1</integer>
<integer>3</integer>
</dict>
</dict>
</dict>
+2 -2
View File
@@ -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)
.iOS(.v13), .watchOS(.v6), .macOS(.v11)
],
products: [
// Products define the executables and libraries produced by a package, and make them visible to other packages.
+39 -11
View File
@@ -2,18 +2,43 @@
Swift package for displaying charts effortlessly.
![SwiftUI Charts](./Resources/showcase1.gif "SwiftUI Charts")
## 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
* [How to install SwiftUI ChartView](https://github.com/AppPear/ChartView/wiki/How-to-install-SwiftUI-ChartView)
* [How to create your first chart](https://github.com/AppPear/ChartView/wiki/How-to-create-your-first-chart)
### 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>
## 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
* Bar charts
* Pie charts
### 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-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:
@@ -29,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.
![Multiine Charts](./Resources/multiline1.gif "Multiine Charts")
<img src="https://user-images.githubusercontent.com/2826764/131211991-eca64276-cf05-423f-a78a-697c55e44bbc.gif" width="50%"></img>
Usage:
```swift
@@ -50,7 +76,6 @@ Available preset gradients:
**Full screen view called LineView!!!**
![Line Charts](./Resources/fullscreen2.gif "Line Charts")
```swift
LineView(data: [8,23,54,32,12,37,7,23,43], title: "Line chart", legend: "Full screen") // legend is optional, use optional .padding()
@@ -58,7 +83,7 @@ Available preset gradients:
Adopts to dark mode automatically
![Line Charts](./Resources/showcase3.gif "Line Charts")
<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:
@@ -80,7 +105,7 @@ You can add a line chart with the following code:
## Bar charts
![Bar Charts](./Resources/showcase2.gif "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**
@@ -158,10 +183,9 @@ You can access built-in styles:
* barChartMidnightGreenLight
* barChartMidnightGreenDark
![Midnightgreen](./Resources/midnightgreen.gif "Midnightgreen")
![Custom Charts](./Resources/showcase5.png "Custom Charts")
<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:
@@ -175,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:
![Pie Charts](./Resources/watchos1.png "Pie Charts")
<img src="https://user-images.githubusercontent.com/2826764/131212000-a058fdd9-af40-4e64-adc3-82201ea2484d.png" width="45%">
## Pie charts
![Pie Charts](./Resources/showcase4.png "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:
Binary file not shown.

Before

Width:  |  Height:  |  Size: 514 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 502 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 343 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 278 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

@@ -12,8 +12,12 @@ public struct BarChartRow : View {
var data: [Double]
var accentColor: Color
var gradient: GradientColor?
var maxValue: Double {
data.max() ?? 0
guard let max = data.max() else {
return 1
}
return max != 0 ? max : 1
}
@Binding var touchLocation: CGFloat
public var body: some View {
@@ -44,7 +48,10 @@ public struct BarChartRow : View {
#if DEBUG
struct ChartRow_Previews : PreviewProvider {
static var previews: some View {
BarChartRow(data: [8,23,54,32,12,37,7], accentColor: Colors.OrangeStart, touchLocation: .constant(-1))
Group {
BarChartRow(data: [0], accentColor: Colors.OrangeStart, touchLocation: .constant(-1))
BarChartRow(data: [8,23,54,32,12,37,7], accentColor: Colors.OrangeStart, touchLocation: .constant(-1))
}
}
}
#endif
@@ -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 {
@@ -50,7 +52,7 @@ public struct BarChartView : View {
Rectangle()
.fill(self.colorScheme == .dark ? self.darkModeStyle.backgroundColor : self.style.backgroundColor)
.cornerRadius(20)
.shadow(color: Color.gray, radius: self.dropShadow ? 8 : 0)
.shadow(color: self.style.dropShadowColor, radius: self.dropShadow ? 8 : 0)
VStack(alignment: .leading){
HStack{
if(!showValue){
@@ -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()
+32 -15
View File
@@ -34,7 +34,7 @@ public struct GradientColor {
public let start: Color
public let end: Color
init(start: Color, end: Color) {
public init(start: Color, end: Color) {
self.start = start
self.end = end
}
@@ -62,63 +62,72 @@ public struct Styles {
accentColor: Colors.OrangeStart,
secondGradientColor: Colors.OrangeEnd,
textColor: Color.black,
legendTextColor: Color.gray)
legendTextColor: Color.gray,
dropShadowColor: Color.gray)
public static let barChartStyleOrangeLight = ChartStyle(
backgroundColor: Color.white,
accentColor: Colors.OrangeStart,
secondGradientColor: Colors.OrangeEnd,
textColor: Color.black,
legendTextColor: Color.gray)
legendTextColor: Color.gray,
dropShadowColor: Color.gray)
public static let barChartStyleOrangeDark = ChartStyle(
backgroundColor: Color.black,
accentColor: Colors.OrangeStart,
secondGradientColor: Colors.OrangeEnd,
textColor: Color.white,
legendTextColor: Color.gray)
legendTextColor: Color.gray,
dropShadowColor: Color.gray)
public static let barChartStyleNeonBlueLight = ChartStyle(
backgroundColor: Color.white,
accentColor: Colors.GradientNeonBlue,
secondGradientColor: Colors.GradientPurple,
textColor: Color.black,
legendTextColor: Color.gray)
legendTextColor: Color.gray,
dropShadowColor: Color.gray)
public static let barChartStyleNeonBlueDark = ChartStyle(
backgroundColor: Color.black,
accentColor: Colors.GradientNeonBlue,
secondGradientColor: Colors.GradientPurple,
textColor: Color.white,
legendTextColor: Color.gray)
legendTextColor: Color.gray,
dropShadowColor: Color.gray)
public static let barChartMidnightGreenDark = ChartStyle(
backgroundColor: Color(hexString: "#36534D"), //3B5147, 313D34
accentColor: Color(hexString: "#FFD603"),
secondGradientColor: Color(hexString: "#FFCA04"),
textColor: Color.white,
legendTextColor: Color(hexString: "#D2E5E1"))
legendTextColor: Color(hexString: "#D2E5E1"),
dropShadowColor: Color.gray)
public static let barChartMidnightGreenLight = ChartStyle(
backgroundColor: Color.white,
accentColor: Color(hexString: "#84A094"), //84A094 , 698378
secondGradientColor: Color(hexString: "#50675D"),
textColor: Color.black,
legendTextColor:Color.gray)
legendTextColor:Color.gray,
dropShadowColor: Color.gray)
public static let pieChartStyleOne = ChartStyle(
backgroundColor: Color.white,
accentColor: Colors.OrangeEnd,
secondGradientColor: Colors.OrangeStart,
textColor: Color.black,
legendTextColor: Color.gray)
legendTextColor: Color.gray,
dropShadowColor: Color.gray)
public static let lineViewDarkMode = ChartStyle(
backgroundColor: Color.black,
accentColor: Colors.OrangeStart,
secondGradientColor: Colors.OrangeEnd,
textColor: Color.white,
legendTextColor: Color.white)
legendTextColor: Color.white,
dropShadowColor: Color.gray)
}
public struct ChartForm {
@@ -126,15 +135,15 @@ public struct ChartForm {
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 extraLarge = 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 extraLarge = CGSize(width:360, height:240)
public static let detail = CGSize(width:180, height:120)
#endif
}
public class ChartStyle {
@@ -143,22 +152,25 @@ public class ChartStyle {
public var gradientColor: GradientColor
public var textColor: Color
public var legendTextColor: Color
public var dropShadowColor: Color
public weak var darkModeStyle: ChartStyle?
public init(backgroundColor: Color, accentColor: Color, secondGradientColor: Color, textColor: Color, legendTextColor: Color){
public init(backgroundColor: Color, accentColor: Color, secondGradientColor: Color, textColor: Color, legendTextColor: Color, dropShadowColor: Color){
self.backgroundColor = backgroundColor
self.accentColor = accentColor
self.gradientColor = GradientColor(start: accentColor, end: secondGradientColor)
self.textColor = textColor
self.legendTextColor = legendTextColor
self.dropShadowColor = dropShadowColor
}
public init(backgroundColor: Color, accentColor: Color, gradientColor: GradientColor, textColor: Color, legendTextColor: Color){
public init(backgroundColor: Color, accentColor: Color, gradientColor: GradientColor, textColor: Color, legendTextColor: Color, dropShadowColor: Color){
self.backgroundColor = backgroundColor
self.accentColor = accentColor
self.gradientColor = gradientColor
self.textColor = textColor
self.legendTextColor = legendTextColor
self.dropShadowColor = dropShadowColor
}
public init(formSize: CGSize){
@@ -167,6 +179,7 @@ public class ChartStyle {
self.gradientColor = GradientColors.orange
self.legendTextColor = Color.gray
self.textColor = Color.black
self.dropShadowColor = Color.gray
}
}
@@ -255,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
}
+3 -2
View File
@@ -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 {
@@ -27,7 +28,7 @@ struct Legend: View {
if (min < 0){
return (frame.size.height-padding) / CGFloat(max - min)
}else{
return (frame.size.height-padding) / CGFloat(max + min)
return (frame.size.height-padding) / CGFloat(max - min)
}
}
return 0
@@ -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)
+1 -3
View File
@@ -34,7 +34,6 @@ public struct Line: View {
if minDataValue != nil && maxDataValue != nil {
min = minDataValue!
max = maxDataValue!
print(min,max)
}else if let minPoint = points.min(), let maxPoint = points.max(), minPoint != maxPoint {
min = minPoint
max = maxPoint
@@ -45,7 +44,7 @@ public struct Line: View {
if (min <= 0){
return (frame.size.height-padding) / CGFloat(max - min)
}else{
return (frame.size.height-padding) / CGFloat(max + min)
return (frame.size.height-padding) / CGFloat(max - min)
}
}
return 0
@@ -81,7 +80,6 @@ public struct Line: View {
.onDisappear {
self.showFull = false
}
.drawingGroup()
if(self.showIndicator) {
IndicatorPoint()
.position(self.getClosestPointOnPath(touchLocation: self.touchLocation))
@@ -30,15 +30,15 @@ public struct LineChartView: View {
}
}
let frame = CGSize(width: 180, height: 120)
private var rateValue: Int
var frame = CGSize(width: 180, height: 120)
private var rateValue: Int?
public init(data: [Double],
title: String,
legend: String? = nil,
style: ChartStyle = Styles.lineChartStyleOne,
form: CGSize? = ChartForm.medium,
rateValue: Int? = 14,
rateValue: Int?,
dropShadow: Bool? = true,
valueSpecifier: String? = "%.1f") {
@@ -48,9 +48,10 @@ public struct LineChartView: View {
self.style = style
self.darkModeStyle = style.darkModeStyle != nil ? style.darkModeStyle! : Styles.lineViewDarkMode
self.formSize = form!
self.rateValue = rateValue!
frame = CGSize(width: self.formSize.width, height: self.formSize.height/2)
self.dropShadow = dropShadow!
self.valueSpecifier = valueSpecifier!
self.rateValue = rateValue
}
public var body: some View {
@@ -58,7 +59,7 @@ public struct LineChartView: View {
RoundedRectangle(cornerRadius: 20)
.fill(self.colorScheme == .dark ? self.darkModeStyle.backgroundColor : self.style.backgroundColor)
.frame(width: frame.width, height: 240, alignment: .center)
.shadow(radius: self.dropShadow ? 8 : 0)
.shadow(color: self.style.dropShadowColor, radius: self.dropShadow ? 8 : 0)
VStack(alignment: .leading){
if(!self.showIndicatorDot){
VStack(alignment: .leading, spacing: 8){
@@ -72,12 +73,16 @@ public struct LineChartView: View {
.foregroundColor(self.colorScheme == .dark ? self.darkModeStyle.legendTextColor :self.style.legendTextColor)
}
HStack {
if (self.rateValue >= 0){
Image(systemName: "arrow.up")
}else{
Image(systemName: "arrow.down")
if let rateValue = self.rateValue
{
if (rateValue ?? 0 >= 0){
Image(systemName: "arrow.up")
}else{
Image(systemName: "arrow.down")
}
Text("\(rateValue!)%")
}
Text("\(self.rateValue)%")
}
}
.transition(.opacity)
@@ -96,14 +101,14 @@ public struct LineChartView: View {
Spacer()
GeometryReader{ geometry in
Line(data: self.data,
frame: .constant(geometry.frame(in: .local)),
touchLocation: self.$touchLocation,
showIndicator: self.$showIndicatorDot,
minDataValue: .constant(nil),
maxDataValue: .constant(nil)
frame: .constant(geometry.frame(in: .local)),
touchLocation: self.$touchLocation,
showIndicator: self.$showIndicatorDot,
minDataValue: .constant(nil),
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)
@@ -139,6 +144,9 @@ struct WidgetView_Previews: PreviewProvider {
Group {
LineChartView(data: [8,23,54,32,12,37,7,23,43], title: "Line chart", legend: "Basic")
.environment(\.colorScheme, .light)
LineChartView(data: [282.502, 284.495, 283.51, 285.019, 285.197, 286.118, 288.737, 288.455, 289.391, 287.691, 285.878, 286.46, 286.252, 284.652, 284.129, 284.188], title: "Line chart", legend: "Basic")
.environment(\.colorScheme, .light)
}
}
}
+15 -6
View File
@@ -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,17 +63,18 @@ 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),
maxDataValue: .constant(nil),
showBackground: false
showBackground: false,
gradient: self.style.gradientColor
)
.offset(x: 30, y: 0)
.onAppear(){
@@ -120,7 +124,12 @@ public struct LineView: View {
struct LineView_Previews: PreviewProvider {
static var previews: some View {
LineView(data: [8,23,54,32,12,37,7,23,43], title: "Full chart", style: Styles.lineChartStyleOne)
Group {
LineView(data: [8,23,54,32,12,37,7,23,43], title: "Full chart", style: Styles.lineChartStyleOne)
LineView(data: [282.502, 284.495, 283.51, 285.019, 285.197, 286.118, 288.737, 288.455, 289.391, 287.691, 285.878, 286.46, 286.252, 284.652, 284.129, 284.188], title: "Full chart", style: Styles.lineChartStyleOne)
}
}
}
@@ -29,5 +29,6 @@ public struct MagnifierRect: View {
.blendMode(.multiply)
}
}
.offset(x: 0, y: -15)
}
}
@@ -14,7 +14,7 @@ public struct MultiLineChartView: View {
public var legend: String?
public var style: ChartStyle
public var darkModeStyle: ChartStyle
public var formSize:CGSize
public var formSize: CGSize
public var dropShadow: Bool
public var valueSpecifier:String
@@ -43,27 +43,28 @@ public struct MultiLineChartView: View {
return 0
}
let frame = CGSize(width: 180, height: 120)
private var rateValue: Int
var frame = CGSize(width: 180, height: 120)
private var rateValue: Int?
public init(data: [([Double], GradientColor)],
title: String,
legend: String? = nil,
style: ChartStyle = Styles.lineChartStyleOne,
form: CGSize? = ChartForm.medium,
rateValue: Int? = 14,
dropShadow: Bool? = true,
valueSpecifier: String? = "%.1f") {
form: CGSize = ChartForm.medium,
rateValue: Int? = nil,
dropShadow: Bool = true,
valueSpecifier: String = "%.1f") {
self.data = data.map({ MultiLineChartData(points: $0.0, gradient: $0.1)})
self.title = title
self.legend = legend
self.style = style
self.darkModeStyle = style.darkModeStyle != nil ? style.darkModeStyle! : Styles.lineViewDarkMode
self.formSize = form!
self.rateValue = rateValue!
self.dropShadow = dropShadow!
self.valueSpecifier = valueSpecifier!
self.formSize = form
frame = CGSize(width: self.formSize.width, height: self.formSize.height/2)
self.rateValue = rateValue
self.dropShadow = dropShadow
self.valueSpecifier = valueSpecifier
}
public var body: some View {
@@ -85,12 +86,12 @@ public struct MultiLineChartView: View {
.foregroundColor(self.colorScheme == .dark ? self.darkModeStyle.legendTextColor : self.style.legendTextColor)
}
HStack {
if (self.rateValue >= 0){
if (rateValue ?? 0 >= 0){
Image(systemName: "arrow.up")
}else{
Image(systemName: "arrow.down")
}
Text("\(self.rateValue)%")
Text("\(rateValue ?? 0)%")
}
}
.transition(.opacity)
@@ -109,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
}))
}
}
}
@@ -39,8 +68,12 @@ public struct PieChartRow : View {
#if DEBUG
struct PieChartRow_Previews : PreviewProvider {
static var previews: some View {
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)
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), 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,14 +15,28 @@ 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
self.style = style
self.formSize = form!
if self.formSize == ChartForm.large {
self.formSize = ChartForm.extraLarge
}
self.dropShadow = dropShadow!
self.valueSpecifier = valueSpecifier!
}
public var body: some View {
@@ -30,18 +44,24 @@ public struct PieChartView : View {
Rectangle()
.fill(self.style.backgroundColor)
.cornerRadius(20)
.shadow(color: Color.gray, radius: self.dropShadow ? 12 : 0)
.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!)