Prepare charts to display x and y values souch as a value for a given point
This commit is contained in:
@@ -2,11 +2,23 @@ import SwiftUI
|
||||
|
||||
/// An observable wrapper for an array of data for use in any chart
|
||||
public class ChartData: ObservableObject {
|
||||
@Published public var data: [Double] = []
|
||||
@Published public var data: [(String, Double)] = []
|
||||
|
||||
var points: [Double] {
|
||||
data.map { $0.1 }
|
||||
}
|
||||
|
||||
var values: [String] {
|
||||
data.map { $0.0 }
|
||||
}
|
||||
|
||||
/// Initialize with data array
|
||||
/// - Parameter data: Array of `Double`
|
||||
public init(_ data: [Double]) {
|
||||
self.data = data.map { ("", $0) }
|
||||
}
|
||||
|
||||
public init(_ data: [(String, Double)]) {
|
||||
self.data = data
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,13 @@ extension View where Self: ChartBase {
|
||||
/// - Parameter data: array of `Double`
|
||||
/// - Returns: modified `View` with data attached
|
||||
public func data(_ data: [Double]) -> some View {
|
||||
chartData.data = data.map { ("", $0) }
|
||||
return self
|
||||
.environmentObject(chartData)
|
||||
.environmentObject(ChartValue())
|
||||
}
|
||||
|
||||
public func data(_ data: [(String, Double)]) -> some View {
|
||||
chartData.data = data
|
||||
return self
|
||||
.environmentObject(chartData)
|
||||
|
||||
@@ -12,12 +12,8 @@ public enum ChartLabelType {
|
||||
/// A chart may contain any number of labels in pre-set positions based on their `ChartLabelType`
|
||||
public struct ChartLabel: View {
|
||||
@EnvironmentObject var chartValue: ChartValue
|
||||
<<<<<<< HEAD
|
||||
@State private var textToDisplay:String = ""
|
||||
=======
|
||||
@State var textToDisplay:String = ""
|
||||
var format: String = "%.01f"
|
||||
>>>>>>> Add custom string format for ChartLabel when interactionInProgress = true (#151)
|
||||
|
||||
private var title: String
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ public struct BarChartRow: View {
|
||||
var style: ChartStyle
|
||||
|
||||
var maxValue: Double {
|
||||
guard let max = chartData.data.max() else {
|
||||
guard let max = chartData.points.max() else {
|
||||
return 1
|
||||
}
|
||||
return max != 0 ? max : 1
|
||||
@@ -62,7 +62,7 @@ public struct BarChartRow: View {
|
||||
/// - Parameter index: index into array of data
|
||||
/// - Returns: data value at given index, divided by data maximum
|
||||
func normalizedValue(index: Int) -> Double {
|
||||
return Double(chartData.data[index])/Double(maxValue)
|
||||
return Double(chartData.points[index])/Double(maxValue)
|
||||
}
|
||||
|
||||
/// Size to scale the touch indicator
|
||||
@@ -84,6 +84,6 @@ public struct BarChartRow: View {
|
||||
func getCurrentValue(width: CGFloat) -> Double? {
|
||||
guard self.chartData.data.count > 0 else { return nil}
|
||||
let index = max(0,min(self.chartData.data.count-1,Int(floor((self.touchLocation*width)/(width/CGFloat(self.chartData.data.count))))))
|
||||
return self.chartData.data[index]
|
||||
return self.chartData.points[index]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,14 +16,14 @@ public struct Line: View {
|
||||
|
||||
/// Step for plotting through data
|
||||
/// - Returns: X and Y delta between each data point based on data and view's frame
|
||||
var step: CGPoint {
|
||||
return CGPoint.getStep(frame: frame, data: chartData.data)
|
||||
var step: CGPoint {
|
||||
return CGPoint.getStep(frame: frame, data: chartData.points)
|
||||
}
|
||||
|
||||
/// Path of line graph
|
||||
/// - Returns: A path for stroking representing the data, either curved or jagged.
|
||||
var path: Path {
|
||||
let points = chartData.data
|
||||
let points = chartData.points
|
||||
|
||||
if curvedLines {
|
||||
return Path.quadCurvedPathWithPoints(points: points,
|
||||
@@ -37,7 +37,7 @@ public struct Line: View {
|
||||
/// Path of linegraph, but also closed at the bottom side
|
||||
/// - Returns: A path for filling representing the data, either curved or jagged
|
||||
var closedPath: Path {
|
||||
let points = chartData.data
|
||||
let points = chartData.points
|
||||
|
||||
if curvedLines {
|
||||
return Path.quadClosedCurvedPathWithPoints(points: points,
|
||||
@@ -47,20 +47,19 @@ public struct Line: View {
|
||||
|
||||
return Path.closedLinePathWithPoints(points: points, step: step)
|
||||
}
|
||||
|
||||
// see https://stackoverflow.com/a/62370919
|
||||
// This lets geometry be recalculated when device rotates. However it doesn't cover issue of app changing
|
||||
// from full screen to split view. Not possible in SwiftUI? Feedback submitted to apple FB8451194.
|
||||
let orientationChanged = NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)
|
||||
.makeConnectable()
|
||||
.autoconnect()
|
||||
|
||||
/// The content and behavior of the `Line`.
|
||||
///
|
||||
/// Draw the background if showing the full line (?) and the `showBackground` option is set. Above that draw the line, and then the data indicator if the graph is currently being touched.
|
||||
/// On appear, set the frame so that the data graph metrics can be calculated. On a drag (touch) gesture, highlight the closest touched data point.
|
||||
/// TODO: explain rotation
|
||||
public var body: some View {
|
||||
|
||||
let orientationChanged = NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)
|
||||
.makeConnectable()
|
||||
.autoconnect() // see https://stackoverflow.com/a/62370919
|
||||
// This lets geometry be recalculated when device rotates. However it doesn't cover issue of app changing
|
||||
// from full screen to split view. Not possible in SwiftUI? Feedback submitted to apple FB8451194.
|
||||
|
||||
GeometryReader { geometry in
|
||||
ZStack {
|
||||
if self.showFull && self.showBackground {
|
||||
@@ -120,7 +119,7 @@ extension Line {
|
||||
private func getClosestDataPoint(point: CGPoint) {
|
||||
let index = Int(round((point.x)/step.x))
|
||||
if (index >= 0 && index < self.chartData.data.count){
|
||||
self.chartValue.currentValue = self.chartData.data[index]
|
||||
self.chartValue.currentValue = self.chartData.points[index]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,9 +10,9 @@ public struct PieChartRow: View {
|
||||
var slices: [PieSlice] {
|
||||
var tempSlices: [PieSlice] = []
|
||||
var lastEndDeg: Double = 0
|
||||
let maxValue: Double = chartData.data.reduce(0, +)
|
||||
let maxValue: Double = chartData.points.reduce(0, +)
|
||||
|
||||
for slice in chartData.data {
|
||||
for slice in chartData.points {
|
||||
let normalized: Double = Double(slice) / (maxValue == 0 ? 1 : maxValue)
|
||||
let startDeg = lastEndDeg
|
||||
let endDeg = lastEndDeg + (normalized * 360)
|
||||
|
||||
@@ -39,7 +39,7 @@ public struct RingsChartRow: View {
|
||||
// make sure it doesn't get to crazy value
|
||||
)
|
||||
|
||||
Ring(ringWidth:scaledWidth, percent: self.chartData.data[index], foregroundColor:self.style.foregroundColor.rotate(for: index),
|
||||
Ring(ringWidth:scaledWidth, percent: self.chartData.points[index], foregroundColor:self.style.foregroundColor.rotate(for: index),
|
||||
touchLocation: self.touchRadius)
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ public struct RingsChartRow: View {
|
||||
func getCurrentValue(maxRadius: CGFloat) -> Double? {
|
||||
|
||||
guard let index = self.touchedCircleIndex(maxRadius: maxRadius) else { return nil }
|
||||
return self.chartData.data[index]
|
||||
return self.chartData.points[index]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user