11import type { vec3 , vec4 } from '@alleninstitute/vis-geometry' ;
22import { logger } from './logger' ;
33
4- const RGB_COLOR_REGEX = / ^ # ( [ 0 - 9 a - f A - F ] { 3 } | [ 0 - 9 a - f A - F ] { 6 } ) $ / ;
5- const RGBA_COLOR_REGEX = / ^ # ( [ 0 - 9 a - f A - F ] { 4 } | [ 0 - 9 a - f A - F ] { 8 } ) $ / ;
4+ // Tests for optional #, then 3 or 6 hex digits
5+ const RGB_COLOR_REGEX = / ^ # ? ( [ 0 - 9 a - f A - F ] { 3 } | [ 0 - 9 a - f A - F ] { 6 } ) $ / ;
6+ // Tests for optional #, then 4 or 8 hex digits
7+ const RGBA_COLOR_REGEX = / ^ # ? ( [ 0 - 9 a - f A - F ] { 4 } | [ 0 - 9 a - f A - F ] { 8 } ) $ / ;
68
9+ /**
10+ * Converts a color hash string to a vec3 RGB color vector.
11+ *
12+ * @param colorHashStr A string representing a color in hex format, e.g., '#f00' or 'ff0000'.
13+ * @param normalized A boolean indicating whether to normalize the color values to the range [0, 1]. Defaults to true.
14+ * @returns A vec3 array representing the RGB color vector. If the input is invalid, returns [0, 0, 0].
15+ */
716export function makeRGBColorVector ( colorHashStr : string , normalized = true ) : vec3 {
817 if ( ! colorHashStr || ! RGB_COLOR_REGEX . test ( colorHashStr ) ) {
918 logger . warn ( 'invalid color hash string; returning black color vector (0, 0, 0)' ) ;
1019 return [ 0 , 0 , 0 ] ;
1120 }
21+ const hasHash = colorHashStr . charAt ( 0 ) === '#' ;
22+ const sanitizedColorHashStr = hasHash ? colorHashStr : `#${ colorHashStr } ` ;
23+
1224 const redCode =
13- colorHashStr . length === 4 ? colorHashStr . charAt ( 1 ) + colorHashStr . charAt ( 1 ) : colorHashStr . slice ( 1 , 3 ) ;
25+ sanitizedColorHashStr . length === 4
26+ ? sanitizedColorHashStr . charAt ( 1 ) + sanitizedColorHashStr . charAt ( 1 )
27+ : sanitizedColorHashStr . slice ( 1 , 3 ) ;
1428 const greenCode =
15- colorHashStr . length === 4 ? colorHashStr . charAt ( 2 ) + colorHashStr . charAt ( 2 ) : colorHashStr . slice ( 3 , 5 ) ;
29+ sanitizedColorHashStr . length === 4
30+ ? sanitizedColorHashStr . charAt ( 2 ) + sanitizedColorHashStr . charAt ( 2 )
31+ : sanitizedColorHashStr . slice ( 3 , 5 ) ;
1632 const blueCode =
17- colorHashStr . length === 4 ? colorHashStr . charAt ( 3 ) + colorHashStr . charAt ( 3 ) : colorHashStr . slice ( 5 , 7 ) ;
33+ sanitizedColorHashStr . length === 4
34+ ? sanitizedColorHashStr . charAt ( 3 ) + sanitizedColorHashStr . charAt ( 3 )
35+ : sanitizedColorHashStr . slice ( 5 , 7 ) ;
36+
1837 const divisor = normalized ? 255 : 1 ;
1938 return [
2039 Number . parseInt ( redCode , 16 ) / divisor ,
@@ -23,20 +42,39 @@ export function makeRGBColorVector(colorHashStr: string, normalized = true): vec
2342 ] ;
2443}
2544
45+ /**
46+ * Converts a color hash string to a vec4 RGBA color vector.
47+ *
48+ * @param colorHashStr A string representing a color in hex format, e.g., '#f00f' or 'ff0000ff'.
49+ * @param normalized A boolean indicating whether to normalize the color values to the range [0, 1]. Defaults to true.
50+ * @returns A vec3 array representing the RGB color vector. If the input is invalid, returns [0, 0, 0, 0].
51+ */
2652export function makeRGBAColorVector ( colorHashStr : string , normalized = true ) : vec4 {
2753 if ( ! colorHashStr ) {
2854 logger . warn ( 'invalid color hash string; returning transparent black color vector (0, 0, 0, 0)' ) ;
2955 return [ 0 , 0 , 0 , 0 ] ;
3056 }
57+
3158 if ( RGBA_COLOR_REGEX . test ( colorHashStr ) ) {
59+ const hashHash = colorHashStr . charAt ( 0 ) === '#' ;
60+ const sanitizedColorHashStr = hashHash ? colorHashStr : `#${ colorHashStr } ` ;
61+
3262 const redCode =
33- colorHashStr . length === 5 ? colorHashStr . charAt ( 1 ) + colorHashStr . charAt ( 1 ) : colorHashStr . slice ( 1 , 3 ) ;
63+ sanitizedColorHashStr . length === 5
64+ ? sanitizedColorHashStr . charAt ( 1 ) + sanitizedColorHashStr . charAt ( 1 )
65+ : sanitizedColorHashStr . slice ( 1 , 3 ) ;
3466 const greenCode =
35- colorHashStr . length === 5 ? colorHashStr . charAt ( 2 ) + colorHashStr . charAt ( 2 ) : colorHashStr . slice ( 3 , 5 ) ;
67+ sanitizedColorHashStr . length === 5
68+ ? sanitizedColorHashStr . charAt ( 2 ) + sanitizedColorHashStr . charAt ( 2 )
69+ : sanitizedColorHashStr . slice ( 3 , 5 ) ;
3670 const blueCode =
37- colorHashStr . length === 5 ? colorHashStr . charAt ( 3 ) + colorHashStr . charAt ( 3 ) : colorHashStr . slice ( 5 , 7 ) ;
71+ sanitizedColorHashStr . length === 5
72+ ? sanitizedColorHashStr . charAt ( 3 ) + sanitizedColorHashStr . charAt ( 3 )
73+ : sanitizedColorHashStr . slice ( 5 , 7 ) ;
3874 const alphaCode =
39- colorHashStr . length === 5 ? colorHashStr . charAt ( 4 ) + colorHashStr . charAt ( 4 ) : colorHashStr . slice ( 7 , 9 ) ;
75+ sanitizedColorHashStr . length === 5
76+ ? sanitizedColorHashStr . charAt ( 4 ) + sanitizedColorHashStr . charAt ( 4 )
77+ : sanitizedColorHashStr . slice ( 7 , 9 ) ;
4078 const divisor = normalized ? 255 : 1 ;
4179 return [
4280 Number . parseInt ( redCode , 16 ) / divisor ,
@@ -46,8 +84,8 @@ export function makeRGBAColorVector(colorHashStr: string, normalized = true): ve
4684 ] ;
4785 }
4886 if ( RGB_COLOR_REGEX . test ( colorHashStr ) ) {
49- const rgb = makeRGBColorVector ( colorHashStr ) ;
50- return [ rgb [ 0 ] , rgb [ 1 ] , rgb [ 2 ] , normalized ? 1.0 : 255.0 ] ;
87+ const rgb = makeRGBColorVector ( colorHashStr , normalized ) ;
88+ return [ ... rgb , normalized ? 1.0 : 255.0 ] ;
5189 }
5290 logger . warn ( 'invalid color hash string; returning transparent black color vector (0, 0, 0, 0)' ) ;
5391 return [ 0 , 0 , 0 , 0 ] ;
0 commit comments