@@ -44,18 +44,23 @@ class Color {
44
44
45
45
static colorMap = { } ;
46
46
static #colorjsMaxes = { } ;
47
+ static #grayscaleMap = { } ;
47
48
48
49
// Used to add additional color modes to p5.js
49
50
// Uses underlying library's definition
50
51
static addColorMode ( mode , definition ) {
51
52
ColorSpace . register ( definition ) ;
52
53
Color . colorMap [ mode ] = definition . id ;
54
+
53
55
// Get colorjs maxes
54
56
Color . #colorjsMaxes[ mode ] = Object . values ( definition . coords ) . reduce ( ( acc , v ) => {
55
57
acc . push ( v . refRange || v . range ) ;
56
58
return acc ;
57
59
} , [ ] ) ;
58
60
Color . #colorjsMaxes[ mode ] . push ( [ 0 , 1 ] ) ;
61
+
62
+ // Get grayscale mapping
63
+ Color . #grayscaleMap[ mode ] = definition . fromGray ;
59
64
}
60
65
61
66
constructor ( vals , colorMode , colorMaxes ) {
@@ -99,15 +104,38 @@ class Color {
99
104
let mappedVals ;
100
105
101
106
if ( colorMaxes ) {
107
+ // NOTE: need to consider different number of arguments (eg. CMYK)
102
108
if ( vals . length === 4 ) {
103
109
mappedVals = Color . mapColorRange ( vals , this . mode , colorMaxes ) ;
104
110
} else if ( vals . length === 3 ) {
105
111
mappedVals = Color . mapColorRange ( [ vals [ 0 ] , vals [ 1 ] , vals [ 2 ] ] , this . mode , colorMaxes ) ;
106
112
mappedVals . push ( 1 ) ;
107
113
} else if ( vals . length === 2 ) {
108
- mappedVals = Color . mapColorRange ( [ vals [ 0 ] , vals [ 0 ] , vals [ 0 ] , vals [ 1 ] ] , this . mode , colorMaxes ) ;
114
+ // Grayscale with alpha
115
+ if ( Color . #grayscaleMap[ this . mode ] ) {
116
+ mappedVals = Color . #grayscaleMap[ this . mode ] ( vals [ 0 ] , colorMaxes ) ;
117
+ } else {
118
+ mappedVals = Color . mapColorRange ( [ vals [ 0 ] , vals [ 0 ] , vals [ 0 ] ] , this . mode , colorMaxes ) ;
119
+ }
120
+ const alphaMaxes = Array . isArray ( colorMaxes [ colorMaxes . length - 1 ] ) ?
121
+ colorMaxes [ colorMaxes . length - 1 ] :
122
+ [ 0 , colorMaxes [ colorMaxes . length - 1 ] ] ;
123
+ mappedVals . push (
124
+ map (
125
+ vals [ 1 ] ,
126
+ alphaMaxes [ 0 ] ,
127
+ alphaMaxes [ 1 ] ,
128
+ 0 ,
129
+ 1
130
+ )
131
+ ) ;
109
132
} else if ( vals . length === 1 ) {
110
- mappedVals = Color . mapColorRange ( [ vals [ 0 ] , vals [ 0 ] , vals [ 0 ] ] , this . mode , colorMaxes ) ;
133
+ // Grayscale only
134
+ if ( Color . #grayscaleMap[ this . mode ] ) {
135
+ mappedVals = Color . #grayscaleMap[ this . mode ] ( vals [ 0 ] , colorMaxes ) ;
136
+ } else {
137
+ mappedVals = Color . mapColorRange ( [ vals [ 0 ] , vals [ 0 ] , vals [ 0 ] ] , this . mode , colorMaxes ) ;
138
+ }
111
139
mappedVals . push ( 1 ) ;
112
140
} else {
113
141
throw new Error ( 'Invalid color' ) ;
@@ -652,6 +680,78 @@ function color(p5, fn, lifecycles){
652
680
*/
653
681
p5 . Color = Color ;
654
682
683
+ sRGB . fromGray = P3 . fromGray = function ( val , maxes ) {
684
+ // Use blue max
685
+ const p5Maxes = maxes . map ( ( max ) => {
686
+ if ( ! Array . isArray ( max ) ) {
687
+ return [ 0 , max ] ;
688
+ } else {
689
+ return max ;
690
+ }
691
+ } ) ;
692
+
693
+ const v = map ( val , p5Maxes [ 2 ] [ 0 ] , p5Maxes [ 2 ] [ 1 ] , 0 , 1 ) ;
694
+ return [ v , v , v ] ;
695
+ } ;
696
+
697
+ HSBSpace . fromGray = HSLSpace . fromGray = function ( val , maxes ) {
698
+ // Use brightness max
699
+ const p5Maxes = maxes . map ( ( max ) => {
700
+ if ( ! Array . isArray ( max ) ) {
701
+ return [ 0 , max ] ;
702
+ } else {
703
+ return max ;
704
+ }
705
+ } ) ;
706
+
707
+ const v = map ( val , p5Maxes [ 2 ] [ 0 ] , p5Maxes [ 2 ] [ 1 ] , 0 , 100 ) ;
708
+ return [ 0 , 0 , v ] ;
709
+ } ;
710
+
711
+ HWBSpace . fromGray = function ( val , maxes ) {
712
+ // Use Whiteness and Blackness to create number line
713
+ const p5Maxes = maxes . map ( ( max ) => {
714
+ if ( ! Array . isArray ( max ) ) {
715
+ return [ 0 , max ] ;
716
+ } else {
717
+ return max ;
718
+ }
719
+ } ) ;
720
+
721
+ const wbMax =
722
+ ( Math . abs ( p5Maxes [ 1 ] [ 0 ] - p5Maxes [ 1 ] [ 1 ] ) ) / 2 +
723
+ ( Math . abs ( p5Maxes [ 2 ] [ 0 ] - p5Maxes [ 2 ] [ 1 ] ) ) / 2 ;
724
+
725
+ const nVal = map ( val , 0 , wbMax , 0 , 100 ) ;
726
+ let white , black ;
727
+ if ( nVal < 50 ) {
728
+ black = nVal ;
729
+ white = 100 - nVal ;
730
+ } else if ( nVal >= 50 ) {
731
+ white = nVal ;
732
+ black = 100 - nVal ;
733
+ }
734
+ return [ 0 , white , black ] ;
735
+ } ;
736
+
737
+ Lab . fromGray =
738
+ LCHSpace . fromGray =
739
+ OKLab . fromGray =
740
+ OKLCHSpace . fromGray =
741
+ function ( val , maxes ) {
742
+ // Use lightness max
743
+ const p5Maxes = maxes . map ( ( max ) => {
744
+ if ( ! Array . isArray ( max ) ) {
745
+ return [ 0 , max ] ;
746
+ } else {
747
+ return max ;
748
+ }
749
+ } ) ;
750
+
751
+ const v = map ( val , p5Maxes [ 0 ] [ 0 ] , p5Maxes [ 0 ] [ 1 ] , 0 , 100 ) ;
752
+ return [ v , 0 , 0 ] ;
753
+ } ;
754
+
655
755
// Register color modes and initialize Color maxes to what p5 has set for itself
656
756
p5 . Color . addColorMode ( RGB , sRGB ) ;
657
757
p5 . Color . addColorMode ( RGBHDR , P3 ) ;
0 commit comments