Last active
August 29, 2015 14:22
-
-
Save mac389/0a5191ece2b870b33658 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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