Skip to content

Instantly share code, notes, and snippets.

@izakpavel
Created November 18, 2020 09:08
Show Gist options
  • Save izakpavel/cb3059a11edb1e61c3c6c4c17a4da6be to your computer and use it in GitHub Desktop.
Save izakpavel/cb3059a11edb1e61c3c6c4c17a4da6be to your computer and use it in GitHub Desktop.
a SwiftUI recreation of an interesting animation by @beesandbombs
//
// RotatorView.swift
//
// Created by Pavel Zak on 16/11/2020.
// original idea by: https://twitter.com/beesandbombs/status/1326312738033983489?s=20
//
import SwiftUI
func pow(_ x: Int, _ y: Int) -> Int {
var result = 1
for _ in 0..<y {
result *= x
}
return result
}
struct RotatorShape: Shape {
static let maxDivision: Int = 6
var division: Int
func path(in rect: CGRect) -> Path {
return Path { path in
let width = rect.width
let height = rect.height
let segments = 3*pow(2, division-1)
let wx = width*0.5/CGFloat(Self.maxDivision)
let wy = height*0.5/CGFloat(Self.maxDivision)
for index in 0..<segments {
let angle = 2*CGFloat.pi/CGFloat(segments)*CGFloat(index)
path.move(to: CGPoint(x: width/2 + cos(angle)*wx*CGFloat(division), y: height/2 + sin(angle)*wy*CGFloat(division)))
path.addLine(to: CGPoint(x: width/2 + cos(angle)*wx*CGFloat(division+1), y: height/2 + sin(angle)*wy*CGFloat(division+1)))
}
}
}
}
struct CompassView: View {
@State var angleStep: Double = 0
func delayForDivision(_ division: Int) -> Double{
return Double(division)*0.1
}
func angleForDivision(_ division: Int) -> Double{
let segments = 3*pow(2, division-1)
let baseAngle = 2*Double.pi/Double(segments)
return baseAngle*angleStep
}
func animate (){
withAnimation() {
self.angleStep += 1.0
}
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
self.animate()
}
}
var body: some View {
let animation = Animation.easeInOut(duration: 1.0)
return ZStack {
ForEach (1 ..< RotatorShape.maxDivision+1) { division in
RotatorShape(division: division)
.stroke(Color.red, lineWidth: 2.0)
.blendMode(.plusLighter)
.rotationEffect(Angle(radians: angleForDivision(division)))
.animation(animation.delay(delayForDivision(division)))
RotatorShape(division: division)
.stroke(Color.green, lineWidth: 2.0)
.blendMode(.plusLighter)
.rotationEffect(Angle(radians: angleForDivision(division)))
.animation(animation.delay(delayForDivision(division)+Double(division)*0.015))
RotatorShape(division: division)
.stroke(Color.blue, lineWidth: 2.0)
.blendMode(.plusLighter)
.rotationEffect(Angle(radians: angleForDivision(division)))
.animation(animation.delay(delayForDivision(division)+Double(division)*0.03))
}
}
.onAppear() {
withAnimation() {
self.animate()
}
}
}
}
struct RotatorView: View {
var body: some View {
CompassView()
.frame(width: 300, height: 300)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment