-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathpathfinder.ts
More file actions
138 lines (118 loc) · 3.48 KB
/
pathfinder.ts
File metadata and controls
138 lines (118 loc) · 3.48 KB
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import { isBrowser } from "./keyframes";
import { KeyframeObject, KeyframeRule } from "./types/keyframes";
type PathFinderOptions = {
bezierSteps?: number;
circleSteps?: number;
transform?: string;
};
type PathFinderKeyframeOptions = PathFinderOptions & KeyframeObject;
type Vector = {
x: number;
y: number;
};
type ArrayVector = [number, number];
function getCirclePoint(radians: number, radius: number, center: Vector) {
return {
x: center.x + radius * Math.cos(radians),
y: center.y + radius * Math.sin(radians)
};
}
//= ===================================\\
// 13thParallel.org Beziér Curve Code \\
// by Dan Pupius (www.pupius.net) \\
//= ===================================\\
const coord = (x = 0, y = 0): Vector => {
return { x, y };
};
const B1 = (t: number) => t * t * t;
const B2 = (t: number) => 3 * t * t * (1 - t);
const B3 = (t: number) => 3 * t * (1 - t) * (1 - t);
const B4 = (t: number) => (1 - t) * (1 - t) * (1 - t);
const getBezier = (
percent: number,
C1: Vector,
C2: Vector,
C3: Vector,
C4: Vector
) => {
const pos = coord();
pos.x =
C1.x * B1(percent) +
C2.x * B2(percent) +
C3.x * B3(percent) +
C4.x * B4(percent);
pos.y =
C1.y * B1(percent) +
C2.y * B2(percent) +
C3.y * B3(percent) +
C4.y * B4(percent);
return pos;
};
export const bezierPath = (
keyframeOptions: PathFinderKeyframeOptions,
p1: ArrayVector,
p2: ArrayVector,
p3: ArrayVector,
p4: ArrayVector
) => {
const opts = { bezierSteps: 100, transform: "", ...keyframeOptions };
if (p4 == null) {
p4 = p1;
}
const vector1 = coord(p1[0], p1[1]);
const vector2 = coord(p2[0], p2[1]);
const vector3 = coord(p3[0], p3[1]);
const vector4 = coord(p4[0], p4[1]);
const points: KeyframeRule = {};
const step = 1 / opts.bezierSteps;
for (let i = 0; i <= 1.01; i += step) {
const newPosition = getBezier(i, vector1, vector4, vector3, vector2);
points[`${100 - Math.round(i * 100)}%`] = {
transform: `translate(${newPosition.x}px,${newPosition.y}px) ${opts.transform}`
};
}
return Object.assign({}, keyframeOptions, points);
};
export const circlePath = (
keyframeOptions: PathFinderKeyframeOptions,
center: ArrayVector,
radius: number
) => {
const opts = { circleSteps: 100, transform: "", ...keyframeOptions };
const points: KeyframeRule = {};
const newCenter = coord(center[0], center[1]);
const pieandahalf = 1.5 * Math.PI;
const notmuchpie = Math.PI / 180;
const stepPercentage = 100 / opts.circleSteps;
const stepDegree = 360 / opts.circleSteps;
for (let i = 0; i <= opts.circleSteps; i += 1) {
const degree = stepDegree * i;
const radians = pieandahalf + degree * notmuchpie;
const newpos = getCirclePoint(radians, radius, newCenter);
points[`${Math.round(stepPercentage * i)}%`] = {
transform: `translate(${newpos.x}px,${newpos.y}px) ${opts.transform}`
};
}
for (const step in keyframeOptions) {
const rules = keyframeOptions[step];
for (const newstep in points) {
const newrules = points[newstep];
if (step === newstep) {
if (newrules.transform && rules.transform) {
points[
newstep
].transform = `${newrules.transform} ${rules.transform}`;
break;
}
}
}
}
return Object.assign({}, keyframeOptions, points);
};
if (isBrowser) {
const _window = window as any;
if (_window.Keyframes) {
_window.Keyframes.bezierPath = bezierPath;
_window.Keyframes.circlePath = circlePath;
}
}