Skip to content

Commit

Permalink
Merge pull request #115 from willdale/fix-bar-chart-all-zeros
Browse files Browse the repository at this point in the history
Add protections for divide by zero.
  • Loading branch information
willdale authored Sep 8, 2021
2 parents 7161987 + 2dbf976 commit 87846fb
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 15 deletions.
2 changes: 1 addition & 1 deletion Sources/SwiftUICharts/BarChart/Views/StackedBarChart.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public struct StackedBarChart<ChartData>: View where ChartData: StackedBarChartD
HStack(alignment: .bottom, spacing: 0) {
ForEach(chartData.dataSets.dataSets) { dataSet in
StackElementSubView(dataSet: dataSet, specifier: chartData.infoView.touchSpecifier)
.scaleEffect(y: startAnimation ? CGFloat(dataSet.maxValue() / chartData.maxValue) : 0, anchor: .bottom)
.scaleEffect(y: startAnimation ? divideByZeroProtection(CGFloat.self, dataSet.maxValue(), chartData.maxValue) : 0, anchor: .bottom)
.scaleEffect(x: chartData.barStyle.barWidth, anchor: .center)
.background(Color(.gray).opacity(0.000000001))
.animateOnAppear(using: chartData.chartStyle.globalAnimation) {
Expand Down
19 changes: 9 additions & 10 deletions Sources/SwiftUICharts/BarChart/Views/SubViews/Bars.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ internal struct ColourBar<CD: CTBarChartDataProtocol & GetDataProtocol,
bl: chartData.barStyle.cornerRadius.bottom,
br: chartData.barStyle.cornerRadius.bottom)
.fill(colour)
.scaleEffect(y: startAnimation ? CGFloat(dataPoint.value / chartData.maxValue) : 0, anchor: .bottom)
.scaleEffect(y: startAnimation ? divideByZeroProtection(CGFloat.self, dataPoint.value, chartData.maxValue) : 0, anchor: .bottom)
.scaleEffect(x: chartData.barStyle.barWidth, anchor: .center)
.background(Color(.gray).opacity(0.000000001))
.animateOnAppear(using: chartData.chartStyle.globalAnimation) {
Expand All @@ -55,7 +55,6 @@ internal struct ColourBar<CD: CTBarChartDataProtocol & GetDataProtocol,
}
}


// MARK: Gradient
/**
Sub view of a single bar using colour gradient.
Expand Down Expand Up @@ -95,7 +94,7 @@ internal struct GradientColoursBar<CD: CTBarChartDataProtocol & GetDataProtocol,
.fill(LinearGradient(gradient: Gradient(colors: colours),
startPoint: startPoint,
endPoint: endPoint))
.scaleEffect(y: startAnimation ? CGFloat(dataPoint.value / chartData.maxValue) : 0, anchor: .bottom)
.scaleEffect(y: startAnimation ? divideByZeroProtection(CGFloat.self, dataPoint.value, chartData.maxValue) : 0, anchor: .bottom)
.scaleEffect(x: chartData.barStyle.barWidth, anchor: .center)
.background(Color(.gray).opacity(0.000000001))
.animateOnAppear(using: chartData.chartStyle.globalAnimation) {
Expand Down Expand Up @@ -148,7 +147,7 @@ internal struct GradientStopsBar<CD: CTBarChartDataProtocol & GetDataProtocol,
.fill(LinearGradient(gradient: Gradient(stops: stops),
startPoint: startPoint,
endPoint: endPoint))
.scaleEffect(y: startAnimation ? CGFloat(dataPoint.value / chartData.maxValue) : 0, anchor: .bottom)
.scaleEffect(y: startAnimation ? divideByZeroProtection(CGFloat.self, dataPoint.value, chartData.maxValue) : 0, anchor: .bottom)
.scaleEffect(x: chartData.barStyle.barWidth, anchor: .center)
.background(Color(.gray).opacity(0.000000001))
.animateOnAppear(using: chartData.chartStyle.globalAnimation) {
Expand Down Expand Up @@ -360,7 +359,7 @@ internal struct RangedBarChartColourCell<CD:RangedBarChartData>: View {
bl: chartData.barStyle.cornerRadius.bottom,
br: chartData.barStyle.cornerRadius.bottom)
.fill(colour)
.scaleEffect(y: startAnimation ? CGFloat((dataPoint.upperValue - dataPoint.lowerValue) / chartData.range) : 0, anchor: .center)
.scaleEffect(y: startAnimation ? divideByZeroProtection(CGFloat.self, (dataPoint.upperValue - dataPoint.lowerValue), chartData.range) : 0, anchor: .center)
.scaleEffect(x: chartData.barStyle.barWidth, anchor: .center)
.position(x: barSize.midX,
y: chartData.getBarPositionX(dataPoint: dataPoint, height: barSize.height))
Expand Down Expand Up @@ -411,7 +410,7 @@ internal struct RangedBarChartColoursCell<CD:RangedBarChartData>: View {
.fill(LinearGradient(gradient: Gradient(colors: colours),
startPoint: startPoint,
endPoint: endPoint))
.scaleEffect(y: startAnimation ? CGFloat((dataPoint.upperValue - dataPoint.lowerValue) / chartData.range) : 0, anchor: .center)
.scaleEffect(y: startAnimation ? divideByZeroProtection(CGFloat.self, (dataPoint.upperValue - dataPoint.lowerValue), chartData.range) : 0, anchor: .center)
.scaleEffect(x: chartData.barStyle.barWidth, anchor: .center)
.position(x: barSize.midX,
y: chartData.getBarPositionX(dataPoint: dataPoint, height: barSize.height))
Expand Down Expand Up @@ -462,7 +461,7 @@ internal struct RangedBarChartStopsCell<CD:RangedBarChartData>: View {
.fill(LinearGradient(gradient: Gradient(stops: stops),
startPoint: startPoint,
endPoint: endPoint))
.scaleEffect(y: startAnimation ? CGFloat((dataPoint.upperValue - dataPoint.lowerValue) / chartData.range) : 0, anchor: .center)
.scaleEffect(y: startAnimation ? divideByZeroProtection(CGFloat.self, (dataPoint.upperValue - dataPoint.lowerValue), chartData.range) : 0, anchor: .center)
.scaleEffect(x: chartData.barStyle.barWidth, anchor: .center)
.position(x: barSize.midX,
y: chartData.getBarPositionX(dataPoint: dataPoint, height: barSize.height))
Expand Down Expand Up @@ -512,7 +511,7 @@ internal struct HorizontalColourBar<CD: CTBarChartDataProtocol & GetDataProtocol
bl: chartData.barStyle.cornerRadius.bottom,
br: chartData.barStyle.cornerRadius.top)
.fill(colour)
.scaleEffect(x: startAnimation ? CGFloat(dataPoint.value / chartData.maxValue) : 0, anchor: .leading)
.scaleEffect(x: startAnimation ? divideByZeroProtection(CGFloat.self, dataPoint.value, chartData.maxValue) : 0, anchor: .leading)
.scaleEffect(y: chartData.barStyle.barWidth, anchor: .center)
.background(Color(.gray).opacity(0.000000001))
.animateOnAppear(using: chartData.chartStyle.globalAnimation) {
Expand Down Expand Up @@ -565,7 +564,7 @@ internal struct HorizontalGradientColoursBar<CD: CTBarChartDataProtocol & GetDat
.fill(LinearGradient(gradient: Gradient(colors: colours),
startPoint: startPoint,
endPoint: endPoint))
.scaleEffect(x: startAnimation ? CGFloat(dataPoint.value / chartData.maxValue) : 0, anchor: .leading)
.scaleEffect(x: startAnimation ? divideByZeroProtection(CGFloat.self, dataPoint.value, chartData.maxValue) : 0, anchor: .leading)
.scaleEffect(y: chartData.barStyle.barWidth, anchor: .center)
.background(Color(.gray).opacity(0.000000001))
.animateOnAppear(using: chartData.chartStyle.globalAnimation) {
Expand Down Expand Up @@ -618,7 +617,7 @@ internal struct HorizontalGradientStopsBar<CD: CTBarChartDataProtocol & GetDataP
.fill(LinearGradient(gradient: Gradient(stops: stops),
startPoint: startPoint,
endPoint: endPoint))
.scaleEffect(x: startAnimation ? CGFloat(dataPoint.value / chartData.maxValue) : 0, anchor: .leading)
.scaleEffect(x: startAnimation ? divideByZeroProtection(CGFloat.self, dataPoint.value, chartData.maxValue) : 0, anchor: .leading)
.scaleEffect(y: chartData.barStyle.barWidth, anchor: .center)
.background(Color(.gray).opacity(0.000000001))
.animateOnAppear(using: chartData.chartStyle.globalAnimation) {
Expand Down
18 changes: 18 additions & 0 deletions Sources/SwiftUICharts/Shared/Extras/Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,21 @@ extension Color {
#endif
}
}

// MARK: - Global Functions
/// Protects against divide by zero.
///
/// Return zero in the case of divide by zero.
///
/// ```
/// divideByZeroProtection(CGFloat.self, value, maxValue)
/// ```
///
/// - Parameters:
/// - outputType: The numeric type required as an output.
/// - lhs: Dividend
/// - rhs: Divisor
/// - Returns: If rhs is not zero it returns the quotient otherwise it returns zero.
func divideByZeroProtection<T: BinaryFloatingPoint, U: BinaryFloatingPoint>(_ outputType: U.Type, _ lhs: T, _ rhs: T) -> U {
U(rhs != 0 ? (lhs / rhs) : 0)
}
Original file line number Diff line number Diff line change
Expand Up @@ -262,13 +262,13 @@ extension CTLineBarChartDataProtocol where Self: CTBarChartDataProtocol & PointO
public func poiValueLabelPositionAxis(frame: CGRect, markerValue: Double, minValue: Double, range: Double) -> CGPoint {
let leading: CGFloat = -((self.viewData.yAxisLabelWidth.max() ?? 0) / 2) - 4 // -4 for padding at the root view.
let trailing: CGFloat = frame.width + ((self.viewData.yAxisLabelWidth.max() ?? 0) / 2) + 4 // +4 for padding at the root view.
let value: CGFloat = CGFloat((markerValue - minValue) / range)
let value: CGFloat = divideByZeroProtection(CGFloat.self, (markerValue - minValue), range)
return CGPoint(x: self.chartStyle.yAxisLabelPosition == .leading ? leading : trailing,
y: frame.height - value * frame.height)
}
public func poiValueLabelPositionCenter(frame: CGRect, markerValue: Double, minValue: Double, range: Double) -> CGPoint {
CGPoint(x: frame.width / 2,
y: frame.height - CGFloat((markerValue - minValue) / range) * frame.height)
y: frame.height - divideByZeroProtection(CGFloat.self, (markerValue - minValue), range) * frame.height)
}
}

Expand All @@ -278,12 +278,12 @@ extension CTLineBarChartDataProtocol where Self: CTBarChartDataProtocol & PointO
public func poiValueLabelPositionAxis(frame: CGRect, markerValue: Double, minValue: Double, range: Double) -> CGPoint {
let bottom: CGFloat = frame.height + ((self.viewData.xAxisLabelHeights.max() ?? 0) / 2) + 4 // +4 for padding at the root view
let top: CGFloat = -((self.viewData.xAxisLabelHeights.max() ?? 0) / 2) - 4 // -4 for padding at the root view
let value: CGFloat = CGFloat((markerValue - minValue) / range)
let value: CGFloat = divideByZeroProtection(CGFloat.self, (markerValue - minValue), range)
return CGPoint(x: value * frame.width,
y: self.chartStyle.xAxisLabelPosition == .bottom ? bottom : top)
}
public func poiValueLabelPositionCenter(frame: CGRect, markerValue: Double, minValue: Double, range: Double) -> CGPoint {
CGPoint(x: CGFloat((markerValue - minValue) / range) * frame.width,
CGPoint(x: divideByZeroProtection(CGFloat.self, (markerValue - minValue), range) * frame.width,
y: frame.height / 2)
}
}
Expand Down

0 comments on commit 87846fb

Please sign in to comment.