/
Shapes.swift
118 lines (103 loc) · 2.94 KB
/
Shapes.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//
// Shapes.swift
// DispLayover
//
// Created by Lyndon Maydwell on 31/10/2023.
//
import SwiftUI
import Foundation
extension Int {
var degrees: Angle { return Angle(degrees: Double(self)) }
var radians: Angle { return Angle(radians: Double(self)) }
}
struct Shrinkable: Shape {
var reference: any Shape
var offset: CGFloat = 0
var animatableData: CGFloat {
get { offset }
set { offset = newValue }
}
func path(in rect: CGRect) -> Path {
let amount = offset * min(rect.width, rect.height) / 20
return reference.path(in: rect.insetBy(dx: amount, dy: amount))
}
}
enum ShapeType: String, CaseIterable {
case circle
case rectangle
case capsule
case ellipse
case pentagon
case hexagon
case heart
case cloud
case blob
}
func mkShape(_ t: ShapeType) -> AnyShape {
switch t {
case .circle: return AnyShape(Circle())
case .rectangle: return AnyShape(RoundedRect())
case .capsule: return AnyShape(Capsule())
case .ellipse: return AnyShape(Ellipse())
case .pentagon: return AnyShape(NGon(sides: 5))
case .hexagon: return AnyShape(NGon(sides: 6))
case .heart: return AnyShape(Heart())
case .cloud: return AnyShape(Cloud(count: 10))
case .blob: return AnyShape(try! Blob(count: 7))
}
}
func mkEvolvingShape(_ t: ShapeType) -> ((TimeInterval) -> AnyShape) {
switch t {
case .pentagon:
var reference = NGon(sides: 5)
return {
reference.rotationRadians = $0 / 10
return AnyShape(reference)
}
case .hexagon:
var reference = NGon(sides: 6)
return {
reference.rotationRadians = $0 / 10
return AnyShape(reference)
}
case .heart:
let reference = Heart()
return {
let s = Shrinkable(reference: reference, offset: (1+CGFloat(sin($0 * 3))) / 2)
return AnyShape(s)
}
case .blob:
var reference = try! Blob(count: 7)
return {
reference.time = $0
return AnyShape(reference)
}
// Everything that isn't special-cased is a regular Shrinkable with a 2s period
default:
let reference = mkShape(t)
return {
let s = Shrinkable(reference: reference, offset: (1+CGFloat(sin($0))) / 2)
return AnyShape(s)
}
}
}
#Preview {
func preview(_ t: ShapeType, _ c: Color) -> some View {
return ZStack {
mkShape(t).frame(width: 200, height: 90).background(c)
Text(t.rawValue).foregroundColor(.black)
}
}
return VStack {
HStack {
preview(.circle, .red)
preview(.rectangle, .green)
preview(.hexagon, .blue)
}
HStack {
preview(.heart, .purple)
preview(.cloud, .cyan)
preview(.blob, .indigo)
}
}
}