Skip to content

Instantly share code, notes, and snippets.

@d-ronnqvist
Created December 22, 2014 19:48
Show Gist options
  • Save d-ronnqvist/996b53b59d6f06b66235 to your computer and use it in GitHub Desktop.
Save d-ronnqvist/996b53b59d6f06b66235 to your computer and use it in GitHub Desktop.
Hexagon Ripple in a Swift Playground
import AppKit
import QuartzCore
import XCPlayground
// Parameters that define the style
let hexSideLength: CGFloat = 15.0
let hexLineWidth: CGFloat = 3.0
let colors = [NSColor.redColor(), NSColor.cyanColor(), NSColor.greenColor(), NSColor.yellowColor(), NSColor.redColor()].map { $0.CGColor }
// The shape used at every point in the hex grid
let π = CGFloat(M_PI)
let hexAngle = 2.0*π/3.0
func pointWithAngle(angle: CGFloat, distance: CGFloat, fromPoint: CGPoint) -> CGPoint {
return CGPoint(
x: fromPoint.x + distance * cos(angle),
y: fromPoint.y + distance * sin(angle)
)
}
let center = CGPointZero
let points = [0, 1, 2]
.map { -π/2.0 + hexAngle*$0 }
.map { pointWithAngle($0, hexSideLength, center) }
let path = CGPathCreateMutable()
for point in points {
CGPathMoveToPoint(path, nil, center.x, center.y)
CGPathAddLineToPoint(path, nil, point.x, point.y)
}
// A layer hosting view, to host the shape layers
let size = CGSize(width: 250, height: 200)
let view = NSView(frame: CGRect(origin: CGPointZero, size: size))
let rootLayer = CALayer()
rootLayer.backgroundColor = NSColor.blackColor().CGColor
view.layer = rootLayer // for a layer _hosting_ view
view.wantsLayer = true
XCPShowView("hex view", view)
// The grid of points for the hex grid
var hexPoints:[CGPoint] = []
let rowHeight = -cos(hexAngle)*hexSideLength + hexSideLength
var isEven = true
var row: CGFloat = hexSideLength
while row < view.frame.height {
let xOffset = isEven ? hexSideLength*sin(hexAngle) : 0.0
var col: CGFloat = hexSideLength/2.0 - xOffset
while col < view.frame.width + hexSideLength {
hexPoints.append(CGPoint(x: col, y: row))
col += 2.0*hexSideLength*sin(hexAngle)
}
row += rowHeight
isEven = !isEven
}
// The two animations (rotation and color)
let timing = CAMediaTimingFunction(controlPoints: 0.85, 0.0, 0.15, 1.0)
var rotation = CABasicAnimation(keyPath: "transform.rotation.z")
rotation.fromValue = 0.0
rotation.byValue = -π/3.0
rotation.duration = 1.0
rotation.repeatCount = HUGE
rotation.timingFunction = timing
rotation.cumulative = true
var colorShift = CAKeyframeAnimation(keyPath: "strokeColor")
colorShift.values = colors
colorShift.duration = Double(colors.count-1)*rotation.duration
colorShift.repeatCount = HUGE
colorShift.timingFunctions = [timing, timing, timing]
let viewCenter = CGPoint(x: view.frame.midX, y: view.frame.midY)
func distanceToViewCenter(point: CGPoint) -> CGFloat {
return sqrt((point.x - viewCenter.x)*(point.x - viewCenter.x) + (point.y - viewCenter.y)*(point.y - viewCenter.y))
}
for point in hexPoints {
let layer = CAShapeLayer()
layer.lineWidth = hexLineWidth
layer.position = point
layer.path = path
view.layer?.addSublayer(layer)
var timeOffset = Double(distanceToViewCenter(point)/view.frame.midX)
rotation.timeOffset = -timeOffset
colorShift.timeOffset = -timeOffset
layer.addAnimation(rotation, forKey: "spin")
layer.addAnimation(colorShift, forKey: "shift color")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment