@@ -30,8 +30,14 @@ import {
3030} from 'colorjs.io/fn' ;
3131import HSBSpace from './color_spaces/hsb.js' ;
3232
33- const map = ( n , start1 , stop1 , start2 , stop2 ) =>
34- ( ( n - start1 ) / ( stop1 - start1 ) * ( stop2 - start2 ) + start2 ) ;
33+ const map = ( n , start1 , stop1 , start2 , stop2 , clamp ) => {
34+ let result = ( ( n - start1 ) / ( stop1 - start1 ) * ( stop2 - start2 ) + start2 ) ;
35+ if ( clamp ) {
36+ result = Math . max ( result , Math . min ( start2 , stop2 ) ) ;
37+ result = Math . min ( result , Math . max ( start2 , stop2 ) ) ;
38+ }
39+ return result ;
40+ }
3541
3642const serializationMap = { } ;
3743
@@ -63,7 +69,7 @@ class Color {
6369 Color . #grayscaleMap[ mode ] = definition . fromGray ;
6470 }
6571
66- constructor ( vals , colorMode , colorMaxes ) {
72+ constructor ( vals , colorMode , colorMaxes , { clamp = false } = { } ) {
6773 // This changes with the color object
6874 this . mode = colorMode || RGB ;
6975
@@ -106,16 +112,16 @@ class Color {
106112 if ( colorMaxes ) {
107113 // NOTE: need to consider different number of arguments (eg. CMYK)
108114 if ( vals . length === 4 ) {
109- mappedVals = Color . mapColorRange ( vals , this . mode , colorMaxes ) ;
115+ mappedVals = Color . mapColorRange ( vals , this . mode , colorMaxes , clamp ) ;
110116 } else if ( vals . length === 3 ) {
111- mappedVals = Color . mapColorRange ( [ vals [ 0 ] , vals [ 1 ] , vals [ 2 ] ] , this . mode , colorMaxes ) ;
117+ mappedVals = Color . mapColorRange ( [ vals [ 0 ] , vals [ 1 ] , vals [ 2 ] ] , this . mode , colorMaxes , clamp ) ;
112118 mappedVals . push ( 1 ) ;
113119 } else if ( vals . length === 2 ) {
114120 // Grayscale with alpha
115121 if ( Color . #grayscaleMap[ this . mode ] ) {
116- mappedVals = Color . #grayscaleMap[ this . mode ] ( vals [ 0 ] , colorMaxes ) ;
122+ mappedVals = Color . #grayscaleMap[ this . mode ] ( vals [ 0 ] , colorMaxes , clamp ) ;
117123 } else {
118- mappedVals = Color . mapColorRange ( [ vals [ 0 ] , vals [ 0 ] , vals [ 0 ] ] , this . mode , colorMaxes ) ;
124+ mappedVals = Color . mapColorRange ( [ vals [ 0 ] , vals [ 0 ] , vals [ 0 ] ] , this . mode , colorMaxes , clamp ) ;
119125 }
120126 const alphaMaxes = Array . isArray ( colorMaxes [ colorMaxes . length - 1 ] ) ?
121127 colorMaxes [ colorMaxes . length - 1 ] :
@@ -126,15 +132,16 @@ class Color {
126132 alphaMaxes [ 0 ] ,
127133 alphaMaxes [ 1 ] ,
128134 0 ,
129- 1
135+ 1 ,
136+ clamp
130137 )
131138 ) ;
132139 } else if ( vals . length === 1 ) {
133140 // Grayscale only
134141 if ( Color . #grayscaleMap[ this . mode ] ) {
135- mappedVals = Color . #grayscaleMap[ this . mode ] ( vals [ 0 ] , colorMaxes ) ;
142+ mappedVals = Color . #grayscaleMap[ this . mode ] ( vals [ 0 ] , colorMaxes , clamp ) ;
136143 } else {
137- mappedVals = Color . mapColorRange ( [ vals [ 0 ] , vals [ 0 ] , vals [ 0 ] ] , this . mode , colorMaxes ) ;
144+ mappedVals = Color . mapColorRange ( [ vals [ 0 ] , vals [ 0 ] , vals [ 0 ] ] , this . mode , colorMaxes , clamp ) ;
138145 }
139146 mappedVals . push ( 1 ) ;
140147 } else {
@@ -157,7 +164,7 @@ class Color {
157164 }
158165
159166 // Convert from p5 color range to color.js color range
160- static mapColorRange ( origin , mode , maxes ) {
167+ static mapColorRange ( origin , mode , maxes , clamp ) {
161168 const p5Maxes = maxes . map ( ( max ) => {
162169 if ( ! Array . isArray ( max ) ) {
163170 return [ 0 , max ] ;
@@ -168,7 +175,7 @@ class Color {
168175 const colorjsMaxes = Color . #colorjsMaxes[ mode ] ;
169176
170177 return origin . map ( ( channel , i ) => {
171- const newval = map ( channel , p5Maxes [ i ] [ 0 ] , p5Maxes [ i ] [ 1 ] , colorjsMaxes [ i ] [ 0 ] , colorjsMaxes [ i ] [ 1 ] ) ;
178+ const newval = map ( channel , p5Maxes [ i ] [ 0 ] , p5Maxes [ i ] [ 1 ] , colorjsMaxes [ i ] [ 0 ] , colorjsMaxes [ i ] [ 1 ] , clamp ) ;
172179 return newval ;
173180 } ) ;
174181 }
@@ -680,7 +687,7 @@ function color(p5, fn, lifecycles){
680687 */
681688 p5 . Color = Color ;
682689
683- sRGB . fromGray = P3 . fromGray = function ( val , maxes ) {
690+ sRGB . fromGray = P3 . fromGray = function ( val , maxes , clamp ) {
684691 // Use blue max
685692 const p5Maxes = maxes . map ( ( max ) => {
686693 if ( ! Array . isArray ( max ) ) {
@@ -690,11 +697,11 @@ function color(p5, fn, lifecycles){
690697 }
691698 } ) ;
692699
693- const v = map ( val , p5Maxes [ 2 ] [ 0 ] , p5Maxes [ 2 ] [ 1 ] , 0 , 1 ) ;
700+ const v = map ( val , p5Maxes [ 2 ] [ 0 ] , p5Maxes [ 2 ] [ 1 ] , 0 , 1 , clamp ) ;
694701 return [ v , v , v ] ;
695702 } ;
696703
697- HSBSpace . fromGray = HSLSpace . fromGray = function ( val , maxes ) {
704+ HSBSpace . fromGray = HSLSpace . fromGray = function ( val , maxes , clamp ) {
698705 // Use brightness max
699706 const p5Maxes = maxes . map ( ( max ) => {
700707 if ( ! Array . isArray ( max ) ) {
@@ -704,11 +711,11 @@ function color(p5, fn, lifecycles){
704711 }
705712 } ) ;
706713
707- const v = map ( val , p5Maxes [ 2 ] [ 0 ] , p5Maxes [ 2 ] [ 1 ] , 0 , 100 ) ;
714+ const v = map ( val , p5Maxes [ 2 ] [ 0 ] , p5Maxes [ 2 ] [ 1 ] , 0 , 100 , clamp ) ;
708715 return [ 0 , 0 , v ] ;
709716 } ;
710717
711- HWBSpace . fromGray = function ( val , maxes ) {
718+ HWBSpace . fromGray = function ( val , maxes , clamp ) {
712719 // Use Whiteness and Blackness to create number line
713720 const p5Maxes = maxes . map ( ( max ) => {
714721 if ( ! Array . isArray ( max ) ) {
@@ -738,7 +745,7 @@ function color(p5, fn, lifecycles){
738745 LCHSpace . fromGray =
739746 OKLab . fromGray =
740747 OKLCHSpace . fromGray =
741- function ( val , maxes ) {
748+ function ( val , maxes , clamp ) {
742749 // Use lightness max
743750 const p5Maxes = maxes . map ( ( max ) => {
744751 if ( ! Array . isArray ( max ) ) {
@@ -748,7 +755,7 @@ function color(p5, fn, lifecycles){
748755 }
749756 } ) ;
750757
751- const v = map ( val , p5Maxes [ 0 ] [ 0 ] , p5Maxes [ 0 ] [ 1 ] , 0 , 100 ) ;
758+ const v = map ( val , p5Maxes [ 0 ] [ 0 ] , p5Maxes [ 0 ] [ 1 ] , 0 , 100 , clamp ) ;
752759 return [ v , 0 , 0 ] ;
753760 } ;
754761
0 commit comments