2
2
TODO: write tests (lazy) like always right? <3
3
3
*/
4
4
const parser = require ( "gradient-parser" ) ;
5
+ const memoize = require ( "fast-memoize" ) ;
5
6
6
7
const getColor = color => {
7
8
switch ( color . type ) {
@@ -14,27 +15,23 @@ const getColor = color => {
14
15
}
15
16
} ;
16
17
17
- const getColorsAndLocations = ( colorStops , maxWidth ) =>
18
+ const getColorsAndLocations = memoize ( ( colorStops , maxWidth ) =>
18
19
colorStops . reduce (
19
20
( acc , color , index ) => {
20
21
acc . colors = [ ...acc . colors , getColor ( color ) ] ;
21
22
22
23
// PX value for location will break!
23
24
// TODO Make it happen for px + repeat?
24
- const locationValue = getPixelsForColor (
25
- color ,
26
- colorStops . length ,
27
- index ,
28
- maxWidth
29
- ) ;
25
+ const locationValue = getPixelsForColor ( color , colorStops . length , index , maxWidth ) ;
30
26
acc [ "locations" ] = [ ...acc . locations , locationValue ] ;
31
27
32
28
return acc ;
33
29
} ,
34
30
{ colors : [ ] , locations : [ ] }
35
- ) ;
31
+ )
32
+ ) ;
36
33
37
- const getPixelsForColor = ( color , colorsLength , index , maxWidth ) => {
34
+ const getPixelsForColor = memoize ( ( color , colorsLength , index , maxWidth ) => {
38
35
const { length } = color ;
39
36
if ( ! length ) {
40
37
return ( 1 / ( colorsLength - 1 ) ) * index ;
@@ -49,33 +46,30 @@ const getPixelsForColor = (color, colorsLength, index, maxWidth) => {
49
46
return length . value / 100 ;
50
47
}
51
48
}
52
- } ;
49
+ } ) ;
50
+
53
51
const getRepeatingColorsAndLocations = ( colorStops , sizes ) => {
54
52
const { width : maxWidth , height : maxHeight } = sizes ;
55
-
56
- if ( ! maxWidth && ! maxHeight ) {
57
- throw new Error (
58
- "You have to define width and height for repeating gradient to work"
59
- ) ;
60
- }
61
-
62
- const {
63
- colors : initialColors ,
64
- locations : initialLocations
65
- } = getColorsAndLocations ( colorStops , maxWidth ) ;
53
+ const { colors : initialColors , locations : initialLocations } = getColorsAndLocations ( colorStops , maxWidth ) ;
66
54
const maxValue = parseFloat ( initialLocations . slice ( - 1 ) [ 0 ] ) ;
67
55
const increment = maxValue / maxWidth ;
68
- const maxChunks = Math . round ( maxWidth / maxValue ) + 1 ;
56
+ // we need to add +1 but this is breaking LinearGradient, maybe can't render
57
+ // it outside the viewport.
58
+ const maxChunks = Math . round ( maxWidth / maxValue ) ;
69
59
const locations = [ ...Array ( maxChunks ) . keys ( ) ] . reduce ( ( acc , i ) => {
70
- return [ ...acc , ...initialLocations . map ( j => j / maxWidth + increment * i ) ] ;
60
+ return [
61
+ ...acc ,
62
+ ...initialLocations . map ( j => {
63
+ return j / maxWidth + increment * i ;
64
+ } )
65
+ ] ;
71
66
} , [ ] ) ;
72
- const colors = locations . map (
73
- ( _ , i ) => initialColors [ i % initialColors . length ]
74
- ) ;
67
+ const colors = locations . map ( ( _ , i ) => initialColors [ i % initialColors . length ] ) ;
75
68
76
- return { locations , colors } ;
69
+ return { colors , locations } ;
77
70
} ;
78
- const getVectorsByDirection = direction => {
71
+
72
+ const getVectorsByDirection = memoize ( direction => {
79
73
switch ( direction ) {
80
74
case "top" :
81
75
return getVectorsByAngle ( 0 ) ;
@@ -94,35 +88,39 @@ const getVectorsByDirection = direction => {
94
88
case "right bottom" :
95
89
return getVectorsByAngle ( 90 + 45 ) ;
96
90
}
97
- } ;
98
- const round = number => Math . round ( number * 1000 ) / 1000 ;
99
- const degreesToRadians = function ( degrees ) {
100
- return ( degrees * Math . PI ) / 180 ;
101
- } ;
102
- const getVectorsByAngle = alfa => {
91
+ } ) ;
92
+
93
+ const round = memoize ( number => Math . round ( number * 10000 ) / 10000 ) ;
94
+ const degreesToRadians = memoize ( degrees => ( degrees * Math . PI ) / 180 ) ;
95
+
96
+ const getVectorsByAngle = memoize ( alfa => {
103
97
const angle = degreesToRadians ( alfa ) ;
104
98
105
- let gradientLineLength = round (
106
- Math . abs ( Math . sin ( angle ) ) + Math . abs ( Math . cos ( angle ) )
107
- ) ;
99
+ let gradientLineLength = round ( Math . abs ( Math . sin ( angle ) ) + Math . abs ( Math . cos ( angle ) ) ) ;
108
100
let center = { x : 0.5 , y : 0.5 } ;
109
101
110
102
let yDiff = ( Math . sin ( angle - Math . PI / 2 ) * gradientLineLength ) / 2 ;
111
103
let xDiff = ( Math . cos ( angle - Math . PI / 2 ) * gradientLineLength ) / 2 ;
112
104
113
105
return {
114
- start : [ center . x - xDiff , center . y - yDiff ] ,
115
- end : [ center . x + xDiff , center . y + yDiff ]
106
+ start : {
107
+ x : center . x - xDiff ,
108
+ y : center . y - yDiff
109
+ } ,
110
+ end : {
111
+ x : center . x + xDiff ,
112
+ y : center . y + yDiff
113
+ }
116
114
} ;
117
- } ;
115
+ } ) ;
118
116
119
117
const getVectorsByOrientation = orientation => {
120
118
return orientation . type === "directional"
121
119
? getVectorsByDirection ( orientation . value )
122
120
: getVectorsByAngle ( orientation . value ) ;
123
121
} ;
124
122
125
- const generateGradient = ( gradient , sizes ) => {
123
+ const generateGradient = memoize ( ( gradient , sizes ) => {
126
124
return parser . parse ( gradient ) . map ( ( { type, colorStops, orientation } ) => {
127
125
// YOLO: Radial gradients <3
128
126
if ( type === "radial-gradient" ) {
@@ -138,6 +136,6 @@ const generateGradient = (gradient, sizes) => {
138
136
...getVectorsByOrientation ( orientation )
139
137
} ;
140
138
} ) ;
141
- } ;
139
+ } ) ;
142
140
143
141
export default generateGradient ;
0 commit comments