@@ -10,7 +10,17 @@ const thisLayer = new Layer();
1010const 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+
1424type Rounding = [ number , number , number , number ] ;
1525
1626interface 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