Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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