@@ -44,18 +44,23 @@ class Color {
4444
4545 static colorMap = { } ;
4646 static #colorjsMaxes = { } ;
47+ static #grayscaleMap = { } ;
4748
4849 // Used to add additional color modes to p5.js
4950 // Uses underlying library's definition
5051 static addColorMode ( mode , definition ) {
5152 ColorSpace . register ( definition ) ;
5253 Color . colorMap [ mode ] = definition . id ;
54+
5355 // Get colorjs maxes
5456 Color . #colorjsMaxes[ mode ] = Object . values ( definition . coords ) . reduce ( ( acc , v ) => {
5557 acc . push ( v . refRange || v . range ) ;
5658 return acc ;
5759 } , [ ] ) ;
5860 Color . #colorjsMaxes[ mode ] . push ( [ 0 , 1 ] ) ;
61+
62+ // Get grayscale mapping
63+ Color . #grayscaleMap[ mode ] = definition . fromGray ;
5964 }
6065
6166 constructor ( vals , colorMode , colorMaxes ) {
@@ -99,15 +104,38 @@ class Color {
99104 let mappedVals ;
100105
101106 if ( colorMaxes ) {
107+ // NOTE: need to consider different number of arguments (eg. CMYK)
102108 if ( vals . length === 4 ) {
103109 mappedVals = Color . mapColorRange ( vals , this . mode , colorMaxes ) ;
104110 } else if ( vals . length === 3 ) {
105111 mappedVals = Color . mapColorRange ( [ vals [ 0 ] , vals [ 1 ] , vals [ 2 ] ] , this . mode , colorMaxes ) ;
106112 mappedVals . push ( 1 ) ;
107113 } 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+ ) ;
109132 } 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+ }
111139 mappedVals . push ( 1 ) ;
112140 } else {
113141 throw new Error ( 'Invalid color' ) ;
@@ -652,6 +680,78 @@ function color(p5, fn, lifecycles){
652680 */
653681 p5 . Color = Color ;
654682
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+
655755 // Register color modes and initialize Color maxes to what p5 has set for itself
656756 p5 . Color . addColorMode ( RGB , sRGB ) ;
657757 p5 . Color . addColorMode ( RGBHDR , P3 ) ;
0 commit comments