Skip to content

Instantly share code, notes, and snippets.

@mac389
Last active August 29, 2015 14:22
Show Gist options
  • Save mac389/0a5191ece2b870b33658 to your computer and use it in GitHub Desktop.
Save mac389/0a5191ece2b870b33658 to your computer and use it in GitHub Desktop.
//
// MasterViewController.swift
// beta
//
// Created by Michael Chary on 5/25/15.
// Copyright (c) 2015 Michael Chary. All rights reserved.
//
import UIKit
import AudioToolbox
private enum Shape {
case NYU, Sinai, Rockefeller
}
class EcosystemMasterViewController: UIViewController, UIScrollViewDelegate {
var objects = [AnyObject]()
var chartPoints = [ChartPointBubble]()
//var gesture: UILongPressGestureRecognizer?
var UniColors = ["nyu": CGFloat(0.5), "sinai":CGFloat(0.2),"rockefeller":CGFloat(0.7)]
private var chart: Chart?
private var chartPointDetail:ChartPointBubble?
var selectedIndex:Int?
private let colorBarHeight: CGFloat = 50
private let useViewsLayer = true
override func awakeFromNib() {
super.awakeFromNib()
}
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.leftBarButtonItem = self.editButtonItem()
//self.gesture = UILongPressGestureRecognizer(target: self, action: "longPressed:")
//self.gesture!.minimumPressDuration = 1.0
//self.view.addGestureRecognizer(self.gesture!)
// Do any additional setup after loading the view, typically from a nib.
let frame = ExamplesDefaults.chartFrame(self.view.bounds)
let chartFrame = CGRectMake(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height - colorBarHeight)
let labelSettings = ChartLabelSettings(font: ExamplesDefaults.labelFont)
let path = NSBundle.mainBundle().pathForResource("data", ofType: "json")
let data = NSData(contentsOfMappedFile: path!)
let json = JSON(data: data!, options: NSJSONReadingOptions.AllowFragments, error: nil)
let scrollViewFrame = ExamplesDefaults.chartFrame(self.view.bounds)
let colorBar = ColorBar(frame: CGRectMake(0, chartFrame.origin.y + chartFrame.size.height, self.view.frame.size.width, self.colorBarHeight), c1: UIColor.redColor(), c2: UIColor.greenColor())
func toColor(institution: String) -> UIColor {
return colorBar.colorForPercentage(UniColors[institution.lowercaseString]!).colorWithAlphaComponent(0.6)
}
for (index: String, object: JSON) in json {
let pointBubble = ChartPointBubble(
x: ChartAxisValueFloat(CGFloat(object["x"].floatValue),
labelSettings:labelSettings),
y:ChartAxisValueFloat(CGFloat(object["y"].floatValue)),
diameterScalar: CGFloat(object["r"].floatValue),
description: object["description"],
bgColor:toColor(object["description"]["institution"].stringValue))
self.chartPoints.append(pointBubble)
}
let xValues = Array(stride(from: -0.6, through: 1.2, by: 0.1)).map {ChartAxisValueFloat($0, labelSettings: labelSettings)}
let yValues = Array(stride(from: -0.6, through: 1.2, by: 0.1)).map {ChartAxisValueFloat($0, labelSettings: labelSettings)}
let xModel = ChartAxisModel(axisValues: xValues, axisTitleLabel: ChartAxisLabel(text: "Semantic Dimension 1", settings: labelSettings))
let yModel = ChartAxisModel(axisValues: yValues, axisTitleLabel: ChartAxisLabel(text: "Semantic Dimension 2", settings: labelSettings))
let coordsSpace = ChartCoordsSpaceLeftBottomSingleAxis(chartSettings: ExamplesDefaults.chartSettings, chartFrame: chartFrame, xModel: xModel, yModel: yModel)
let (xAxis, yAxis, innerFrame) = (coordsSpace.xAxis, coordsSpace.yAxis, coordsSpace.chartInnerFrame)
let lineModel = ChartLineModel(chartPoints: chartPoints, lineColor: UIColor.redColor(), animDuration: 0.5, animDelay: 0)
let bubbleLayer = self.bubblesLayer(xAxis: xAxis, yAxis: yAxis, chartInnerFrame: innerFrame, chartPoints: chartPoints)
let guidelinesLayerSettings = ChartGuideLinesDottedLayerSettings(linesColor: UIColor.blackColor(), linesWidth: ExamplesDefaults.guidelinesWidth)
let guidelinesLayer = ChartGuideLinesDottedLayer(xAxis: xAxis, yAxis: yAxis, innerFrame: innerFrame, settings: guidelinesLayerSettings)
let guidelinesHighlightLayerSettings = ChartGuideLinesDottedLayerSettings(linesColor: UIColor.redColor(), linesWidth: 1, dotWidth: 4, dotSpacing: 4)
let guidelinesHighlightLayer = ChartGuideLinesForValuesDottedLayer(xAxis: xAxis, yAxis: yAxis, innerFrame: innerFrame, settings: guidelinesHighlightLayerSettings, axisValuesX: [ChartAxisValueFloat(0)], axisValuesY: [ChartAxisValueFloat(0)])
let scrollView = UIScrollView(frame: scrollViewFrame)
scrollView.contentSize = CGSizeMake(chartFrame.size.width, scrollViewFrame.size.height)
let chart = Chart(
frame: chartFrame,
layers: [
xAxis,
yAxis,
guidelinesLayer,
guidelinesHighlightLayer,
bubbleLayer
]
)
self.view.addSubview(chart.view)
self.chart = chart
}
/*
//MARK: -- Touch handling
func longPressed(longPress: UIGestureRecognizer){
if (longPress.state == UIGestureRecognizerState.Ended)
{
AudioServicesPlayAlertSound(SystemSoundID(kSystemSoundID_Vibrate))
self.performSegueWithIdentifier("showDetail", sender: self.chartPoints[self.selectedIndex!])
}
}*/
private func bubblesLayer(#xAxis: ChartAxisLayer, yAxis: ChartAxisLayer, chartInnerFrame: CGRect, chartPoints: [ChartPointBubble]) -> ChartLayer {
let maxBubbleDiameter: CGFloat = 30, minBubbleDiameter: CGFloat = 2
if self.useViewsLayer == true {
let (minDiameterScalar: CGFloat, maxDiameterScalar: CGFloat) = chartPoints.reduce((min: CGFloat(0), max: CGFloat(0))) {tuple, chartPoint in
(min: min(tuple.min, chartPoint.diameterScalar), max: max(tuple.max, chartPoint.diameterScalar))
}
let diameterFactor = (maxBubbleDiameter - minBubbleDiameter) / (maxDiameterScalar - minDiameterScalar)
var popups: [UIView] = []
return ChartPointsViewsLayer(xAxis: xAxis, yAxis: yAxis, innerFrame: chartInnerFrame, chartPoints: chartPoints, viewGenerator: {(chartPointModel, layer, chart) -> UIView? in
let (chartPoint, screenLoc) = (chartPointModel.chartPoint, chartPointModel.screenLoc)
self.chartPointDetail = chartPoint
self.selectedIndex = chartPointModel.index
let diameter = chartPointModel.chartPoint.diameterScalar * diameterFactor
let rect = CGRectMake(chartPointModel.screenLoc.x - diameter / 2, chartPointModel.screenLoc.y - diameter / 2, diameter, diameter)
let bubbleView = MyBubbleView(frame: rect, fillColor: chartPointModel.chartPoint.bgColor, borderColor: UIColor.blackColor().colorWithAlphaComponent(0.6), animDelay: 0.1*Float(chartPointModel.index) * 0.2, animDuration: 1.2)
bubbleView.longPressHandler = { [weak self] view in
bubbleView.addGestureRecognizer(bubbleView.gesture!)
AudioServicesPlayAlertSound(SystemSoundID(kSystemSoundID_Vibrate))
println("here")
self!.performSegueWithIdentifier("showDetail", sender: self!.chartPoints[self!.selectedIndex!])
}
bubbleView.touchHandler = {[weak self] view in
for p in popups {p.removeFromSuperview()}
let w: CGFloat = Env.iPad ? 250 : 150
let h: CGFloat = Env.iPad ? 100 : 80
let x: CGFloat = {
let attempt = screenLoc.x - (w/2)
let leftBound: CGFloat = chart.bounds.origin.x
let rightBound = chart.bounds.size.width - 5
if attempt < leftBound {
return view.frame.origin.x
} else if attempt + w > rightBound {
return rightBound - w
}
return attempt
}()
let frame = CGRectMake(x, screenLoc.y - (h + (Env.iPad ? 30 : 12)), w, h)
let bubbleView = BubbleView(frame: frame, arrowWidth: Env.iPad ? 40 : 28, arrowHeight: Env.iPad ? 20 : 14, bgColor: UIColor.blackColor(), arrowX: screenLoc.x - x)
chart.addSubview(bubbleView)
bubbleView.transform = CGAffineTransformConcat(CGAffineTransformMakeScale(0, 0), CGAffineTransformMakeTranslation(0, 100))
let infoView = UILabel(frame: CGRectMake(0, 10, w, h - 20))
infoView.textColor = UIColor.whiteColor()
infoView.backgroundColor = UIColor.blackColor()
infoView.text = chartPoint.description["name"].stringValue
infoView.font = ExamplesDefaults.fontWithSize(Env.iPad ? 14 : 12)
infoView.textAlignment = NSTextAlignment.Center
bubbleView.addSubview(infoView)
popups.append(bubbleView)
UIView.animateWithDuration(0.2, delay: 0, options: UIViewAnimationOptions.allZeros, animations: {
bubbleView.transform = CGAffineTransformIdentity
}, completion: {finished in})
}
return bubbleView
})
} else {
return ChartPointsBubbleLayer(xAxis: xAxis, yAxis: yAxis, innerFrame: chartInnerFrame, chartPoints: chartPoints)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Segues
//TODO Include vibrate on selection
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showDetail" {
if let destination = segue.destinationViewController as? DetailViewController
{
self.navigationItem.title = "Ecosystem"
println(sender)
/*
let payload = self.chartPoints[self.selectedIndex!].description
let theName = payload["name"].stringValue
let theInstitution = payload["institution"].stringValue
let technologyDescription = payload["keywords"].count == 0 ? "None" : ", ".join(payload["keywords"].arrayValue.map{(var item) -> String in return item.stringValue})
destination.detailItem = "Name: \(theName) \n\n Institution: \(theInstitution) \n\n Areas: \(technologyDescription)"
*/
destination.detailItem = "bob"
}
}
}
}
class MyBubbleView: UIView {
let fillColor: UIColor
let borderColor: UIColor
let borderWidth: CGFloat
let animDelay: Float
let animDuration: Float
var touchHandler: ((MyBubbleView) -> ())?
var longPressHandler: ((MyBubbleView) -> ())?
var gesture: UILongPressGestureRecognizer?
init(frame: CGRect, fillColor: UIColor, borderColor: UIColor, borderWidth: CGFloat = 1, animDelay: Float, animDuration: Float) {
self.fillColor = fillColor
self.borderColor = borderColor
self.borderWidth = borderWidth
self.animDelay = animDelay
self.animDuration = animDuration
super.init(frame: CGRectInset(frame, -borderWidth, -borderWidth))
self.backgroundColor = UIColor.clearColor()
self.gesture = UILongPressGestureRecognizer(target: self, action: "longPressed:")
self.gesture!.minimumPressDuration = 1.0
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//MARK: -- Touch handling
func longPressed(longPress: UIGestureRecognizer){
if (longPress.state == UIGestureRecognizerState.Ended)
{
self.longPressHandler!(self)
}
}
override func drawRect(rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
CGContextSetLineWidth(context, self.borderWidth)
CGContextSetStrokeColorWithColor(context, self.borderColor.CGColor)
CGContextSetFillColorWithColor(context, self.fillColor.CGColor)
let circleRect = (CGRectMake(self.borderWidth, self.borderWidth, self.frame.size.width - (self.borderWidth * 2), self.frame.size.height - (self.borderWidth * 2)))
CGContextFillEllipseInRect(context, circleRect)
CGContextStrokeEllipseInRect(context, circleRect)
}
override func didMoveToSuperview() {
self.transform = CGAffineTransformMakeScale(0.1, 0.1)
self.alpha = 0
UIView.animateWithDuration(NSTimeInterval(self.animDuration), delay: NSTimeInterval(self.animDelay), usingSpringWithDamping: 0.4, initialSpringVelocity: 0.5, options: UIViewAnimationOptions.allZeros, animations: { () -> Void in
self.transform = CGAffineTransformMakeScale(1, 1)
self.alpha = 1
}, completion: nil)
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
self.touchHandler?(self)
}
}
class ColorBar: UIView {
let dividers: [CGFloat]
let gradientImg: UIImage
lazy var imgData: UnsafePointer<UInt8> = {
let provider = CGImageGetDataProvider(self.gradientImg.CGImage)
let pixelData = CGDataProviderCopyData(provider)
return CFDataGetBytePtr(pixelData)
}()
init(frame: CGRect, c1: UIColor, c2: UIColor) {
var gradient: CAGradientLayer = CAGradientLayer()
gradient.frame = CGRectMake(0, 0, frame.width, 30)
gradient.colors = [UIColor.blueColor().CGColor, UIColor.cyanColor().CGColor, UIColor.yellowColor().CGColor, UIColor.redColor().CGColor]
gradient.startPoint = CGPointMake(0, 0.5)
gradient.endPoint = CGPointMake(1.0, 0.5)
let imgHeight = 1
let imgWidth = Int(gradient.bounds.size.width)
let bitmapBytesPerRow = imgWidth * 4
let bitmapByteCount = bitmapBytesPerRow * imgHeight
let colorSpace:CGColorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGBitmapInfo(CGImageAlphaInfo.PremultipliedLast.rawValue)
let context = CGBitmapContextCreate (nil,
imgWidth,
imgHeight,
8,
bitmapBytesPerRow,
colorSpace,
bitmapInfo)
UIGraphicsBeginImageContext(gradient.bounds.size)
gradient.renderInContext(context)
let gradientImg = UIImage(CGImage: CGBitmapContextCreateImage(context))!
UIGraphicsEndImageContext()
self.gradientImg = gradientImg
let segmentSize = gradient.frame.size.width / 6
self.dividers = Array(stride(from: segmentSize, through: gradient.frame.size.width, by: segmentSize))
super.init(frame: frame)
self.layer.insertSublayer(gradient, atIndex: 0)
let numberFormatter = NSNumberFormatter()
numberFormatter.maximumFractionDigits = 2
for x in stride(from: segmentSize, through: gradient.frame.size.width - 1, by: segmentSize) {
let dividerW: CGFloat = 1
let divider = UIView(frame: CGRectMake(x - dividerW / 2, 25, dividerW, 5))
divider.backgroundColor = UIColor.blackColor()
self.addSubview(divider)
let text = "\(numberFormatter.stringFromNumber(x / gradient.frame.size.width)!)"
let labelWidth = ChartUtils.textSize(text, font: ExamplesDefaults.labelFont).width
let label = UILabel()
label.center = CGPointMake(x - labelWidth / 2, 30)
label.font = ExamplesDefaults.labelFont
label.text = text
label.sizeToFit()
self.addSubview(label)
}
}
func colorForPercentage(percentage: CGFloat) -> UIColor {
let data = self.imgData
let xNotRounded = self.gradientImg.size.width * percentage
let x = 4 * (floor(abs(xNotRounded / 4)))
let pixelIndex = Int(x * 4)
let color = UIColor(
red: CGFloat(data[pixelIndex + 0]) / 255.0,
green: CGFloat(data[pixelIndex + 1]) / 255.0,
blue: CGFloat(data[pixelIndex + 2]) / 255.0,
alpha: CGFloat(data[pixelIndex + 3]) / 255.0
)
return color
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment