Skip to content

Commit d7d7a77

Browse files
committed
convert scaling function to work for more anchors
1 parent e9d386a commit d7d7a77

File tree

1 file changed

+157
-80
lines changed

1 file changed

+157
-80
lines changed

src/index.ts

Lines changed: 157 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,17 @@ const thisLayer = new Layer();
1010
const thisProperty = new PathProperty([[0, 0]]);
1111

1212
// eBox types
13-
type Anchor = 'topLeft' | 'topRight' | 'bottomRight' | 'bottomLeft' | 'center';
13+
type Anchor =
14+
| 'topLeft'
15+
| 'topCenter'
16+
| 'topRight'
17+
| 'bottomRight'
18+
| 'bottomCenter'
19+
| 'bottomLeft'
20+
| 'centerLeft'
21+
| 'center'
22+
| 'centerRight';
23+
1424
type Rounding = [number, number, number, number];
1525

1626
interface BoxProps {
@@ -41,55 +51,116 @@ function createBox({
4151
function scaleBoxPoints(scale: Vector2D, anchor: Anchor): void {
4252
// Remap scale to [0..1]
4353
const normalizedScale: Vector2D = scale.map(
44-
scale => scale / 100
54+
(scale) => scale / 100
4555
) as Vector2D;
4656

47-
// Get index of anchor point
48-
const pointOrder: Anchor[] = [
49-
'topLeft',
50-
'topRight',
51-
'bottomRight',
52-
'bottomLeft',
53-
];
54-
const anchorPointIndex: number = pointOrder.indexOf(anchor);
55-
const anchorPoint: Vector2D = boxPoints[anchorPointIndex];
57+
const [pTl, pTr, pBr, pBl] = boxPoints;
58+
const boxWidth = pTr[0] - pTl[0];
59+
const boxHeight = pBr[1] - pTl[1];
60+
const boxCenter = thisLayer.add(pTl, [boxWidth / 2, boxHeight / 2]);
5661

57-
// Calculate distance from anchor point
58-
const pointDeltas: Points = boxPoints.map(point => {
59-
return point.map((dimension, dimensionIndex): number => {
60-
return dimension - anchorPoint[dimensionIndex];
61-
}) as Vector2D;
62-
}) as Points;
62+
// Get offsets from center for each point
63+
const deltasFromCenter = boxPoints.map((point) =>
64+
thisLayer.sub(point, boxCenter)
65+
);
66+
67+
boxPoints = getScaledDeltas().map((delta) =>
68+
thisLayer.add(boxCenter, delta)
69+
);
70+
71+
function getScaledDeltas() {
72+
const [dTl, dTr, dBr, dBl] = deltasFromCenter;
73+
const [sx, sy] = normalizedScale;
74+
75+
/**
76+
* Used to multiply a delta so it scales not to zero,
77+
* but to -1, for scaling from corner anchors
78+
*/
79+
const doubleMult = (val: number, mul: number) => val * (2 * mul - 1);
80+
81+
if (anchor === 'topLeft') {
82+
const sTl = dTl;
83+
const sTr = [doubleMult(dTr[0], sx), dTr[1]];
84+
const sBr = [doubleMult(dBr[0], sx), doubleMult(dBr[1], sy)];
85+
const sBl = [dBl[0], doubleMult(dBl[1], sy)];
86+
87+
return [sTl, sTr, sBr, sBl];
88+
}
89+
90+
if (anchor === 'topRight') {
91+
const sTl = [doubleMult(dTl[0], sx), dTl[1]];
92+
const sTr = dTr;
93+
const sBr = [dBr[0], doubleMult(dBr[1], sy)];
94+
const sBl = [doubleMult(dBl[0], sx), doubleMult(dBl[1], sy)];
6395

64-
// Scale the point deltas according to input scale
65-
const scaledPointDeltas: Points = pointDeltas.map(
66-
(point): Vector2D => {
67-
return point.map((dimension, dimensionIndex): number => {
68-
return dimension * normalizedScale[dimensionIndex];
69-
}) as Vector2D;
96+
return [sTl, sTr, sBr, sBl];
7097
}
71-
) as Points;
72-
73-
const scaledPoints: Points = boxPoints.map(
74-
(point, pointIndex): Vector2D => {
75-
if (pointIndex !== anchorPointIndex) {
76-
// If not the anchor point
77-
// Create the point from the scaledPointDelta
78-
return point.map((pointDimension, dimensionIndex): number => {
79-
return (
80-
anchorPoint[dimensionIndex] +
81-
scaledPointDeltas[pointIndex][dimensionIndex]
82-
);
83-
}) as Vector2D;
84-
} else {
85-
// If the anchor point
86-
// Return as is
87-
return point;
88-
}
98+
99+
if (anchor === 'topCenter') {
100+
const sTl = [dTl[0] * sx, dTl[1]];
101+
const sTr = [dTr[0] * sx, dTr[1]];
102+
const sBr = [dBr[0] * sx, doubleMult(dBr[1], sy)];
103+
const sBl = [dBl[0] * sx, doubleMult(dBl[1], sy)];
104+
105+
return [sTl, sTr, sBr, sBl];
89106
}
90-
) as Points;
91107

92-
boxPoints = scaledPoints;
108+
if (anchor === 'bottomRight') {
109+
const sTl = [doubleMult(dTl[0], sx), doubleMult(dTl[1], sy)];
110+
const sTr = [dTr[0], doubleMult(dTr[1], sy)];
111+
const sBr = dBr;
112+
const sBl = [doubleMult(dBl[0], sx), dBl[1]];
113+
114+
return [sTl, sTr, sBr, sBl];
115+
}
116+
117+
if (anchor === 'bottomLeft') {
118+
const sTl = [dTl[0], doubleMult(dTl[1], sy)];
119+
const sTr = [doubleMult(dTr[0], sx), doubleMult(dTr[1], sy)];
120+
const sBr = [doubleMult(dBr[0], sx), dBr[1]];
121+
const sBl = dBl;
122+
123+
return [sTl, sTr, sBr, sBl];
124+
}
125+
126+
if (anchor === 'bottomCenter') {
127+
const sTl = [dTl[0] * sx, doubleMult(dTl[1], sy)];
128+
const sTr = [dTr[0] * sx, doubleMult(dTr[1], sy)];
129+
const sBr = [dBr[0] * sx, dBr[1]];
130+
const sBl = [dBl[0] * sx, dBl[1]];
131+
132+
return [sTl, sTr, sBr, sBl];
133+
}
134+
135+
if (anchor === 'centerLeft') {
136+
const sTl = [dTl[0], dTl[1] * sy];
137+
const sTr = [doubleMult(dTr[0], sx), dTr[1] * sy];
138+
const sBr = [doubleMult(dBr[0], sx), dBr[1] * sy];
139+
const sBl = [dBl[0], dBl[1] * sy];
140+
141+
return [sTl, sTr, sBr, sBl];
142+
}
143+
144+
if (anchor === 'centerRight') {
145+
const sTl = [doubleMult(dTl[0], sx), dTl[1] * sy];
146+
const sTr = [dTr[0], dTr[1] * sy];
147+
const sBr = [dBr[0], dBr[1] * sy];
148+
const sBl = [doubleMult(dBl[0], sx), dBl[1] * sy];
149+
150+
return [sTl, sTr, sBr, sBl];
151+
}
152+
153+
/**
154+
* anchor === 'center'
155+
* no doubling needed, just scale
156+
* each delta
157+
*/
158+
return deltasFromCenter.map((delta) => {
159+
return delta.map((dimension, index) => {
160+
return dimension * normalizedScale[index];
161+
});
162+
});
163+
}
93164
}
94165

95166
function getRoundedPathForPoints(points: Points) {
@@ -98,7 +169,7 @@ function createBox({
98169
const width = pTr[0] - pTl[0];
99170
const height = pBl[1] - pTl[1];
100171

101-
const [rTl, rTr, rBr, rBl] = rounding.map(radius => {
172+
const [rTl, rTr, rBr, rBl] = rounding.map((radius) => {
102173
const minDimension = Math.min(width, height);
103174
return Math.max(Math.min(minDimension / 2, radius), 0);
104175
});
@@ -118,35 +189,39 @@ function createBox({
118189
thisLayer.add(pBl, [0, -rBl]),
119190
];
120191

121-
const inTangents = ([
122-
// Top left
123-
[0, 0],
124-
[-rTl, 0],
125-
// Top right
126-
[0, 0],
127-
[0, -rTr],
128-
// Bottom right
129-
[0, 0],
130-
[rBr, 0],
131-
// Bottom left
132-
[0, 0],
133-
[0, rBl],
134-
] as Vector2D[]).map(p => thisLayer.mul(p, tangentMult));
192+
const inTangents = (
193+
[
194+
// Top left
195+
[0, 0],
196+
[-rTl, 0],
197+
// Top right
198+
[0, 0],
199+
[0, -rTr],
200+
// Bottom right
201+
[0, 0],
202+
[rBr, 0],
203+
// Bottom left
204+
[0, 0],
205+
[0, rBl],
206+
] as Vector2D[]
207+
).map((p) => thisLayer.mul(p, tangentMult));
135208

136-
const outTangents = ([
137-
// Top left
138-
[0, -rTl],
139-
[0, 0],
140-
// Top right
141-
[rTr, 0],
142-
[0, 0],
143-
// Bottom right
144-
[0, rBr],
145-
[0, 0],
146-
// Bottom left
147-
[-rBl, 0],
148-
[0, 0],
149-
] as Vector2D[]).map(p => thisLayer.mul(p, tangentMult));
209+
const outTangents = (
210+
[
211+
// Top left
212+
[0, -rTl],
213+
[0, 0],
214+
// Top right
215+
[rTr, 0],
216+
[0, 0],
217+
// Bottom right
218+
[0, rBr],
219+
[0, 0],
220+
// Bottom left
221+
[-rBl, 0],
222+
[0, 0],
223+
] as Vector2D[]
224+
).map((p) => thisLayer.mul(p, tangentMult));
150225

151226
return thisProperty.createPath(
152227
cornerPoints,
@@ -167,19 +242,23 @@ function createBox({
167242
anchor: Anchor
168243
): Vector2D {
169244
const positionCalculations = {
170-
center: (): Vector2D => position,
171245
topLeft: (): Vector2D => [
172246
position[0] + size[0] / 2,
173247
position[1] + size[1] / 2,
174248
],
249+
topCenter: (): Vector2D => [position[0], position[1] + size[1] / 2],
175250
topRight: (): Vector2D => [
176251
position[0] - size[0] / 2,
177252
position[1] + size[1] / 2,
178253
],
254+
centerLeft: (): Vector2D => [position[0] + size[1] / 2, position[1]],
255+
center: (): Vector2D => position,
256+
centerRight: (): Vector2D => [position[0] - size[1] / 2, position[1]],
179257
bottomLeft: (): Vector2D => [
180258
position[0] + size[0] / 2,
181259
position[1] - size[1] / 2,
182260
],
261+
bottomCenter: (): Vector2D => [position[0], position[1] - size[1] / 2],
183262
bottomRight: (): Vector2D => [
184263
position[0] - size[0] / 2,
185264
position[1] - size[1] / 2,
@@ -209,13 +288,11 @@ function createBox({
209288
}
210289
) as Vector2D;
211290

212-
return points.map(
213-
(point: Vector2D): Vector2D => {
214-
return point.map((dimension, dimensionIndex) => {
215-
return dimension + positionDelta[dimensionIndex];
216-
}) as Vector2D;
217-
}
218-
) as Points;
291+
return points.map((point: Vector2D): Vector2D => {
292+
return point.map((dimension, dimensionIndex) => {
293+
return dimension + positionDelta[dimensionIndex];
294+
}) as Vector2D;
295+
}) as Points;
219296
}
220297

221298
function pointsToComp(points: Points): Points {

0 commit comments

Comments
 (0)