CollectionGraph

Beautiful graphs made with UICollectionViews

Subscribe to updates I use CollectionGraph


Statistics on CollectionGraph

Number of watchers on Github 5
Number of open issues 3
Average time to close an issue 2 days
Main language Swift
Average time to merge a PR 2 days
Open pull requests 1+
Closed pull requests 3+
Last commit 11 months ago
Repo Created over 2 years ago
Repo Last Updated about 1 year ago
Size 3.81 MB
Organization / Authorcollectiveidea
Latest Releasev1.0.0
Contributors2
Page Updated
Do you use CollectionGraph? Leave a review!
View open issues (3)
View on github
Fresh, new opensource launches 🚀🚀🚀
Trendy new open source projects in your inbox! View examples

Subscribe to our mailing list

Evaluating CollectionGraph for your project? Score Explanation
Commits Score (?)
Issues & PR Score (?)

CollectionGraph Travis CI

A flexible and customizable scatter, bar, and line graphing tool for iOS. Backed by UICollectionViews.

Features

  • Plot numerous collections of data on one graph.
  • Supply custom views for data points, and other elements.
  • Callbacks to customize specific elements.
  • Layout using storyboards (However, IBDesignables do not carry over in linked frameworks)

Installation

Carthage

To integrate CollectionGraph into your Xcode project using Carthage, specify it in your Cartfile:

github "collectiveidea/CollectionGraph"

Usage

  • Check out the CollectionGraphExample target in the project to see some examples

Plotting Points

/////////////// example image //////////////

To plot a graph of simple points, assign the CollectionGraph's graphData property.

import CollectionGraph

var graphData: [[GraphDatum]]?

Each array of [GraphDatum] represents a new section in the graph. Each section should represent a different set of data.

For example:


func losAngelesGraphData() -> [GraphhDatum] { ... }
func newYorkGraphData() -> [GraphhDatum] { ... }
func grandRapidsGraphData() -> [GraphhDatum] { ... }

let data = [losAngelesGraphData(), newYorkGraphData(), grandRapidsGraphData()]

Three different sets of points (each city) will be plotted on the same graph.

GraphDatum is a protocol that requires a CGPoint. You can add other properties you may want to surface during the Callbacks to better identify the data.

Example
struct Data: GraphDatum {
    var point: CGPoint
    var id: String
}

Customization

Graph Cells

Custom graphCells

If you want a custom graphCell instead of the default square, you can set the graphCell property.

var graphCell: UICollectionViewCell?

Using the provided Delegate Callbacks, you can set your graphCell properties for specific graphData points

This is great for setting images or labels that change depending on the data.

Gif of Miles Ran

Cell Delegate Callbacks

protocol CollectionGraphCellDelegate: class {

  func collectionGraph(
    cell: UICollectionViewCell,
    forData data: GraphDatum,
    atSection section: Int
    )

  func collectionGraph(
    sizeForGraphCellWithData data: GraphDatum,
    inSection section: Int
    ) -> CGSize
}

1) Properties Callback - Set the visual treatment on a cell.
func collectionGraph(cell: UICollectionViewCell, forData data: GraphDatum, atSection section: Int)

Example properties:

  • backgroundColor
  • layer.cornerRadius
  • Any custom properties you added in a subclass
  • etc...
Example usage:
collectionGraph.collectionGraphCellDelegate = self
func collectionGraph(cell: UICollectionViewCell, forData data: GraphDatum, atSection section: Int) {
        cell.backgroundColor = UIColor.darkText
        cell.layer.cornerRadius = cell.frame.width / 2

        // custom graphCell
        if let myCell = cell as? myCell {
          myCell.image = UIImage(named: "donut.png")
        }
    }

2) Size Callback

func collectionGraph(sizeForGraphCellWithData data: GraphDatum, inSection section: Int) -> CGSize {
    if section == 0 {
        return CGSize(width: 3, height: 3)
    }

    return CGSize(width: 8, height: 8)
}

Bar Graph Views

Used for bar graphs. These are the views that start at the bottom of the graph and extend up to the graphCell. Can be used with line graphs as well.

Custom barViews

If you want a custom barView instead of the default view, you can set the barView property

var barView: UICollectionReusableView?

Gif of bar Graph

BarView Delegate Callbacks

protocol CollectionGraphBarDelegate: class {

    func collectionGraph(
      barView: UICollectionReusableView,
      withData data: GraphDatum,
      inSection section: Int
      )

    func collectionGraph(
      widthForBarViewWithData data: GraphDatum,
      inSection section: Int
      ) -> CGFloat
}

1) Propery Callback - Set the visual treatment on a bar view.
func collectionGraph(barView: UICollectionReusableView, withData data: GraphDatum, inSection section: Int)

Example properties:

  • backgroundColor
  • Any custom properties you added in a subclass
  • etc...
Example usage:
collectionGraph.collectionGraphBarDelegate = self
func collectionGraph(barView: UICollectionReusableView, withData data: GraphDatum, inSection section: Int) {
        barView.backgroundColor = UIColor.lightGray
    }

Line Graph Connector Lines

Used for line graphs. These are the lines that connect the graphCells. Can be used with bar graphs as well.

Gif of line Graph

Customizing a Connector Line with Delegate Callbacks

To display connector lines, you need to use the delegate callback and set the line's properties.

protocol CollectionGraphLineDelegate: class {

    func collectionGraph(
      connectorLine: GraphLineShapeLayer,
      withData data: GraphDatum,
      inSection section: Int)
}

The connectorLine property provides a GraphLineShapeLayer which is a subclass of CAShapeLayer, and provides an additional property of straightLines.

class GraphLineShapeLayer: CAShapeLayer {
    public var straightLines: Bool = false
}

You can set all the visual properties of a CAShapeLayer to achieve the look you want.

Example properties:

  • lineWidth
  • straightLines
  • lineDashPattern
  • strokeColor

Example usage:

collectionGraph.collectionGraphLineDelegate = self
func collectionGraph(connectorLine: GraphLineShapeLayer, withData data: GraphDatum, inSection section: Int) {
        connectorLine.lineWidth = 2
        connectorLine.lineDashPattern = [4, 2]
        connectorLine.straightLines = true
        connectorLine.lineCap = kCALineCapRound
        connectorLine.strokeColor = UIColor.darkGray.cgColor
    }

X Labels

To change the text displayed along the X axis, use CollectionGraphLabelsDelegate

public protocol CollectionGraphLabelsDelegate: class {

    func collectionGraph(
      textForXLabelWithCurrentText currentText: String,
      inSection section: Int
      ) -> String
}

Example usage:

collectionGraph.collectionGraphLabelsDelegate = self
func collectionGraph(textForXLabelWithCurrentText currentText: String, inSection section: Int) -> String {
        return ""
    }

Horizontal Y Divider Lines

These are the horizontal lines next to the Y labels that span the length of the graph.

public protocol CollectionGraphYDividerLineDelegate: class {

    func collectionGraph(yDividerLine: CAShapeLayer)
}

Example usage:

collectionGraph.collectionGraphYDividerLineDelegate = self
func collectionGraph(yDividerLine: CAShapeLayer) {
        yDividerLine.lineDashPattern = [1, 8]
        yDividerLine.lineWidth = 2
    }

Settable Properties

Graph width and Insets

Width:
By default the graphCells are plotted within the width of the CollectionGraph.
By setting graphContentWidth you can extend the content width to allow scrolling.

var graphContentWidth: CGFloat

Insets:
Adjust space along the edges of the CollectionGraph.
The left and bottom space is used to layout the labels.

 var topInset: CGFloat

 var leftInset: CGFloat

 var bottomInset: CGFloat

 var rightInset: CGFloat

Side Bar View

A view that lies behind the y axis labels and above the plotted graph. Useful for covering the graph when it scrolls behind the y labels.

var ySideBarView: UICollectionReusableView?

Note! You need to provide a subclass of UICollectionReusableView and override init(frame: CGRect). Inside the init block is where you set your customizations

Initializiing a UICollectionReusableView() and then settings its background color will not work.

Example:

class MySideBarClass: UICollectionReusableView {

  override init(frame: CGRect) {
     super.init(frame: frame)
     backgroundColor = UIColor.red
  }

}

Y Divider Lines

Set the color of the horizontal lines that go across the graph along the Y axis.

var yDividerLineColor: UIColor

Number of labels along the X and Y axes

X:

 var xSteps: Int

Y:

var ySteps: Int

Text for X and Y labels

Color:

var textColor: UIColor

Size:

var textSize: CGFloat

Font Name:

var fontName: String?

Graph Offset

Get and Set the current offset of the CollectionGraph.

var contentOffset: CGPoint

Scroll to a specific data point.

func scrollToDataPoint(
  graphDatum: GraphDatum,
  withAnimation animation: Bool,
  andScrollPosition scrollPosition: UICollectionViewScrollPosition)

Develoment

Install SwiftLint for static analysis:

$ brew install swiftlint
CollectionGraph open issues Ask a question     (View All Issues)
  • almost 2 years Return the item # in barView:withData:inSection
  • almost 2 years Return the item # in widthForBarViewWithData
  • almost 2 years Change section to item in textForXLabelWithCurrentText:
  • almost 2 years Set starting value and ending values for X and Y axes.
  • about 2 years Crash when setting graphData to 0 values
  • about 2 years Setting yDividerLineColor doesn't change color
  • about 2 years Supply section number in setCellSize() callback.
  • over 2 years Y Labels can grow too large and get cut off
  • over 2 years Configure Travis CI
CollectionGraph open pull requests (View All Pulls)
  • Add Travis builds to Buildlight
CollectionGraph list of languages used
CollectionGraph latest release notes
v1.0.0 Legacy Version 1.0

This is the current stable release of v1.0.

I will be re-writing the collection graph in v2.0 to not hide the UICollectionView implementation and hopefully make things more optimized along the way.

V2.0 will be a complete re-write and therefore break v1.0's implementation.

There is a branch called v1-stable that will remain if you do not wish to use v2.

Other projects in Swift