Skip to content

Commit

Permalink
Add RoundedCornersBarChatRenderer which provides the ability to draw …
Browse files Browse the repository at this point in the history
…bar charts with rounded corners
  • Loading branch information
Pavlo Zakharov authored and Pavlo Zakharov committed Oct 26, 2020
1 parent ae78bad commit 563d23b
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Charts.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@
EB56849433A76B08606B73EB /* ScatterChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB1DD1A0F64266A10EE94194 /* ScatterChartDataSet.swift */; };
ECE7EAE7179A7F57CE9BBD8F /* Legend.swift in Sources */ = {isa = PBXBuildFile; fileRef = E64A75540C627E09080B402A /* Legend.swift */; };
ECECC58CEF03B1718F8267E8 /* AxisRendererBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C75935E899183DDFA181E2CC /* AxisRendererBase.swift */; };
EEA6B71B2546D6D100015850 /* RoundedCornersBarChatRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA6B71A2546D6D100015850 /* RoundedCornersBarChatRenderer.swift */; };
F100D68395F169B93590FA96 /* HorizontalBarChartRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 539382766378B702660FDFB2 /* HorizontalBarChartRenderer.swift */; };
F103D90FC5DEEA0D7BB4407E /* ChevronUpShapeRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA70259ED16FF80D8EEB0F94 /* ChevronUpShapeRenderer.swift */; };
F37B07008B8AE7F3909FFB9C /* ChartDataRendererBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0216EDC6A1FE272F4EB19FCF /* ChartDataRendererBase.swift */; };
Expand Down Expand Up @@ -315,6 +316,7 @@
EAE417AAA0FCA0DD00E77489 /* YAxisRendererHorizontalBarChart.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = YAxisRendererHorizontalBarChart.swift; path = Source/Charts/Renderers/YAxisRendererHorizontalBarChart.swift; sourceTree = "<group>"; };
ECE1B1623D3AF69CECAE8562 /* CircleShapeRenderer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CircleShapeRenderer.swift; path = Source/Charts/Renderers/Scatter/CircleShapeRenderer.swift; sourceTree = "<group>"; };
EDEAF554FD0D68EA4C0E7E49 /* BubbleChartDataProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BubbleChartDataProvider.swift; path = Source/Charts/Interfaces/BubbleChartDataProvider.swift; sourceTree = "<group>"; };
EEA6B71A2546D6D100015850 /* RoundedCornersBarChatRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoundedCornersBarChatRenderer.swift; sourceTree = "<group>"; };
F22750328058DEC2F019646F /* ChartDataEntry.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ChartDataEntry.swift; path = Source/Charts/Data/Implementations/Standard/ChartDataEntry.swift; sourceTree = "<group>"; };
F368CF209744D8F3B85B1028 /* RadarHighlighter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RadarHighlighter.swift; path = Source/Charts/Highlight/RadarHighlighter.swift; sourceTree = "<group>"; };
F3788EC55EF908B0805D7C2F /* IBubbleChartDataSet.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = IBubbleChartDataSet.swift; path = Source/Charts/Data/Interfaces/IBubbleChartDataSet.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -644,6 +646,7 @@
children = (
C75935E899183DDFA181E2CC /* AxisRendererBase.swift */,
75F279974FE650E57A061B09 /* BarChartRenderer.swift */,
EEA6B71A2546D6D100015850 /* RoundedCornersBarChatRenderer.swift */,
5B1C588E9DF6FFD56D7ADF8E /* BarLineScatterCandleBubbleRenderer.swift */,
2194AA554712E6BA2677F114 /* BubbleChartRenderer.swift */,
BD5C6D20243EC2F19069AACD /* CandleStickChartRenderer.swift */,
Expand Down Expand Up @@ -936,6 +939,7 @@
02A6E6E1A82A27A66B8D08C4 /* MoveViewJob.swift in Sources */,
9400725714D0DA707DDECD2E /* ViewPortJob.swift in Sources */,
AEE9C4E4AC02B8FB3CD21975 /* ZoomViewJob.swift in Sources */,
EEA6B71B2546D6D100015850 /* RoundedCornersBarChatRenderer.swift in Sources */,
ECECC58CEF03B1718F8267E8 /* AxisRendererBase.swift in Sources */,
23FA50B2730D8C7ACA091C4F /* BarChartRenderer.swift in Sources */,
219192CA6B4895319AB49DCA /* BarLineScatterCandleBubbleRenderer.swift in Sources */,
Expand Down
18 changes: 18 additions & 0 deletions RoundedCornersBarChatRenderer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Foundation

open class RoundedCornersBarChatRenderer: BarChartRenderer {

open var cornerRadius: CGFloat = 0.0

open var corners: UIRectCorner = [.allCorners]

open override func drawDataSet(context: CGContext, dataSet: IBarChartDataSet, index: Int) {
drawDataSet(context: context, dataSet: dataSet, index: index, cornerRadius: cornerRadius, roundedCorners: corners)
}

init?(renderer: DataRenderer?) {
guard let renderer = renderer as? BarChartRenderer, let dataProvider = renderer.dataProvider else { return nil }

super.init(dataProvider: dataProvider, animator: renderer.animator, viewPortHandler: renderer.viewPortHandler)
}
}
153 changes: 153 additions & 0 deletions Source/Charts/Renderers/BarChartRenderer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,159 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer
}

private var _barShadowRectBuffer: CGRect = CGRect()

@objc open func drawDataSet(context: CGContext, dataSet: IBarChartDataSet, index: Int, cornerRadius: CGFloat, roundedCorners: UIRectCorner) {
guard let dataProvider = dataProvider else { return }

let trans = dataProvider.getTransformer(forAxis: dataSet.axisDependency)

prepareBuffer(dataSet: dataSet, index: index)
trans.rectValuesToPixel(&_buffers[index].rects)

let borderWidth = dataSet.barBorderWidth
let borderColor = dataSet.barBorderColor
let drawBorder = borderWidth > 0.0

context.saveGState()

// draw the bar shadow before the values
if dataProvider.isDrawBarShadowEnabled
{
guard let barData = dataProvider.barData else { return }

let barWidth = barData.barWidth
let barWidthHalf = barWidth / 2.0
var x: Double = 0.0

for i in stride(from: 0, to: min(Int(ceil(Double(dataSet.entryCount) * animator.phaseX)), dataSet.entryCount), by: 1)
{
guard let e = dataSet.entryForIndex(i) as? BarChartDataEntry else { continue }

x = e.x

_barShadowRectBuffer.origin.x = CGFloat(x - barWidthHalf)
_barShadowRectBuffer.size.width = CGFloat(barWidth)

trans.rectValueToPixel(&_barShadowRectBuffer)

if !viewPortHandler.isInBoundsLeft(_barShadowRectBuffer.origin.x + _barShadowRectBuffer.size.width)
{
continue
}

if !viewPortHandler.isInBoundsRight(_barShadowRectBuffer.origin.x)
{
break
}

_barShadowRectBuffer.origin.y = viewPortHandler.contentTop
_barShadowRectBuffer.size.height = viewPortHandler.contentHeight

context.setFillColor(dataSet.barShadowColor.cgColor)
context.fill(_barShadowRectBuffer)
}
}

let buffer = _buffers[index]

// draw the bar shadow before the values
if dataProvider.isDrawBarShadowEnabled
{
for j in stride(from: 0, to: buffer.rects.count, by: 1)
{
let barRect = buffer.rects[j]

let maskPath = UIBezierPath(roundedRect: barRect,
byRoundingCorners: [.topLeft, .topRight],
cornerRadii: CGSize(width: 10.0, height: 10.0))

let cgPath = maskPath.cgPath
context.addPath(cgPath)
context.setFillColor(dataSet.color(atIndex: j).cgColor)

if (!viewPortHandler.isInBoundsLeft(barRect.origin.x + barRect.size.width))
{
continue
}

if (!viewPortHandler.isInBoundsRight(barRect.origin.x))
{
break
}

context.setFillColor(dataSet.barShadowColor.cgColor)
context.fillPath()
}
}

let isSingleColor = dataSet.colors.count == 1

if isSingleColor
{
context.setFillColor(dataSet.color(atIndex: 0).cgColor)
}

// In case the chart is stacked, we need to accomodate individual bars within accessibilityOrdereredElements
let isStacked = dataSet.isStacked
let stackSize = isStacked ? dataSet.stackSize : 1

for j in stride(from: 0, to: buffer.rects.count, by: 1)
{
let barRect = buffer.rects[j]

let maskPath = UIBezierPath(roundedRect: barRect,
byRoundingCorners: [.topLeft, .topRight],
cornerRadii: CGSize(width: 10.0, height: 10.0))

let cgPath = maskPath.cgPath
context.addPath(cgPath)
context.setFillColor(dataSet.color(atIndex: j).cgColor)

if (!viewPortHandler.isInBoundsLeft(barRect.origin.x + barRect.size.width))
{
continue
}

if (!viewPortHandler.isInBoundsRight(barRect.origin.x))
{
break
}

if !isSingleColor
{
// Set the color for the currently drawn value. If the index is out of bounds, reuse colors.
context.setFillColor(dataSet.color(atIndex: j).cgColor)
}

context.fillPath()

if drawBorder
{
context.setStrokeColor(borderColor.cgColor)
context.setLineWidth(borderWidth)
context.strokePath()
}

// Create and append the corresponding accessibility element to accessibilityOrderedElements
if let chart = dataProvider as? BarChartView
{
let element = createAccessibleElement(withIndex: j,
container: chart,
dataSet: dataSet,
dataSetIndex: index,
stackSize: stackSize)
{ (element) in
element.accessibilityFrame = barRect
}

accessibilityOrderedElements[j/stackSize].append(element)
}
}

context.restoreGState()

}


@objc open func drawDataSet(context: CGContext, dataSet: IBarChartDataSet, index: Int)
{
Expand Down

0 comments on commit 563d23b

Please sign in to comment.