Skip to content

Commit 164feec

Browse files
authored
Merge pull request #2 from motiondeveloper/typescript
Typescript migration
2 parents f4ed618 + d097e66 commit 164feec

File tree

5 files changed

+369
-0
lines changed

5 files changed

+369
-0
lines changed

package-lock.json

Lines changed: 134 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"name": "ebox",
3+
"version": "1.0.0",
4+
"description": "Create rectangles within After Effects expressions ",
5+
"main": "src/index.ts",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1",
8+
"tsc": "tsc",
9+
"build": "rollup -c",
10+
"watch": "rollup -cw",
11+
"release": "hub release create -a 'dist/eKeys.jsx"
12+
},
13+
"repository": {
14+
"type": "git",
15+
"url": "git+https://github.com/motiondeveloper/ebox.git"
16+
},
17+
"author": "Tim Haywood",
18+
"license": "MIT",
19+
"bugs": {
20+
"url": "https://github.com/motiondeveloper/ebox/issues"
21+
},
22+
"homepage": "https://github.com/motiondeveloper/ebox#readme",
23+
"devDependencies": {
24+
"@rollup/plugin-typescript": "^5.0.2",
25+
"prettier": "^1.16.4",
26+
"rollup": "^2.26.3",
27+
"rollup-plugin-ae-jsx": "^1.1.3",
28+
"tslib": "^2.0.1",
29+
"typescript": "^3.9.7"
30+
},
31+
"dependencies": {
32+
"expression-globals-typescript": "^1.1.1"
33+
}
34+
}

prettier.config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
trailingComma: "es5",
3+
singleQuote: true,
4+
};

rollup.config.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import typescript from '@rollup/plugin-typescript';
2+
import afterEffectJsx from 'rollup-plugin-ae-jsx';
3+
4+
export default {
5+
input: 'src/index.ts',
6+
output: {
7+
file: 'dist/eBox.jsx',
8+
format: 'cjs',
9+
},
10+
plugins: [
11+
typescript({
12+
module: 'esnext',
13+
target: 'esnext',
14+
noImplicitAny: true,
15+
moduleResolution: 'node',
16+
strict: true,
17+
lib: ['esnext'],
18+
}),
19+
afterEffectJsx(),
20+
],
21+
};

src/index.ts

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
import {
2+
LayerBase,
3+
PropertyBase,
4+
Vector2D,
5+
Points,
6+
} from 'expression-globals-typescript';
7+
8+
// Creating layer and property mocks
9+
const thisLayer = Object.create(LayerBase);
10+
const thisProperty = Object.create(PropertyBase);
11+
12+
// eBox types
13+
type Anchor = 'topLeft' | 'topRight' | 'bottomRight' | 'bottomLeft' | 'center';
14+
interface BoxProps {
15+
size: Vector2D;
16+
position: Vector2D;
17+
anchor: Anchor;
18+
isClosed: boolean;
19+
}
20+
21+
function createBox({
22+
size = [100, 100],
23+
position = [0, 0],
24+
anchor = 'center',
25+
isClosed = true,
26+
}: BoxProps) {
27+
const pointOrder: Anchor[] = [
28+
'topLeft',
29+
'topRight',
30+
'bottomRight',
31+
'bottomLeft',
32+
];
33+
34+
function positionToCenter(
35+
position: Vector2D,
36+
size: Vector2D,
37+
anchor: Anchor
38+
): Vector2D {
39+
const positionCalculations = {
40+
center: (): Vector2D => position,
41+
topLeft: (): Vector2D => [
42+
position[0] + size[0] / 2,
43+
position[1] + size[1] / 2,
44+
],
45+
topRight: (): Vector2D => [
46+
position[0] - size[0] / 2,
47+
position[1] + size[1] / 2,
48+
],
49+
bottomLeft: (): Vector2D => [
50+
position[0] + size[0] / 2,
51+
position[1] - size[1] / 2,
52+
],
53+
bottomRight: (): Vector2D => [
54+
position[0] - size[0] / 2,
55+
position[1] - size[1] / 2,
56+
],
57+
};
58+
59+
return positionCalculations[anchor]();
60+
}
61+
62+
function sizeToPoints(size: Vector2D): Points {
63+
return [
64+
[-size[0] / 2, -size[1] / 2],
65+
[size[0] / 2, -size[1] / 2],
66+
[size[0] / 2, size[1] / 2],
67+
[-size[0] / 2, size[1] / 2],
68+
];
69+
}
70+
function movePoints(
71+
points: Points,
72+
oldPosition: Vector2D,
73+
newPosition: Vector2D
74+
): Points {
75+
const positionDelta: Vector2D = newPosition.map(
76+
(dimension, dimensionIndex): number => {
77+
return dimension - oldPosition[dimensionIndex];
78+
}
79+
) as Vector2D;
80+
81+
return points.map(
82+
(point: Vector2D): Vector2D => {
83+
return point.map((dimension, dimensionIndex) => {
84+
return dimension + positionDelta[dimensionIndex];
85+
}) as Vector2D;
86+
}
87+
) as Points;
88+
}
89+
90+
function pointsToComp(points: Points): Points {
91+
return points.map(
92+
(point): Vector2D => thisLayer.fromCompToSurface(point) as Vector2D
93+
) as Points;
94+
}
95+
function pointsToPath(points: Points, isClosed: boolean) {
96+
return thisProperty.createPath(points, [], [], isClosed);
97+
}
98+
99+
const centerPosition = positionToCenter(position, size, anchor);
100+
interface OutputBox extends BoxProps {
101+
centerPosition: Vector2D;
102+
}
103+
let boxPoints: Points = createPointsFromBoxProps({
104+
size,
105+
position,
106+
anchor,
107+
isClosed,
108+
centerPosition,
109+
});
110+
111+
function getBoxPath() {
112+
return pointsToPath(boxPoints, isClosed);
113+
}
114+
function createPointsFromBoxProps(boxProps: OutputBox): Points {
115+
const points = sizeToPoints(boxProps.size);
116+
const centeredPoints = movePoints(points, [0, 0], boxProps.centerPosition);
117+
const compPositionPoints = pointsToComp(centeredPoints);
118+
119+
return compPositionPoints;
120+
}
121+
122+
function scalePoints(scale: Vector2D = [100, 100], anchor: Anchor): void {
123+
// Remap scale to [0..1]
124+
const normalizedScale: Vector2D = scale.map(
125+
scale => scale / 100
126+
) as Vector2D;
127+
128+
// Get index of anchor point
129+
const anchorPointIndex: number = pointOrder.indexOf(anchor);
130+
const anchorPoint: Vector2D = boxPoints[anchorPointIndex];
131+
132+
// Calculate distance from anchor point
133+
const pointDeltas: Points = boxPoints.map(point => {
134+
return point.map((dimension, dimensionIndex): number => {
135+
return dimension - anchorPoint[dimensionIndex];
136+
}) as Vector2D;
137+
}) as Points;
138+
139+
// Scale the point deltas according to input scale
140+
const scaledPointDeltas: Points = pointDeltas.map(
141+
(point): Vector2D => {
142+
return point.map((dimension, dimensionIndex): number => {
143+
return dimension * normalizedScale[dimensionIndex];
144+
}) as Vector2D;
145+
}
146+
) as Points;
147+
148+
const scaledPoints: Points = boxPoints.map(
149+
(point, pointIndex): Vector2D => {
150+
if (pointIndex !== anchorPointIndex) {
151+
// If not the anchor point
152+
// Create the point from the scaledPointDelta
153+
return point.map((pointDimension, dimensionIndex): number => {
154+
return (
155+
anchorPoint[dimensionIndex] +
156+
scaledPointDeltas[pointIndex][dimensionIndex]
157+
);
158+
}) as Vector2D;
159+
} else {
160+
// If the anchor point
161+
// Return as is
162+
return point;
163+
}
164+
}
165+
) as Points;
166+
167+
boxPoints = scaledPoints;
168+
}
169+
170+
return {
171+
setScale: scalePoints,
172+
getPath: getBoxPath,
173+
};
174+
}
175+
176+
export { createBox };

0 commit comments

Comments
 (0)