diff --git a/src/color/creating_reading.js b/src/color/creating_reading.js index cda1d9bfcc..976aba3176 100644 --- a/src/color/creating_reading.js +++ b/src/color/creating_reading.js @@ -6,21 +6,91 @@ * @requires constants */ -import './p5.Color'; -import { range } from 'colorjs.io/fn'; +import { Color } from './p5.Color'; + +export const RGB = 'rgb'; +export const RGBHDR = 'rgbhdr'; +export const HSB = 'hsb'; +export const HSL = 'hsl'; +export const HWB = 'hwb'; + +export const LAB = 'lab'; +export const LCH = 'lch'; + +export const OKLAB = 'oklab'; +export const OKLCH = 'oklch'; + +export const RGBA = 'rgba'; function creatingReading(p5, fn){ + fn.RGB = RGB; + fn.RGBHDR = RGBHDR; + fn.HSB = HSB; + fn.HSL = HSL; + fn.HWB = HWB; + + fn.LAB = LAB; + fn.LCH = LCH; + + fn.OKLAB = OKLAB; + fn.OKLCH = OKLCH; + + fn.RGBA = RGBA; + + // Add color states to renderer state machine + p5.Renderer.states.colorMode = RGB; + p5.Renderer.states.colorMaxes = { + [RGB]: [255, 255, 255, 255], + [RGBHDR]: [255, 255, 255, 255], + [HSB]: [360, 100, 100, 1], + [HSL]: [360, 100, 100, 1], + [HWB]: [360, 100, 100, 1], + + [LAB]: [100, [-125, 125], [-125, 125], 1], + [LCH]: [100, 150, 360, 1], + + [OKLAB]: [100, [-125, 125], [-125, 125], 1], + [OKLCH]: [100, 150, 360, 1], + clone: function(){ + let ret = {}; + for(const key in this){ + if(typeof this[key] !== 'function'){ + ret[key] = structuredClone(this[key]); + }else{ + ret[key] = this[key]; + } + } + return ret; + } + }; + /** - * Gets the alpha (transparency) value of a color. + * Creates a p5.Color object. * - * `alpha()` extracts the alpha value from a - * p5.Color object, an array of color components, or - * a CSS color string. + * By default, the parameters are interpreted as RGB values. Calling + * `color(255, 204, 0)` will return a bright yellow color. The way these + * parameters are interpreted may be changed with the + * colorMode() function. * - * @method alpha - * @param {p5.Color|Number[]|String} color p5.Color object, array of - * color components, or CSS color string. - * @return {Number} the alpha value. + * The version of `color()` with one parameter interprets the value one of two + * ways. If the parameter is a number, it's interpreted as a grayscale value. + * If the parameter is a string, it's interpreted as a CSS color string. + * + * The version of `color()` with two parameters interprets the first one as a + * grayscale value. The second parameter sets the alpha (transparency) value. + * + * The version of `color()` with three parameters interprets them as RGB, HSB, + * or HSL colors, depending on the current `colorMode()`. + * + * The version of `color()` with four parameters interprets them as RGBA, HSBA, + * or HSLA colors, depending on the current `colorMode()`. The last parameter + * sets the alpha (transparency) value. + * + * @method color + * @param {Number} gray number specifying value between white and black. + * @param {Number} [alpha] alpha value relative to current color range + * (default is 0-255). + * @return {p5.Color} resulting color. * * @example *
@@ -30,22 +100,15 @@ function creatingReading(p5, fn){ * * background(200); * - * // Create a p5.Color object. - * let c = color(0, 126, 255, 102); + * // Create a p5.Color object using RGB values. + * let c = color(255, 204, 0); * - * // Draw the left rectangle. - * noStroke(); + * // Draw the square. * fill(c); - * rect(15, 15, 35, 70); - * - * // Set 'alphaValue' to 102. - * let alphaValue = alpha(c); - * - * // Draw the right rectangle. - * fill(alphaValue); - * rect(50, 15, 35, 70); + * noStroke(); + * square(30, 20, 55); * - * describe('Two rectangles. The left one is light blue and the right one is charcoal gray.'); + * describe('A yellow square on a gray canvas.'); * } * *
@@ -58,22 +121,24 @@ function creatingReading(p5, fn){ * * background(200); * - * // Create a color array. - * let c = [0, 126, 255, 102]; + * // Create a p5.Color object using RGB values. + * let c1 = color(255, 204, 0); * - * // Draw the left rectangle. + * // Draw the left circle. + * fill(c1); * noStroke(); - * fill(c); - * rect(15, 15, 35, 70); + * circle(25, 25, 80); * - * // Set 'alphaValue' to 102. - * let alphaValue = alpha(c); + * // Create a p5.Color object using a grayscale value. + * let c2 = color(65); * - * // Draw the left rectangle. - * fill(alphaValue); - * rect(50, 15, 35, 70); + * // Draw the right circle. + * fill(c2); + * circle(75, 75, 80); * - * describe('Two rectangles. The left one is light blue and the right one is charcoal gray.'); + * describe( + * 'Two circles on a gray canvas. The circle in the top-left corner is yellow and the one at the bottom-right is gray.' + * ); * } * * @@ -86,46 +151,46 @@ function creatingReading(p5, fn){ * * background(200); * - * // Create a CSS color string. - * let c = 'rgba(0, 126, 255, 0.4)'; + * // Create a p5.Color object using a named color. + * let c = color('magenta'); + * + * // Draw the square. + * fill(c); + * noStroke(); + * square(20, 20, 60); + * + * describe('A magenta square on a gray canvas.'); + * } + * + * + * + * @example + *
+ * + * function setup() { + * createCanvas(100, 100); + * + * background(200); + * + * // Create a p5.Color object using a hex color code. + * let c1 = color('#0f0'); * * // Draw the left rectangle. + * fill(c1); * noStroke(); - * fill(c); - * rect(15, 15, 35, 70); + * rect(0, 10, 45, 80); * - * // Set 'alphaValue' to 102. - * let alphaValue = alpha(c); + * // Create a p5.Color object using a hex color code. + * let c2 = color('#00ff00'); * * // Draw the right rectangle. - * fill(alphaValue); - * rect(50, 15, 35, 70); + * fill(c2); + * rect(55, 10, 45, 80); * - * describe('Two rectangles. The left one is light blue and the right one is charcoal gray.'); + * describe('Two bright green rectangles on a gray canvas.'); * } * *
- */ - fn.alpha = function(c) { - p5._validateParameters('alpha', arguments); - return this.color(c)._getAlpha(); - }; - - /** - * Gets the blue value of a color. - * - * `blue()` extracts the blue value from a - * p5.Color object, an array of color components, or - * a CSS color string. - * - * By default, `blue()` returns a color's blue value in the range 0 - * to 255. If the colorMode() is set to RGB, it - * returns the blue value in the given range. - * - * @method blue - * @param {p5.Color|Number[]|String} color p5.Color object, array of - * color components, or CSS color string. - * @return {Number} the blue value. * * @example *
@@ -135,22 +200,35 @@ function creatingReading(p5, fn){ * * background(200); * - * // Create a p5.Color object using RGB values. - * let c = color(175, 100, 220); + * // Create a p5.Color object using a RGB color string. + * let c1 = color('rgb(0, 0, 255)'); * - * // Draw the left rectangle. - * noStroke(); - * fill(c); - * rect(15, 15, 35, 70); + * // Draw the top-left square. + * fill(c1); + * square(10, 10, 35); * - * // Set 'blueValue' to 220. - * let blueValue = blue(c); + * // Create a p5.Color object using a RGB color string. + * let c2 = color('rgb(0%, 0%, 100%)'); * - * // Draw the right rectangle. - * fill(0, 0, blueValue); - * rect(50, 15, 35, 70); + * // Draw the top-right square. + * fill(c2); + * square(55, 10, 35); * - * describe('Two rectangles. The left one is light purple and the right one is royal blue.'); + * // Create a p5.Color object using a RGBA color string. + * let c3 = color('rgba(0, 0, 255, 1)'); + * + * // Draw the bottom-left square. + * fill(c3); + * square(10, 55, 35); + * + * // Create a p5.Color object using a RGBA color string. + * let c4 = color('rgba(0%, 0%, 100%, 1)'); + * + * // Draw the bottom-right square. + * fill(c4); + * square(55, 55, 35); + * + * describe('Four blue squares in the corners of a gray canvas.'); * } * *
@@ -163,27 +241,26 @@ function creatingReading(p5, fn){ * * background(200); * - * // Create a color array. - * let c = [175, 100, 220]; + * // Create a p5.Color object using a HSL color string. + * let c1 = color('hsl(160, 100%, 50%)'); * * // Draw the left rectangle. * noStroke(); - * fill(c); - * rect(15, 15, 35, 70); + * fill(c1); + * rect(0, 10, 45, 80); * - * // Set 'blueValue' to 220. - * let blueValue = blue(c); + * // Create a p5.Color object using a HSLA color string. + * let c2 = color('hsla(160, 100%, 50%, 0.5)'); * * // Draw the right rectangle. - * fill(0, 0, blueValue); - * rect(50, 15, 35, 70); + * fill(c2); + * rect(55, 10, 45, 80); * - * describe('Two rectangles. The left one is light purple and the right one is royal blue.'); + * describe('Two sea green rectangles. A darker rectangle on the left and a brighter one on the right.'); * } * * * - * @example *
* * function setup() { @@ -191,27 +268,26 @@ function creatingReading(p5, fn){ * * background(200); * - * // Create a CSS color string. - * let c = 'rgb(175, 100, 220)'; + * // Create a p5.Color object using a HSB color string. + * let c1 = color('hsb(160, 100%, 50%)'); * * // Draw the left rectangle. * noStroke(); - * fill(c); - * rect(15, 15, 35, 70); + * fill(c1); + * rect(0, 10, 45, 80); * - * // Set 'blueValue' to 220. - * let blueValue = blue(c); + * // Create a p5.Color object using a HSBA color string. + * let c2 = color('hsba(160, 100%, 50%, 0.5)'); * * // Draw the right rectangle. - * fill(0, 0, blueValue); - * rect(50, 15, 35, 70); + * fill(c2); + * rect(55, 10, 45, 80); * - * describe('Two rectangles. The left one is light purple and the right one is royal blue.'); + * describe('Two green rectangles. A darker rectangle on the left and a brighter one on the right.'); * } * *
* - * @example *
* * function setup() { @@ -219,49 +295,89 @@ function creatingReading(p5, fn){ * * background(200); * - * // Use RGB color with values in the range 0-100. - * colorMode(RGB, 100); - * * // Create a p5.Color object using RGB values. - * let c = color(69, 39, 86); + * let c1 = color(50, 55, 100); * * // Draw the left rectangle. - * noStroke(); - * fill(c); - * rect(15, 15, 35, 70); + * fill(c1); + * rect(0, 10, 45, 80); * - * // Set 'blueValue' to 86. - * let blueValue = blue(c); + * // Switch the color mode to HSB. + * colorMode(HSB, 100); + * + * // Create a p5.Color object using HSB values. + * let c2 = color(50, 55, 100); * * // Draw the right rectangle. - * fill(0, 0, blueValue); - * rect(50, 15, 35, 70); + * fill(c2); + * rect(55, 10, 45, 80); * - * describe('Two rectangles. The left one is light purple and the right one is royal blue.'); + * describe('Two blue rectangles. A darker rectangle on the left and a brighter one on the right.'); * } * *
*/ - fn.blue = function(c) { - p5._validateParameters('blue', arguments); - return this.color(c)._getBlue(); + + /** + * @method color + * @param {Number} v1 red or hue value relative to + * the current color range. + * @param {Number} v2 green or saturation value + * relative to the current color range. + * @param {Number} v3 blue or brightness value + * relative to the current color range. + * @param {Number} [alpha] + * @return {p5.Color} + */ + + /** + * @method color + * @param {String} value a color string. + * @return {p5.Color} + */ + + /** + * @method color + * @param {Number[]} values an array containing the red, green, blue, + * and alpha components of the color. + * @return {p5.Color} + */ + + /** + * @method color + * @param {p5.Color} color + * @return {p5.Color} + */ + fn.color = function(...args) { + p5._validateParameters('color', args); + if (args[0] instanceof Color) { + // TODO: perhaps change color mode to match instance mode? + return args[0]; // Do nothing if argument is already a color object. + } + + const arg = Array.isArray(args[0]) ? args[0] : args; + return new Color( + arg, + this._renderer.states.colorMode, + this._renderer.states.colorMaxes[this._renderer.states.colorMode] + ); }; /** - * Gets the brightness value of a color. + * Gets the red value of a color. * - * `brightness()` extracts the HSB brightness value from a + * `red()` extracts the red value from a * p5.Color object, an array of color components, or * a CSS color string. * - * By default, `brightness()` returns a color's HSB brightness in the range 0 - * to 100. If the colorMode() is set to HSB, it - * returns the brightness value in the given range. + * By default, `red()` returns a color's red value in the range 0 + * to 255. If the colorMode() is set to RGB, it + * returns the red value in the given range. * - * @method brightness + * @method red * @param {p5.Color|Number[]|String} color p5.Color object, array of * color components, or CSS color string. - * @return {Number} the brightness value. + * @return {Number} the red value. * * @example *
@@ -271,25 +387,22 @@ function creatingReading(p5, fn){ * * background(200); * - * // Use HSB color. - * colorMode(HSB); - * * // Create a p5.Color object. - * let c = color(0, 50, 100); + * let c = color(175, 100, 220); * * // Draw the left rectangle. * noStroke(); * fill(c); * rect(15, 15, 35, 70); * - * // Set 'brightValue' to 100. - * let brightValue = brightness(c); + * // Set 'redValue' to 175. + * let redValue = red(c); * * // Draw the right rectangle. - * fill(brightValue); + * fill(redValue, 0, 0); * rect(50, 15, 35, 70); * - * describe('Two rectangles. The left one is salmon pink and the right one is white.'); + * describe('Two rectangles. The left one is light purple and the right one is red.'); * } * *
@@ -302,25 +415,22 @@ function creatingReading(p5, fn){ * * background(200); * - * // Use HSB color. - * colorMode(HSB); - * * // Create a color array. - * let c = [0, 50, 100]; + * let c = [175, 100, 220]; * * // Draw the left rectangle. * noStroke(); * fill(c); * rect(15, 15, 35, 70); * - * // Set 'brightValue' to 100. - * let brightValue = brightness(c); + * // Set 'redValue' to 175. + * let redValue = red(c); * * // Draw the right rectangle. - * fill(brightValue); + * fill(redValue, 0, 0); * rect(50, 15, 35, 70); * - * describe('Two rectangles. The left one is salmon pink and the right one is white.'); + * describe('Two rectangles. The left one is light purple and the right one is red.'); * } * * @@ -333,25 +443,22 @@ function creatingReading(p5, fn){ * * background(200); * - * // Use HSB color. - * colorMode(HSB); - * * // Create a CSS color string. - * let c = 'rgb(255, 128, 128)'; + * let c = 'rgb(175, 100, 220)'; * * // Draw the left rectangle. * noStroke(); * fill(c); * rect(15, 15, 35, 70); * - * // Set 'brightValue' to 100. - * let brightValue = brightness(c); + * // Set 'redValue' to 175. + * let redValue = red(c); * * // Draw the right rectangle. - * fill(brightValue); + * fill(redValue, 0, 0); * rect(50, 15, 35, 70); * - * describe('Two rectangles. The left one is salmon pink and the right one is white.'); + * describe('Two rectangles. The left one is light purple and the right one is red.'); * } * * @@ -364,61 +471,50 @@ function creatingReading(p5, fn){ * * background(200); * - * // Use HSB color with values in the range 0-255. - * colorMode(HSB, 255); + * // Use RGB color with values in the range 0-100. + * colorMode(RGB, 100); * * // Create a p5.Color object. - * let c = color(0, 127, 255); + * let c = color(69, 39, 86); * * // Draw the left rectangle. * noStroke(); * fill(c); * rect(15, 15, 35, 70); * - * // Set 'brightValue' to 255. - * let brightValue = brightness(c); + * // Set 'redValue' to 69. + * let redValue = red(c); * * // Draw the right rectangle. - * fill(brightValue); + * fill(redValue, 0, 0); * rect(50, 15, 35, 70); * - * describe('Two rectangles. The left one is salmon pink and the right one is white.'); + * describe('Two rectangles. The left one is light purple and the right one is red.'); * } * * */ - fn.brightness = function(c) { - p5._validateParameters('brightness', arguments); - return this.color(c)._getBrightness(); + fn.red = function(c) { + p5._validateParameters('red', arguments); + // Get current red max + return this.color(c)._getRed(); }; /** - * Creates a p5.Color object. - * - * By default, the parameters are interpreted as RGB values. Calling - * `color(255, 204, 0)` will return a bright yellow color. The way these - * parameters are interpreted may be changed with the - * colorMode() function. - * - * The version of `color()` with one parameter interprets the value one of two - * ways. If the parameter is a number, it's interpreted as a grayscale value. - * If the parameter is a string, it's interpreted as a CSS color string. - * - * The version of `color()` with two parameters interprets the first one as a - * grayscale value. The second parameter sets the alpha (transparency) value. + * Gets the green value of a color. * - * The version of `color()` with three parameters interprets them as RGB, HSB, - * or HSL colors, depending on the current `colorMode()`. + * `green()` extracts the green value from a + * p5.Color object, an array of color components, or + * a CSS color string. * - * The version of `color()` with four parameters interprets them as RGBA, HSBA, - * or HSLA colors, depending on the current `colorMode()`. The last parameter - * sets the alpha (transparency) value. + * By default, `green()` returns a color's green value in the range 0 + * to 255. If the colorMode() is set to RGB, it + * returns the green value in the given range. * - * @method color - * @param {Number} gray number specifying value between white and black. - * @param {Number} [alpha] alpha value relative to current color range - * (default is 0-255). - * @return {p5.Color} resulting color. + * @method green + * @param {p5.Color|Number[]|String} color p5.Color object, array of + * color components, or CSS color string. + * @return {Number} the green value. * * @example *
@@ -428,15 +524,22 @@ function creatingReading(p5, fn){ * * background(200); * - * // Create a p5.Color object using RGB values. - * let c = color(255, 204, 0); + * // Create a p5.Color object. + * let c = color(175, 100, 220); * - * // Draw the square. - * fill(c); + * // Draw the left rectangle. * noStroke(); - * square(30, 20, 55); + * fill(c); + * rect(15, 15, 35, 70); * - * describe('A yellow square on a gray canvas.'); + * // Set 'greenValue' to 100. + * let greenValue = green(c); + * + * // Draw the right rectangle. + * fill(0, greenValue, 0); + * rect(50, 15, 35, 70); + * + * describe('Two rectangles. The left one is light purple and the right one is dark green.'); * } * *
@@ -449,24 +552,22 @@ function creatingReading(p5, fn){ * * background(200); * - * // Create a p5.Color object using RGB values. - * let c1 = color(255, 204, 0); + * // Create a color array. + * let c = [175, 100, 220]; * - * // Draw the left circle. - * fill(c1); + * // Draw the left rectangle. * noStroke(); - * circle(25, 25, 80); + * fill(c); + * rect(15, 15, 35, 70); * - * // Create a p5.Color object using a grayscale value. - * let c2 = color(65); + * // Set 'greenValue' to 100. + * let greenValue = green(c); * - * // Draw the right circle. - * fill(c2); - * circle(75, 75, 80); + * // Draw the right rectangle. + * fill(0, greenValue, 0); + * rect(50, 15, 35, 70); * - * describe( - * 'Two circles on a gray canvas. The circle in the top-left corner is yellow and the one at the bottom-right is gray.' - * ); + * describe('Two rectangles. The left one is light purple and the right one is dark green.'); * } * * @@ -479,15 +580,22 @@ function creatingReading(p5, fn){ * * background(200); * - * // Create a p5.Color object using a named color. - * let c = color('magenta'); + * // Create a CSS color string. + * let c = 'rgb(175, 100, 220)'; * - * // Draw the square. - * fill(c); + * // Draw the left rectangle. * noStroke(); - * square(20, 20, 60); + * fill(c); + * rect(15, 15, 35, 70); * - * describe('A magenta square on a gray canvas.'); + * // Set 'greenValue' to 100. + * let greenValue = green(c); + * + * // Draw the right rectangle. + * fill(0, greenValue, 0); + * rect(50, 15, 35, 70); + * + * describe('Two rectangles. The left one is light purple and the right one is dark green.'); * } * * @@ -500,25 +608,50 @@ function creatingReading(p5, fn){ * * background(200); * - * // Create a p5.Color object using a hex color code. - * let c1 = color('#0f0'); + * // Use RGB color with values in the range 0-100. + * colorMode(RGB, 100); + * + * // Create a p5.Color object using RGB values. + * let c = color(69, 39, 86); * * // Draw the left rectangle. - * fill(c1); * noStroke(); - * rect(0, 10, 45, 80); + * fill(c); + * rect(15, 15, 35, 70); * - * // Create a p5.Color object using a hex color code. - * let c2 = color('#00ff00'); + * // Set 'greenValue' to 39. + * let greenValue = green(c); * * // Draw the right rectangle. - * fill(c2); - * rect(55, 10, 45, 80); + * fill(0, greenValue, 0); + * rect(50, 15, 35, 70); * - * describe('Two bright green rectangles on a gray canvas.'); + * describe('Two rectangles. The left one is light purple and the right one is dark green.'); * } * * + */ + fn.green = function(c) { + p5._validateParameters('green', arguments); + // Get current green max + return this.color(c)._getGreen(); + }; + + /** + * Gets the blue value of a color. + * + * `blue()` extracts the blue value from a + * p5.Color object, an array of color components, or + * a CSS color string. + * + * By default, `blue()` returns a color's blue value in the range 0 + * to 255. If the colorMode() is set to RGB, it + * returns the blue value in the given range. + * + * @method blue + * @param {p5.Color|Number[]|String} color p5.Color object, array of + * color components, or CSS color string. + * @return {Number} the blue value. * * @example *
@@ -528,35 +661,22 @@ function creatingReading(p5, fn){ * * background(200); * - * // Create a p5.Color object using a RGB color string. - * let c1 = color('rgb(0, 0, 255)'); - * - * // Draw the top-left square. - * fill(c1); - * square(10, 10, 35); - * - * // Create a p5.Color object using a RGB color string. - * let c2 = color('rgb(0%, 0%, 100%)'); - * - * // Draw the top-right square. - * fill(c2); - * square(55, 10, 35); - * - * // Create a p5.Color object using a RGBA color string. - * let c3 = color('rgba(0, 0, 255, 1)'); + * // Create a p5.Color object using RGB values. + * let c = color(175, 100, 220); * - * // Draw the bottom-left square. - * fill(c3); - * square(10, 55, 35); + * // Draw the left rectangle. + * noStroke(); + * fill(c); + * rect(15, 15, 35, 70); * - * // Create a p5.Color object using a RGBA color string. - * let c4 = color('rgba(0%, 0%, 100%, 1)'); + * // Set 'blueValue' to 220. + * let blueValue = blue(c); * - * // Draw the bottom-right square. - * fill(c4); - * square(55, 55, 35); + * // Draw the right rectangle. + * fill(0, 0, blueValue); + * rect(50, 15, 35, 70); * - * describe('Four blue squares in the corners of a gray canvas.'); + * describe('Two rectangles. The left one is light purple and the right one is royal blue.'); * } * *
@@ -569,26 +689,27 @@ function creatingReading(p5, fn){ * * background(200); * - * // Create a p5.Color object using a HSL color string. - * let c1 = color('hsl(160, 100%, 50%)'); + * // Create a color array. + * let c = [175, 100, 220]; * * // Draw the left rectangle. * noStroke(); - * fill(c1); - * rect(0, 10, 45, 80); + * fill(c); + * rect(15, 15, 35, 70); * - * // Create a p5.Color object using a HSLA color string. - * let c2 = color('hsla(160, 100%, 50%, 0.5)'); + * // Set 'blueValue' to 220. + * let blueValue = blue(c); * * // Draw the right rectangle. - * fill(c2); - * rect(55, 10, 45, 80); + * fill(0, 0, blueValue); + * rect(50, 15, 35, 70); * - * describe('Two sea green rectangles. A darker rectangle on the left and a brighter one on the right.'); + * describe('Two rectangles. The left one is light purple and the right one is royal blue.'); * } * * * + * @example *
* * function setup() { @@ -596,26 +717,27 @@ function creatingReading(p5, fn){ * * background(200); * - * // Create a p5.Color object using a HSB color string. - * let c1 = color('hsb(160, 100%, 50%)'); + * // Create a CSS color string. + * let c = 'rgb(175, 100, 220)'; * * // Draw the left rectangle. * noStroke(); - * fill(c1); - * rect(0, 10, 45, 80); + * fill(c); + * rect(15, 15, 35, 70); * - * // Create a p5.Color object using a HSBA color string. - * let c2 = color('hsba(160, 100%, 50%, 0.5)'); + * // Set 'blueValue' to 220. + * let blueValue = blue(c); * * // Draw the right rectangle. - * fill(c2); - * rect(55, 10, 45, 80); + * fill(0, 0, blueValue); + * rect(50, 15, 35, 70); * - * describe('Two green rectangles. A darker rectangle on the left and a brighter one on the right.'); + * describe('Two rectangles. The left one is light purple and the right one is royal blue.'); * } * *
* + * @example *
* * function setup() { @@ -623,84 +745,46 @@ function creatingReading(p5, fn){ * * background(200); * + * // Use RGB color with values in the range 0-100. + * colorMode(RGB, 100); + * * // Create a p5.Color object using RGB values. - * let c1 = color(50, 55, 100); + * let c = color(69, 39, 86); * * // Draw the left rectangle. - * fill(c1); - * rect(0, 10, 45, 80); - * - * // Switch the color mode to HSB. - * colorMode(HSB, 100); + * noStroke(); + * fill(c); + * rect(15, 15, 35, 70); * - * // Create a p5.Color object using HSB values. - * let c2 = color(50, 55, 100); + * // Set 'blueValue' to 86. + * let blueValue = blue(c); * * // Draw the right rectangle. - * fill(c2); - * rect(55, 10, 45, 80); + * fill(0, 0, blueValue); + * rect(50, 15, 35, 70); * - * describe('Two blue rectangles. A darker rectangle on the left and a brighter one on the right.'); + * describe('Two rectangles. The left one is light purple and the right one is royal blue.'); * } * *
*/ - - /** - * @method color - * @param {Number} v1 red or hue value relative to - * the current color range. - * @param {Number} v2 green or saturation value - * relative to the current color range. - * @param {Number} v3 blue or brightness value - * relative to the current color range. - * @param {Number} [alpha] - * @return {p5.Color} - */ - - /** - * @method color - * @param {String} value a color string. - * @return {p5.Color} - */ - - /** - * @method color - * @param {Number[]} values an array containing the red, green, blue, - * and alpha components of the color. - * @return {p5.Color} - */ - - /** - * @method color - * @param {p5.Color} color - * @return {p5.Color} - */ - fn.color = function(...args) { - p5._validateParameters('color', args); - if (args[0] instanceof p5.Color) { - return args[0]; // Do nothing if argument is already a color object. - } - - const arg = Array.isArray(args[0]) ? args[0] : args; - return new p5.Color(arg, this._colorMode, this._colorMaxes); + fn.blue = function(c) { + p5._validateParameters('blue', arguments); + // Get current blue max + return this.color(c)._getBlue(); }; /** - * Gets the green value of a color. + * Gets the alpha (transparency) value of a color. * - * `green()` extracts the green value from a + * `alpha()` extracts the alpha value from a * p5.Color object, an array of color components, or * a CSS color string. * - * By default, `green()` returns a color's green value in the range 0 - * to 255. If the colorMode() is set to RGB, it - * returns the green value in the given range. - * - * @method green + * @method alpha * @param {p5.Color|Number[]|String} color p5.Color object, array of * color components, or CSS color string. - * @return {Number} the green value. + * @return {Number} the alpha value. * * @example *
@@ -711,21 +795,21 @@ function creatingReading(p5, fn){ * background(200); * * // Create a p5.Color object. - * let c = color(175, 100, 220); + * let c = color(0, 126, 255, 102); * * // Draw the left rectangle. * noStroke(); * fill(c); * rect(15, 15, 35, 70); * - * // Set 'greenValue' to 100. - * let greenValue = green(c); + * // Set 'alphaValue' to 102. + * let alphaValue = alpha(c); * * // Draw the right rectangle. - * fill(0, greenValue, 0); + * fill(alphaValue); * rect(50, 15, 35, 70); * - * describe('Two rectangles. The left one is light purple and the right one is dark green.'); + * describe('Two rectangles. The left one is light blue and the right one is charcoal gray.'); * } * *
@@ -739,49 +823,21 @@ function creatingReading(p5, fn){ * background(200); * * // Create a color array. - * let c = [175, 100, 220]; + * let c = [0, 126, 255, 102]; * * // Draw the left rectangle. * noStroke(); * fill(c); * rect(15, 15, 35, 70); * - * // Set 'greenValue' to 100. - * let greenValue = green(c); - * - * // Draw the right rectangle. - * fill(0, greenValue, 0); - * rect(50, 15, 35, 70); - * - * describe('Two rectangles. The left one is light purple and the right one is dark green.'); - * } - * - * - * - * @example - *
- * - * function setup() { - * createCanvas(100, 100); - * - * background(200); - * - * // Create a CSS color string. - * let c = 'rgb(175, 100, 220)'; + * // Set 'alphaValue' to 102. + * let alphaValue = alpha(c); * * // Draw the left rectangle. - * noStroke(); - * fill(c); - * rect(15, 15, 35, 70); - * - * // Set 'greenValue' to 100. - * let greenValue = green(c); - * - * // Draw the right rectangle. - * fill(0, greenValue, 0); + * fill(alphaValue); * rect(50, 15, 35, 70); * - * describe('Two rectangles. The left one is light purple and the right one is dark green.'); + * describe('Two rectangles. The left one is light blue and the right one is charcoal gray.'); * } * *
@@ -794,32 +850,30 @@ function creatingReading(p5, fn){ * * background(200); * - * // Use RGB color with values in the range 0-100. - * colorMode(RGB, 100); - * - * // Create a p5.Color object using RGB values. - * let c = color(69, 39, 86); + * // Create a CSS color string. + * let c = 'rgba(0, 126, 255, 0.4)'; * * // Draw the left rectangle. * noStroke(); * fill(c); * rect(15, 15, 35, 70); * - * // Set 'greenValue' to 39. - * let greenValue = green(c); + * // Set 'alphaValue' to 102. + * let alphaValue = alpha(c); * * // Draw the right rectangle. - * fill(0, greenValue, 0); + * fill(alphaValue); * rect(50, 15, 35, 70); * - * describe('Two rectangles. The left one is light purple and the right one is dark green.'); + * describe('Two rectangles. The left one is light blue and the right one is charcoal gray.'); * } * * */ - fn.green = function(c) { - p5._validateParameters('green', arguments); - return this.color(c)._getGreen(); + fn.alpha = function(c) { + p5._validateParameters('alpha', arguments); + // Get current alpha max + return this.color(c)._getAlpha(); }; /** @@ -944,23 +998,21 @@ function creatingReading(p5, fn){ }; /** - * Blends two colors to find a third color between them. + * Gets the saturation value of a color. * - * The `amt` parameter specifies the amount to interpolate between the two - * values. 0 is equal to the first color, 0.1 is very near the first color, - * 0.5 is halfway between the two colors, and so on. Negative numbers are set - * to 0. Numbers greater than 1 are set to 1. This differs from the behavior of - * lerp. It's necessary because numbers outside of the - * interval [0, 1] will produce strange and unexpected colors. + * `saturation()` extracts the saturation value from a + * p5.Color object, an array of color components, or + * a CSS color string. * - * The way that colors are interpolated depends on the current - * colorMode(). + * Saturation is scaled differently in HSB and HSL. By default, `saturation()` + * returns a color's HSL saturation in the range 0 to 100. If the + * colorMode() is set to HSB or HSL, it returns the + * saturation value in the given mode. * - * @method lerpColor - * @param {p5.Color} c1 interpolate from this color. - * @param {p5.Color} c2 interpolate to this color. - * @param {Number} amt number between 0 and 1. - * @return {p5.Color} interpolated color. + * @method saturation + * @param {p5.Color|Number[]|String} color p5.Color object, array of + * color components, or CSS color string. + * @return {Number} the saturation value * * @example *
@@ -968,83 +1020,30 @@ function creatingReading(p5, fn){ * function setup() { * createCanvas(100, 100); * - * background(200); + * background(50); * - * // Create p5.Color objects to interpolate between. - * let from = color(218, 165, 32); - * let to = color(72, 61, 139); + * // Use HSB color. + * colorMode(HSB); * - * // Create intermediate colors. - * let interA = lerpColor(from, to, 0.33); - * let interB = lerpColor(from, to, 0.66); + * // Create a p5.Color object. + * let c = color(0, 50, 100); * * // Draw the left rectangle. * noStroke(); - * fill(from); - * rect(10, 20, 20, 60); - * - * // Draw the left-center rectangle. - * fill(interA); - * rect(30, 20, 20, 60); + * fill(c); + * rect(15, 15, 35, 70); * - * // Draw the right-center rectangle. - * fill(interB); - * rect(50, 20, 20, 60); + * // Set 'satValue' to 50. + * let satValue = saturation(c); * * // Draw the right rectangle. - * fill(to); - * rect(70, 20, 20, 60); + * fill(satValue); + * rect(50, 15, 35, 70); * - * describe( - * 'Four rectangles. From left to right, the rectangles are tan, brown, brownish purple, and purple.' - * ); + * describe('Two rectangles. The left one is salmon pink and the right one is dark gray.'); * } * *
- */ - fn.lerpColor = function(c1, c2, amt) { - p5._validateParameters('lerpColor', arguments); - - // Find the closest common ancestor color space - let spaceIndex = -1; - while( - ( - spaceIndex+1 < c1.color.space.path.length || - spaceIndex+1 < c2.color.space.path.length - ) && - c1.color.space.path[spaceIndex+1] === c2.color.space.path[spaceIndex+1] - ){ - spaceIndex += 1; - } - - if (spaceIndex === -1) { - // This probably will not occur in practice - throw new Error('Cannot lerp colors. No common color space found'); - } - - // Get lerp value as a color in the common ancestor color space - const lerpColor = range(c1.color, c2.color, { - space: c1.color.space.path[spaceIndex].id - })(amt); - - return new p5.Color(lerpColor, this._colorMode, this._colorMaxes); - }; - - /** - * Gets the lightness value of a color. - * - * `lightness()` extracts the HSL lightness value from a - * p5.Color object, an array of color components, or - * a CSS color string. - * - * By default, `lightness()` returns a color's HSL lightness in the range 0 - * to 100. If the colorMode() is set to HSL, it - * returns the lightness value in the given range. - * - * @method lightness - * @param {p5.Color|Number[]|String} color p5.Color object, array of - * color components, or CSS color string. - * @return {Number} the lightness value. * * @example *
@@ -1054,22 +1053,22 @@ function creatingReading(p5, fn){ * * background(50); * - * // Use HSL color. - * colorMode(HSL); + * // Use HSB color. + * colorMode(HSB); * - * // Create a p5.Color object using HSL values. - * let c = color(0, 100, 75); + * // Create a color array. + * let c = [0, 50, 100]; * * // Draw the left rectangle. * noStroke(); * fill(c); * rect(15, 15, 35, 70); * - * // Set 'lightValue' to 75. - * let lightValue = lightness(c); + * // Set 'satValue' to 100. + * let satValue = saturation(c); * * // Draw the right rectangle. - * fill(lightValue); + * fill(satValue); * rect(50, 15, 35, 70); * * describe('Two rectangles. The left one is salmon pink and the right one is gray.'); @@ -1085,22 +1084,22 @@ function creatingReading(p5, fn){ * * background(50); * - * // Use HSL color. - * colorMode(HSL); + * // Use HSB color. + * colorMode(HSB); * - * // Create a color array. - * let c = [0, 100, 75]; + * // Create a CSS color string. + * let c = 'rgb(255, 128, 128)'; * * // Draw the left rectangle. * noStroke(); * fill(c); * rect(15, 15, 35, 70); * - * // Set 'lightValue' to 75. - * let lightValue = lightness(c); + * // Set 'satValue' to 100. + * let satValue = saturation(c); * * // Draw the right rectangle. - * fill(lightValue); + * fill(satValue); * rect(50, 15, 35, 70); * * describe('Two rectangles. The left one is salmon pink and the right one is gray.'); @@ -1119,22 +1118,22 @@ function creatingReading(p5, fn){ * // Use HSL color. * colorMode(HSL); * - * // Create a CSS color string. - * let c = 'rgb(255, 128, 128)'; + * // Create a p5.Color object. + * let c = color(0, 100, 75); * * // Draw the left rectangle. * noStroke(); * fill(c); * rect(15, 15, 35, 70); * - * // Set 'lightValue' to 75. - * let lightValue = lightness(c); + * // Set 'satValue' to 100. + * let satValue = saturation(c); * * // Draw the right rectangle. - * fill(lightValue); + * fill(satValue); * rect(50, 15, 35, 70); * - * describe('Two rectangles. The left one is salmon pink and the right one is gray.'); + * describe('Two rectangles. The left one is salmon pink and the right one is white.'); * } * *
@@ -1150,7 +1149,7 @@ function creatingReading(p5, fn){ * // Use HSL color with values in the range 0-255. * colorMode(HSL, 255); * - * // Create a p5.Color object using HSL values. + * // Create a p5.Color object. * let c = color(0, 255, 191.5); * * // Draw the left rectangle. @@ -1158,38 +1157,38 @@ function creatingReading(p5, fn){ * fill(c); * rect(15, 15, 35, 70); * - * // Set 'lightValue' to 191.5. - * let lightValue = lightness(c); + * // Set 'satValue' to 255. + * let satValue = saturation(c); * * // Draw the right rectangle. - * fill(lightValue); + * fill(satValue); * rect(50, 15, 35, 70); * - * describe('Two rectangles. The left one is salmon pink and the right one is gray.'); + * describe('Two rectangles. The left one is salmon pink and the right one is white.'); * } * * */ - fn.lightness = function(c) { - p5._validateParameters('lightness', arguments); - return this.color(c)._getLightness(); + fn.saturation = function(c) { + p5._validateParameters('saturation', arguments); + return this.color(c)._getSaturation(); }; /** - * Gets the red value of a color. + * Gets the brightness value of a color. * - * `red()` extracts the red value from a + * `brightness()` extracts the HSB brightness value from a * p5.Color object, an array of color components, or * a CSS color string. * - * By default, `red()` returns a color's red value in the range 0 - * to 255. If the colorMode() is set to RGB, it - * returns the red value in the given range. + * By default, `brightness()` returns a color's HSB brightness in the range 0 + * to 100. If the colorMode() is set to HSB, it + * returns the brightness value in the given range. * - * @method red + * @method brightness * @param {p5.Color|Number[]|String} color p5.Color object, array of * color components, or CSS color string. - * @return {Number} the red value. + * @return {Number} the brightness value. * * @example *
@@ -1199,22 +1198,25 @@ function creatingReading(p5, fn){ * * background(200); * + * // Use HSB color. + * colorMode(HSB); + * * // Create a p5.Color object. - * let c = color(175, 100, 220); + * let c = color(0, 50, 100); * * // Draw the left rectangle. * noStroke(); * fill(c); * rect(15, 15, 35, 70); * - * // Set 'redValue' to 175. - * let redValue = red(c); + * // Set 'brightValue' to 100. + * let brightValue = brightness(c); * * // Draw the right rectangle. - * fill(redValue, 0, 0); + * fill(brightValue); * rect(50, 15, 35, 70); * - * describe('Two rectangles. The left one is light purple and the right one is red.'); + * describe('Two rectangles. The left one is salmon pink and the right one is white.'); * } * *
@@ -1227,22 +1229,25 @@ function creatingReading(p5, fn){ * * background(200); * + * // Use HSB color. + * colorMode(HSB); + * * // Create a color array. - * let c = [175, 100, 220]; + * let c = [0, 50, 100]; * * // Draw the left rectangle. * noStroke(); * fill(c); * rect(15, 15, 35, 70); * - * // Set 'redValue' to 175. - * let redValue = red(c); + * // Set 'brightValue' to 100. + * let brightValue = brightness(c); * * // Draw the right rectangle. - * fill(redValue, 0, 0); + * fill(brightValue); * rect(50, 15, 35, 70); * - * describe('Two rectangles. The left one is light purple and the right one is red.'); + * describe('Two rectangles. The left one is salmon pink and the right one is white.'); * } * * @@ -1255,22 +1260,25 @@ function creatingReading(p5, fn){ * * background(200); * + * // Use HSB color. + * colorMode(HSB); + * * // Create a CSS color string. - * let c = 'rgb(175, 100, 220)'; + * let c = 'rgb(255, 128, 128)'; * * // Draw the left rectangle. * noStroke(); * fill(c); * rect(15, 15, 35, 70); * - * // Set 'redValue' to 175. - * let redValue = red(c); + * // Set 'brightValue' to 100. + * let brightValue = brightness(c); * * // Draw the right rectangle. - * fill(redValue, 0, 0); + * fill(brightValue); * rect(50, 15, 35, 70); * - * describe('Two rectangles. The left one is light purple and the right one is red.'); + * describe('Two rectangles. The left one is salmon pink and the right one is white.'); * } * * @@ -1283,50 +1291,49 @@ function creatingReading(p5, fn){ * * background(200); * - * // Use RGB color with values in the range 0-100. - * colorMode(RGB, 100); + * // Use HSB color with values in the range 0-255. + * colorMode(HSB, 255); * * // Create a p5.Color object. - * let c = color(69, 39, 86); + * let c = color(0, 127, 255); * * // Draw the left rectangle. * noStroke(); * fill(c); * rect(15, 15, 35, 70); * - * // Set 'redValue' to 69. - * let redValue = red(c); + * // Set 'brightValue' to 255. + * let brightValue = brightness(c); * * // Draw the right rectangle. - * fill(redValue, 0, 0); + * fill(brightValue); * rect(50, 15, 35, 70); * - * describe('Two rectangles. The left one is light purple and the right one is red.'); + * describe('Two rectangles. The left one is salmon pink and the right one is white.'); * } * * */ - fn.red = function(c) { - p5._validateParameters('red', arguments); - return this.color(c)._getRed(); + fn.brightness = function(c) { + p5._validateParameters('brightness', arguments); + return this.color(c)._getBrightness(); }; /** - * Gets the saturation value of a color. + * Gets the lightness value of a color. * - * `saturation()` extracts the saturation value from a + * `lightness()` extracts the HSL lightness value from a * p5.Color object, an array of color components, or * a CSS color string. * - * Saturation is scaled differently in HSB and HSL. By default, `saturation()` - * returns a color's HSL saturation in the range 0 to 100. If the - * colorMode() is set to HSB or HSL, it returns the - * saturation value in the given mode. + * By default, `lightness()` returns a color's HSL lightness in the range 0 + * to 100. If the colorMode() is set to HSL, it + * returns the lightness value in the given range. * - * @method saturation + * @method lightness * @param {p5.Color|Number[]|String} color p5.Color object, array of * color components, or CSS color string. - * @return {Number} the saturation value + * @return {Number} the lightness value. * * @example *
@@ -1336,25 +1343,25 @@ function creatingReading(p5, fn){ * * background(50); * - * // Use HSB color. - * colorMode(HSB); + * // Use HSL color. + * colorMode(HSL); * - * // Create a p5.Color object. - * let c = color(0, 50, 100); + * // Create a p5.Color object using HSL values. + * let c = color(0, 100, 75); * * // Draw the left rectangle. * noStroke(); * fill(c); * rect(15, 15, 35, 70); * - * // Set 'satValue' to 50. - * let satValue = saturation(c); + * // Set 'lightValue' to 75. + * let lightValue = lightness(c); * * // Draw the right rectangle. - * fill(satValue); + * fill(lightValue); * rect(50, 15, 35, 70); * - * describe('Two rectangles. The left one is salmon pink and the right one is dark gray.'); + * describe('Two rectangles. The left one is salmon pink and the right one is gray.'); * } * *
@@ -1367,22 +1374,22 @@ function creatingReading(p5, fn){ * * background(50); * - * // Use HSB color. - * colorMode(HSB); + * // Use HSL color. + * colorMode(HSL); * * // Create a color array. - * let c = [0, 50, 100]; + * let c = [0, 100, 75]; * * // Draw the left rectangle. * noStroke(); * fill(c); * rect(15, 15, 35, 70); * - * // Set 'satValue' to 100. - * let satValue = saturation(c); + * // Set 'lightValue' to 75. + * let lightValue = lightness(c); * * // Draw the right rectangle. - * fill(satValue); + * fill(lightValue); * rect(50, 15, 35, 70); * * describe('Two rectangles. The left one is salmon pink and the right one is gray.'); @@ -1398,8 +1405,8 @@ function creatingReading(p5, fn){ * * background(50); * - * // Use HSB color. - * colorMode(HSB); + * // Use HSL color. + * colorMode(HSL); * * // Create a CSS color string. * let c = 'rgb(255, 128, 128)'; @@ -1409,11 +1416,11 @@ function creatingReading(p5, fn){ * fill(c); * rect(15, 15, 35, 70); * - * // Set 'satValue' to 100. - * let satValue = saturation(c); + * // Set 'lightValue' to 75. + * let lightValue = lightness(c); * * // Draw the right rectangle. - * fill(satValue); + * fill(lightValue); * rect(50, 15, 35, 70); * * describe('Two rectangles. The left one is salmon pink and the right one is gray.'); @@ -1429,28 +1436,52 @@ function creatingReading(p5, fn){ * * background(50); * - * // Use HSL color. - * colorMode(HSL); + * // Use HSL color with values in the range 0-255. + * colorMode(HSL, 255); * - * // Create a p5.Color object. - * let c = color(0, 100, 75); + * // Create a p5.Color object using HSL values. + * let c = color(0, 255, 191.5); * * // Draw the left rectangle. * noStroke(); * fill(c); * rect(15, 15, 35, 70); * - * // Set 'satValue' to 100. - * let satValue = saturation(c); + * // Set 'lightValue' to 191.5. + * let lightValue = lightness(c); * * // Draw the right rectangle. - * fill(satValue); + * fill(lightValue); * rect(50, 15, 35, 70); * - * describe('Two rectangles. The left one is salmon pink and the right one is white.'); + * describe('Two rectangles. The left one is salmon pink and the right one is gray.'); * } * * + */ + fn.lightness = function(c) { + p5._validateParameters('lightness', arguments); + return this.color(c)._getLightness(); + }; + + /** + * Blends two colors to find a third color between them. + * + * The `amt` parameter specifies the amount to interpolate between the two + * values. 0 is equal to the first color, 0.1 is very near the first color, + * 0.5 is halfway between the two colors, and so on. Negative numbers are set + * to 0. Numbers greater than 1 are set to 1. This differs from the behavior of + * lerp. It's necessary because numbers outside of the + * interval [0, 1] will produce strange and unexpected colors. + * + * The way that colors are interpolated depends on the current + * colorMode(). + * + * @method lerpColor + * @param {p5.Color} c1 interpolate from this color. + * @param {p5.Color} c2 interpolate to this color. + * @param {Number} amt number between 0 and 1. + * @return {p5.Color} interpolated color. * * @example *
@@ -1458,34 +1489,43 @@ function creatingReading(p5, fn){ * function setup() { * createCanvas(100, 100); * - * background(50); + * background(200); * - * // Use HSL color with values in the range 0-255. - * colorMode(HSL, 255); + * // Create p5.Color objects to interpolate between. + * let from = color(218, 165, 32); + * let to = color(72, 61, 139); * - * // Create a p5.Color object. - * let c = color(0, 255, 191.5); + * // Create intermediate colors. + * let interA = lerpColor(from, to, 0.33); + * let interB = lerpColor(from, to, 0.66); * * // Draw the left rectangle. * noStroke(); - * fill(c); - * rect(15, 15, 35, 70); + * fill(from); + * rect(10, 20, 20, 60); * - * // Set 'satValue' to 255. - * let satValue = saturation(c); + * // Draw the left-center rectangle. + * fill(interA); + * rect(30, 20, 20, 60); + * + * // Draw the right-center rectangle. + * fill(interB); + * rect(50, 20, 20, 60); * * // Draw the right rectangle. - * fill(satValue); - * rect(50, 15, 35, 70); + * fill(to); + * rect(70, 20, 20, 60); * - * describe('Two rectangles. The left one is salmon pink and the right one is white.'); + * describe( + * 'Four rectangles. From left to right, the rectangles are tan, brown, brownish purple, and purple.' + * ); * } * *
*/ - fn.saturation = function(c) { - p5._validateParameters('saturation', arguments); - return this.color(c)._getSaturation(); + fn.lerpColor = function(c1, c2, amt) { + p5._validateParameters('lerpColor', arguments); + return c1.lerp(c2, amt, this._renderer.states.colorMode); }; } diff --git a/src/color/p5.Color.culori.js b/src/color/p5.Color.culori.js new file mode 100644 index 0000000000..0e184b13dc --- /dev/null +++ b/src/color/p5.Color.culori.js @@ -0,0 +1,66 @@ +class Color { + _color; + maxes; + mode; + array; + + static addColorMode(mode, definition){ + + } + + constructor(vals){ + + } + + toString(){ + + } + + setRed(new_red){ + + } + + setGreen(new_green){ + + } + + setBlue(new_blue){ + + } + + setAlpha(new_alpha){ + + } + + _getRed(){ + + } + + _getGreen(){ + + } + + _getBlue(){ + + } + + _getAlpha(){ + + } + + _getHue(){ + + } + + _getSaturation(){ + + } + + _getBrightness(){ + + } + + _getLightness(){ + + } +} diff --git a/src/color/p5.Color.js b/src/color/p5.Color.js index 213821bf14..0df96a4abd 100644 --- a/src/color/p5.Color.js +++ b/src/color/p5.Color.js @@ -3,144 +3,198 @@ * @submodule Creating & Reading * @for p5 * @requires core - * @requires constants * @requires color_conversion */ -import * as constants from '../core/constants'; +import { RGB, RGBHDR, HSL, HSB, HWB, LAB, LCH, OKLAB, OKLCH } from './creating_reading'; + import { ColorSpace, to, - // toGamut, + toGamut, serialize, parse, - // range, + range, - XYZ_D65, - sRGB_Linear, sRGB, - HSL, - HSV, - HWB, + HSL as HSLSpace, + HWB as HWBSpace, - XYZ_D50, Lab, - LCH, + LCH as LCHSpace, OKLab, - OKLCH, - - P3_Linear, - P3, + OKLCH as OKLCHSpace, - A98RGB_Linear, - A98RGB + P3 } from 'colorjs.io/fn'; -import HSB from './color_spaces/hsb.js'; - -ColorSpace.register(XYZ_D65); -ColorSpace.register(sRGB_Linear); -ColorSpace.register(sRGB); -ColorSpace.register(HSL); -ColorSpace.register(HSV); -ColorSpace.register(HWB); -ColorSpace.register(HSB); - -ColorSpace.register(XYZ_D50); -ColorSpace.register(Lab); -ColorSpace.register(LCH); +import HSBSpace from './color_spaces/hsb.js'; -ColorSpace.register(OKLab); -ColorSpace.register(OKLCH); - -ColorSpace.register(P3_Linear); -ColorSpace.register(P3); - -ColorSpace.register(A98RGB_Linear); -ColorSpace.register(A98RGB); +const map = (n, start1, stop1, start2, stop2) => + ((n - start1) / (stop1 - start1) * (stop2 - start2) + start2); class Color { - color; - maxes; + // Reference to underlying color object depending on implementation + // Not meant to be used publicly unless the implementation is known for sure + _color; + // Color mode of the Color object, uses p5 color modes mode; - constructor(vals, colorMode='rgb', colorMaxes={rgb: [255, 255, 255, 255]}) { - // This changes with the sketch's setting - // NOTE: Maintaining separate maxes for different color space is awkward. - // Consider just one universal maxes. - // this.maxes = pInst._colorMaxes; - this.maxes = colorMaxes; + static colorMap = {}; + static #colorjsMaxes = {}; + + // Used to add additional color modes to p5.js + // Uses underlying library's definition + static addColorMode(mode, definition){ + ColorSpace.register(definition); + Color.colorMap[mode] = definition.id; + // Get colorjs maxes + Color.#colorjsMaxes[mode] = Object.values(definition.coords).reduce((acc, v) => { + acc.push(v.refRange || v.range); + return acc; + }, []); + Color.#colorjsMaxes[mode].push([0, 1]); + } + + constructor(vals, colorMode, colorMaxes) { // This changes with the color object - // this.mode = pInst._colorMode; - this.mode = colorMode; + this.mode = colorMode || RGB; + + if(vals instanceof Color){ + // Received Color object to be used for color mode conversion + const mode = colorMode ? + Color.colorMap[colorMode] : + Color.colorMap[vals.mode]; + this._color = to(vals._color, mode); + this.mode = mode; + + }else if (typeof vals === 'object' && !Array.isArray(vals) && vals !== null){ + // Received color.js object to be used internally + const mode = colorMode ? + Color.colorMap[colorMode] : + vals.spaceId; + this._color = to(vals, mode); + this.mode = colorMode || Object.entries(Color.colorMap).find(([key, val]) => { + return val === this._color.spaceId; + }); - if (typeof vals === 'object' && !Array.isArray(vals) && vals !== null){ - this.color = vals; } else if(typeof vals[0] === 'string') { + // Received string try{ - // NOTE: this will not necessarily have the right color mode - this.color = parse(vals[0]); + this._color = parse(vals[0]); + const [mode] = Object.entries(Color.colorMap).find(([key, val]) => { + return val === this._color.spaceId; + }); + this.mode = mode; + this._color = to(this._color, this._color.spaceId); }catch(err){ // TODO: Invalid color string console.error('Invalid color string'); } }else{ - let alpha; - - if(vals.length === 4){ - alpha = vals[vals.length-1]; - }else if (vals.length === 2){ - alpha = vals[1]; - vals = [vals[0], vals[0], vals[0]]; - }else if(vals.length === 1){ - vals = [vals[0], vals[0], vals[0]]; - } - alpha = alpha !== undefined - ? alpha / this.maxes[this.mode][3] - : 1; - - // _colorMode can be 'rgb', 'hsb', or 'hsl' - // These should map to color.js color space - let space = 'srgb'; - let coords = vals; - switch(this.mode){ - case 'rgb': - space = 'srgb'; - coords = [ - vals[0] / this.maxes[this.mode][0], - vals[1] / this.maxes[this.mode][1], - vals[2] / this.maxes[this.mode][2] - ]; - break; - case 'hsb': - // TODO: need implementation - space = 'hsb'; - coords = [ - vals[0] / this.maxes[this.mode][0] * 360, - vals[1] / this.maxes[this.mode][1] * 100, - vals[2] / this.maxes[this.mode][2] * 100 - ]; - break; - case 'hsl': - space = 'hsl'; - coords = [ - vals[0] / this.maxes[this.mode][0] * 360, - vals[1] / this.maxes[this.mode][1] * 100, - vals[2] / this.maxes[this.mode][2] * 100 - ]; - break; - default: - console.error('Invalid color mode'); + // Received individual channel values + let mappedVals; + + if(colorMaxes){ + if(vals.length === 4){ + mappedVals = Color.mapColorRange(vals, this.mode, colorMaxes); + }else if(vals.length === 3){ + mappedVals = Color.mapColorRange([vals[0], vals[1], vals[2]], this.mode, colorMaxes); + mappedVals.push(1); + }else if(vals.length === 2){ + mappedVals = Color.mapColorRange([vals[0], vals[0], vals[0], vals[1]], this.mode, colorMaxes); + }else if(vals.length === 1){ + mappedVals = Color.mapColorRange([vals[0], vals[0], vals[0]], this.mode, colorMaxes); + mappedVals.push(1); + } + }else{ + mappedVals = vals; } + const space = Color.colorMap[this.mode] || console.error('Invalid color mode'); + const coords = mappedVals.slice(0, 3); + const color = { space, coords, - alpha + alpha: mappedVals[3] }; - this.color = to(color, space); + this._color = to(color, space); + } + } + + // Convert from p5 color range to color.js color range + static mapColorRange(origin, mode, maxes){ + const p5Maxes = maxes.map((max) => { + if(!Array.isArray(max)){ + return [0, max]; + }else{ + return max; + } + }); + const colorjsMaxes = Color.#colorjsMaxes[mode]; + + return origin.map((channel, i) => { + const newval = map(channel, p5Maxes[i][0], p5Maxes[i][1], colorjsMaxes[i][0], colorjsMaxes[i][1]); + return newval; + }); + } + + // Convert from color.js color range to p5 color range + static unmapColorRange(origin, mode, maxes){ + const p5Maxes = maxes.map((max) => { + if(!Array.isArray(max)){ + return [0, max]; + }else{ + return max; + } + }); + const colorjsMaxes = Color.#colorjsMaxes[mode]; + + return origin.map((channel, i) => { + const newval = map(channel, colorjsMaxes[i][0], colorjsMaxes[i][1], p5Maxes[i][0], p5Maxes[i][1]); + return newval; + }); + } + + // Will do conversion in-Gamut as out of Gamut conversion is only really useful for futher conversions + #toColorMode(mode){ + return new Color(this._color, mode); + } + + // Get raw coordinates of underlying library, can differ between libraries + get _array() { + return [...this._color.coords, this._color.alpha]; + } + + array(){ + return this._array; + } + + lerp(color, amt, mode){ + // Find the closest common ancestor color space + let spaceIndex = -1; + while( + ( + spaceIndex+1 < this._color.space.path.length || + spaceIndex+1 < color._color.space.path.length + ) && + this._color.space.path[spaceIndex+1] === color._color.space.path[spaceIndex+1] + ){ + spaceIndex += 1; } + + if (spaceIndex === -1) { + // This probably will not occur in practice + throw new Error('Cannot lerp colors. No common color space found'); + } + + const obj = range(this._color, color._color, { + space: this._color.space.path[spaceIndex].id + })(amt); + + return new Color(obj, mode || this.mode); } /** @@ -186,7 +240,7 @@ class Color { */ toString(format) { // NOTE: memoize - return serialize(this.color, { + return serialize(this._color, { format }); } @@ -227,16 +281,22 @@ class Color { * * */ - setRed(new_red) { - const red_val = new_red / this.maxes[constants.RGB][0]; - if(this.mode === constants.RGB){ - this.color.coords[0] = red_val; + setRed(new_red, max=[0, 1]) { + if(!Array.isArray(max)){ + max = [0, max]; + } + + const colorjsMax = Color.#colorjsMaxes[RGB][0]; + const newval = map(new_red, max[0], max[1], colorjsMax[0], colorjsMax[1]); + + if(this.mode === RGB || this.mode === RGBHDR){ + this._color.coords[0] = newval; }else{ // Will do an imprecise conversion to 'srgb', not recommended - const space = this.color.space.id; - const representation = to(this.color, 'srgb'); - representation.coords[0] = red_val; - this.color = to(representation, space); + const space = this._color.space.id; + const representation = to(this._color, 'srgb'); + representation.coords[0] = newval; + this._color = to(representation, space); } } @@ -276,16 +336,22 @@ class Color { * * **/ - setGreen(new_green) { - const green_val = new_green / this.maxes[constants.RGB][1]; - if(this.mode === constants.RGB){ - this.color.coords[1] = green_val; + setGreen(new_green, max=[0, 1]) { + if(!Array.isArray(max)){ + max = [0, max]; + } + + const colorjsMax = Color.#colorjsMaxes[RGB][1]; + const newval = map(new_green, max[0], max[1], colorjsMax[0], colorjsMax[1]); + + if(this.mode === RGB || this.mode === RGBHDR){ + this._color.coords[1] = newval; }else{ // Will do an imprecise conversion to 'srgb', not recommended - const space = this.color.space.id; - const representation = to(this.color, 'srgb'); - representation.coords[1] = green_val; - this.color = to(representation, space); + const space = this._color.space.id; + const representation = to(this._color, 'srgb'); + representation.coords[1] = newval; + this._color = to(representation, space); } } @@ -325,16 +391,22 @@ class Color { * * **/ - setBlue(new_blue) { - const blue_val = new_blue / this.maxes[constants.RGB][2]; - if(this.mode === constants.RGB){ - this.color.coords[2] = blue_val; + setBlue(new_blue, max=[0, 1]) { + if(!Array.isArray(max)){ + max = [0, max]; + } + + const colorjsMax = Color.#colorjsMaxes[RGB][2]; + const newval = map(new_blue, max[0], max[1], colorjsMax[0], colorjsMax[1]); + + if(this.mode === RGB || this.mode === RGBHDR){ + this._color.coords[2] = newval; }else{ // Will do an imprecise conversion to 'srgb', not recommended - const space = this.color.space.id; - const representation = to(this.color, 'srgb'); - representation.coords[2] = blue_val; - this.color = to(representation, space); + const space = this._color.space.id; + const representation = to(this._color, 'srgb'); + representation.coords[2] = newval; + this._color = to(representation, space); } } @@ -375,47 +447,96 @@ class Color { * * **/ - setAlpha(new_alpha) { - this.color.alpha = new_alpha / this.maxes[this.mode][3]; + setAlpha(new_alpha, max=[0, 1]) { + if(!Array.isArray(max)){ + max = [0, max]; + } + + const colorjsMax = Color.#colorjsMaxes[this.mode][3]; + const newval = map(new_alpha, max[0], max[1], colorjsMax[0], colorjsMax[1]); + + this._color.alpha = newval; + } + + _getRGBA(maxes=[1, 1, 1, 1]) { + // Get colorjs maxes + const colorjsMaxes = Color.#colorjsMaxes[this.mode]; + + // Normalize everything to 0,1 or the provided range (map) + let coords = structuredClone(to(this._color, 'srgb').coords); + coords.push(this._color.alpha); + + const rangeMaxes = maxes.map((v) => { + if(!Array.isArray(v)){ + return [0, v]; + }else{ + return v + } + }); + + coords = coords.map((coord, i) => { + return map(coord, colorjsMaxes[i][0], colorjsMaxes[i][1], rangeMaxes[i][0], rangeMaxes[i][1]); + }); + + return coords; } - _getRed() { - if(this.mode === constants.RGB){ - return this.color.coords[0] * this.maxes[constants.RGB][0]; + _getMode() { + return this.mode; + } + + _getRed(max=[0, 1]) { + if(!Array.isArray(max)){ + max = [0, max]; + } + + if(this.mode === RGB || this.mode === RGBHDR){ + const colorjsMax = Color.#colorjsMaxes[this.mode][0]; + return map(this._color.coords[0], colorjsMax[0], colorjsMax[1], max[0], max[1]); }else{ // Will do an imprecise conversion to 'srgb', not recommended - return to(this.color, 'srgb').coords[0] * this.maxes[constants.RGB][0]; + const colorjsMax = Color.#colorjsMaxes[RGB][0]; + return map(to(this._color, 'srgb').coords[0], colorjsMax[0], colorjsMax[1], max[0], max[1]); } } - _getGreen() { - if(this.mode === constants.RGB){ - return this.color.coords[1] * this.maxes[constants.RGB][1]; + _getGreen(max=[0, 1]) { + if(!Array.isArray(max)){ + max = [0, max]; + } + + if(this.mode === RGB || this.mode === RGBHDR){ + const colorjsMax = Color.#colorjsMaxes[this.mode][1]; + return map(this._color.coords[1], colorjsMax[0], colorjsMax[1], max[0], max[1]); }else{ // Will do an imprecise conversion to 'srgb', not recommended - return to(this.color, 'srgb').coords[1] * this.maxes[constants.RGB][1]; + const colorjsMax = Color.#colorjsMaxes[RGB][1]; + return map(to(this._color, 'srgb').coords[1], colorjsMax[0], colorjsMax[1], max[0], max[1]); } } - _getBlue() { - if(this.mode === constants.RGB){ - return this.color.coords[2] * this.maxes[constants.RGB][2]; + _getBlue(max=[0, 1]) { + if(!Array.isArray(max)){ + max = [0, max]; + } + + if(this.mode === RGB || this.mode === RGBHDR){ + const colorjsMax = Color.#colorjsMaxes[this.mode][2]; + return map(this._color.coords[2], colorjsMax[0], colorjsMax[1], max[0], max[1]); }else{ // Will do an imprecise conversion to 'srgb', not recommended - return to(this.color, 'srgb').coords[2] * this.maxes[constants.RGB][2]; + const colorjsMax = Color.#colorjsMaxes[RGB][2]; + return map(to(this._color, 'srgb').coords[2], colorjsMax[0], colorjsMax[1], max[0], max[1]); } } - _getAlpha() { - return this.color.alpha * this.maxes[this.mode][3]; - } - - _getMode() { - return this.mode; - } + _getAlpha(max=[0, 1]) { + if(!Array.isArray(max)){ + max = [0, max]; + } - _getMaxes() { - return this.maxes; + const colorjsMax = Color.#colorjsMaxes[this.mode][3]; + return map(this._color.alpha, colorjsMax[0], colorjsMax[1], max[0], max[1]); } /** @@ -424,12 +545,18 @@ class Color { * an HSB color object, but will default to the HSL-normalized saturation * otherwise. */ - _getHue() { - if(this.mode === constants.HSB || this.mode === constants.HSL){ - return this.color.coords[0] / 360 * this.maxes[this.mode][0]; + _getHue(max=[0, 360]) { + if(!Array.isArray(max)){ + max = [0, max]; + } + + if(this.mode === HSB || this.mode === HSL){ + const colorjsMax = Color.#colorjsMaxes[this.mode][0]; + return map(this._color.coords[0], colorjsMax[0], colorjsMax[1], max[0], max[1]); }else{ // Will do an imprecise conversion to 'HSL', not recommended - return to(this.color, 'hsl').coords[0] / 360 * this.maxes[this.mode][0]; + const colorjsMax = Color.#colorjsMaxes[HSL][0]; + return map(to(this._color, 'hsl').coords[0], colorjsMax[0], colorjsMax[1], max[0], max[1]); } } @@ -438,47 +565,53 @@ class Color { * the HSB saturation when supplied with an HSB color object, but will default * to the HSL saturation otherwise. */ - _getSaturation() { - if(this.mode === constants.HSB || this.mode === constants.HSL){ - return this.color.coords[1] / 100 * this.maxes[this.mode][1]; + _getSaturation(max=[0, 100]) { + if(!Array.isArray(max)){ + max = [0, max]; + } + + if(this.mode === HSB || this.mode === HSL){ + const colorjsMax = Color.#colorjsMaxes[this.mode][1]; + return map(this._color.coords[1], colorjsMax[0], colorjsMax[1], max[0], max[1]); }else{ // Will do an imprecise conversion to 'HSL', not recommended - return to(this.color, 'hsl').coords[1] / 100 * this.maxes[this.mode][1]; + const colorjsMax = Color.#colorjsMaxes[HSL][1]; + return map(to(this._color, 'hsl').coords[1], colorjsMax[0], colorjsMax[1], max[0], max[1]); } } - _getBrightness() { - if(this.mode === constants.HSB){ - return this.color.coords[2] / 100 * this.maxes[this.mode][2]; - }else{ - // Will do an imprecise conversion to 'HSB', not recommended - return to(this.color, 'hsb').coords[2] / 100 * this.maxes[this.mode][2]; + _getBrightness(max=[0, 100]) { + if(!Array.isArray(max)){ + max = [0, max]; } - } - _getLightness() { - if(this.mode === constants.HSL){ - return this.color.coords[2] / 100 * this.maxes[this.mode][2]; + if(this.mode === HSB){ + const colorjsMax = Color.#colorjsMaxes[this.mode][2]; + return map(this._color.coords[2], colorjsMax[0], colorjsMax[1], max[0], max[1]); }else{ // Will do an imprecise conversion to 'HSB', not recommended - return to(this.color, 'hsl').coords[2] / 100 * this.maxes[this.mode][2]; + const colorjsMax = Color.#colorjsMaxes[HSB][2]; + return map(to(this._color, 'hsb').coords[2], colorjsMax[0], colorjsMax[1], max[0], max[1]); } } - get _array() { - return this.array(); - } - - array() { - return [...this.color.coords, this.color.alpha]; - } + _getLightness(max=[0, 100]) { + if(!Array.isArray(max)){ + max = [0, max]; + } - get levels() { - return this._array.map(v => v * 255); + if(this.mode === HSL){ + const colorjsMax = Color.#colorjsMaxes[this.mode][2]; + return map(this._color.coords[2], colorjsMax[0], colorjsMax[1], max[0], max[1]); + }else{ + // Will do an imprecise conversion to 'HSL', not recommended + const colorjsMax = Color.#colorjsMaxes[HSL][2]; + return map(to(this._color, 'hsl').coords[2], colorjsMax[0], colorjsMax[1], max[0], max[1]); + } } } -function color(p5, fn){ +function color(p5, fn, lifecycles){ /** * A class to describe a color. * @@ -507,6 +640,89 @@ function color(p5, fn){ * or CSS color. */ p5.Color = Color; + + // Register color modes and initialize Color maxes to what p5 has set for itself + p5.Color.addColorMode(RGB, sRGB); + p5.Color.addColorMode(RGBHDR, P3); + p5.Color.addColorMode(HSB, HSBSpace); + p5.Color.addColorMode(HSL, HSLSpace); + p5.Color.addColorMode(HWB, HWBSpace); + p5.Color.addColorMode(LAB, Lab); + p5.Color.addColorMode(LCH, LCHSpace); + p5.Color.addColorMode(OKLAB, OKLab); + p5.Color.addColorMode(OKLCH, OKLCHSpace); + + lifecycles.presetup = function(){ + const pInst = this; + + // Decorate set methods + const setMethods = ['Red', 'Green', 'Blue', 'Alpha']; + for(let i in setMethods){ + const method = setMethods[i]; + const setCopy = p5.Color.prototype['set' + method]; + p5.Color.prototype['set' + method] = function(newval, max){ + max = max || pInst?._renderer?.states?.colorMaxes?.[RGB][i]; + return setCopy.call(this, newval, max); + } + } + + // Decorate get methods + function decorateGet(channel, modes){ + const getCopy = p5.Color.prototype['_get' + channel]; + p5.Color.prototype['_get' + channel] = function(max){ + if(Object.keys(modes).includes(this.mode)){ + max = max || pInst?._renderer?.states?.colorMaxes?.[this.mode][modes[this.mode]]; + }else{ + const defaultMode = Object.keys(modes)[0]; + max = max || pInst?._renderer?.states?.colorMaxes?.[defaultMode][modes[defaultMode]]; + } + + return getCopy.call(this, max); + } + } + + decorateGet('Red', { + [RGB]: 0, + [RGBHDR]: 0 + }); + decorateGet('Green', { + [RGB]: 1, + [RGBHDR]: 1 + }); + decorateGet('Blue', { + [RGB]: 2, + [RGBHDR]: 2 + }); + decorateGet('Alpha', { + [RGB]: 3, + [RGBHDR]: 3, + [HSB]: 3, + [HSL]: 3, + [HWB]: 3, + [LAB]: 3, + [LCH]: 3, + [OKLAB]: 3, + [OKLCH]: 3 + }); + + decorateGet('Hue', { + [HSL]: 0, + [HSB]: 0, + [HWB]: 0, + [LCH]: 2, + [OKLCH]: 2 + }); + decorateGet('Saturation', { + [HSL]: 1, + [HSB]: 1 + }); + decorateGet('Brightness', { + [HSB]: 2 + }); + decorateGet('Lightness', { + [HSL]: 2 + }); + }; } export default color; diff --git a/src/color/setting.js b/src/color/setting.js index 8103aae975..05f8f684ba 100644 --- a/src/color/setting.js +++ b/src/color/setting.js @@ -7,6 +7,7 @@ */ import * as constants from '../core/constants'; +import { RGB, RGBHDR, HSL, HSB, HWB, LAB, LCH, OKLAB, OKLCH } from './creating_reading'; function setting(p5, fn){ /** @@ -944,20 +945,29 @@ function setting(p5, fn){ * @param {Number} max3 range for the blue or brightness/lightness * depending on the current color mode. * @param {Number} [maxA] range for the alpha. - * @chainable + * + * @return {String} The current color mode. */ fn.colorMode = function(mode, max1, max2, max3, maxA) { p5._validateParameters('colorMode', arguments); if ( - mode === constants.RGB || - mode === constants.HSB || - mode === constants.HSL + [ + RGB, + RGBHDR, + HSB, + HSL, + HWB, + LAB, + LCH, + OKLAB, + OKLCH + ].includes(mode) ) { // Set color mode. - this._colorMode = mode; + this._renderer.states.colorMode = mode; // Set color maxes. - const maxes = this._colorMaxes[mode]; + const maxes = this._renderer.states.colorMaxes[mode]; if (arguments.length === 2) { maxes[0] = max1; // Red maxes[1] = max1; // Green @@ -975,7 +985,7 @@ function setting(p5, fn){ } } - return this; + return this._renderer.states.colorMode; }; /** @@ -1577,7 +1587,6 @@ function setting(p5, fn){ * @param {p5.Color} color the stroke color. * @chainable */ - fn.stroke = function(...args) { this._renderer.stroke(...args); return this; diff --git a/src/core/constants.js b/src/core/constants.js index 8142772026..ff9c873433 100644 --- a/src/core/constants.js +++ b/src/core/constants.js @@ -21,6 +21,9 @@ export const VERSION = 'VERSION_WILL_BE_REPLACED_BY_BUILD'; * @final */ export const P2D = Symbol('p2d'); + +export const P2DHDR = 'p2d-hdr'; + /** * One of the two render modes in p5.js, used for computationally intensive tasks like 3D rendering and shaders. * @@ -841,7 +844,7 @@ export const MITER = 'miter'; * @property {RGB} RGB * @final */ -export const RGB = 'rgb'; +// export const RGB = 'rgb'; /** * HSB (hue, saturation, brightness) is a type of color model. * You can learn more about it at @@ -851,13 +854,19 @@ export const RGB = 'rgb'; * @property {HSB} HSB * @final */ -export const HSB = 'hsb'; +// export const HSB = 'hsb'; /** * @typedef {'hsl'} HSL * @property {HSL} HSL * @final */ -export const HSL = 'hsl'; +// export const HSL = 'hsl'; +/** + * @typedef {'rgba'} RGBA + * @property {RGBA} RGBA + * @final + */ +// export const RGBA = 'rgba'; // DOM EXTENSION /** @@ -1337,13 +1346,6 @@ export const FLOAT = 'float'; */ export const HALF_FLOAT = 'half-float'; -/** - * @typedef {'rgba'} RGBA - * @property {RGBA} RGBA - * @final - */ -export const RGBA = 'rgba'; - /** * The `splineEnds` mode where splines curve through * their first and last points. diff --git a/src/core/main.js b/src/core/main.js index b7b935dbb0..af2b37f68c 100644 --- a/src/core/main.js +++ b/src/core/main.js @@ -413,14 +413,6 @@ class p5 { }; this._styles = []; - - this._colorMode = constants.RGB; - this._colorMaxes = { - rgb: [255, 255, 255, 255], - hsb: [360, 100, 100, 1], - hsl: [360, 100, 100, 1] - }; - this._downKeys = {}; //Holds the key codes of currently pressed keys } } diff --git a/src/core/p5.Graphics.js b/src/core/p5.Graphics.js index eda81d8ba3..403f934e2c 100644 --- a/src/core/p5.Graphics.js +++ b/src/core/p5.Graphics.js @@ -4,8 +4,8 @@ * @for p5 */ -// import p5 from './main'; import * as constants from './constants'; +import { RGB, HSB, HSL } from '../color/creating_reading'; import primitives2D from '../shape/2d_primitives'; import attributes from '../shape/attributes'; import curves from '../shape/curves'; @@ -576,12 +576,12 @@ class Graphics { this._bezierDetail = 20; this._curveDetail = 20; - this._colorMode = constants.RGB; - this._colorMaxes = { - rgb: [255, 255, 255, 255], - hsb: [360, 100, 100, 1], - hsl: [360, 100, 100, 1] - }; + // this._colorMode = RGB; + // this._colorMaxes = { + // rgb: [255, 255, 255, 255], + // hsb: [360, 100, 100, 1], + // hsl: [360, 100, 100, 1] + // }; this._downKeys = {}; //Holds the key codes of currently pressed keys } diff --git a/src/core/p5.Renderer.js b/src/core/p5.Renderer.js index 61d6ea0c2f..bcc69ed086 100644 --- a/src/core/p5.Renderer.js +++ b/src/core/p5.Renderer.js @@ -11,6 +11,37 @@ import { Vector } from '../math/p5.Vector'; import { Shape } from '../shape/custom_shapes'; class Renderer { + static states = { + strokeColor: null, + strokeSet: false, + fillColor: null, + fillSet: false, + tint: null, + + imageMode: constants.CORNER, + rectMode: constants.CORNER, + ellipseMode: constants.CENTER, + strokeWeight: 1, + + textFont: { family: 'sans-serif' }, + textLeading: 15, + leadingSet: false, + textSize: 12, + textAlign: constants.LEFT, + textBaseline: constants.BASELINE, + bezierOrder: 3, + splineEnds: constants.INCLUDE, + textWrap: constants.WORD, + + // added v2.0 + fontStyle: constants.NORMAL, // v1: textStyle + fontStretch: constants.NORMAL, + fontWeight: constants.NORMAL, + lineHeight: constants.NORMAL, + fontVariant: constants.NORMAL, + direction: 'inherit' + } + constructor(pInst, w, h, isMainCanvas) { this._pInst = pInst; this._isMainCanvas = isMainCanvas; @@ -27,36 +58,19 @@ class Renderer { } // Renderer state machine - this.states = { - strokeColor: new Color([0, 0, 0]), - strokeSet: false, - fillColor: new Color([255, 255, 255]), - fillSet: false, - tint: null, - imageMode: constants.CORNER, - rectMode: constants.CORNER, - ellipseMode: constants.CENTER, - strokeWeight: 1, - - textFont: { family: 'sans-serif' }, - textLeading: 15, - leadingSet: false, - textSize: 12, - textAlign: constants.LEFT, - textBaseline: constants.BASELINE, - bezierOrder: 3, - splineEnds: constants.INCLUDE, - - textWrap: constants.WORD, - - // added v2.0 - fontStyle: constants.NORMAL, // v1: textStyle - fontStretch: constants.NORMAL, - fontWeight: constants.NORMAL, - lineHeight: constants.NORMAL, - fontVariant: constants.NORMAL, - direction: 'inherit' - }; + this.states = Object.assign({}, Renderer.states); + // Clone properties that support it + for (const key in this.states) { + if (this.states[key] instanceof Array) { + this.states[key] = this.states[key].slice(); + } else if (this.states[key] && this.states[key].clone instanceof Function) { + this.states[key] = this.states[key].clone(); + } + } + + this.states.strokeColor = new Color([0, 0, 0]); + this.states.fillColor = new Color([255, 255, 255]); + this._pushPopStack = []; // NOTE: can use the length of the push pop stack instead this._pushPopDepth = 0; diff --git a/src/core/p5.Renderer2D.js b/src/core/p5.Renderer2D.js index d914c52439..6367fb9fdb 100644 --- a/src/core/p5.Renderer2D.js +++ b/src/core/p5.Renderer2D.js @@ -5,9 +5,8 @@ import { Graphics } from './p5.Graphics'; import { Image } from '../image/p5.Image'; import { Element } from '../dom/p5.Element'; import { MediaElement } from '../dom/p5.MediaElement'; - +import { RGBHDR } from '../color/creating_reading'; import FilterRenderer2D from '../image/filterRenderer2D'; - import { PrimitiveToPath2DConverter } from '../shape/custom_shapes'; @@ -15,7 +14,7 @@ const styleEmpty = 'rgba(0,0,0,0)'; // const alphaThreshold = 0.00125; // minimum visible class Renderer2D extends Renderer { - constructor(pInst, w, h, isMainCanvas, elt) { + constructor(pInst, w, h, isMainCanvas, elt, attributes = {}) { super(pInst, w, h, isMainCanvas); this.canvas = this.elt = elt || document.createElement('canvas'); @@ -33,7 +32,6 @@ class Renderer2D extends Renderer { this.elt.classList.add('p5Canvas'); // Extend renderer with methods of p5.Element with getters - // this.wrappedElt = new p5.Element(elt, pInst); for (const p of Object.getOwnPropertyNames(Element.prototype)) { if (p !== 'constructor' && p[0] !== '_') { Object.defineProperty(this, p, { @@ -65,7 +63,10 @@ class Renderer2D extends Renderer { } // Get and store drawing context - this.drawingContext = this.canvas.getContext('2d'); + this.drawingContext = this.canvas.getContext('2d', attributes); + if(attributes.colorSpace === 'display-p3'){ + this.states.colorMode = RGBHDR; + } if (isMainCanvas) { this._pInst.drawingContext = this.drawingContext; } @@ -181,7 +182,7 @@ class Renderer2D extends Renderer { //accessible Outputs if (this._pInst._addAccsOutput()) { - this._pInst._accsBackground(color.levels); + this._pInst._accsBackground(color._getRGBA([255, 255, 255, 255])); } const newFill = color.toString(); @@ -216,7 +217,7 @@ class Renderer2D extends Renderer { //accessible Outputs if (this._pInst._addAccsOutput()) { - this._pInst._accsCanvasColors('fill', color.levels); + this._pInst._accsCanvasColors('fill', color._getRGBA([255, 255, 255, 255])); } } @@ -227,7 +228,7 @@ class Renderer2D extends Renderer { //accessible Outputs if (this._pInst._addAccsOutput()) { - this._pInst._accsCanvasColors('stroke', color.levels); + this._pInst._accsCanvasColors('stroke', color._getRGBA([255, 255, 255, 255])); } } @@ -580,10 +581,7 @@ class Renderer2D extends Renderer { } } else if (imgOrCol instanceof p5.Color) { if (idx < this.pixels.length) { - r = imgOrCol.levels[0]; - g = imgOrCol.levels[1]; - b = imgOrCol.levels[2]; - a = imgOrCol.levels[3]; + [r, g, b, a] = imgOrCol._getRGBA([255, 255, 255, 255]); //this.updatePixels.call(this); } } @@ -1224,6 +1222,11 @@ function renderer2D(p5, fn){ */ p5.Renderer2D = Renderer2D; p5.renderers[constants.P2D] = Renderer2D; + p5.renderers['p2d-hdr'] = new Proxy(Renderer2D, { + construct(target, [pInst, w, h, isMainCanvas, elt]){ + return new target(pInst, w, h, isMainCanvas, elt, {colorSpace: "display-p3"}) + } + }) } export default renderer2D; diff --git a/src/dom/dom.js b/src/dom/dom.js index 76265cffcb..50713d327b 100644 --- a/src/dom/dom.js +++ b/src/dom/dom.js @@ -1716,6 +1716,8 @@ function dom(p5, fn){ */ fn.createColorPicker = function (value) { p5._validateParameters('createColorPicker', arguments); + // TODO: This implementation needs to be rechecked or reimplemented + // The way it worked with color is a bit too complex const elt = document.createElement('input'); let self; elt.type = 'color'; @@ -1723,29 +1725,27 @@ function dom(p5, fn){ if (value instanceof p5.Color) { elt.value = value.toString('#rrggbb'); } else { - fn._colorMode = 'rgb'; - fn._colorMaxes = { - rgb: [255, 255, 255, 255], - hsb: [360, 100, 100, 1], - hsl: [360, 100, 100, 1] - }; - elt.value = fn.color(value).toString('#rrggbb'); + this.push(); + this.colorMode('rgb'); + elt.value = this.color(value).toString('#rrggbb'); + this.pop(); } } else { elt.value = '#000000'; } self = addElement(elt, this); // Method to return a p5.Color object for the given color. + const inst = this; self.color = function () { + inst.push(); if (value) { if (value.mode) { - fn._colorMode = value.mode; - } - if (value.maxes) { - fn._colorMaxes = value.maxes; + inst.colorMode(value.mode, ...value?.maxes[value.mode]); } } - return fn.color(this.elt.value); + const c = inst.color(this.elt.value); + inst.pop(); + return c; }; return self; }; diff --git a/src/dom/p5.Element.js b/src/dom/p5.Element.js index 3a896af89a..6ecb74f5b6 100644 --- a/src/dom/p5.Element.js +++ b/src/dom/p5.Element.js @@ -1215,16 +1215,7 @@ class Element { const self = this; if (val instanceof Color) { - val = - 'rgba(' + - val.levels[0] + - ',' + - val.levels[1] + - ',' + - val.levels[2] + - ',' + - val.levels[3] / 255 + - ')'; + val = val.toString(); } if (typeof val === 'undefined') { diff --git a/src/image/loading_displaying.js b/src/image/loading_displaying.js index e46f901c51..b8fa13db81 100644 --- a/src/image/loading_displaying.js +++ b/src/image/loading_displaying.js @@ -1293,7 +1293,7 @@ function loadingDisplaying(p5, fn){ fn.tint = function(...args) { p5._validateParameters('tint', args); const c = this.color(...args); - this._renderer.states.tint = c.levels; + this._renderer.states.tint = c._getRGBA([255, 255, 255, 255]); }; /** diff --git a/src/image/p5.Image.js b/src/image/p5.Image.js index b87827be81..e550501e03 100644 --- a/src/image/p5.Image.js +++ b/src/image/p5.Image.js @@ -668,10 +668,7 @@ class Image { } } else if (imgOrCol instanceof p5.Color) { if (idx < pixelsState.pixels.length) { - r = imgOrCol.levels[0]; - g = imgOrCol.levels[1]; - b = imgOrCol.levels[2]; - a = imgOrCol.levels[3]; + [r, g, b, a] = imgOrCol._getRGBA([255, 255, 255, 255]); //this.updatePixels.call(this); } } diff --git a/src/shape/custom_shapes.js b/src/shape/custom_shapes.js index ce718f9f3c..84724486c4 100644 --- a/src/shape/custom_shapes.js +++ b/src/shape/custom_shapes.js @@ -650,17 +650,15 @@ class Shape { } else if (original instanceof Vector) { return new Vector(queue.shift(), queue.shift(), queue.shift()); } else if (original instanceof Color) { + // NOTE: Not sure what intention here is, `Color` constructor signature + // has changed so needed to be reviewed const array = [ queue.shift(), queue.shift(), queue.shift(), queue.shift() ]; - return new Color( - array.map((v, i) => v * original.maxes[original.mode][i]), - original.mode, - original.maxes - ); + return new Color(array); } } diff --git a/src/webgl/material.js b/src/webgl/material.js index 1768e0cfaa..d63b9a6b69 100644 --- a/src/webgl/material.js +++ b/src/webgl/material.js @@ -3626,7 +3626,7 @@ function material(p5, fn){ this.states.drawMode = constants.TEXTURE; this.states._useNormalMaterial = false; this.states._tex = tex; - this.states.fillColor = new Color(255); + this.states.fillColor = new Color([1, 1, 1]); }; RendererGL.prototype.normalMaterial = function(...args) { @@ -3635,7 +3635,7 @@ function material(p5, fn){ this.states._useEmissiveMaterial = false; this.states._useNormalMaterial = true; this.states.curFillColor = [1, 1, 1, 1]; - this.states.fillColor = new Color(255); + this.states.fillColor = new Color([1, 1, 1]); this.states.strokeColor = null; } diff --git a/src/webgl/p5.Framebuffer.js b/src/webgl/p5.Framebuffer.js index 2a5ced5f7a..37081f3b09 100644 --- a/src/webgl/p5.Framebuffer.js +++ b/src/webgl/p5.Framebuffer.js @@ -4,6 +4,7 @@ */ import * as constants from '../core/constants'; +import { RGB, RGBA } from '../color/creating_reading'; import { checkWebGLCapabilities } from './p5.Texture'; import { readPixelsWebGL, readPixelWebGL } from './p5.RendererGL'; import { Camera } from './p5.Camera'; @@ -63,8 +64,8 @@ class Framebuffer { this.format = settings.format || constants.UNSIGNED_BYTE; this.channels = settings.channels || ( this.renderer._pInst._glAttributes.alpha - ? constants.RGBA - : constants.RGB + ? RGBA + : RGB ); this.useDepth = settings.depth === undefined ? true : settings.depth; this.depthFormat = settings.depthFormat || constants.FLOAT; @@ -449,14 +450,14 @@ class Framebuffer { } if ( - this.channels === constants.RGB && + this.channels === RGB && [constants.FLOAT, constants.HALF_FLOAT].includes(this.format) ) { console.warn( 'FLOAT and HALF_FLOAT formats do not work cross-platform with only ' + 'RGB channels. Falling back to RGBA.' ); - this.channels = constants.RGBA; + this.channels = RGBA; } } @@ -640,7 +641,7 @@ class Framebuffer { type = gl.UNSIGNED_BYTE; } - if (this.channels === constants.RGBA) { + if (this.channels === RGBA) { format = gl.RGBA; } else { format = gl.RGB; diff --git a/src/webgl/p5.RendererGL.js b/src/webgl/p5.RendererGL.js index b929542869..6756ebc62d 100644 --- a/src/webgl/p5.RendererGL.js +++ b/src/webgl/p5.RendererGL.js @@ -1003,11 +1003,7 @@ class RendererGL extends Renderer { */ background(...args) { const _col = this._pInst.color(...args); - const _r = _col.levels[0] / 255; - const _g = _col.levels[1] / 255; - const _b = _col.levels[2] / 255; - const _a = _col.levels[3] / 255; - this.clear(_r, _g, _b, _a); + this.clear(..._col._getRGBA()); } // Combines the model and view matrices to get the uMVMatrix diff --git a/test/js/mocks.js b/test/js/mocks.js index 63d0cc7951..80a4cd68f8 100644 --- a/test/js/mocks.js +++ b/test/js/mocks.js @@ -18,11 +18,15 @@ const httpMocks = [ export const httpMock = setupWorker(...httpMocks); // p5.js module mocks +const rendererStates = {}; export const mockP5 = vi.fn(); Object.assign(mockP5, { _validateParameters: vi.fn(), _friendlyFileLoadError: vi.fn(), - _friendlyError: vi.fn() + _friendlyError: vi.fn(), + Renderer: { + states: rendererStates + } }); const mockCanvas = document.createElement('canvas'); @@ -38,5 +42,8 @@ export const mockP5Prototype = { canvas: { id: 'myCanvasID' }, - _elements: [] + _elements: [], + _renderer: { + states: rendererStates + } }; diff --git a/test/unit/color/color_conversion.js b/test/unit/color/color_conversion.js index aa0e8b31c2..777ddee526 100644 --- a/test/unit/color/color_conversion.js +++ b/test/unit/color/color_conversion.js @@ -7,7 +7,7 @@ assert.arrayApproximately = function(arr1, arr2, delta) { } }; -suite('color/p5.ColorConversion', function() { +suite.todo('color/p5.ColorConversion', function() { var rgba = [1, 0, 0.4, 0.8]; var rgbaWithMaxHue = [1, 0, 0, 0.6]; var rgbaWithHighLightness = [0.969, 0.753, 0.122, 0.8]; diff --git a/test/unit/color/creating_reading.js b/test/unit/color/creating_reading.js index da0d42abed..f4b134c204 100644 --- a/test/unit/color/creating_reading.js +++ b/test/unit/color/creating_reading.js @@ -1,21 +1,13 @@ -import p5 from '../../../src/app.js'; +import { mockP5, mockP5Prototype } from '../../js/mocks'; +import creatingReading from '../../../src/color/creating_reading'; +import setting from '../../../src/color/setting'; +import p5Color from '../../../src/color/p5.Color'; suite('color/CreatingReading', function() { - var myp5; - - beforeEach(async function() { - await new Promise(resolve => { - new p5(function(p) { - p.setup = function() { - myp5 = p; - resolve(); - }; - }); - }); - }); - - afterEach(function() { - myp5.remove(); + beforeAll(async function() { + creatingReading(mockP5, mockP5Prototype); + setting(mockP5, mockP5Prototype); + p5Color(mockP5, mockP5Prototype, {}); }); var fromColor; @@ -23,76 +15,76 @@ suite('color/CreatingReading', function() { suite.todo('p5.prototype.alpha', function() { beforeEach(function() { - myp5.colorMode(myp5.RGB); + mockP5Prototype.colorMode(mockP5Prototype.RGB); }); }); suite.todo('p5.prototype.red, green, blue', function() { beforeEach(function() { - myp5.colorMode(myp5.RGB); + mockP5Prototype.colorMode(mockP5Prototype.RGB); }); }); suite.todo('p5.prototype.hue, brightness, lightness, saturation', function() { beforeEach(function() { - myp5.colorMode(myp5.HSL); + mockP5Prototype.colorMode(mockP5Prototype.HSL); }); }); suite('p5.prototype.lerpColor', function() { beforeEach(function() { - myp5.colorMode(myp5.RGB); - fromColor = myp5.color(218, 165, 32); - toColor = myp5.color(72, 61, 139); + mockP5Prototype.colorMode(mockP5Prototype.RGB); + fromColor = mockP5Prototype.color(218, 165, 32); + toColor = mockP5Prototype.color(72, 61, 139); }); test('should correctly get lerp colors in RGB', function() { - var interA = myp5.lerpColor(fromColor, toColor, 0.33); - var interB = myp5.lerpColor(fromColor, toColor, 0.66); + var interA = mockP5Prototype.lerpColor(fromColor, toColor, 0.33); + var interB = mockP5Prototype.lerpColor(fromColor, toColor, 0.66); - assert.closeTo(interA.color.coords[0] * 255, 170, 1); - assert.closeTo(interA.color.coords[1] * 255, 131, 1); - assert.closeTo(interA.color.coords[2] * 255, 67, 1); + assert.closeTo(interA._color.coords[0] * 255, 170, 1); + assert.closeTo(interA._color.coords[1] * 255, 131, 1); + assert.closeTo(interA._color.coords[2] * 255, 67, 1); - assert.closeTo(interB.color.coords[0] * 255, 122, 1); - assert.closeTo(interB.color.coords[1] * 255, 96, 1); - assert.closeTo(interB.color.coords[2] * 255, 103, 1); + assert.closeTo(interB._color.coords[0] * 255, 122, 1); + assert.closeTo(interB._color.coords[1] * 255, 96, 1); + assert.closeTo(interB._color.coords[2] * 255, 103, 1); }); test('should correctly get lerp colors in HSL', function() { // NOTE: This is equivalent to RGB case so is testing nothing new - myp5.colorMode(myp5.HSL); - var interA = myp5.lerpColor(fromColor, toColor, 0.33); - var interB = myp5.lerpColor(fromColor, toColor, 0.66); + mockP5Prototype.colorMode(mockP5Prototype.HSL); + var interA = mockP5Prototype.lerpColor(fromColor, toColor, 0.33); + var interB = mockP5Prototype.lerpColor(fromColor, toColor, 0.66); - assert.closeTo(interA.color.coords[0] * 255, 170, 1); - assert.closeTo(interA.color.coords[1] * 255, 131, 1); - assert.closeTo(interA.color.coords[2] * 255, 67, 1); + assert.closeTo(interA._color.coords[0], 37, 1); + assert.closeTo(interA._color.coords[1], 43, 1); + assert.closeTo(interA._color.coords[2], 46, 1); - assert.closeTo(interB.color.coords[0] * 255, 122, 1); - assert.closeTo(interB.color.coords[1] * 255, 96, 1); - assert.closeTo(interB.color.coords[2] * 255, 103, 1); + assert.closeTo(interB._color.coords[0], 345, 1); + assert.closeTo(interB._color.coords[1], 12, 1); + assert.closeTo(interB._color.coords[2], 43, 1); }); test('should correctly get lerp colors in HSB', function() { // NOTE: This is equivalent to RGB case so is testing nothing new - myp5.colorMode(myp5.HSB); - var interA = myp5.lerpColor(fromColor, toColor, 0.33); - var interB = myp5.lerpColor(fromColor, toColor, 0.66); + mockP5Prototype.colorMode(mockP5Prototype.HSB); + var interA = mockP5Prototype.lerpColor(fromColor, toColor, 0.33); + var interB = mockP5Prototype.lerpColor(fromColor, toColor, 0.66); - assert.closeTo(interA.color.coords[0] * 255, 170, 1); - assert.closeTo(interA.color.coords[1] * 255, 131, 1); - assert.closeTo(interA.color.coords[2] * 255, 67, 1); + assert.closeTo(interA._color.coords[0], 37, 1); + assert.closeTo(interA._color.coords[1], 60, 1); + assert.closeTo(interA._color.coords[2], 66, 1); - assert.closeTo(interB.color.coords[0] * 255, 122, 1); - assert.closeTo(interB.color.coords[1] * 255, 96, 1); - assert.closeTo(interB.color.coords[2] * 255, 103, 1); + assert.closeTo(interB._color.coords[0], 345, 1); + assert.closeTo(interB._color.coords[1], 20, 1); + assert.closeTo(interB._color.coords[2], 47, 1); }); test.todo('should not extrapolate', function() { // NOTE: maybe it should extrapolate - var interA = myp5.lerpColor(fromColor, toColor, -0.5); - var interB = myp5.lerpColor(fromColor, toColor, 1.5); + var interA = mockP5Prototype.lerpColor(fromColor, toColor, -0.5); + var interB = mockP5Prototype.lerpColor(fromColor, toColor, 1.5); assert.deepEqual(interA.levels, [218, 165, 32, 255]); assert.deepEqual(interB.levels, [72, 61, 139, 255]); }); @@ -100,64 +92,62 @@ suite('color/CreatingReading', function() { suite('p5.prototype.lerpColor with alpha', function() { beforeEach(function() { - myp5.colorMode(myp5.RGB); - fromColor = myp5.color(218, 165, 32, 49); - toColor = myp5.color(72, 61, 139, 200); + mockP5Prototype.colorMode(mockP5Prototype.RGB); + fromColor = mockP5Prototype.color(218, 165, 32, 49); + toColor = mockP5Prototype.color(72, 61, 139, 200); }); test('should correctly get lerp colors in RGB with alpha', function() { - var interA = myp5.lerpColor(fromColor, toColor, 0.33); - var interB = myp5.lerpColor(fromColor, toColor, 0.66); - - assert.closeTo(interA.color.coords[0] * 255, 170, 1); - assert.closeTo(interA.color.coords[1] * 255, 131, 1); - assert.closeTo(interA.color.coords[2] * 255, 67, 1); - assert.closeTo(interA.color.alpha * 255, 99, 1); - - assert.closeTo(interB.color.coords[0] * 255, 122, 1); - assert.closeTo(interB.color.coords[1] * 255, 96, 1); - assert.closeTo(interB.color.coords[2] * 255, 103, 1); - assert.closeTo(interB.color.alpha * 255, 149, 1); + var interA = mockP5Prototype.lerpColor(fromColor, toColor, 0.33); + var interB = mockP5Prototype.lerpColor(fromColor, toColor, 0.66); + + assert.closeTo(interA._color.coords[0], 0.66, 0.01); + assert.closeTo(interA._color.coords[1], 0.51, 0.01); + assert.closeTo(interA._color.coords[2], 0.26, 0.01); + assert.closeTo(interA._color.alpha, 0.38, 0.01); + + assert.closeTo(interB._color.coords[0], 0.47, 0.01); + assert.closeTo(interB._color.coords[1], 0.37, 0.01); + assert.closeTo(interB._color.coords[2], 0.40, 0.01); + assert.closeTo(interB._color.alpha, 0.58, 0.01); }); test('should correctly get lerp colors in HSL with alpha', function() { - // NOTE: This is equivalent to RGBA case so is testing nothing new - myp5.colorMode(myp5.HSL); - var interA = myp5.lerpColor(fromColor, toColor, 0.33); - var interB = myp5.lerpColor(fromColor, toColor, 0.66); - - assert.closeTo(interA.color.coords[0] * 255, 170, 1); - assert.closeTo(interA.color.coords[1] * 255, 131, 1); - assert.closeTo(interA.color.coords[2] * 255, 67, 1); - assert.closeTo(interA.color.alpha * 255, 99, 1); - - assert.closeTo(interB.color.coords[0] * 255, 122, 1); - assert.closeTo(interB.color.coords[1] * 255, 96, 1); - assert.closeTo(interB.color.coords[2] * 255, 103, 1); - assert.closeTo(interB.color.alpha * 255, 149, 1); + mockP5Prototype.colorMode(mockP5Prototype.HSL); + var interA = mockP5Prototype.lerpColor(fromColor, toColor, 0.33); + var interB = mockP5Prototype.lerpColor(fromColor, toColor, 0.66); + + assert.closeTo(interA._color.coords[0], 37, 1); + assert.closeTo(interA._color.coords[1], 43, 1); + assert.closeTo(interA._color.coords[2], 46, 1); + assert.closeTo(interA._color.alpha, 0.38, 0.01); + + assert.closeTo(interB._color.coords[0], 345, 1); + assert.closeTo(interB._color.coords[1], 11, 1); + assert.closeTo(interB._color.coords[2], 42, 1); + assert.closeTo(interB._color.alpha, 0.58, 0.01); }); test('should correctly get lerp colors in HSB with alpha', function() { - // NOTE: This is equivalent to RGBA case so is testing nothing new - myp5.colorMode(myp5.HSB); - var interA = myp5.lerpColor(fromColor, toColor, 0.33); - var interB = myp5.lerpColor(fromColor, toColor, 0.66); - - assert.closeTo(interA.color.coords[0] * 255, 170, 1); - assert.closeTo(interA.color.coords[1] * 255, 131, 1); - assert.closeTo(interA.color.coords[2] * 255, 67, 1); - assert.closeTo(interA.color.alpha * 255, 99, 1); - - assert.closeTo(interB.color.coords[0] * 255, 122, 1); - assert.closeTo(interB.color.coords[1] * 255, 96, 1); - assert.closeTo(interB.color.coords[2] * 255, 103, 1); - assert.closeTo(interB.color.alpha * 255, 149, 1); + mockP5Prototype.colorMode(mockP5Prototype.HSB); + var interA = mockP5Prototype.lerpColor(fromColor, toColor, 0.33); + var interB = mockP5Prototype.lerpColor(fromColor, toColor, 0.66); + + assert.closeTo(interA._color.coords[0], 37, 1); + assert.closeTo(interA._color.coords[1], 60, 1); + assert.closeTo(interA._color.coords[2], 66, 1); + assert.closeTo(interA._color.alpha, 0.38, 0.01); + + assert.closeTo(interB._color.coords[0], 345, 1); + assert.closeTo(interB._color.coords[1], 20, 1); + assert.closeTo(interB._color.coords[2], 47, 1); + assert.closeTo(interB._color.alpha, 0.58, 0.01); }); test.todo('should not extrapolate', function() { // NOTE: maybe it should extrapolate - var interA = myp5.lerpColor(fromColor, toColor, -0.5); - var interB = myp5.lerpColor(fromColor, toColor, 1.5); + var interA = mockP5Prototype.lerpColor(fromColor, toColor, -0.5); + var interB = mockP5Prototype.lerpColor(fromColor, toColor, 1.5); assert.deepEqual(interA.levels, [218, 165, 32, 49]); assert.deepEqual(interB.levels, [72, 61, 139, 200]); }); diff --git a/test/unit/color/p5.Color.js b/test/unit/color/p5.Color.js index 45adc03987..12fc3e6648 100644 --- a/test/unit/color/p5.Color.js +++ b/test/unit/color/p5.Color.js @@ -1,49 +1,42 @@ -import p5 from '../../../src/app.js'; +import { mockP5, mockP5Prototype } from '../../js/mocks'; +import creatingReading from '../../../src/color/creating_reading'; +import setting from '../../../src/color/setting'; +import { Color } from '../../../src/color/p5.Color'; +import p5Color from '../../../src/color/p5.Color'; suite('p5.Color', function() { - var myp5; - - beforeEach(async function() { - await new Promise(resolve => { - new p5(function(p) { - p.setup = function() { - myp5 = p; - resolve(); - }; - }); - }); - }); - - afterEach(function() { - myp5.remove(); + beforeAll(() => { + creatingReading(mockP5, mockP5Prototype); + setting(mockP5, mockP5Prototype); + p5Color(mockP5, mockP5Prototype, {}); }); var c; suite('p5.prototype.color(r,g,b)', function() { beforeEach(function() { - c = myp5.color(255, 0, 102); + c = mockP5Prototype.color(255, 0, 102); }); test('should create instance of p5.Color', function() { - assert.instanceOf(c, p5.Color); + assert.instanceOf(c, Color); }); test('should correctly set RGBA property', function() { - assert.deepEqual(c.color.coords, [1, 0, 0.4]); - assert.equal(c.color.alpha, 1); + assert.deepEqual(c._color.coords, [1, 0, 0.4]); + assert.equal(c._color.alpha, 1); }); }); suite('p5.prototype.color(r,g,b,a)', function() { beforeEach(function() { - c = myp5.color(255, 0, 102, 204); + c = mockP5Prototype.color(255, 0, 102, 204); }); test('should create instance of p5.Color', function() { - assert.instanceOf(c, p5.Color); + assert.instanceOf(c, Color); }); test('should correctly set RGBA property', function() { - assert.deepEqual(c.color.coords, [1, 0, 0.4]); - assert.equal(c.color.alpha, 0.8); + assert.deepEqual(c._color.coords, [1, 0, 0.4]); + assert.equal(c._color.alpha, 0.8); }); }); @@ -52,200 +45,200 @@ suite('p5.Color', function() { suite('p5.prototype.color(string)', function(){ suite('#rgb', function(){ beforeEach(function() { - c = myp5.color('#f06'); + c = mockP5Prototype.color('#f06'); }); test('should create instance of p5.Color', function() { - assert.instanceOf(c, p5.Color); + assert.instanceOf(c, Color); }); test('should correctly set RGBA property', function() { - assert.deepEqual(c.color.coords, [1, 0, 0.4]); - assert.equal(c.color.alpha, 1); + assert.deepEqual(c._color.coords, [1, 0, 0.4]); + assert.equal(c._color.alpha, 1); }); }); suite('#rgba', function(){ beforeEach(function() { - c = myp5.color('#f066'); + c = mockP5Prototype.color('#f066'); }); test('should create instance of p5.Color', function() { - assert.instanceOf(c, p5.Color); + assert.instanceOf(c, Color); }); test('should correctly set RGBA property', function() { - assert.deepEqual(c.color.coords, [1, 0, 0.4]); - assert.equal(c.color.alpha, 0.4); + assert.deepEqual(c._color.coords, [1, 0, 0.4]); + assert.equal(c._color.alpha, 0.4); }); }); suite('#rrggbb', function(){ beforeEach(function() { - c = myp5.color('#ff0066'); + c = mockP5Prototype.color('#ff0066'); }); test('should create instance of p5.Color', function() { - assert.instanceOf(c, p5.Color); + assert.instanceOf(c, Color); }); test('should correctly set RGBA property', function() { - assert.deepEqual(c.color.coords, [1, 0, 0.4]); - assert.equal(c.color.alpha, 1); + assert.deepEqual(c._color.coords, [1, 0, 0.4]); + assert.equal(c._color.alpha, 1); }); }); suite('#rrggbbaa', function(){ beforeEach(function() { - c = myp5.color('#f01dab1e'); + c = mockP5Prototype.color('#f01dab1e'); }); test('should create instance of p5.Color', function() { - assert.instanceOf(c, p5.Color); + assert.instanceOf(c, Color); }); test('should correctly set RGBA property', function() { - assert.deepEqual(c.color.coords, [240, 29, 171].map(c => c/255)); - assert.equal(c.color.alpha, 30/255); + assert.deepEqual(c._color.coords, [240, 29, 171].map(c => c/255)); + assert.equal(c._color.alpha, 30/255); }); }); suite('rgb(r,g,b)', function(){ beforeEach(function() { - c = myp5.color('rgb(255,0,102)'); + c = mockP5Prototype.color('rgb(255,0,102)'); }); test('should create instance of p5.Color', function() { - assert.instanceOf(c, p5.Color); + assert.instanceOf(c, Color); }); test('should correctly set RGBA property', function() { - assert.deepEqual(c.color.coords, [1, 0, 0.4]); - assert.equal(c.color.alpha, 1); + assert.deepEqual(c._color.coords, [1, 0, 0.4]); + assert.equal(c._color.alpha, 1); }); }); suite('rgb(r%,g%,b%)', function(){ beforeEach(function() { - c = myp5.color('rgb(100%, 0%, 40%)'); + c = mockP5Prototype.color('rgb(100%, 0%, 40%)'); }); test('should create instance of p5.Color', function() { - assert.instanceOf(c, p5.Color); + assert.instanceOf(c, Color); }); test('should correctly set RGBA property', function() { - assert.deepEqual(c.color.coords, [1, 0, 0.4]); - assert.equal(c.color.alpha, 1); + assert.deepEqual(c._color.coords, [1, 0, 0.4]); + assert.equal(c._color.alpha, 1); }); }); suite('rgba(r,g,b,a)', function(){ beforeEach(function() { - c = myp5.color('rgba(255,0,102,0.8)'); + c = mockP5Prototype.color('rgba(255,0,102,0.8)'); }); test('should create instance of p5.Color', function() { - assert.instanceOf(c, p5.Color); + assert.instanceOf(c, Color); }); test('should correctly set RGBA property', function() { - assert.deepEqual(c.color.coords, [1, 0, 0.4]); - assert.equal(c.color.alpha, 0.8); + assert.deepEqual(c._color.coords, [1, 0, 0.4]); + assert.equal(c._color.alpha, 0.8); }); }); suite('rgba(r%,g%,b%,a)', function(){ beforeEach(function() { - c = myp5.color('rgba(100.0%,0.0%,40%,0.8)'); + c = mockP5Prototype.color('rgba(100.0%,0.0%,40%,0.8)'); }); test('should create instance of p5.Color', function() { - assert.instanceOf(c, p5.Color); + assert.instanceOf(c, Color); }); test('should correctly set RGBA property', function() { - assert.deepEqual(c.color.coords, [1, 0, 0.4]); - assert.equal(c.color.alpha, 0.8); + assert.deepEqual(c._color.coords, [1, 0, 0.4]); + assert.equal(c._color.alpha, 0.8); }); }); suite('hsl(h, s%, l%)', function(){ beforeEach(function() { - c = myp5.color('hsl(336, 100%, 50%)'); + c = mockP5Prototype.color('hsl(336, 100%, 50%)'); }); test('should create instance of p5.Color', function() { - assert.instanceOf(c, p5.Color); + assert.instanceOf(c, Color); }); test('should correctly set RGBA property', function() { // NOTE: 0.5.2 of color.js uses `new Number` which is corrected in future version // assert.deepEqual(c.color.coords, [336, 100, 50]); - assert.equal(+c.color.coords[0], 336); - assert.equal(c.color.coords[1], 100); - assert.equal(c.color.coords[2], 50); - assert.equal(c.color.alpha, 1); + assert.equal(+c._color.coords[0], 336); + assert.equal(c._color.coords[1], 100); + assert.equal(c._color.coords[2], 50); + assert.equal(c._color.alpha, 1); }); }); suite('hsla(h, s%, l%, a)', function() { beforeEach(function() { - c = myp5.color('hsla(336, 100%, 50%, 0.8)'); + c = mockP5Prototype.color('hsla(336, 100%, 50%, 0.8)'); }); test('should create instance of p5.Color', function() { - assert.instanceOf(c, p5.Color); + assert.instanceOf(c, Color); }); test('should correctly set RGBA property', function() { // NOTE: 0.5.2 of color.js uses `new Number` which is corrected in future version // assert.deepEqual(c.color.coords, [336, 100, 50]); - assert.equal(+c.color.coords[0], 336); - assert.equal(c.color.coords[1], 100); - assert.equal(c.color.coords[2], 50); - assert.equal(c.color.alpha, 0.8); + assert.equal(+c._color.coords[0], 336); + assert.equal(c._color.coords[1], 100); + assert.equal(c._color.coords[2], 50); + assert.equal(c._color.alpha, 0.8); }); }); suite('hsb(h, s%, b%)', function() { beforeEach(function() { - c = myp5.color('hsb(336, 100%, 100%)'); + c = mockP5Prototype.color('hsb(336, 100%, 100%)'); }); test('should create instance of p5.Color', function() { - assert.instanceOf(c, p5.Color); + assert.instanceOf(c, Color); }); test('should correctly set RGBA property', function() { // NOTE: 0.5.2 of color.js uses `new Number` which is corrected in future version // assert.deepEqual(c.color.coords, [336, 100, 100]); - assert.equal(+c.color.coords[0], 336); - assert.equal(c.color.coords[1], 100); - assert.equal(c.color.coords[2], 100); - assert.equal(c.color.alpha, 1); + assert.equal(+c._color.coords[0], 336); + assert.equal(c._color.coords[1], 100); + assert.equal(c._color.coords[2], 100); + assert.equal(c._color.alpha, 1); }); }); suite('hsba(h, s%, b%, a)', function() { beforeEach(function() { - c = myp5.color('hsba(336, 100%, 100%, 0.8)'); + c = mockP5Prototype.color('hsba(336, 100%, 100%, 0.8)'); }); test('should create instance of p5.Color', function() { - assert.instanceOf(c, p5.Color); + assert.instanceOf(c, Color); }); test('should correctly set RGBA property', function() { // NOTE: 0.5.2 of color.js uses `new Number` which is corrected in future version // assert.deepEqual(c.color.coords, [336, 100, 50]); - assert.equal(+c.color.coords[0], 336); - assert.equal(c.color.coords[1], 100); - assert.equal(c.color.coords[2], 100); - assert.equal(c.color.alpha, 0.8); + assert.equal(+c._color.coords[0], 336); + assert.equal(c._color.coords[1], 100); + assert.equal(c._color.coords[2], 100); + assert.equal(c._color.alpha, 0.8); }); }); suite('named colors', function() { beforeEach(function() { - c = myp5.color('papayawhip'); + c = mockP5Prototype.color('papayawhip'); }); test('should create instance of p5.Color', function() { - assert.instanceOf(c, p5.Color); + assert.instanceOf(c, Color); }); test('should correctly set RGBA property', function() { - assert.deepEqual(c.color.coords, [255, 239, 213].map(c => c/255)); - assert.equal(c.color.alpha, 1); + assert.deepEqual(c._color.coords, [255, 239, 213].map(c => c/255)); + assert.equal(c._color.alpha, 1); }); }); @@ -255,56 +248,56 @@ suite('p5.Color', function() { suite('p5.prototype.color([])', function() { beforeEach(function() { - c = myp5.color([255, 0, 102]); + c = mockP5Prototype.color([255, 0, 102]); }); test('should create instance of p5.Color', function() { - assert.instanceOf(c, p5.Color); + assert.instanceOf(c, Color); }); test('should correctly set RGBA property', function() { - assert.deepEqual(c.color.coords, [1, 0, 0.4]); - assert.equal(c.color.alpha, 1); + assert.deepEqual(c._color.coords, [1, 0, 0.4]); + assert.equal(c._color.alpha, 1); }); }); // color level setters suite('in default mode', function() { test('can be modified with alpha setter', function() { - let cc = myp5.color(255, 0, 102, 204); - assert.deepEqual(cc.color.coords, [1, 0, 0.4]); - assert.equal(cc.color.alpha, 0.8); - cc.setAlpha(98); - assert.deepEqual(cc.color.coords, [1, 0, 0.4]); - assert.equal(cc.color.alpha, 98/255); + let cc = mockP5Prototype.color(255, 0, 102, 204); + assert.deepEqual(cc._color.coords, [1, 0, 0.4]); + assert.equal(cc._color.alpha, 0.8); + cc.setAlpha(98/255); + assert.deepEqual(cc._color.coords, [1, 0, 0.4]); + assert.equal(cc._color.alpha, 98/255); }); test('can be modified with rgb setters', function() { - var cc = myp5.color(255, 0, 102, 204); - assert.deepEqual(cc.color.coords, [1, 0, 0.4]); - assert.equal(cc.color.alpha, 0.8); - cc.setRed(98); - assert.deepEqual(cc.color.coords, [98/255, 0, 0.4]); - assert.equal(cc.color.alpha, 0.8); - cc.setGreen(44); - assert.deepEqual(cc.color.coords, [98/255, 44/255, 0.4]); - assert.equal(cc.color.alpha, 0.8); - cc.setBlue(244); - assert.deepEqual(cc.color.coords, [98/255, 44/255, 244/255]); - assert.equal(cc.color.alpha, 0.8); + var cc = mockP5Prototype.color(255, 0, 102, 204); + assert.deepEqual(cc._color.coords, [1, 0, 0.4]); + assert.equal(cc._color.alpha, 0.8); + cc.setRed(98/255); + assert.deepEqual(cc._color.coords, [98/255, 0, 0.4]); + assert.equal(cc._color.alpha, 0.8); + cc.setGreen(44/255); + assert.deepEqual(cc._color.coords, [98/255, 44/255, 0.4]); + assert.equal(cc._color.alpha, 0.8); + cc.setBlue(244/255); + assert.deepEqual(cc._color.coords, [98/255, 44/255, 244/255]); + assert.equal(cc._color.alpha, 0.8); }); }); // Color Mode suite('p5.Color in RGB mode with custom range', function() { beforeEach(function() { - myp5.colorMode(myp5.RGB, 1); - c = myp5.color(1, 0, 0.4, 0.8); + mockP5Prototype.colorMode(mockP5Prototype.RGB, 1); + c = mockP5Prototype.color(1, 0, 0.4, 0.8); }); test('should correctly convert to RGBA', function() { - assert.deepEqual(c.color.coords, [1, 0, 0.4]); - assert.equal(c.color.alpha, 0.8); + assert.deepEqual(c._color.coords, [1, 0, 0.4]); + assert.equal(c._color.alpha, 0.8); }); test('should correctly get RGBA property', function() { @@ -319,75 +312,75 @@ suite('p5.Color', function() { }); test('should correctly get RGBA property after overwrite', function() { - myp5.colorMode(myp5.RGB, 255, 255, 255, 255); - assert.equal(c._getRed(), 255); - assert.equal(c._getGreen(), 0); - assert.equal(c._getBlue(), 102); - assert.equal(c._getAlpha(), 204); + mockP5Prototype.colorMode(mockP5Prototype.RGB, 255, 255, 255, 255); + assert.equal(c._getRed(), 255/255); + assert.equal(c._getGreen(), 0/255); + assert.equal(c._getBlue(), 102/255); + assert.equal(c._getAlpha(), 204/255); }); }); suite('p5.Color in HSL mode', function() { beforeEach(function() { - myp5.colorMode(myp5.HSL); - c = myp5.color(336, 100, 50); + mockP5Prototype.colorMode(mockP5Prototype.HSL); + c = mockP5Prototype.color(336, 100, 50); }); test('should create instance of p5.Color', function() { - assert.instanceOf(c, p5.Color); + assert.instanceOf(c, Color); }); test('should correctly set RGBA property', function() { - assert.deepEqual(c.color.coords, [336, 100, 50]); - assert.equal(c.color.alpha, 1); + assert.deepEqual(c._color.coords, [336, 100, 50]); + assert.equal(c._color.alpha, 1); }); test('can be modified with alpha setter', function() { - let cc = myp5.color(336, 100, 50); + let cc = mockP5Prototype.color(336, 100, 50); cc.setAlpha(0.73); - assert.deepEqual(cc.color.coords, [336, 100, 50]); - assert.equal(cc.color.alpha, 0.73); + assert.deepEqual(cc._color.coords, [336, 100, 50]); + assert.equal(cc._color.alpha, 0.73); }); test('can be modified with rgb setters', function() { - let cc = myp5.color(336, 100, 50); - assert.deepEqual(cc.color.coords, [336, 100, 50]); - assert.equal(cc.color.alpha, 1); + let cc = mockP5Prototype.color(336, 100, 50); + assert.deepEqual(cc._color.coords, [336, 100, 50]); + assert.equal(cc._color.alpha, 1); // TODO: separately check these values are correct (not in test here) - cc.setRed(98); - assert.closeTo(cc.color.coords[0], 297, 1); - assert.closeTo(cc.color.coords[1], 100, 1); - assert.closeTo(cc.color.coords[2], 20, 1); - assert.equal(cc.color.alpha, 1); - - cc.setGreen(44); - assert.closeTo(cc.color.coords[0], 295, 1); - assert.closeTo(cc.color.coords[1], 39, 1); - assert.closeTo(cc.color.coords[2], 28, 1); - assert.equal(cc.color.alpha, 1); - - cc.setBlue(244); - assert.closeTo(cc.color.coords[0], 256, 1); - assert.closeTo(cc.color.coords[1], 90, 1); - assert.closeTo(cc.color.coords[2], 56, 1); - assert.equal(cc.color.alpha, 1); + cc.setRed(98/255); + assert.closeTo(cc._color.coords[0], 297, 1); + assert.closeTo(cc._color.coords[1], 100, 1); + assert.closeTo(cc._color.coords[2], 20, 1); + assert.equal(cc._color.alpha, 1); + + cc.setGreen(44/255); + assert.closeTo(cc._color.coords[0], 295, 1); + assert.closeTo(cc._color.coords[1], 39, 1); + assert.closeTo(cc._color.coords[2], 28, 1); + assert.equal(cc._color.alpha, 1); + + cc.setBlue(244/255); + assert.closeTo(cc._color.coords[0], 256, 1); + assert.closeTo(cc._color.coords[1], 90, 1); + assert.closeTo(cc._color.coords[2], 56, 1); + assert.equal(cc._color.alpha, 1); }); }); suite('p5.Color in HSL mode with Alpha', function() { beforeEach(function() { - myp5.colorMode(myp5.HSL); - c = myp5.color(336, 100, 50, 0.8); + mockP5Prototype.colorMode(mockP5Prototype.HSL); + c = mockP5Prototype.color(336, 100, 50, 0.8); }); test('should create instance of p5.Color', function() { - assert.instanceOf(c, p5.Color); + assert.instanceOf(c, Color); }); test('should correctly set RGBA property', function() { - assert.deepEqual(c.color.coords, [336, 100, 50]); - assert.equal(c.color.alpha, 0.8); + assert.deepEqual(c._color.coords, [336, 100, 50]); + assert.equal(c._color.alpha, 0.8); }); test('should correctly get hue/saturation/lightness/alpha', function() { @@ -400,22 +393,22 @@ suite('p5.Color', function() { suite('p5.Color in HSL mode with custom range', function() { beforeEach(function() { - myp5.colorMode(myp5.HSL, 100, 200, 300, 10); - c = myp5.color(93.33, 200, 150, 8); + mockP5Prototype.colorMode(mockP5Prototype.HSL, 100, 200, 300, 10); + c = mockP5Prototype.color(93.33, 200, 150, 8); }); test('should correctly get HSLA property', function() { - assert.approximately(c._getHue(), 93, 0.5); - assert.approximately(c._getSaturation(), 200, 0.5); - assert.approximately(c._getLightness(), 150, 0.5); - assert.approximately(c._getAlpha(), 8, 0.5); + assert.approximately(c._getHue(), 336, 0.5); + assert.approximately(c._getSaturation(), 100, 0.5); + assert.approximately(c._getLightness(), 50, 0.5); + assert.approximately(c._getAlpha(), 0.8, 0.5); }); test('should correctly convert to RGBA', function() { - assert.closeTo(c.color.coords[0], 336, 1); - assert.equal(c.color.coords[1], 100); - assert.equal(c.color.coords[2], 50); - assert.equal(c.color.alpha, 0.8); + assert.closeTo(c._color.coords[0], 336, 1); + assert.equal(c._color.coords[1], 100); + assert.equal(c._color.coords[2], 50); + assert.equal(c._color.alpha, 0.8); }); test('should correctly render color string', function() { @@ -423,46 +416,46 @@ suite('p5.Color', function() { }); test('can be modified with alpha setter', function() { - let cc = myp5.color(93.33, 200, 150, 8); - cc.setAlpha(7.3); - assert.closeTo(cc.color.coords[0], 336, 1); - assert.equal(cc.color.coords[1], 100); - assert.equal(cc.color.coords[2], 50); - assert.equal(cc.color.alpha, 0.73); + let cc = mockP5Prototype.color(93.33, 200, 150, 8); + cc.setAlpha(0.73); + assert.closeTo(cc._color.coords[0], 336, 1); + assert.equal(cc._color.coords[1], 100); + assert.equal(cc._color.coords[2], 50); + assert.equal(cc._color.alpha, 0.73); }); test('can be modified with rgb setters', function() { - let cc = myp5.color(93.33, 200, 150, 8); - assert.closeTo(c.color.coords[0], 336, 1); - assert.equal(c.color.coords[1], 100); - assert.equal(c.color.coords[2], 50); - assert.equal(c.color.alpha, 0.8); - - cc.setRed(98); - assert.closeTo(cc.color.coords[0], 297, 1); - assert.closeTo(cc.color.coords[1], 100, 1); - assert.closeTo(cc.color.coords[2], 20, 1); - assert.equal(cc.color.alpha, 0.8); - - cc.setGreen(44); - assert.closeTo(cc.color.coords[0], 295, 1); - assert.closeTo(cc.color.coords[1], 39, 1); - assert.closeTo(cc.color.coords[2], 28, 1); - assert.equal(cc.color.alpha, 0.8); - - cc.setBlue(244); - assert.closeTo(cc.color.coords[0], 256, 1); - assert.closeTo(cc.color.coords[1], 90, 1); - assert.closeTo(cc.color.coords[2], 56, 1); - assert.equal(cc.color.alpha, 0.8); + let cc = mockP5Prototype.color(93.33, 200, 150, 8); + assert.closeTo(c._color.coords[0], 336, 1); + assert.equal(c._color.coords[1], 100); + assert.equal(c._color.coords[2], 50); + assert.equal(c._color.alpha, 0.8); + + cc.setRed(98/255); + assert.closeTo(cc._color.coords[0], 297, 1); + assert.closeTo(cc._color.coords[1], 100, 1); + assert.closeTo(cc._color.coords[2], 20, 1); + assert.equal(cc._color.alpha, 0.8); + + cc.setGreen(44/255); + assert.closeTo(cc._color.coords[0], 295, 1); + assert.closeTo(cc._color.coords[1], 39, 1); + assert.closeTo(cc._color.coords[2], 28, 1); + assert.equal(cc._color.alpha, 0.8); + + cc.setBlue(244/255); + assert.closeTo(cc._color.coords[0], 256, 1); + assert.closeTo(cc._color.coords[1], 90, 1); + assert.closeTo(cc._color.coords[2], 56, 1); + assert.equal(cc._color.alpha, 0.8); }); }); suite('p5.Color in HSL mode with RGB string', function() { // NOTE: will still create a sRGB color in this case beforeEach(function() { - myp5.colorMode(myp5.HSL, 360, 100, 100, 1); - c = myp5.color('rgba(255, 0, 102, 0.8)'); + mockP5Prototype.colorMode(mockP5Prototype.HSL, 360, 100, 100, 1); + c = mockP5Prototype.color('rgba(255, 0, 102, 0.8)'); }); test.todo('should correctly get HSLA property', function() { @@ -473,8 +466,8 @@ suite('p5.Color', function() { }); test('should correctly convert to RGBA', function() { - assert.deepEqual(c.color.coords, [1, 0, 0.4]); - assert.equal(c.color.alpha, 0.8); + assert.deepEqual(c._color.coords, [1, 0, 0.4]); + assert.equal(c._color.alpha, 0.8); }); test('should correctly render color string', function() { @@ -484,8 +477,8 @@ suite('p5.Color', function() { suite('p5.Color in HSL mode with HSL string', function() { beforeEach(function() { - myp5.colorMode(myp5.HSL, 360, 100, 100, 1); - c = myp5.color('hsla(336, 100%, 50%, 0.8)'); + mockP5Prototype.colorMode(mockP5Prototype.HSL, 360, 100, 100, 1); + c = mockP5Prototype.color('hsla(336, 100%, 50%, 0.8)'); }); test.todo('should correctly get HSLA property', function() { @@ -498,10 +491,10 @@ suite('p5.Color', function() { test('should correctly convert to RGBA', function() { // NOTE: 0.5.2 of color.js uses `new Number` which is corrected in future version // assert.deepEqual(c.color.coords, [336, 100, 50]); - assert.equal(+c.color.coords[0], 336); - assert.equal(c.color.coords[1], 100); - assert.equal(c.color.coords[2], 50); - assert.equal(c.color.alpha, 0.8); + assert.equal(+c._color.coords[0], 336); + assert.equal(c._color.coords[1], 100); + assert.equal(c._color.coords[2], 50); + assert.equal(c._color.alpha, 0.8); }); test('should correctly render color string', function() { @@ -511,8 +504,8 @@ suite('p5.Color', function() { suite('p5.Color in HSL mode with HSB string', function() { beforeEach(function() { - myp5.colorMode(myp5.HSL, 360, 100, 100, 1); - c = myp5.color('hsba(336, 100%, 100%, 0.8)'); + mockP5Prototype.colorMode(mockP5Prototype.HSL, 360, 100, 100, 1); + c = mockP5Prototype.color('hsba(336, 100%, 100%, 0.8)'); }); test.todo('should correctly get HSLA property', function() { @@ -525,10 +518,10 @@ suite('p5.Color', function() { test('should correctly convert to RGBA', function() { // NOTE: 0.5.2 of color.js uses `new Number` which is corrected in future version // assert.deepEqual(c.color.coords, [336, 100, 50]); - assert.equal(+c.color.coords[0], 336); - assert.equal(c.color.coords[1], 100); - assert.equal(c.color.coords[2], 100); - assert.equal(c.color.alpha, 0.8); + assert.equal(+c._color.coords[0], 336); + assert.equal(c._color.coords[1], 100); + assert.equal(c._color.coords[2], 100); + assert.equal(c._color.alpha, 0.8); }); test('should correctly render color string', function() { @@ -538,62 +531,62 @@ suite('p5.Color', function() { suite('p5.Color in HSB mode', function() { beforeEach(function() { - myp5.colorMode(myp5.HSB); - c = myp5.color(336, 100, 100); + mockP5Prototype.colorMode(mockP5Prototype.HSB); + c = mockP5Prototype.color(336, 100, 100); }); test('should create instance of p5.Color', function() { - assert.instanceOf(c, p5.Color); + assert.instanceOf(c, Color); }); test('should correctly set RGBA property', function() { - assert.deepEqual(c.color.coords, [336, 100, 100]); - assert.equal(c.color.alpha, 1); + assert.deepEqual(c._color.coords, [336, 100, 100]); + assert.equal(c._color.alpha, 1); }); test('can be modified with alpha setter', function() { - var cc = myp5.color(336, 100, 100); + var cc = mockP5Prototype.color(336, 100, 100); cc.setAlpha(0.73); - assert.deepEqual(cc.color.coords, [336, 100, 100]); - assert.equal(cc.color.alpha, 0.73); + assert.deepEqual(cc._color.coords, [336, 100, 100]); + assert.equal(cc._color.alpha, 0.73); }); test('can be modified with rgb setters', function() { - var cc = myp5.color(336, 100, 100); - assert.deepEqual(cc.color.coords, [336, 100, 100]); - assert.equal(cc.color.alpha, 1); - - cc.setRed(98); - assert.closeTo(cc.color.coords[0], 297, 1); - assert.closeTo(cc.color.coords[1], 100, 1); - assert.closeTo(cc.color.coords[2], 40, 1); - assert.equal(cc.color.alpha, 1); - - cc.setGreen(44); - assert.closeTo(cc.color.coords[0], 295, 1); - assert.closeTo(cc.color.coords[1], 56, 1); - assert.closeTo(cc.color.coords[2], 40, 1); - assert.equal(cc.color.alpha, 1); - - cc.setBlue(244); - assert.closeTo(cc.color.coords[0], 256, 1); - assert.closeTo(cc.color.coords[1], 81, 1); - assert.closeTo(cc.color.coords[2], 95, 1); - assert.equal(cc.color.alpha, 1); + var cc = mockP5Prototype.color(336, 100, 100); + assert.deepEqual(cc._color.coords, [336, 100, 100]); + assert.equal(cc._color.alpha, 1); + + cc.setRed(98/255); + assert.closeTo(cc._color.coords[0], 297, 1); + assert.closeTo(cc._color.coords[1], 100, 1); + assert.closeTo(cc._color.coords[2], 40, 1); + assert.equal(cc._color.alpha, 1); + + cc.setGreen(44/255); + assert.closeTo(cc._color.coords[0], 295, 1); + assert.closeTo(cc._color.coords[1], 56, 1); + assert.closeTo(cc._color.coords[2], 40, 1); + assert.equal(cc._color.alpha, 1); + + cc.setBlue(244/255); + assert.closeTo(cc._color.coords[0], 256, 1); + assert.closeTo(cc._color.coords[1], 81, 1); + assert.closeTo(cc._color.coords[2], 95, 1); + assert.equal(cc._color.alpha, 1); }); }); suite('p5.Color in HSB mode with Alpha', function() { beforeEach(function() { - myp5.colorMode(myp5.HSB); - c = myp5.color(336, 100, 100, 0.8); + mockP5Prototype.colorMode(mockP5Prototype.HSB); + c = mockP5Prototype.color(336, 100, 100, 0.8); }); test('should create instance of p5.Color', function() { - assert.instanceOf(c, p5.Color); + assert.instanceOf(c, Color); }); test('should correctly set RGBA property', function() { - assert.deepEqual(c.color.coords, [336, 100, 100]); - assert.equal(c.color.alpha, 0.8); + assert.deepEqual(c._color.coords, [336, 100, 100]); + assert.equal(c._color.alpha, 0.8); }); test('should correctly get hue/saturation/brightness/alpha', function() { @@ -606,22 +599,22 @@ suite('p5.Color', function() { suite('p5.Color in HSB mode with custom range', function() { beforeEach(function() { - myp5.colorMode(myp5.HSB, 100, 200, 300, 10); - c = myp5.color(93.33, 200, 300, 8); + mockP5Prototype.colorMode(mockP5Prototype.HSB, 100, 200, 300, 10); + c = mockP5Prototype.color(93.33, 200, 300, 8); }); test('should correctly get HSBA property', function() { - assert.approximately(c._getHue(), 93, 0.5); - assert.approximately(c._getSaturation(), 200, 0.5); - assert.approximately(c._getBrightness(), 300, 0.5); - assert.approximately(c._getAlpha(), 8, 0.5); + assert.approximately(c._getHue(), 336, 0.5); + assert.approximately(c._getSaturation(), 100, 0.5); + assert.approximately(c._getBrightness(), 100, 0.5); + assert.approximately(c._getAlpha(), 0.8, 0.5); }); test('should correctly convert to RGBA', function() { - assert.closeTo(c.color.coords[0], 336, 1); - assert.equal(c.color.coords[1], 100); - assert.equal(c.color.coords[2], 100); - assert.equal(c.color.alpha, 0.8); + assert.closeTo(c._color.coords[0], 336, 1); + assert.equal(c._color.coords[1], 100); + assert.equal(c._color.coords[2], 100); + assert.equal(c._color.alpha, 0.8); }); test('should correctly render color string', function() { @@ -631,8 +624,8 @@ suite('p5.Color', function() { suite('p5.Color in HSB mode with RGB string', function() { beforeEach(function() { - myp5.colorMode(myp5.HSB, 360, 100, 100, 1); - c = myp5.color('rgba(255, 0, 102, 0.8)'); + mockP5Prototype.colorMode(mockP5Prototype.HSB, 360, 100, 100, 1); + c = mockP5Prototype.color('rgba(255, 0, 102, 0.8)'); }); test.todo('should correctly get HSBA property', function() { @@ -643,8 +636,8 @@ suite('p5.Color', function() { }); test('should correctly convert to RGBA', function() { - assert.deepEqual(c.color.coords, [1, 0, 0.4]); - assert.equal(c.color.alpha, 0.8); + assert.deepEqual(c._color.coords, [1, 0, 0.4]); + assert.equal(c._color.alpha, 0.8); }); test('should correctly render color string', function() { @@ -654,8 +647,8 @@ suite('p5.Color', function() { suite('p5.Color in HSB mode with HSB string', function() { beforeEach(function() { - myp5.colorMode(myp5.HSB, 360, 100, 100, 1); - c = myp5.color('hsba(336, 100%, 100%, 0.8)'); + mockP5Prototype.colorMode(mockP5Prototype.HSB, 360, 100, 100, 1); + c = mockP5Prototype.color('hsba(336, 100%, 100%, 0.8)'); }); test('should correctly get HSBA property', function() { @@ -666,10 +659,10 @@ suite('p5.Color', function() { }); test('should correctly convert to RGBA', function() { - assert.equal(+c.color.coords[0], 336); - assert.equal(c.color.coords[1], 100); - assert.equal(c.color.coords[2], 100); - assert.equal(c.color.alpha, 0.8); + assert.equal(+c._color.coords[0], 336); + assert.equal(c._color.coords[1], 100); + assert.equal(c._color.coords[2], 100); + assert.equal(c._color.alpha, 0.8); }); test('should correctly render color string', function() { @@ -679,8 +672,8 @@ suite('p5.Color', function() { suite('p5.Color in HSB mode with HSL string', function() { beforeEach(function() { - myp5.colorMode(myp5.HSB, 360, 100, 100, 1); - c = myp5.color('hsla(336, 100%, 50%, 0.8)'); + mockP5Prototype.colorMode(mockP5Prototype.HSB, 360, 100, 100, 1); + c = mockP5Prototype.color('hsla(336, 100%, 50%, 0.8)'); }); test.todo('should correctly get HSBA property', function() { @@ -691,10 +684,10 @@ suite('p5.Color', function() { }); test('should correctly convert to RGBA', function() { - assert.equal(+c.color.coords[0], 336); - assert.equal(c.color.coords[1], 100); - assert.equal(c.color.coords[2], 50); - assert.equal(c.color.alpha, 0.8); + assert.equal(+c._color.coords[0], 336); + assert.equal(c._color.coords[1], 100); + assert.equal(c._color.coords[2], 50); + assert.equal(c._color.alpha, 0.8); }); test('should correctly render color string', function() { @@ -704,97 +697,97 @@ suite('p5.Color', function() { suite('p5.Color in RGB mode with grayscale value', function() { beforeEach(function() { - myp5.colorMode(myp5.RGB); - c = myp5.color(100); + mockP5Prototype.colorMode(mockP5Prototype.RGB); + c = mockP5Prototype.color(100); }); test('should create instance of p5.Color', function() { - assert.instanceOf(c, p5.Color); + assert.instanceOf(c, Color); }); test('should correctly set RGB levels', function() { - assert.deepEqual(c.color.coords, [100/255, 100/255, 100/255]); - assert.equal(c.color.alpha, 1); + assert.deepEqual(c._color.coords, [100/255, 100/255, 100/255]); + assert.equal(c._color.alpha, 1); }); }); suite('p5.Color in RGB mode with grayscale value and alpha', function() { beforeEach(function() { - myp5.colorMode(myp5.RGB); - c = myp5.color(100, 70); + mockP5Prototype.colorMode(mockP5Prototype.RGB); + c = mockP5Prototype.color(100, 70); }); test('should create instance of p5.Color', function() { - assert.instanceOf(c, p5.Color); + assert.instanceOf(c, Color); }); test('should correctly set RGB levels', function() { - assert.deepEqual(c.color.coords, [100/255, 100/255, 100/255]); - assert.equal(c.color.alpha, 70/255); + assert.deepEqual(c._color.coords, [100/255, 100/255, 100/255]); + assert.equal(c._color.alpha, 70/255); }); }); suite('p5.Color in HSB mode with grayscale value', function() { beforeEach(function() { - myp5.colorMode(myp5.HSB); - c = myp5.color(39.3); + mockP5Prototype.colorMode(mockP5Prototype.HSB); + c = mockP5Prototype.color(39.3); }); test('should create instance of p5.Color', function() { - assert.instanceOf(c, p5.Color); + assert.instanceOf(c, Color); }); test('should correctly set RGB levels', function() { - assert.deepEqual(c.color.coords, [39.3, 39.3, 39.3]); - assert.equal(c.color.alpha, 1); + assert.deepEqual(c._color.coords, [39.3, 39.3, 39.3]); + assert.equal(c._color.alpha, 1); }); }); suite('p5.Color in HSB mode with grayscale value and alpha', function() { beforeEach(function() { - myp5.colorMode(myp5.HSB); - c = myp5.color(39.3, 0.275); + mockP5Prototype.colorMode(mockP5Prototype.HSB); + c = mockP5Prototype.color(39.3, 0.275); }); test('should create instance of p5.Color', function() { - assert.instanceOf(c, p5.Color); + assert.instanceOf(c, Color); }); test('should correctly set RGB levels', function() { - assert.deepEqual(c.color.coords, [39.3, 39.3, 39.3]); - assert.equal(c.color.alpha, 0.275); + assert.deepEqual(c._color.coords, [39.3, 39.3, 39.3]); + assert.equal(c._color.alpha, 0.275); }); }); suite('p5.Color in HSL mode with grayscale value', function() { beforeEach(function() { - myp5.colorMode(myp5.HSL); - c = myp5.color(39.3); + mockP5Prototype.colorMode(mockP5Prototype.HSL); + c = mockP5Prototype.color(39.3); }); test('should create instance of p5.Color', function() { - assert.instanceOf(c, p5.Color); + assert.instanceOf(c, Color); }); test('should correctly set RGB levels', function() { - assert.deepEqual(c.color.coords, [39.3, 39.3, 39.3]); - assert.equal(c.color.alpha, 1); + assert.deepEqual(c._color.coords, [39.3, 39.3, 39.3]); + assert.equal(c._color.alpha, 1); }); }); suite('p5.Color in HSL mode with grayscale value and alpha', function() { beforeEach(function() { - myp5.colorMode(myp5.HSL); - c = myp5.color(39.3, 0.275); + mockP5Prototype.colorMode(mockP5Prototype.HSL); + c = mockP5Prototype.color(39.3, 0.275); }); test('should create instance of p5.Color', function() { - assert.instanceOf(c, p5.Color); + assert.instanceOf(c, Color); }); test('should correctly set RGB levels', function() { - assert.deepEqual(c.color.coords, [39.3, 39.3, 39.3]); - assert.equal(c.color.alpha, 0.275); + assert.deepEqual(c._color.coords, [39.3, 39.3, 39.3]); + assert.equal(c._color.alpha, 0.275); }); }); @@ -802,8 +795,8 @@ suite('p5.Color', function() { // var colorStr; // beforeEach(function() { - // myp5.colorMode(myp5.RGB, 255, 255, 255, 255); - // c = myp5.color(128, 0, 128, 128); + // mockP5Prototype.colorMode(mockP5Prototype.RGB, 255, 255, 255, 255); + // c = mockP5Prototype.color(128, 0, 128, 128); // colorStr = c.toString(); // }); diff --git a/test/unit/color/setting.js b/test/unit/color/setting.js index 6bf5dbcfc6..12a44f195d 100644 --- a/test/unit/color/setting.js +++ b/test/unit/color/setting.js @@ -1,10 +1,32 @@ import p5 from '../../../src/app.js'; +import { vi } from 'vitest'; +import { mockP5, mockP5Prototype } from '../../js/mocks'; +import creatingReading from '../../../src/color/creating_reading'; +import setting from '../../../src/color/setting'; + // NOTE: Require ESM compatible libtess suite('color/Setting', function() { let myp5; // sketch without WEBGL Mode let my3D; // sketch with WEBGL mode + beforeAll(() => { + creatingReading(mockP5, mockP5Prototype); + setting(mockP5, mockP5Prototype); + // mockP5Prototype.states = { + // colorMode: 'rgb', + // colorMaxes: { + // rgb: [255, 255, 255, 255], + // hsb: [360, 100, 100, 1], + // hsl: [360, 100, 100, 1] + // } + // } + }); + + afterAll(() => { + delete mockP5Prototype._colorMaxes; + }); + beforeEach(async function() { await new Promise(resolve => { new p5(function(p) { @@ -32,15 +54,35 @@ suite('color/Setting', function() { }); suite('p5.prototype.erase', function() { + beforeEach(() => { + mockP5Prototype._renderer = { + erase: vi.fn(), + states: { + colorMode: 'rgb', + colorMaxes: { + rgb: [255, 255, 255, 255], + hsb: [360, 100, 100, 1], + hsl: [360, 100, 100, 1] + } + } + } + }); + + afterEach(() => { + vi.resetAllMocks(); + }); + test('should be a function', function() { - assert.ok(myp5.erase); + assert.ok(mockP5Prototype.erase); }); - test('should set renderer to erasing state', function() { - myp5.erase(); - assert.isTrue(myp5._renderer._isErasing); + test('should call the renderer erase method with default arguments', function() { + mockP5Prototype.erase(); + expect(mockP5Prototype._renderer.erase).toHaveBeenCalledWith(255, 255); }); + // TODO: test in renderer + test.todo('should set renderer to erasing state'); test.todo('should cache renderer fill', function() { myp5.fill(255, 0, 0); const fillStyle = myp5.drawingContext.fillStyle; @@ -55,13 +97,13 @@ suite('color/Setting', function() { assert.deepEqual(myp5._renderer._cachedStrokeStyle, strokeStyle); }); - test('should cache renderer blend', function() { + test.todo('should cache renderer blend', function() { myp5.blendMode(myp5.SCREEN); myp5.erase(); assert.deepEqual(myp5._renderer._cachedBlendMode, myp5.SCREEN); }); - test('should set fill strength', function() { + test.todo('should set fill strength', function() { myp5.erase(125); assert.equal( myp5.color(myp5.drawingContext.fillStyle).array, @@ -69,7 +111,7 @@ suite('color/Setting', function() { ); }); - test('should set stroke strength', function() { + test.todo('should set stroke strength', function() { myp5.erase(255, 50); assert.equal( myp5.color(myp5.drawingContext.strokeStyle).array, @@ -123,7 +165,7 @@ suite('color/Setting', function() { suite('p5.prototype.noErase', function() { test('should be a function', function() { - assert.ok(myp5.noErase); + assert.ok(mockP5Prototype.noErase); }); test('should turn off renderer erasing state', function() { @@ -175,123 +217,123 @@ suite('color/Setting', function() { suite('p5.prototype.colorMode', function() { test('should be a function', function() { - assert.ok(myp5.colorMode); + assert.ok(mockP5Prototype.colorMode); }); test('should set mode to RGB', function() { - myp5.colorMode(myp5.RGB); - assert.equal(myp5._colorMode, myp5.RGB); + mockP5Prototype.colorMode('rgb'); + assert.equal(mockP5Prototype._renderer.states.colorMode, 'rgb'); }); test('should correctly set color RGB maxes', function() { - assert.deepEqual(myp5._colorMaxes[myp5.RGB], [255, 255, 255, 255]); - myp5.colorMode(myp5.RGB, 1, 1, 1); - assert.deepEqual(myp5._colorMaxes[myp5.RGB], [1, 1, 1, 255]); - myp5.colorMode(myp5.RGB, 1); - assert.deepEqual(myp5._colorMaxes[myp5.RGB], [1, 1, 1, 1]); - myp5.colorMode(myp5.RGB, 255, 255, 255, 1); - assert.deepEqual(myp5._colorMaxes[myp5.RGB], [255, 255, 255, 1]); - myp5.colorMode(myp5.RGB, 255); + assert.deepEqual(mockP5Prototype._renderer.states.colorMaxes['rgb'], [255, 255, 255, 255]); + mockP5Prototype.colorMode('rgb', 1, 1, 1); + assert.deepEqual(mockP5Prototype._renderer.states.colorMaxes['rgb'], [1, 1, 1, 255]); + mockP5Prototype.colorMode('rgb', 1); + assert.deepEqual(mockP5Prototype._renderer.states.colorMaxes['rgb'], [1, 1, 1, 1]); + mockP5Prototype.colorMode('rgb', 255, 255, 255, 1); + assert.deepEqual(mockP5Prototype._renderer.states.colorMaxes['rgb'], [255, 255, 255, 1]); + mockP5Prototype.colorMode('rgb', 255); }); test('should set mode to HSL', function() { - myp5.colorMode(myp5.HSL); - assert.equal(myp5._colorMode, myp5.HSL); + mockP5Prototype.colorMode('hsl'); + assert.equal(mockP5Prototype._renderer.states.colorMode, 'hsl'); }); test('should correctly set color HSL maxes', function() { - assert.deepEqual(myp5._colorMaxes[myp5.HSL], [360, 100, 100, 1]); - myp5.colorMode(myp5.HSL, 255, 255, 255); - assert.deepEqual(myp5._colorMaxes[myp5.HSL], [255, 255, 255, 1]); - myp5.colorMode(myp5.HSL, 360); - assert.deepEqual(myp5._colorMaxes[myp5.HSL], [360, 360, 360, 360]); - myp5.colorMode(myp5.HSL, 360, 100, 100, 1); - assert.deepEqual(myp5._colorMaxes[myp5.HSL], [360, 100, 100, 1]); + assert.deepEqual(mockP5Prototype._renderer.states.colorMaxes['hsl'], [360, 100, 100, 1]); + mockP5Prototype.colorMode('hsl', 255, 255, 255); + assert.deepEqual(mockP5Prototype._renderer.states.colorMaxes['hsl'], [255, 255, 255, 1]); + mockP5Prototype.colorMode('hsl', 360); + assert.deepEqual(mockP5Prototype._renderer.states.colorMaxes['hsl'], [360, 360, 360, 360]); + mockP5Prototype.colorMode('hsl', 360, 100, 100, 1); + assert.deepEqual(mockP5Prototype._renderer.states.colorMaxes['hsl'], [360, 100, 100, 1]); }); test('should set mode to HSB', function() { - myp5.colorMode(myp5.HSB); - assert.equal(myp5._colorMode, myp5.HSB); + mockP5Prototype.colorMode('hsb'); + assert.equal(mockP5Prototype._renderer.states.colorMode, 'hsb'); }); test('should correctly set color HSB maxes', function() { - assert.deepEqual(myp5._colorMaxes[myp5.HSB], [360, 100, 100, 1]); - myp5.colorMode(myp5.HSB, 255, 255, 255); - assert.deepEqual(myp5._colorMaxes[myp5.HSB], [255, 255, 255, 1]); - myp5.colorMode(myp5.HSB, 360); - assert.deepEqual(myp5._colorMaxes[myp5.HSB], [360, 360, 360, 360]); - myp5.colorMode(myp5.HSB, 360, 100, 100, 1); - assert.deepEqual(myp5._colorMaxes[myp5.HSB], [360, 100, 100, 1]); + assert.deepEqual(mockP5Prototype._renderer.states.colorMaxes['hsb'], [360, 100, 100, 1]); + mockP5Prototype.colorMode('hsb', 255, 255, 255); + assert.deepEqual(mockP5Prototype._renderer.states.colorMaxes['hsb'], [255, 255, 255, 1]); + mockP5Prototype.colorMode('hsb', 360); + assert.deepEqual(mockP5Prototype._renderer.states.colorMaxes['hsb'], [360, 360, 360, 360]); + mockP5Prototype.colorMode('hsb', 360, 100, 100, 1); + assert.deepEqual(mockP5Prototype._renderer.states.colorMaxes['hsb'], [360, 100, 100, 1]); }); }); suite('p5.Color components', function() { test('setRed() correctly sets red component', function() { - myp5.colorMode(myp5.RGB, 255); - const c = myp5.color(0, 162, 205, 255); + mockP5Prototype.colorMode('rgb', 255); + const c = mockP5Prototype.color(0, 162, 205, 255); c.setRed(100); - assert.equal(myp5.red(c), 100); - assert.equal(myp5.green(c), 162); - assert.equal(myp5.blue(c), 205); - assert.equal(myp5.alpha(c), 255); + assert.equal(mockP5Prototype.red(c), 100); + assert.equal(mockP5Prototype.green(c), 162); + assert.equal(mockP5Prototype.blue(c), 205); + assert.equal(mockP5Prototype.alpha(c), 255); }); test('setGreen() correctly sets green component', function() { - myp5.colorMode(myp5.RGB, 255); - const c = myp5.color(0, 162, 205, 255); + mockP5Prototype.colorMode('rgb', 255); + const c = mockP5Prototype.color(0, 162, 205, 255); c.setGreen(100); - assert.equal(myp5.red(c), 0); - assert.equal(myp5.green(c), 100); - assert.equal(myp5.blue(c), 205); - assert.equal(myp5.alpha(c), 255); + assert.equal(mockP5Prototype.red(c), 0); + assert.equal(mockP5Prototype.green(c), 100); + assert.equal(mockP5Prototype.blue(c), 205); + assert.equal(mockP5Prototype.alpha(c), 255); }); test('setBlue() correctly sets blue component', function() { - myp5.colorMode(myp5.RGB, 255); - const c = myp5.color(0, 162, 205, 255); + mockP5Prototype.colorMode('rgb', 255); + const c = mockP5Prototype.color(0, 162, 205, 255); c.setBlue(100); - assert.equal(myp5.red(c), 0); - assert.equal(myp5.green(c), 162); - assert.equal(myp5.blue(c), 100); - assert.equal(myp5.alpha(c), 255); + assert.equal(mockP5Prototype.red(c), 0); + assert.equal(mockP5Prototype.green(c), 162); + assert.equal(mockP5Prototype.blue(c), 100); + assert.equal(mockP5Prototype.alpha(c), 255); }); test('setAlpha correctly sets alpha component', function() { - myp5.colorMode(myp5.RGB, 255); - const c = myp5.color(0, 162, 205, 255); + mockP5Prototype.colorMode('rgb', 255); + const c = mockP5Prototype.color(0, 162, 205, 255); c.setAlpha(100); - assert.equal(myp5.red(c), 0); - assert.equal(myp5.green(c), 162); - assert.equal(myp5.blue(c), 205); - assert.equal(myp5.alpha(c), 100); + assert.equal(mockP5Prototype.red(c), 0); + assert.equal(mockP5Prototype.green(c), 162); + assert.equal(mockP5Prototype.blue(c), 205); + assert.equal(mockP5Prototype.alpha(c), 100); }); test('changing the red/green/blue/alpha components should clear the cached HSL/HSB values', function() { - myp5.colorMode(myp5.RGB, 255); - const c = myp5.color(0, 162, 205, 255); + mockP5Prototype.colorMode('rgb', 255); + const c = mockP5Prototype.color(0, 162, 205, 255); // create HSL/HSB values - myp5.lightness(c); - myp5.brightness(c); - c.setRed(100); + mockP5Prototype.lightness(c); + mockP5Prototype.brightness(c); + c.setRed(100/255); assert(!c.hsba); assert(!c.hsla); - myp5.lightness(c); - myp5.brightness(c); - c.setGreen(100); + mockP5Prototype.lightness(c); + mockP5Prototype.brightness(c); + c.setGreen(100/255); assert(!c.hsba); assert(!c.hsla); - myp5.lightness(c); - myp5.brightness(c); - c.setBlue(100); + mockP5Prototype.lightness(c); + mockP5Prototype.brightness(c); + c.setBlue(100/255); assert(!c.hsba); assert(!c.hsla); - myp5.lightness(c); - myp5.brightness(c); - c.setAlpha(100); + mockP5Prototype.lightness(c); + mockP5Prototype.brightness(c); + c.setAlpha(100/255); assert(!c.hsba); assert(!c.hsla); }); diff --git a/test/unit/core/rendering.js b/test/unit/core/rendering.js index 9f0fa44762..47b2fc2240 100644 --- a/test/unit/core/rendering.js +++ b/test/unit/core/rendering.js @@ -25,21 +25,21 @@ suite('Rendering', function() { suite('p5.prototype.createCanvas', function() { test('should have correct initial colors', function() { - var white = myp5.color(255, 255, 255).levels; - var black = myp5.color(0, 0, 0).levels; - assert.deepEqual(myp5.color(myp5._renderer._getFill()).levels, white); - assert.deepEqual(myp5.color(myp5._renderer._getStroke()).levels, black); - assert.deepEqual(myp5.color(myp5.drawingContext.fillStyle).levels, white); + var white = myp5.color(255, 255, 255)._array; + var black = myp5.color(0, 0, 0)._array; + assert.deepEqual(myp5.color(myp5._renderer._getFill())._array, white); + assert.deepEqual(myp5.color(myp5._renderer._getStroke())._array, black); + assert.deepEqual(myp5.color(myp5.drawingContext.fillStyle)._array, white); assert.deepEqual( - myp5.color(myp5.drawingContext.strokeStyle).levels, + myp5.color(myp5.drawingContext.strokeStyle)._array, black ); myp5.createCanvas(100, 100); - assert.deepEqual(myp5.color(myp5._renderer._getFill()).levels, white); - assert.deepEqual(myp5.color(myp5._renderer._getStroke()).levels, black); - assert.deepEqual(myp5.color(myp5.drawingContext.fillStyle).levels, white); + assert.deepEqual(myp5.color(myp5._renderer._getFill())._array, white); + assert.deepEqual(myp5.color(myp5._renderer._getStroke())._array, black); + assert.deepEqual(myp5.color(myp5.drawingContext.fillStyle)._array, white); assert.deepEqual( - myp5.color(myp5.drawingContext.strokeStyle).levels, + myp5.color(myp5.drawingContext.strokeStyle)._array, black ); }); diff --git a/test/unit/data/local_storage.js b/test/unit/data/local_storage.js index 75a9f94da0..6c8719c777 100644 --- a/test/unit/data/local_storage.js +++ b/test/unit/data/local_storage.js @@ -17,7 +17,7 @@ suite('local storage', function() { beforeAll(function() { storage(mockP5, mockP5Prototype); - p5Color(mockP5, mockP5Prototype); + p5Color(mockP5, mockP5Prototype, {}); creatingReading(mockP5, mockP5Prototype); p5Vector(mockP5, mockP5Prototype); math(mockP5, mockP5Prototype); diff --git a/test/unit/dom/dom.js b/test/unit/dom/dom.js index 96c1a7ec81..e6a8df86ab 100644 --- a/test/unit/dom/dom.js +++ b/test/unit/dom/dom.js @@ -10,7 +10,7 @@ suite('DOM', function() { beforeAll(() => { dom(mockP5, mockP5Prototype); creatingReading(mockP5, mockP5Prototype); - p5Color(mockP5, mockP5Prototype); + p5Color(mockP5, mockP5Prototype, {}); }); // Selectors diff --git a/test/unit/webgl/p5.RendererGL.js b/test/unit/webgl/p5.RendererGL.js index b857e1f904..b3abec9cd4 100644 --- a/test/unit/webgl/p5.RendererGL.js +++ b/test/unit/webgl/p5.RendererGL.js @@ -1316,7 +1316,7 @@ suite('p5.RendererGL', function() { ); }; - for (const alpha of [255, 200]) { + for (const alpha of [1, 200/255]) { const red = myp5.color('#F53'); const blue = myp5.color('#13F'); red.setAlpha(alpha);