1- import standards from '../../standards ' ;
1+ import { Colorjs } from '../../core/imports ' ;
22
33const hexRegex = / ^ # [ 0 - 9 a - f ] { 3 , 8 } $ / i;
4- const colorFnRegex = / ^ ( (?: r g b | h s l ) a ? ) \s * \( ( [ ^ \) ] * ) \) / i ;
4+ const hslRegex = / h s l \( \s * ( [ \d . ] + ) ( r a d | t u r n ) / ;
55
66/**
77 * @class Color
@@ -57,26 +57,35 @@ export default class Color {
5757 * @instance
5858 */
5959 parseString ( colorString ) {
60- // IE occasionally returns named colors instead of RGB(A) values
61- if ( standards . cssColors [ colorString ] || colorString === 'transparent' ) {
62- const [ red , green , blue ] = standards . cssColors [ colorString ] || [ 0 , 0 , 0 ] ;
63- this . red = red ;
64- this . green = green ;
65- this . blue = blue ;
66- this . alpha = colorString === 'transparent' ? 0 : 1 ;
67- return this ;
68- }
60+ // Colorjs currently does not support rad or turn angle values
61+ // @see https://github.com/LeaVerou/color.js/issues/311
62+ colorString = colorString . replace ( hslRegex , ( match , angle , unit ) => {
63+ const value = angle + unit ;
64+
65+ switch ( unit ) {
66+ case 'rad' :
67+ return match . replace ( value , radToDeg ( angle ) ) ;
68+ case 'turn' :
69+ return match . replace ( value , turnToDeg ( angle ) ) ;
70+ }
71+ } ) ;
6972
70- if ( colorString . match ( colorFnRegex ) ) {
71- this . parseColorFnString ( colorString ) ;
72- return this ;
73+ try {
74+ // srgb values are between 0 and 1
75+ const color = new Colorjs ( colorString ) . to ( 'srgb' ) ;
76+ // when converting from one color space to srgb
77+ // the values of rgb may be above 1 so we need to clamp them
78+ // we also need to round the final value as rgb values don't have decimals
79+ this . red = Math . round ( clamp ( color . r , 0 , 1 ) * 255 ) ;
80+ this . green = Math . round ( clamp ( color . g , 0 , 1 ) * 255 ) ;
81+ this . blue = Math . round ( clamp ( color . b , 0 , 1 ) * 255 ) ;
82+ // color.alpha is a Number object so convert it to a number
83+ this . alpha = + color . alpha ;
84+ } catch ( err ) {
85+ throw new Error ( `Unable to parse color "${ colorString } "` ) ;
7386 }
7487
75- if ( colorString . match ( hexRegex ) ) {
76- this . parseHexString ( colorString ) ;
77- return this ;
78- }
79- throw new Error ( `Unable to parse color "${ colorString } "` ) ;
88+ return this ;
8089 }
8190
8291 /**
@@ -88,15 +97,7 @@ export default class Color {
8897 * @param {string } rgb The string value
8998 */
9099 parseRgbString ( colorString ) {
91- // IE can pass transparent as value instead of rgba
92- if ( colorString === 'transparent' ) {
93- this . red = 0 ;
94- this . green = 0 ;
95- this . blue = 0 ;
96- this . alpha = 0 ;
97- return ;
98- }
99- this . parseColorFnString ( colorString ) ;
100+ this . parseString ( colorString ) ;
100101 }
101102
102103 /**
@@ -111,24 +112,8 @@ export default class Color {
111112 if ( ! colorString . match ( hexRegex ) || [ 6 , 8 ] . includes ( colorString . length ) ) {
112113 return ;
113114 }
114- colorString = colorString . replace ( '#' , '' ) ;
115- if ( colorString . length < 6 ) {
116- const [ r , g , b , a ] = colorString ;
117- colorString = r + r + g + g + b + b ;
118- if ( a ) {
119- colorString += a + a ;
120- }
121- }
122115
123- var aRgbHex = colorString . match ( / .{ 1 , 2 } / g) ;
124- this . red = parseInt ( aRgbHex [ 0 ] , 16 ) ;
125- this . green = parseInt ( aRgbHex [ 1 ] , 16 ) ;
126- this . blue = parseInt ( aRgbHex [ 2 ] , 16 ) ;
127- if ( aRgbHex [ 3 ] ) {
128- this . alpha = parseInt ( aRgbHex [ 3 ] , 16 ) / 255 ;
129- } else {
130- this . alpha = 1 ;
131- }
116+ this . parseString ( colorString ) ;
132117 }
133118
134119 /**
@@ -140,30 +125,7 @@ export default class Color {
140125 * @param {string } rgb The string value
141126 */
142127 parseColorFnString ( colorString ) {
143- const [ , colorFunc , colorValStr ] = colorString . match ( colorFnRegex ) || [ ] ;
144- if ( ! colorFunc || ! colorValStr ) {
145- return ;
146- }
147-
148- // Get array of color number strings from the string:
149- const colorVals = colorValStr
150- . split ( / \s * [ , \/ \s ] \s * / )
151- . map ( str => str . replace ( ',' , '' ) . trim ( ) )
152- . filter ( str => str !== '' ) ;
153-
154- // Convert to numbers
155- let colorNums = colorVals . map ( ( val , index ) => {
156- return convertColorVal ( colorFunc , val , index ) ;
157- } ) ;
158-
159- if ( colorFunc . substr ( 0 , 3 ) === 'hsl' ) {
160- colorNums = hslToRgb ( colorNums ) ;
161- }
162-
163- this . red = colorNums [ 0 ] ;
164- this . green = colorNums [ 1 ] ;
165- this . blue = colorNums [ 2 ] ;
166- this . alpha = typeof colorNums [ 3 ] === 'number' ? colorNums [ 3 ] : 1 ;
128+ this . parseString ( colorString ) ;
167129 }
168130
169131 /**
@@ -190,66 +152,17 @@ export default class Color {
190152 }
191153}
192154
193- /**
194- * Convert a CSS color value into a number
195- */
196- function convertColorVal ( colorFunc , value , index ) {
197- if ( / % $ / . test ( value ) ) {
198- //<percentage>
199- if ( index === 3 ) {
200- // alpha
201- return parseFloat ( value ) / 100 ;
202- }
203- return ( parseFloat ( value ) * 255 ) / 100 ;
204- }
205- if ( colorFunc [ index ] === 'h' ) {
206- // hue
207- if ( / t u r n $ / . test ( value ) ) {
208- return parseFloat ( value ) * 360 ;
209- }
210- if ( / r a d $ / . test ( value ) ) {
211- return parseFloat ( value ) * 57.3 ;
212- }
213- }
214- return parseFloat ( value ) ;
155+ // clamp a value between two numbers (inclusive)
156+ function clamp ( value , min , max ) {
157+ return Math . min ( Math . max ( min , value ) , max ) ;
215158}
216159
217- /**
218- * Convert HSL to RGB
219- */
220- function hslToRgb ( [ hue , saturation , lightness , alpha ] ) {
221- // Must be fractions of 1
222- saturation /= 255 ;
223- lightness /= 255 ;
224-
225- const high = ( 1 - Math . abs ( 2 * lightness - 1 ) ) * saturation ;
226- const low = high * ( 1 - Math . abs ( ( ( hue / 60 ) % 2 ) - 1 ) ) ;
227- const base = lightness - high / 2 ;
228-
229- let colors ;
230- if ( hue < 60 ) {
231- // red - yellow
232- colors = [ high , low , 0 ] ;
233- } else if ( hue < 120 ) {
234- // yellow - green
235- colors = [ low , high , 0 ] ;
236- } else if ( hue < 180 ) {
237- // green - cyan
238- colors = [ 0 , high , low ] ;
239- } else if ( hue < 240 ) {
240- // cyan - blue
241- colors = [ 0 , low , high ] ;
242- } else if ( hue < 300 ) {
243- // blue - purple
244- colors = [ low , 0 , high ] ;
245- } else {
246- // purple - red
247- colors = [ high , 0 , low ] ;
248- }
160+ // convert radians to degrees
161+ function radToDeg ( rad ) {
162+ return ( rad * 180 ) / Math . PI ;
163+ }
249164
250- return colors
251- . map ( color => {
252- return Math . round ( ( color + base ) * 255 ) ;
253- } )
254- . concat ( alpha ) ;
165+ // convert turn to degrees
166+ function turnToDeg ( turn ) {
167+ return turn * 360 ;
255168}
0 commit comments