Skip to content

Instantly share code, notes, and snippets.

@blakejakopovic
Created July 2, 2014 08:57
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save blakejakopovic/92c60421b399179873ee to your computer and use it in GitHub Desktop.
Save blakejakopovic/92c60421b399179873ee to your computer and use it in GitHub Desktop.
Simple spark graph NSView example written in Swift. Open with Xcode for live preview and coding.
import Cocoa
import XCPlayground
@IBDesignable
class SparkGraph: NSView {
// Background Colour
@IBInspectable var backgroundColor:NSColor?
// Border
@IBInspectable var borderColor:NSColor?
@IBInspectable var borderLineWidth:CGFloat?
// Sparkline
@IBInspectable var lineWidth:CGFloat?
@IBInspectable var maxValues:Int {
didSet {
self.values = Array(self.values[0..self.maxValues])
}
}
@IBInspectable var yMax:Int?
var values: Int[] {
didSet {
setNeedsDisplayInRect(self.frame)
}
}
init(frame: NSRect, values:Int[]) {
self.values = values
self.backgroundColor = nil
self.borderColor = NSColor.grayColor()
self.borderLineWidth = 1.0
self.lineWidth = 1.0
self.maxValues = 60
self.yMax = nil
super.init(frame: frame)
}
override func drawRect(dirtyRect: NSRect) {
super.drawRect(dirtyRect)
// Background
if (self.backgroundColor) {
self.backgroundColor!.setFill()
NSRectFill(self.bounds)
}
// Border
if (self.borderLineWidth! > 0 && self.borderColor) {
let frameRect = self.bounds
let newRect = NSMakeRect(frame.origin.x + 1, frame.origin.y + 1, frame.size.width - 1, frame.size.height - 1)
var borderPath = NSBezierPath(rect:newRect)
borderPath.lineWidth = self.borderLineWidth!
self.borderColor!.setStroke()
borderPath.stroke()
}
// Check for at least two values
if (self.values.count < 2) {
return
}
// Graph
let innerRect = NSMakeRect(self.frame.origin.x, self.frame.origin.y, self.frame.width - (1.5 * self.borderLineWidth!), self.frame.height - ( 1.5 * self.borderLineWidth!))
// Calculate maximum Y value (or use given)
var yMax:Int? = nil
if (self.yMax) {
yMax = self.yMax
} else {
yMax = (self.values as AnyObject).valueForKeyPath("@max.self") as? Int
}
// Allow for border offset
let xOffset = (self.borderLineWidth!/2)
let yOffset = (self.borderLineWidth!/2)
// Scale data points to frame
let yRatio = Double(innerRect.size.height) / Double(yMax!);
let xRatio = Double(innerRect.size.width) / (Double(values.count) - 1);
// Create sparkline path
var sparkline = NSBezierPath()
sparkline.lineWidth = self.lineWidth!
// Add data points to path
for var i = 0; i < self.values.count; i++ {
let x = (Double(i) * xRatio) + xOffset
let y = (Double(values[i] as NSNumber) * yRatio) + yOffset
let point = CGPointMake(x, y);
if i == 0 { // starting point
sparkline.moveToPoint(point)
} else {
sparkline.lineToPoint(point)
}
}
// Draw sparkline
NSColor.redColor().setStroke()
sparkline.stroke()
}
func addValue(newValue:Int) {
if self.values.count >= self.maxValues {
self.values.removeAtIndex(0)
}
self.values.append(newValue)
}
func addValues(values:Int[]) {
for value in values {
self.addValue(value)
}
}
func addValues(values:Int...) {
self.addValues(values)
}
}
var frame = NSRect(x: 0, y: 0, width: 1024, height: 128)
var values = [500, 200, 500, 600, 50, 80, 700, 900, 1000, 1000]
var s = SparkGraph(frame: frame, values: values)
s.backgroundColor = NSColor.whiteColor()
s.borderColor = NSColor.grayColor()
s.borderLineWidth = 1.0
s.lineWidth = 5.0
//s.yMax = 500
//s.maxValues = 3
//s.addValue(230)
//s.addValues(400,300,200,100,0)
//s.addValues(8,5,3,4,5,6,7,8,9,100)
XCPShowView("Spark Graph", s)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment