From 093592998f7086f3a85e642f277177603889c1fd Mon Sep 17 00:00:00 2001 From: Diana Galindo Date: Wed, 6 Nov 2024 15:21:33 +0000 Subject: [PATCH 01/14] culori.js implementation --- package-lock.json | 10 +++ package.json | 3 +- preview/index.html | 3 +- src/color/p5.Color.js | 192 +++++++++++++++++++++++++----------------- 4 files changed, 128 insertions(+), 80 deletions(-) diff --git a/package-lock.json b/package-lock.json index d4b2181b8f..fe4b75259a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "acorn": "^8.12.1", "acorn-walk": "^8.3.4", "colorjs.io": "^0.5.2", + "culori": "^4.0.1", "file-saver": "^1.3.8", "gifenc": "^1.0.3", "libtess": "^1.2.2", @@ -3764,6 +3765,15 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/culori": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/culori/-/culori-4.0.1.tgz", + "integrity": "sha512-LSnjA6HuIUOlkfKVbzi2OlToZE8OjFi667JWN9qNymXVXzGDmvuP60SSgC+e92sd7B7158f7Fy3Mb6rXS5EDPw==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, "node_modules/data-uri-to-buffer": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", diff --git a/package.json b/package.json index 37c0804100..92409ef831 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "acorn": "^8.12.1", "acorn-walk": "^8.3.4", "colorjs.io": "^0.5.2", + "culori": "^4.0.1", "file-saver": "^1.3.8", "gifenc": "^1.0.3", "libtess": "^1.2.2", @@ -84,4 +85,4 @@ "pre-commit": "lint-staged" } } -} \ No newline at end of file +} diff --git a/preview/index.html b/preview/index.html index deb1e21e11..524c69472b 100644 --- a/preview/index.html +++ b/preview/index.html @@ -27,8 +27,7 @@ p.draw = function () { p.background(0, 50, 50); p.circle(100, 100, 50); - - p.fill('white'); + p.fill(255, 255, 0, 0.5); p.textSize(30); p.text('hello', 10, 30); }; diff --git a/src/color/p5.Color.js b/src/color/p5.Color.js index ab4b3f13e6..690428c73a 100644 --- a/src/color/p5.Color.js +++ b/src/color/p5.Color.js @@ -8,56 +8,84 @@ */ import * as constants from '../core/constants'; +// import { +// ColorSpace, +// to, +// // toGamut, +// serialize, +// parse, +// // range, + +// XYZ_D65, +// sRGB_Linear, +// sRGB, +// HSL, +// HSV, +// HWB, + +// XYZ_D50, +// Lab, +// LCH, + +// OKLab, +// OKLCH, + +// P3_Linear, +// P3, + +// A98RGB_Linear, +// A98RGB +// } from 'colorjs.io/fn'; + + +//for CSS string parsing +//import 'culori/css'; + +//importing culori/fn to optimize bundle size and +//'opting into' the tree-shakable version +// handle operations and conversions within color spaces import { - ColorSpace, - to, - // toGamut, - serialize, - parse, - // range, - - XYZ_D65, - sRGB_Linear, - sRGB, - HSL, - HSV, - HWB, - - XYZ_D50, - Lab, - LCH, - - OKLab, - OKLCH, - - P3_Linear, - P3, - - A98RGB_Linear, - A98RGB -} 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); - -ColorSpace.register(OKLab); -ColorSpace.register(OKLCH); - -ColorSpace.register(P3_Linear); -ColorSpace.register(P3); - -ColorSpace.register(A98RGB_Linear); -ColorSpace.register(A98RGB); + //converter, // string or color objects -> return object + //parse, // string -> return object + useMode, + modeHsl, + modeHwb, + modeOklab, + modeOklch, + modeP3, + modeRgb +} from 'culori/fn'; + +import {converter, parse} from 'culori'; + +//Registering color spaces with useMode() +const hsl = useMode(modeHsl); +const hwb = useMode(modeHwb); +const oklab = useMode(modeOklab); +const oklch = useMode(modeOklch); +const p3 = useMode(modeP3); +const rgb = useMode(modeRgb); + +// 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); + +// ColorSpace.register(OKLab); +// ColorSpace.register(OKLCH); + +// ColorSpace.register(P3_Linear); +// ColorSpace.register(P3); + +// ColorSpace.register(A98RGB_Linear); +// ColorSpace.register(A98RGB); class Color { color; @@ -65,20 +93,20 @@ class Color { 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; - // This changes with the color object - // this.mode = pInst._colorMode; + + //storing default rgb color mode and maxes this.mode = colorMode; + this.maxes = colorMaxes; + //if vals is an object if (typeof vals === 'object' && !Array.isArray(vals) && vals !== null){ - this.color = vals; - } else if(typeof vals[0] === 'string') { + this.color = vals; //color-compatible format + console.log("Color object detected:", this.color); + console.log("Current color mode:", this.color.mode); + + } else if( typeof vals[0] === 'string') { try{ - // NOTE: this will not necessarily have the right color mode + // parse the string this.color = parse(vals[0]); }catch(err){ // TODO: Invalid color string @@ -102,11 +130,11 @@ class Color { // _colorMode can be 'rgb', 'hsb', or 'hsl' // These should map to color.js color space - let space = 'srgb'; + let space = 'rgb'; let coords = vals; switch(this.mode){ case 'rgb': - space = 'srgb'; + space = 'rgb'; coords = [ vals[0] / this.maxes[this.mode][0], vals[1] / this.maxes[this.mode][1], @@ -118,28 +146,38 @@ class Color { 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 + vals[1] / this.maxes[this.mode][1] , + vals[2] / this.maxes[this.mode][2] ]; 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 + vals[1] / this.maxes[this.mode][1] , + vals[2] / this.maxes[this.mode][2] ]; break; default: console.error('Invalid color mode'); } - const color = { - space, - coords, - alpha - }; - this.color = to(color, space); + // Set the color object with space, coordinates, and alpha + this.color = { space, coords, alpha }; + console.log("Constructed color object:", this.color); + + // Use converter to ensure compatibility with Culori's color space conversion + const convertToSpace = converter(space); + this.color = convertToSpace(this.color); // Convert color to specified space + console.log("Converted color object:", this.color); + + // const color = { + // space, + // coords, + // alpha + // }; + // //this.color = to(color, space); + // this.color = converter(space); } } @@ -184,12 +222,12 @@ class Color { * * */ - toString(format) { - // NOTE: memoize - return serialize(this.color, { - format - }); - } + // toString(format) { + // // NOTE: memoize + // return serialize(this.color, { + // format + // }); + // } /** * Sets the red component of a color. From d60878ff725a40154917e88ac705fb9460d5d576 Mon Sep 17 00:00:00 2001 From: Diana Galindo Date: Sat, 9 Nov 2024 18:05:41 +0000 Subject: [PATCH 02/14] culori.js implementation --- preview/index.html | 5 +- src/color/p5.Color.js | 114 ++++++++++++++++++++++++++++++------------ 2 files changed, 86 insertions(+), 33 deletions(-) diff --git a/preview/index.html b/preview/index.html index 524c69472b..601e855de4 100644 --- a/preview/index.html +++ b/preview/index.html @@ -22,12 +22,13 @@ const sketch = function (p) { p.setup = function () { p.createCanvas(200, 200); + //p.background(255, 255, 255); }; p.draw = function () { - p.background(0, 50, 50); p.circle(100, 100, 50); - p.fill(255, 255, 0, 0.5); + //p.fill('hsl(160, 100%, 50%)'); + p.fill('hsb(160, 100%, 50%)'); //hsb seems to be having issues to render p.textSize(30); p.text('hello', 10, 30); }; diff --git a/src/color/p5.Color.js b/src/color/p5.Color.js index 690428c73a..6d15520092 100644 --- a/src/color/p5.Color.js +++ b/src/color/p5.Color.js @@ -56,7 +56,14 @@ import { modeRgb } from 'culori/fn'; -import {converter, parse} from 'culori'; +import { + converter, + parse, + formatHex, + formatHex8, + formatRgb, + formatHsl, + formatCss} from 'culori'; //Registering color spaces with useMode() const hsl = useMode(modeHsl); @@ -129,45 +136,70 @@ class Color { : 1; // _colorMode can be 'rgb', 'hsb', or 'hsl' - // These should map to color.js color space - let space = 'rgb'; - let coords = vals; + // Color representation for Culori.js + + //let space = 'rgb'; -> to specify color mode + //let coords = vals; -> to access coordinates switch(this.mode){ case 'rgb': - space = 'rgb'; - coords = [ - vals[0] / this.maxes[this.mode][0], - vals[1] / this.maxes[this.mode][1], - vals[2] / this.maxes[this.mode][2] - ]; + this.color = { + mode: 'rgb', + r: vals[0]/ this.maxes[this.mode][0], + g: vals[1] / this.maxes[this.mode][1], + b: vals[2]/ this.maxes[this.mode][2], + alpha: alpha + }; + // space = 'rgb'; + // 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] , - vals[2] / this.maxes[this.mode][2] - ]; + this.color = { + mode: 'hsv', // Culori uses "hsv" instead of "hsb" + h: (vals[0] / this.maxes.hsb[0]) * 360, + s: vals[1] / this.maxes.hsb[1], + v: vals[2] / this.maxes.hsb[2], + alpha: alpha + }; + // space = 'hsb'; + // coords = [ + // vals[0] / this.maxes[this.mode][0] * 360, + // vals[1] / this.maxes[this.mode][1] , + // vals[2] / this.maxes[this.mode][2] + // ]; break; case 'hsl': - space = 'hsl'; - coords = [ - vals[0] / this.maxes[this.mode][0] * 360, - vals[1] / this.maxes[this.mode][1] , - vals[2] / this.maxes[this.mode][2] - ]; + this.color = { + mode: 'hsl', + h: (vals[0] / this.maxes.hsl[0]) * 360, + s: vals[1] / this.maxes.hsl[1], + l: vals[2] / this.maxes.hsl[2], + alpha: alpha + }; + // space = 'hsl'; + // coords = [ + // vals[0] / this.maxes[this.mode][0] * 360, + // vals[1] / this.maxes[this.mode][1] , + // vals[2] / this.maxes[this.mode][2] + // ]; break; default: console.error('Invalid color mode'); - } - - // Set the color object with space, coordinates, and alpha - this.color = { space, coords, alpha }; - console.log("Constructed color object:", this.color); + }; + + // Define `toSpace` as an inline function within the constructor + // this.toSpace = (targetSpace) => { + // const toTargetSpace = converter(targetSpace); + // const convertedColor = toTargetSpace(this.color); + // console.log(`Converted color to ${targetSpace} mode:`, convertedColor); + // return convertedColor; + // }; - // Use converter to ensure compatibility with Culori's color space conversion - const convertToSpace = converter(space); + // // Use converter to ensure compatibility with Culori's color space conversion + const convertToSpace = converter(this.mode); this.color = convertToSpace(this.color); // Convert color to specified space console.log("Converted color object:", this.color); @@ -228,6 +260,25 @@ class Color { // format // }); // } + + //Culori.js doesn't have a single serialize function + //it rather has the following methods to serialize + //colours to strings in various formats + toString(format) { + switch (format) { + case 'hex': + return formatHex(this.color); + case 'hex8': + return formatHex8(this.color); + case 'rgb': + return formatRgb(this.color); + case 'hsl': + return formatHsl(this.color); + default: + // Fallback to a default format, like RGB + return formatRgb(this.color); + } + } /** * Sets the red component of a color. @@ -268,7 +319,8 @@ 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; + //this.color.coords[0] = red_val; + this.color.r = red_val; }else{ // Will do an imprecise conversion to 'srgb', not recommended const space = this.color.space.id; From 6c9c8b6d8375ad33310c688d440bf65983797b86 Mon Sep 17 00:00:00 2001 From: Diana Galindo Date: Sat, 9 Nov 2024 19:35:50 +0000 Subject: [PATCH 03/14] testing culori.js --- preview/index.html | 10 ++++++++-- src/color/p5.Color.js | 18 +++++++++++++----- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/preview/index.html b/preview/index.html index 601e855de4..c5e841fed1 100644 --- a/preview/index.html +++ b/preview/index.html @@ -22,13 +22,19 @@ const sketch = function (p) { p.setup = function () { p.createCanvas(200, 200); + //p.colorMode(''); //p.background(255, 255, 255); }; p.draw = function () { + + let c = p.color(255, 128, 128); + p.fill(c); p.circle(100, 100, 50); - //p.fill('hsl(160, 100%, 50%)'); - p.fill('hsb(160, 100%, 50%)'); //hsb seems to be having issues to render + c.setRed(64); + p.fill(c); + p.rect(50, 20, 35, 60); + //p.fill('hsb(160, 100%, 50%)'); //hsb seems to be having issues to render p.textSize(30); p.text('hello', 10, 30); }; diff --git a/src/color/p5.Color.js b/src/color/p5.Color.js index 6d15520092..6c3c06f402 100644 --- a/src/color/p5.Color.js +++ b/src/color/p5.Color.js @@ -50,6 +50,7 @@ import { useMode, modeHsl, modeHwb, + modeHsv, modeOklab, modeOklch, modeP3, @@ -72,6 +73,7 @@ const oklab = useMode(modeOklab); const oklch = useMode(modeOklch); const p3 = useMode(modeP3); const rgb = useMode(modeRgb); +const hsv = useMode(modeHsv); // ColorSpace.register(XYZ_D65); // ColorSpace.register(sRGB_Linear); @@ -137,7 +139,7 @@ class Color { // _colorMode can be 'rgb', 'hsb', or 'hsl' // Color representation for Culori.js - + //let space = 'rgb'; -> to specify color mode //let coords = vals; -> to access coordinates switch(this.mode){ @@ -274,6 +276,8 @@ class Color { return formatRgb(this.color); case 'hsl': return formatHsl(this.color); + case 'css': + return formatCss(this.color); //not sure of the use for CSS here default: // Fallback to a default format, like RGB return formatRgb(this.color); @@ -323,10 +327,14 @@ class Color { this.color.r = red_val; }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] = red_val; + //this.color = to(representation, space); + const space = this.color.mode; + const representation = converter('rgb')(this.color) + representation.color.r = red_val; + this.color = converter(space)(representation) } } From e35442d9d88807ddc94e438fdaca48453d52fc34 Mon Sep 17 00:00:00 2001 From: Diana Galindo Date: Sun, 10 Nov 2024 13:46:41 +0000 Subject: [PATCH 04/14] implementing methods in Culori.js --- preview/index.html | 16 +++++---- src/color/p5.Color.js | 81 ++++++++++++++++++++++++++++--------------- 2 files changed, 63 insertions(+), 34 deletions(-) diff --git a/preview/index.html b/preview/index.html index c5e841fed1..fae57c6dae 100644 --- a/preview/index.html +++ b/preview/index.html @@ -21,22 +21,24 @@ const sketch = function (p) { p.setup = function () { - p.createCanvas(200, 200); - //p.colorMode(''); - //p.background(255, 255, 255); + p.createCanvas(600, 600); + p.background(200); }; p.draw = function () { + p.colorMode('HSB'); + // Create a p5.Color object using RGB values let c = p.color(255, 128, 128); p.fill(c); - p.circle(100, 100, 50); + p.circle(200, 200, 100); + c.setRed(64); p.fill(c); - p.rect(50, 20, 35, 60); + p.rect(150, 300, 200, 100); //p.fill('hsb(160, 100%, 50%)'); //hsb seems to be having issues to render - p.textSize(30); - p.text('hello', 10, 30); + p.textSize(50); + p.text('hello', 50, 80); }; }; diff --git a/src/color/p5.Color.js b/src/color/p5.Color.js index 6c3c06f402..05849b83e5 100644 --- a/src/color/p5.Color.js +++ b/src/color/p5.Color.js @@ -210,8 +210,8 @@ class Color { // coords, // alpha // }; - // //this.color = to(color, space); - // this.color = converter(space); + //this.color = to(color, space); + } } @@ -321,20 +321,20 @@ class Color { * */ setRed(new_red) { - const red_val = new_red / this.maxes[constants.RGB][0]; + const red_val = new_red / this.maxes[constants.RGB][0]; //normalize red value if(this.mode === constants.RGB){ //this.color.coords[0] = red_val; this.color.r = red_val; }else{ - // Will do an imprecise conversion to 'srgb', not recommended + // Handling Non-RGB Color Modes //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.mode; - const representation = converter('rgb')(this.color) - representation.color.r = red_val; - this.color = converter(space)(representation) + const representation = converter('rgb')(this.color) //temporarily convert to RGB + representation.r = red_val; //update red value + this.color = converter(space)(representation) //convert back to original space } } @@ -377,13 +377,18 @@ 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; + //this.color.coords[1] = green_val; + this.color.g = green_val; }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] = green_val; + //this.color = to(representation, space); + const space = this.color.mode; + const representation = converter('rgb')(this.color) //temporarily convert to RGB + representation.g = green_val; //update green value + this.color = converter(space)(representation) //convert back to original space } } @@ -426,13 +431,18 @@ 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; + //this.color.coords[2] = blue_val; + this.color.b = blue_val; }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] = blue_val; + //this.color = to(representation, space); + const space = this.color.mode; + const representation = converter('rgb')(this.color) //temporarily convert to RGB + representation.b = blue_val; //update red value + this.color = converter(space)(representation) //convert back to original space } } @@ -479,28 +489,37 @@ class Color { _getRed() { if(this.mode === constants.RGB){ - return this.color.coords[0] * this.maxes[constants.RGB][0]; + //return this.color.coords[0] * this.maxes[constants.RGB][0]; + return this.color.r * this.maxes[constants.RGB][0]; }else{ // Will do an imprecise conversion to 'srgb', not recommended - return to(this.color, 'srgb').coords[0] * this.maxes[constants.RGB][0]; + //return to(this.color, 'srgb').coords[0] * this.maxes[constants.RGB][0]; + const rgbColor = converter('rgb')(this.color) //Convert to RGB + return rgbColor.r * this.maxes[constants.RGB][0]; //Access red channel and scale } } _getGreen() { if(this.mode === constants.RGB){ - return this.color.coords[1] * this.maxes[constants.RGB][1]; + //return this.color.coords[1] * this.maxes[constants.RGB][1]; + return this.color.g * this.maxes[constants.RGB][1]; }else{ // Will do an imprecise conversion to 'srgb', not recommended - return to(this.color, 'srgb').coords[1] * this.maxes[constants.RGB][1]; + //return to(this.color, 'srgb').coords[1] * this.maxes[constants.RGB][1]; + const rgbColor = converter('rgb')(this.color) //Convert to RGB + return rgbColor.g * this.maxes[constants.RGB][1]; //Access red channel and scale } } _getBlue() { if(this.mode === constants.RGB){ - return this.color.coords[2] * this.maxes[constants.RGB][2]; + //return this.color.coords[2] * this.maxes[constants.RGB][2]; + return this.color.b * this.maxes[constants.RGB][2]; }else{ // Will do an imprecise conversion to 'srgb', not recommended - return to(this.color, 'srgb').coords[2] * this.maxes[constants.RGB][2]; + //return to(this.color, 'srgb').coords[2] * this.maxes[constants.RGB][2]; + const rgbColor = converter('rgb')(this.color) //Convert to RGB + return rgbColor.b * this.maxes[constants.RGB][2]; //Access red channel and scale } } @@ -524,10 +543,13 @@ class Color { */ _getHue() { if(this.mode === constants.HSB || this.mode === constants.HSL){ - return this.color.coords[0] / 360 * this.maxes[this.mode][0]; + //return this.color.coords[0] / 360 * this.maxes[this.mode][0]; + return this.color.h / 360 * this.maxes[this.mode][0]; }else{ // Will do an imprecise conversion to 'HSL', not recommended - return to(this.color, 'hsl').coords[0] / 360 * this.maxes[this.mode][0]; + //return to(this.color, 'hsl').coords[0] / 360 * this.maxes[this.mode][0]; + const hslColor = converter('hsl')(this.color) //Convert to HSL + return hslColor.h / 360 * this.maxes[this.mode][0]; //Access Hue channel and scale } } @@ -538,13 +560,17 @@ class Color { */ _getSaturation() { if(this.mode === constants.HSB || this.mode === constants.HSL){ - return this.color.coords[1] / 100 * this.maxes[this.mode][1]; + //return this.color.coords[1] / 100 * this.maxes[this.mode][1]; + return this.color.s * this.maxes[this.mode][1]; }else{ // Will do an imprecise conversion to 'HSL', not recommended - return to(this.color, 'hsl').coords[1] / 100 * this.maxes[this.mode][1]; + //return to(this.color, 'hsl').coords[1] / 100 * this.maxes[this.mode][1]; + const hslColor = converter('hsl')(this.color) //Convert to HSL + return hslColor.s * this.maxes[this.mode][1]; //Access Hue channel and scale } } + //HSB/ HSV - Brightness channel _getBrightness() { if(this.mode === constants.HSB){ return this.color.coords[2] / 100 * this.maxes[this.mode][2]; @@ -554,6 +580,7 @@ class Color { } } + //HSL - Lightness channel _getLightness() { if(this.mode === constants.HSL){ return this.color.coords[2] / 100 * this.maxes[this.mode][2]; From a5600b423fd8179a80ef4c47116c72e287bd25dd Mon Sep 17 00:00:00 2001 From: Diana Galindo Date: Sun, 10 Nov 2024 17:10:28 +0000 Subject: [PATCH 05/14] testing culori.js --- preview/index.html | 18 +++++++++++------- src/color/p5.Color.js | 40 +++++++++++++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/preview/index.html b/preview/index.html index fae57c6dae..3f217b48f5 100644 --- a/preview/index.html +++ b/preview/index.html @@ -23,18 +23,22 @@ p.setup = function () { p.createCanvas(600, 600); p.background(200); + p.colorMode('RGB'); }; p.draw = function () { - - p.colorMode('HSB'); // Create a p5.Color object using RGB values - let c = p.color(255, 128, 128); - p.fill(c); - p.circle(200, 200, 100); - - c.setRed(64); + let c = p.color(175, 100, 220); + p.noStroke(); p.fill(c); + p.rect(100, 150, 90, 150); + + let redValue = red(c); + //c.setRed(64) + //c.setGreen(255); + //c.setBlue(255); + //c.setAlpha(128); + p.fill(0, 0, redValue); p.rect(150, 300, 200, 100); //p.fill('hsb(160, 100%, 50%)'); //hsb seems to be having issues to render p.textSize(50); diff --git a/src/color/p5.Color.js b/src/color/p5.Color.js index 05849b83e5..6aa14ed7bb 100644 --- a/src/color/p5.Color.js +++ b/src/color/p5.Color.js @@ -485,6 +485,7 @@ class Color { **/ setAlpha(new_alpha) { this.color.alpha = new_alpha / this.maxes[this.mode][3]; + console.log("Updated alpha:", this.color.alpha); } _getRed() { @@ -573,26 +574,51 @@ class Color { //HSB/ HSV - Brightness channel _getBrightness() { if(this.mode === constants.HSB){ - return this.color.coords[2] / 100 * this.maxes[this.mode][2]; + //return this.color.coords[2] / 100 * this.maxes[this.mode][2]; + return this.color.v * 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]; + //return to(this.color, 'hsb').coords[2] / 100 * this.maxes[this.mode][2]; + const hsbColor = converter('hsv')(this.color) //Convert to HSV + return hsbColor.v * this.maxes[this.mode][2]; //Access Brightness channel and scale } } //HSL - Lightness channel _getLightness() { if(this.mode === constants.HSL){ - return this.color.coords[2] / 100 * this.maxes[this.mode][2]; + //return this.color.coords[2] / 100 * this.maxes[this.mode][2]; + return this.color.l * this.maxes[this.mode][2]; }else{ - // Will do an imprecise conversion to 'HSB', not recommended - return to(this.color, 'hsl').coords[2] / 100 * this.maxes[this.mode][2]; + // Will do an imprecise conversion to 'HSL', not recommended + //return to(this.color, 'hsl').coords[2] / 100 * this.maxes[this.mode][2]; + const hslColor = converter('hsl')(this.color) //Convert to HSL + return hslColor.l * this.maxes[this.mode][2]; //Access Lightness channel and scale } } + // get _array() { + // return [...this.color.coords, this.color.alpha]; + // } + + //Since Culori.js uses plain objects with named properties, + //get_array would need to adjust to this structure. get _array() { - return [...this.color.coords, this.color.alpha]; - } + // For RGB mode, check for `r`, `g`, and `b`; for HSL, check for `h`, `s`, and `l`, etc. + const colorComponents = []; + + if (this.color.mode === 'rgb') { + colorComponents.push(this.color.r, this.color.g, this.color.b); + } else if (this.color.mode === 'hsl') { + colorComponents.push(this.color.h, this.color.s, this.color.l); + } else if (this.color.mode === 'hsv') { + colorComponents.push(this.color.h, this.color.s, this.color.v); + } + // Add alpha, if present, or default to 1 if alpha is undefined + colorComponents.push(this.color.alpha !== undefined ? this.color.alpha : 1); + + return colorComponents; +} get levels() { return this._array.map(v => v * 255); From c27c84817eb95339832b9971830bd823b3cf9fc1 Mon Sep 17 00:00:00 2001 From: Diana Galindo Date: Tue, 12 Nov 2024 15:13:07 +0000 Subject: [PATCH 06/14] testing alpha values and HSB --- preview/index.html | 27 ++++++++------- src/color/p5.Color.js | 81 +++++++++---------------------------------- 2 files changed, 31 insertions(+), 77 deletions(-) diff --git a/preview/index.html b/preview/index.html index 3f217b48f5..ee45424a92 100644 --- a/preview/index.html +++ b/preview/index.html @@ -23,23 +23,24 @@ p.setup = function () { p.createCanvas(600, 600); p.background(200); - p.colorMode('RGB'); - }; + //p.colorMode('hsl'); - p.draw = function () { - // Create a p5.Color object using RGB values - let c = p.color(175, 100, 220); + //let c1 = p.color('hsl(160, 100%, 50%)'); + //let c1 = p.color('rgb(0, 0, 255)'); + let c1 = p.color('hsb(160, 100%, 50%)'); //triggers 'invalid color string' p.noStroke(); - p.fill(c); + p.fill(c1); p.rect(100, 150, 90, 150); - let redValue = red(c); - //c.setRed(64) - //c.setGreen(255); - //c.setBlue(255); - //c.setAlpha(128); - p.fill(0, 0, redValue); - p.rect(150, 300, 200, 100); + //let c2 = p.color('hsla(160, 100%, 50%, 0.5)'); + //let c2 = p.color('rgba(0, 0, 255, 0.1)'); + let c2 = p.color('hsba(160, 100%, 50%, 0.5)'); //triggers 'invalid color string' + p.fill(c2); + p.rect(200,150,90,150); + }; + + p.draw = function () { + // Create a p5.Color object using RGB values //p.fill('hsb(160, 100%, 50%)'); //hsb seems to be having issues to render p.textSize(50); p.text('hello', 50, 80); diff --git a/src/color/p5.Color.js b/src/color/p5.Color.js index 6aa14ed7bb..a577b66070 100644 --- a/src/color/p5.Color.js +++ b/src/color/p5.Color.js @@ -75,26 +75,6 @@ const p3 = useMode(modeP3); const rgb = useMode(modeRgb); const hsv = useMode(modeHsv); -// 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); - -// ColorSpace.register(OKLab); -// ColorSpace.register(OKLCH); - -// ColorSpace.register(P3_Linear); -// ColorSpace.register(P3); - -// ColorSpace.register(A98RGB_Linear); -// ColorSpace.register(A98RGB); class Color { color; @@ -107,7 +87,7 @@ class Color { this.mode = colorMode; this.maxes = colorMaxes; - //if vals is an object + //if vals is an object or a non-array, non-null object if (typeof vals === 'object' && !Array.isArray(vals) && vals !== null){ this.color = vals; //color-compatible format console.log("Color object detected:", this.color); @@ -117,6 +97,9 @@ class Color { try{ // parse the string this.color = parse(vals[0]); + console.log("Color object detected:", this.color); + console.log("Current color mode:", this.color.mode); + console.log("Current alpha:", this.color.alpha); }catch(err){ // TODO: Invalid color string console.error('Invalid color string'); @@ -137,11 +120,12 @@ class Color { ? alpha / this.maxes[this.mode][3] : 1; + console.log("Color object detected:", vals); + console.log("Current color mode:", this.mode); + // _colorMode can be 'rgb', 'hsb', or 'hsl' // Color representation for Culori.js - - //let space = 'rgb'; -> to specify color mode - //let coords = vals; -> to access coordinates + switch(this.mode){ case 'rgb': this.color = { @@ -151,66 +135,35 @@ class Color { b: vals[2]/ this.maxes[this.mode][2], alpha: alpha }; - // space = 'rgb'; - // 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': this.color = { mode: 'hsv', // Culori uses "hsv" instead of "hsb" - h: (vals[0] / this.maxes.hsb[0]) * 360, - s: vals[1] / this.maxes.hsb[1], - v: vals[2] / this.maxes.hsb[2], + h: (vals[0] / this.maxes[0]) * 360, + s: vals[1] / this.maxes[1], + v: vals[2] / this.maxes[2], alpha: alpha }; - // space = 'hsb'; - // coords = [ - // vals[0] / this.maxes[this.mode][0] * 360, - // vals[1] / this.maxes[this.mode][1] , - // vals[2] / this.maxes[this.mode][2] - // ]; + break; case 'hsl': this.color = { mode: 'hsl', - h: (vals[0] / this.maxes.hsl[0]) * 360, - s: vals[1] / this.maxes.hsl[1], - l: vals[2] / this.maxes.hsl[2], + h: (vals[0] / this.maxes[0]) * 360, + s: vals[1] / this.maxes[1], + l: vals[2] / this.maxes[2], alpha: alpha }; - // space = 'hsl'; - // coords = [ - // vals[0] / this.maxes[this.mode][0] * 360, - // vals[1] / this.maxes[this.mode][1] , - // vals[2] / this.maxes[this.mode][2] - // ]; break; default: console.error('Invalid color mode'); }; - // Define `toSpace` as an inline function within the constructor - // this.toSpace = (targetSpace) => { - // const toTargetSpace = converter(targetSpace); - // const convertedColor = toTargetSpace(this.color); - // console.log(`Converted color to ${targetSpace} mode:`, convertedColor); - // return convertedColor; - // }; - + // // Use converter to ensure compatibility with Culori's color space conversion const convertToSpace = converter(this.mode); this.color = convertToSpace(this.color); // Convert color to specified space - console.log("Converted color object:", this.color); - - // const color = { - // space, - // coords, - // alpha - // }; - //this.color = to(color, space); + //console.log("Converted color object:", this.color); } } From d851a4e418ea1ad71655ac86a729c286d086a58b Mon Sep 17 00:00:00 2001 From: Diana Galindo Date: Wed, 13 Nov 2024 13:01:26 +0000 Subject: [PATCH 07/14] _getRed, _getGreen, _getBlue fix --- preview/index.html | 15 ++++++----- src/color/p5.Color.js | 63 ++++++++++++++++++++++++++++--------------- 2 files changed, 50 insertions(+), 28 deletions(-) diff --git a/preview/index.html b/preview/index.html index ee45424a92..5b4f2c75b7 100644 --- a/preview/index.html +++ b/preview/index.html @@ -24,19 +24,20 @@ p.createCanvas(600, 600); p.background(200); //p.colorMode('hsl'); - + //let c1 = p.color('hsl(160, 100%, 50%)'); - //let c1 = p.color('rgb(0, 0, 255)'); - let c1 = p.color('hsb(160, 100%, 50%)'); //triggers 'invalid color string' + let c = 'hsl(50, 90%, 37%)'; + //let c1 = p.color('hsb(160, 100%, 50%)'); //triggers 'invalid color string' p.noStroke(); - p.fill(c1); + p.fill(c); p.rect(100, 150, 90, 150); //let c2 = p.color('hsla(160, 100%, 50%, 0.5)'); //let c2 = p.color('rgba(0, 0, 255, 0.1)'); - let c2 = p.color('hsba(160, 100%, 50%, 0.5)'); //triggers 'invalid color string' - p.fill(c2); - p.rect(200,150,90,150); + //let c2 = p.color('hsba(160, 100%, 50%, 0.5)'); //triggers 'invalid color string' + let redValue = p.red(c); + p.fill(redValue, 0, 0); + p.rect(200, 150, 90, 150); }; p.draw = function () { diff --git a/src/color/p5.Color.js b/src/color/p5.Color.js index a577b66070..11ca88e762 100644 --- a/src/color/p5.Color.js +++ b/src/color/p5.Color.js @@ -130,18 +130,18 @@ class Color { case 'rgb': this.color = { mode: 'rgb', - r: vals[0]/ this.maxes[this.mode][0], - g: vals[1] / this.maxes[this.mode][1], - b: vals[2]/ this.maxes[this.mode][2], + r: vals[0]/ this.maxes[this.mode][0], // R /255 -> Range [0 , 1] + g: vals[1]/ this.maxes[this.mode][1], // G /255 + b: vals[2]/ this.maxes[this.mode][2], // B /255 alpha: alpha }; break; case 'hsb': this.color = { mode: 'hsv', // Culori uses "hsv" instead of "hsb" - h: (vals[0] / this.maxes[0]) * 360, - s: vals[1] / this.maxes[1], - v: vals[2] / this.maxes[2], + h: (vals[0] / this.maxes[this.mode][0]) * 360, //(H/360) * 360 -> Range [0, 360] + s: vals[1] / this.maxes[this.mode][1], //S /100 [0,1] + v: vals[2] / this.maxes[this.mode][2], //V /100 [0,1] alpha: alpha }; @@ -149,9 +149,9 @@ class Color { case 'hsl': this.color = { mode: 'hsl', - h: (vals[0] / this.maxes[0]) * 360, - s: vals[1] / this.maxes[1], - l: vals[2] / this.maxes[2], + h: (vals[0] / this.maxes[this.mode][0]) * 360, //(H/360) * 360 ->Range [0, 360] + s: vals[1] / this.maxes[this.mode][1], //S / 100 [0,1] + l: vals[2] / this.maxes[this.mode][2], //L / 100 [0,1] alpha: alpha }; break; @@ -159,7 +159,6 @@ class Color { console.error('Invalid color mode'); }; - // // Use converter to ensure compatibility with Culori's color space conversion const convertToSpace = converter(this.mode); this.color = convertToSpace(this.color); // Convert color to specified space @@ -443,8 +442,15 @@ class Color { _getRed() { if(this.mode === constants.RGB){ - //return this.color.coords[0] * this.maxes[constants.RGB][0]; + console.log("The color mode is RGB"); + //Check if the color is in RGB format; otherwise, convert it to RGB + if (typeof this.color.r === 'undefined'){ + const rgbColor = converter('rgb')(this.color) //Convert to RGB + return rgbColor.r * this.maxes[constants.RGB][0]; //Access red channel and scale + } else { + //return this.color.coords[0] * this.maxes[constants.RGB][0]; return this.color.r * this.maxes[constants.RGB][0]; + } }else{ // Will do an imprecise conversion to 'srgb', not recommended //return to(this.color, 'srgb').coords[0] * this.maxes[constants.RGB][0]; @@ -455,25 +461,40 @@ class Color { _getGreen() { if(this.mode === constants.RGB){ - //return this.color.coords[1] * this.maxes[constants.RGB][1]; - return this.color.g * this.maxes[constants.RGB][1]; + console.log("The color mode is RGB"); + //Check if the color is in RGB format; otherwise, convert it to RGB + if (typeof this.color.g === 'undefined'){ + //Convert to RGB first, if `g` (green channel) is not directly accessible + const rgbColor = converter('rgb')(this.color); + return rgbColor.g * this.maxes[constants.RGB][1]; + } else { + //if color is already in RGB, just use it directly + return this.color.g * this.maxes[constants.RGB][1]; + } }else{ - // Will do an imprecise conversion to 'srgb', not recommended - //return to(this.color, 'srgb').coords[1] * this.maxes[constants.RGB][1]; + console.log("The color mode is something else"); const rgbColor = converter('rgb')(this.color) //Convert to RGB - return rgbColor.g * this.maxes[constants.RGB][1]; //Access red channel and scale + return rgbColor.g * this.maxes[constants.RGB][1]; //Access green channel and scale } } _getBlue() { if(this.mode === constants.RGB){ - //return this.color.coords[2] * this.maxes[constants.RGB][2]; - return this.color.b * this.maxes[constants.RGB][2]; + console.log("The color mode is RGB"); + // Check if the color is in RGB format; otherwise, convert it to RGB + if (typeof this.color.b === 'undefined') { + // Convert to RGB first, if `b` (blue channel) is not directly accessible + const rgbColor = converter('rgb')(this.color); // Convert to RGB + return rgbColor.b * this.maxes[constants.RGB][2]; + } else { + // If color is already in RGB, just use it directly + return this.color.b * this.maxes[constants.RGB][2]; + } }else{ - // Will do an imprecise conversion to 'srgb', not recommended - //return to(this.color, 'srgb').coords[2] * this.maxes[constants.RGB][2]; + console.log("The color mode is something else"); const rgbColor = converter('rgb')(this.color) //Convert to RGB - return rgbColor.b * this.maxes[constants.RGB][2]; //Access red channel and scale + return rgbColor.b * this.maxes[constants.RGB][2]; //Access blue channel and scale + } } From e3d17a0cb02124d25a016478b6b080fb39289a63 Mon Sep 17 00:00:00 2001 From: Diana Galindo Date: Thu, 14 Nov 2024 10:41:59 +0000 Subject: [PATCH 08/14] debugging HSB/HSV color space - ongoing --- preview/index.html | 10 +- src/color/p5.Color.js | 253 +++++++++++++++++++++++------------------- 2 files changed, 141 insertions(+), 122 deletions(-) diff --git a/preview/index.html b/preview/index.html index 5b4f2c75b7..024a863561 100644 --- a/preview/index.html +++ b/preview/index.html @@ -23,11 +23,11 @@ p.setup = function () { p.createCanvas(600, 600); p.background(200); - //p.colorMode('hsl'); + //p.colorMode('hsb'); //let c1 = p.color('hsl(160, 100%, 50%)'); - let c = 'hsl(50, 90%, 37%)'; - //let c1 = p.color('hsb(160, 100%, 50%)'); //triggers 'invalid color string' + //let c = [250, 100, 200]; + let c = 'hsb(160,100%,50%)'; //triggers 'invalid color string' p.noStroke(); p.fill(c); p.rect(100, 150, 90, 150); @@ -35,8 +35,8 @@ //let c2 = p.color('hsla(160, 100%, 50%, 0.5)'); //let c2 = p.color('rgba(0, 0, 255, 0.1)'); //let c2 = p.color('hsba(160, 100%, 50%, 0.5)'); //triggers 'invalid color string' - let redValue = p.red(c); - p.fill(redValue, 0, 0); + //let redValue = p.red(c); + //p.fill(redValue, 0, 0); p.rect(200, 150, 90, 150); }; diff --git a/src/color/p5.Color.js b/src/color/p5.Color.js index 11ca88e762..e9e26c7d33 100644 --- a/src/color/p5.Color.js +++ b/src/color/p5.Color.js @@ -7,7 +7,7 @@ * @requires color_conversion */ -import * as constants from '../core/constants'; +import * as constants from "../core/constants"; // import { // ColorSpace, // to, @@ -37,8 +37,7 @@ import * as constants from '../core/constants'; // A98RGB // } from 'colorjs.io/fn'; - -//for CSS string parsing +//for CSS string parsing //import 'culori/css'; //importing culori/fn to optimize bundle size and @@ -54,17 +53,18 @@ import { modeOklab, modeOklch, modeP3, - modeRgb -} from 'culori/fn'; + modeRgb, +} from "culori/fn"; import { - converter, + converter, parse, formatHex, formatHex8, formatRgb, formatHsl, - formatCss} from 'culori'; + formatCss, +} from "culori"; //Registering color spaces with useMode() const hsl = useMode(modeHsl); @@ -75,95 +75,115 @@ const p3 = useMode(modeP3); const rgb = useMode(modeRgb); const hsv = useMode(modeHsv); - class Color { color; maxes; mode; - constructor(vals, colorMode='rgb', colorMaxes={rgb: [255, 255, 255, 255]}) { - + constructor( + vals, + colorMode = "rgb", + colorMaxes = { rgb: [255, 255, 255, 255] } + ) { //storing default rgb color mode and maxes this.mode = colorMode; this.maxes = colorMaxes; //if vals is an object or a non-array, non-null object - if (typeof vals === 'object' && !Array.isArray(vals) && vals !== null){ + if (typeof vals === "object" && !Array.isArray(vals) && vals !== null) { this.color = vals; //color-compatible format console.log("Color object detected:", this.color); console.log("Current color mode:", this.color.mode); - - } else if( typeof vals[0] === 'string') { - try{ + } else if (typeof vals[0] === "string") { + try { // parse the string - this.color = parse(vals[0]); + //this.color = parse(vals[0]); + let colorString = vals[0].trim(); + console.log("Original color string:", colorString); // Debugging + // Preprocess string to replace 'hsb' or 'hsba' with 'hsv' or 'hsva' for Culori compatibility + if (colorString.toLowerCase().startsWith("hsba(")) { + colorString = colorString.replace(/hsba/i, "hsva"); + } else if (colorString.toLowerCase().startsWith("hsb(")) { + colorString = colorString.replace(/hsb/i, "hsv"); + } + + console.log("Modified color string for parsing:", colorString); // Debugging + + // Parse the modified string + this.color = parse(colorString); console.log("Color object detected:", this.color); console.log("Current color mode:", this.color.mode); console.log("Current alpha:", this.color.alpha); - }catch(err){ + } catch (err) { // TODO: Invalid color string - console.error('Invalid color string'); + console.error("Invalid color string format:", vals[0], "\nError:", err); } - - }else{ + } else { let alpha; - if(vals.length === 4){ - alpha = vals[vals.length-1]; - }else if (vals.length === 2){ + 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){ + } else if (vals.length === 1) { vals = [vals[0], vals[0], vals[0]]; } - alpha = alpha !== undefined - ? alpha / this.maxes[this.mode][3] - : 1; + alpha = alpha !== undefined ? alpha / this.maxes[this.mode][3] : 1; console.log("Color object detected:", vals); console.log("Current color mode:", this.mode); - + // _colorMode can be 'rgb', 'hsb', or 'hsl' // Color representation for Culori.js - - switch(this.mode){ - case 'rgb': + + switch (this.mode) { + case "rgb": this.color = { - mode: 'rgb', - r: vals[0]/ this.maxes[this.mode][0], // R /255 -> Range [0 , 1] - g: vals[1]/ this.maxes[this.mode][1], // G /255 - b: vals[2]/ this.maxes[this.mode][2], // B /255 - alpha: alpha + mode: "rgb", + r: vals[0] / this.maxes[this.mode][0], // R /255 -> Range [0 , 1] + g: vals[1] / this.maxes[this.mode][1], // G /255 + b: vals[2] / this.maxes[this.mode][2], // B /255 + alpha: alpha, }; break; - case 'hsb': + case "hsb": this.color = { - mode: 'hsv', // Culori uses "hsv" instead of "hsb" - h: (vals[0] / this.maxes[this.mode][0]) * 360, //(H/360) * 360 -> Range [0, 360] - s: vals[1] / this.maxes[this.mode][1], //S /100 [0,1] - v: vals[2] / this.maxes[this.mode][2], //V /100 [0,1] - alpha: alpha + mode: "hsv", // Culori uses "hsv" instead of "hsb" + h: (vals[0] / this.maxes[this.mode][0]) * 360, //(H/360) * 360 -> Range [0, 360] + s: vals[1] / this.maxes[this.mode][1], //S /100 [0,1] + v: vals[2] / this.maxes[this.mode][2], //V /100 [0,1] + alpha: alpha, }; break; - case 'hsl': + case "hsl": this.color = { - mode: 'hsl', - h: (vals[0] / this.maxes[this.mode][0]) * 360, //(H/360) * 360 ->Range [0, 360] - s: vals[1] / this.maxes[this.mode][1], //S / 100 [0,1] - l: vals[2] / this.maxes[this.mode][2], //L / 100 [0,1] - alpha: alpha + mode: "hsl", + h: (vals[0] / this.maxes[this.mode][0]) * 360, //(H/360) * 360 ->Range [0, 360] + s: vals[1] / this.maxes[this.mode][1], //S / 100 [0,1] + l: vals[2] / this.maxes[this.mode][2], //L / 100 [0,1] + alpha: alpha, }; break; default: - console.error('Invalid color mode'); - }; - + console.error("Invalid color mode"); + } + // // Use converter to ensure compatibility with Culori's color space conversion - const convertToSpace = converter(this.mode); + //const convertToSpace = converter(this.mode); + //this.color = convertToSpace(this.color); // Convert color to specified space + + // Convert 'hsb' to 'hsv' and 'hsba' to 'hsva' for compatibility with Culori + const convertToSpace = converter( + this.mode === "hsb" || this.mode === "hsba" + ? this.mode === "hsb" + ? "hsv" + : "hsva" + : this.mode + ); this.color = convertToSpace(this.color); // Convert color to specified space //console.log("Converted color object:", this.color); - } } @@ -214,22 +234,22 @@ class Color { // format // }); // } - + //Culori.js doesn't have a single serialize function - //it rather has the following methods to serialize + //it rather has the following methods to serialize //colours to strings in various formats toString(format) { switch (format) { - case 'hex': + case "hex": return formatHex(this.color); - case 'hex8': + case "hex8": return formatHex8(this.color); - case 'rgb': + case "rgb": return formatRgb(this.color); - case 'hsl': + case "hsl": return formatHsl(this.color); - case 'css': - return formatCss(this.color); //not sure of the use for CSS here + case "css": + return formatCss(this.color); //not sure of the use for CSS here default: // Fallback to a default format, like RGB return formatRgb(this.color); @@ -274,19 +294,19 @@ class Color { */ setRed(new_red) { const red_val = new_red / this.maxes[constants.RGB][0]; //normalize red value - if(this.mode === constants.RGB){ + if (this.mode === constants.RGB) { //this.color.coords[0] = red_val; this.color.r = red_val; - }else{ + } else { // Handling Non-RGB Color Modes //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.mode; - const representation = converter('rgb')(this.color) //temporarily convert to RGB + const representation = converter("rgb")(this.color); //temporarily convert to RGB representation.r = red_val; //update red value - this.color = converter(space)(representation) //convert back to original space + this.color = converter(space)(representation); //convert back to original space } } @@ -328,19 +348,19 @@ class Color { **/ setGreen(new_green) { const green_val = new_green / this.maxes[constants.RGB][1]; - if(this.mode === constants.RGB){ + if (this.mode === constants.RGB) { //this.color.coords[1] = green_val; this.color.g = green_val; - }else{ + } 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.mode; - const representation = converter('rgb')(this.color) //temporarily convert to RGB + const representation = converter("rgb")(this.color); //temporarily convert to RGB representation.g = green_val; //update green value - this.color = converter(space)(representation) //convert back to original space + this.color = converter(space)(representation); //convert back to original space } } @@ -382,19 +402,19 @@ class Color { **/ setBlue(new_blue) { const blue_val = new_blue / this.maxes[constants.RGB][2]; - if(this.mode === constants.RGB){ + if (this.mode === constants.RGB) { //this.color.coords[2] = blue_val; this.color.b = blue_val; - }else{ + } 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.mode; - const representation = converter('rgb')(this.color) //temporarily convert to RGB + const representation = converter("rgb")(this.color); //temporarily convert to RGB representation.b = blue_val; //update red value - this.color = converter(space)(representation) //convert back to original space + this.color = converter(space)(representation); //convert back to original space } } @@ -441,60 +461,59 @@ class Color { } _getRed() { - if(this.mode === constants.RGB){ + if (this.mode === constants.RGB) { console.log("The color mode is RGB"); //Check if the color is in RGB format; otherwise, convert it to RGB - if (typeof this.color.r === 'undefined'){ - const rgbColor = converter('rgb')(this.color) //Convert to RGB + if (typeof this.color.r === "undefined") { + const rgbColor = converter("rgb")(this.color); //Convert to RGB return rgbColor.r * this.maxes[constants.RGB][0]; //Access red channel and scale } else { //return this.color.coords[0] * this.maxes[constants.RGB][0]; - return this.color.r * this.maxes[constants.RGB][0]; + return this.color.r * this.maxes[constants.RGB][0]; } - }else{ + } else { // Will do an imprecise conversion to 'srgb', not recommended //return to(this.color, 'srgb').coords[0] * this.maxes[constants.RGB][0]; - const rgbColor = converter('rgb')(this.color) //Convert to RGB + const rgbColor = converter("rgb")(this.color); //Convert to RGB return rgbColor.r * this.maxes[constants.RGB][0]; //Access red channel and scale } } _getGreen() { - if(this.mode === constants.RGB){ + if (this.mode === constants.RGB) { console.log("The color mode is RGB"); //Check if the color is in RGB format; otherwise, convert it to RGB - if (typeof this.color.g === 'undefined'){ + if (typeof this.color.g === "undefined") { //Convert to RGB first, if `g` (green channel) is not directly accessible - const rgbColor = converter('rgb')(this.color); + const rgbColor = converter("rgb")(this.color); return rgbColor.g * this.maxes[constants.RGB][1]; } else { //if color is already in RGB, just use it directly return this.color.g * this.maxes[constants.RGB][1]; } - }else{ + } else { console.log("The color mode is something else"); - const rgbColor = converter('rgb')(this.color) //Convert to RGB + const rgbColor = converter("rgb")(this.color); //Convert to RGB return rgbColor.g * this.maxes[constants.RGB][1]; //Access green channel and scale } } _getBlue() { - if(this.mode === constants.RGB){ + if (this.mode === constants.RGB) { console.log("The color mode is RGB"); // Check if the color is in RGB format; otherwise, convert it to RGB - if (typeof this.color.b === 'undefined') { + if (typeof this.color.b === "undefined") { // Convert to RGB first, if `b` (blue channel) is not directly accessible - const rgbColor = converter('rgb')(this.color); // Convert to RGB + const rgbColor = converter("rgb")(this.color); // Convert to RGB return rgbColor.b * this.maxes[constants.RGB][2]; - } else { + } else { // If color is already in RGB, just use it directly return this.color.b * this.maxes[constants.RGB][2]; - } - }else{ + } + } else { console.log("The color mode is something else"); - const rgbColor = converter('rgb')(this.color) //Convert to RGB + const rgbColor = converter("rgb")(this.color); //Convert to RGB return rgbColor.b * this.maxes[constants.RGB][2]; //Access blue channel and scale - } } @@ -517,14 +536,14 @@ class Color { * otherwise. */ _getHue() { - if(this.mode === constants.HSB || this.mode === constants.HSL){ + if (this.mode === constants.HSB || this.mode === constants.HSL) { //return this.color.coords[0] / 360 * this.maxes[this.mode][0]; - return this.color.h / 360 * this.maxes[this.mode][0]; - }else{ + return (this.color.h / 360) * this.maxes[this.mode][0]; + } else { // Will do an imprecise conversion to 'HSL', not recommended //return to(this.color, 'hsl').coords[0] / 360 * this.maxes[this.mode][0]; - const hslColor = converter('hsl')(this.color) //Convert to HSL - return hslColor.h / 360 * this.maxes[this.mode][0]; //Access Hue channel and scale + const hslColor = converter("hsl")(this.color); //Convert to HSL + return (hslColor.h / 360) * this.maxes[this.mode][0]; //Access Hue channel and scale } } @@ -534,39 +553,39 @@ class Color { * to the HSL saturation otherwise. */ _getSaturation() { - if(this.mode === constants.HSB || this.mode === constants.HSL){ + if (this.mode === constants.HSB || this.mode === constants.HSL) { //return this.color.coords[1] / 100 * this.maxes[this.mode][1]; return this.color.s * this.maxes[this.mode][1]; - }else{ + } else { // Will do an imprecise conversion to 'HSL', not recommended //return to(this.color, 'hsl').coords[1] / 100 * this.maxes[this.mode][1]; - const hslColor = converter('hsl')(this.color) //Convert to HSL + const hslColor = converter("hsl")(this.color); //Convert to HSL return hslColor.s * this.maxes[this.mode][1]; //Access Hue channel and scale } } //HSB/ HSV - Brightness channel _getBrightness() { - if(this.mode === constants.HSB){ + if (this.mode === constants.HSB) { //return this.color.coords[2] / 100 * this.maxes[this.mode][2]; return this.color.v * this.maxes[this.mode][2]; - }else{ + } else { // Will do an imprecise conversion to 'HSB', not recommended //return to(this.color, 'hsb').coords[2] / 100 * this.maxes[this.mode][2]; - const hsbColor = converter('hsv')(this.color) //Convert to HSV + const hsbColor = converter("hsv")(this.color); //Convert to HSV return hsbColor.v * this.maxes[this.mode][2]; //Access Brightness channel and scale } } //HSL - Lightness channel _getLightness() { - if(this.mode === constants.HSL){ + if (this.mode === constants.HSL) { //return this.color.coords[2] / 100 * this.maxes[this.mode][2]; return this.color.l * this.maxes[this.mode][2]; - }else{ + } else { // Will do an imprecise conversion to 'HSL', not recommended //return to(this.color, 'hsl').coords[2] / 100 * this.maxes[this.mode][2]; - const hslColor = converter('hsl')(this.color) //Convert to HSL + const hslColor = converter("hsl")(this.color); //Convert to HSL return hslColor.l * this.maxes[this.mode][2]; //Access Lightness channel and scale } } @@ -575,31 +594,31 @@ class Color { // return [...this.color.coords, this.color.alpha]; // } - //Since Culori.js uses plain objects with named properties, + //Since Culori.js uses plain objects with named properties, //get_array would need to adjust to this structure. get _array() { // For RGB mode, check for `r`, `g`, and `b`; for HSL, check for `h`, `s`, and `l`, etc. const colorComponents = []; - if (this.color.mode === 'rgb') { - colorComponents.push(this.color.r, this.color.g, this.color.b); - } else if (this.color.mode === 'hsl') { - colorComponents.push(this.color.h, this.color.s, this.color.l); - } else if (this.color.mode === 'hsv') { - colorComponents.push(this.color.h, this.color.s, this.color.v); + if (this.color.mode === "rgb") { + colorComponents.push(this.color.r, this.color.g, this.color.b); + } else if (this.color.mode === "hsl") { + colorComponents.push(this.color.h, this.color.s, this.color.l); + } else if (this.color.mode === "hsv") { + colorComponents.push(this.color.h, this.color.s, this.color.v); } // Add alpha, if present, or default to 1 if alpha is undefined colorComponents.push(this.color.alpha !== undefined ? this.color.alpha : 1); return colorComponents; -} + } get levels() { - return this._array.map(v => v * 255); + return this._array.map((v) => v * 255); } } -function color(p5, fn){ +function color(p5, fn) { /** * A class to describe a color. * @@ -631,8 +650,8 @@ function color(p5, fn){ } export default color; -export { Color } +export { Color }; -if(typeof p5 !== 'undefined'){ +if (typeof p5 !== "undefined") { color(p5, p5.prototype); } From 09571ec2c942e7c81fc95d63026a41b30fa4293b Mon Sep 17 00:00:00 2001 From: Diana Galindo Date: Thu, 14 Nov 2024 17:34:36 +0000 Subject: [PATCH 09/14] lerpColor implementation with culori.js --- preview/index.html | 120 ++++++++++++++++++++-------------- src/color/creating_reading.js | 113 ++++++++++++++++++++------------ src/color/p5.Color.js | 14 ++-- 3 files changed, 152 insertions(+), 95 deletions(-) diff --git a/preview/index.html b/preview/index.html index 024a863561..01397ab73d 100644 --- a/preview/index.html +++ b/preview/index.html @@ -1,55 +1,79 @@ + + P5 test + + + - - P5 test - - - - - - - - - - + // Draw the left-center rectangle. + p.fill(interA); + p.rect(30, 20, 20, 60); + + // Draw the right-center rectangle. + p.fill(interB); + p.rect(50, 20, 20, 60); + + // Draw the right rectangle. + p.fill(to); + p.rect(70, 20, 20, 60); + + //let c1 = p.color('hsl(160, 100%, 50%)'); + //let c = [250, 100, 200]; + //let c = 'rgb(170, 128, 128)'; //triggers 'invalid color string' + //p.noStroke(); + //p.fill(c); + //p.rect(100, 150, 90, 150); + + //let c2 = p.color('hsla(160, 100%, 50%, 0.5)'); + //let c2 = p.color('rgba(0, 0, 255, 0.1)'); + //let c2 = p.color('hsba(160, 100%, 50%, 0.5)'); //triggers 'invalid color string' + //let redValue = p.red(c); + //let hueValue = p.hue(c); + //p.fill(hueValue, 100, 90); + // p.rect(200, 150, 90, 150); + }; + + p.draw = function () { + // Create a p5.Color object using RGB values + //p.fill('hsb(160, 100%, 50%)'); //hsb seems to be having issues to render + p.textSize(50); + p.text("hello", 200, 80); + }; + }; - \ No newline at end of file + new p5(sketch); + + + diff --git a/src/color/creating_reading.js b/src/color/creating_reading.js index cda1d9bfcc..34265d7372 100644 --- a/src/color/creating_reading.js +++ b/src/color/creating_reading.js @@ -6,10 +6,11 @@ * @requires constants */ -import './p5.Color'; -import { range } from 'colorjs.io/fn'; +import "./p5.Color"; +import { range } from "colorjs.io/fn"; +import { interpolate, parse, converter } from "culori"; -function creatingReading(p5, fn){ +function creatingReading(p5, fn) { /** * Gets the alpha (transparency) value of a color. * @@ -106,8 +107,8 @@ function creatingReading(p5, fn){ * * */ - fn.alpha = function(c) { - p5._validateParameters('alpha', arguments); + fn.alpha = function (c) { + p5._validateParameters("alpha", arguments); return this.color(c)._getAlpha(); }; @@ -242,8 +243,8 @@ function creatingReading(p5, fn){ * * */ - fn.blue = function(c) { - p5._validateParameters('blue', arguments); + fn.blue = function (c) { + p5._validateParameters("blue", arguments); return this.color(c)._getBlue(); }; @@ -387,8 +388,8 @@ function creatingReading(p5, fn){ * * */ - fn.brightness = function(c) { - p5._validateParameters('brightness', arguments); + fn.brightness = function (c) { + p5._validateParameters("brightness", arguments); return this.color(c)._getBrightness(); }; @@ -676,8 +677,8 @@ function creatingReading(p5, fn){ * @param {p5.Color} color * @return {p5.Color} */ - fn.color = function(...args) { - p5._validateParameters('color', args); + 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. } @@ -817,8 +818,8 @@ function creatingReading(p5, fn){ * * */ - fn.green = function(c) { - p5._validateParameters('green', arguments); + fn.green = function (c) { + p5._validateParameters("green", arguments); return this.color(c)._getGreen(); }; @@ -938,8 +939,8 @@ function creatingReading(p5, fn){ * * */ - fn.hue = function(c) { - p5._validateParameters('hue', arguments); + fn.hue = function (c) { + p5._validateParameters("hue", arguments); return this.color(c)._getHue(); }; @@ -1002,31 +1003,59 @@ function creatingReading(p5, fn){ * * */ - fn.lerpColor = function(c1, c2, amt) { - p5._validateParameters('lerpColor', arguments); + + // 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; - } + // // 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); + // }; + + fn.lerpColor = function (c1, c2, amt) { + p5._validateParameters("lerpColor", arguments); + + // Check if both colors are in the same color space + const mode1 = c1.color.mode; + console.log("ColorMode 1 is:", mode1); + const mode2 = c2.color.mode; + console.log("ColorMode 2 is:", mode2); + + let interpolator; - if (spaceIndex === -1) { - // This probably will not occur in practice - throw new Error('Cannot lerp colors. No common color space found'); + if (mode1 === mode2) { + // If they are in the same color space, interpolate directly in that space + interpolator = interpolate([c1.color, c2.color], mode1); + } else { + // If not in the same space, convert `c2` to `c1`'s color space for interpolation + const convertedC2 = converter(mode1)(c2.color); + interpolator = interpolate([c1.color, convertedC2], mode1); } - // 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); + // Interpolate the color based on amt + const lerpColor = interpolator(amt); + // Return the new p5.Color object with the interpolated color return new p5.Color(lerpColor, this._colorMode, this._colorMaxes); }; @@ -1170,8 +1199,8 @@ function creatingReading(p5, fn){ * * */ - fn.lightness = function(c) { - p5._validateParameters('lightness', arguments); + fn.lightness = function (c) { + p5._validateParameters("lightness", arguments); return this.color(c)._getLightness(); }; @@ -1306,8 +1335,8 @@ function creatingReading(p5, fn){ * * */ - fn.red = function(c) { - p5._validateParameters('red', arguments); + fn.red = function (c) { + p5._validateParameters("red", arguments); return this.color(c)._getRed(); }; @@ -1483,14 +1512,14 @@ function creatingReading(p5, fn){ * * */ - fn.saturation = function(c) { - p5._validateParameters('saturation', arguments); + fn.saturation = function (c) { + p5._validateParameters("saturation", arguments); return this.color(c)._getSaturation(); }; } export default creatingReading; -if(typeof p5 !== 'undefined'){ +if (typeof p5 !== "undefined") { creatingReading(p5, p5.prototype); } diff --git a/src/color/p5.Color.js b/src/color/p5.Color.js index e9e26c7d33..0b4401c956 100644 --- a/src/color/p5.Color.js +++ b/src/color/p5.Color.js @@ -83,7 +83,7 @@ class Color { constructor( vals, colorMode = "rgb", - colorMaxes = { rgb: [255, 255, 255, 255] } + colorMaxes = { rgb: [255, 255, 255, 255] , hsb: [360, 100, 100, 1] } ) { //storing default rgb color mode and maxes this.mode = colorMode; @@ -108,7 +108,6 @@ class Color { } console.log("Modified color string for parsing:", colorString); // Debugging - // Parse the modified string this.color = parse(colorString); console.log("Color object detected:", this.color); @@ -147,7 +146,7 @@ class Color { alpha: alpha, }; break; - case "hsb": + case "hsv": this.color = { mode: "hsv", // Culori uses "hsv" instead of "hsb" h: (vals[0] / this.maxes[this.mode][0]) * 360, //(H/360) * 360 -> Range [0, 360] @@ -537,12 +536,17 @@ class Color { */ _getHue() { if (this.mode === constants.HSB || this.mode === constants.HSL) { - //return this.color.coords[0] / 360 * this.maxes[this.mode][0]; - return (this.color.h / 360) * this.maxes[this.mode][0]; + if (typeof this.color.h === "undefined"){ + const hslColor = converter("hsl")(this.color); + return (hslColor.h / 360) * this.maxes[this.mode][0]; + } else { + return (this.color.h / 360) * this.maxes[this.mode][0]; + } } else { // Will do an imprecise conversion to 'HSL', not recommended //return to(this.color, 'hsl').coords[0] / 360 * this.maxes[this.mode][0]; const hslColor = converter("hsl")(this.color); //Convert to HSL + console.log("If color mode isn't HSB||HSL", hslColor) return (hslColor.h / 360) * this.maxes[this.mode][0]; //Access Hue channel and scale } } From c3b360f8c82ea69d47183e6bdb918696818de8e1 Mon Sep 17 00:00:00 2001 From: Diana Galindo Date: Mon, 18 Nov 2024 12:29:51 +0000 Subject: [PATCH 10/14] adding paletteLerp(), and testing --- preview/index.html | 37 ++++++++++++--------- src/color/creating_reading.js | 60 ++++++++++++++++++++++++++++++++++- 2 files changed, 81 insertions(+), 16 deletions(-) diff --git a/preview/index.html b/preview/index.html index 01397ab73d..896050f477 100644 --- a/preview/index.html +++ b/preview/index.html @@ -21,33 +21,33 @@ const sketch = function (p) { p.setup = function () { p.createCanvas(600, 600); - p.background(200); - p.colorMode('hsl'); + //p.background(200); + //p.colorMode('hsl'); //Testing interpolation - let from = p.color('hsl(305, 69%,53%)'); - let to = p.color('hsl(160, 100%, 50%)'); + //let from = p.color(50, 55, 100); + //let to = p.color('hsl(160, 100%, 50%)'); - let interA = p.lerpColor(from, to, 0.33); - let interB = p.lerpColor(from, to, 0.66); + //let interA = p.lerpColor(from, to, 0.33); + //let interB = p.lerpColor(from, to, 0.66); // Draw the left rectangle. - p.noStroke(); - p.fill(from); - p.rect(10, 20, 20, 60); + //p.noStroke(); + //p.fill(from); + //p.rect(10, 20, 20, 60); // Draw the left-center rectangle. - p.fill(interA); - p.rect(30, 20, 20, 60); + //p.fill(interA); + //p.rect(30, 20, 20, 60); // Draw the right-center rectangle. - p.fill(interB); - p.rect(50, 20, 20, 60); + //p.fill(interB); + //p.rect(50, 20, 20, 60); // Draw the right rectangle. - p.fill(to); - p.rect(70, 20, 20, 60); + //p.fill(to); + //p.rect(70, 20, 20, 60); //let c1 = p.color('hsl(160, 100%, 50%)'); //let c = [250, 100, 200]; @@ -70,6 +70,13 @@ //p.fill('hsb(160, 100%, 50%)'); //hsb seems to be having issues to render p.textSize(50); p.text("hello", 200, 80); + // The background goes from white to red to green to blue fill + p.background(p.paletteLerp([ + ['rgb(0,255,0)', 0], + ['red', 0.05], + ['green', 0.25], + ['blue', 1] + ], p.millis() / 10000 % 1)); }; }; diff --git a/src/color/creating_reading.js b/src/color/creating_reading.js index 34265d7372..dbb75b93e4 100644 --- a/src/color/creating_reading.js +++ b/src/color/creating_reading.js @@ -1003,7 +1003,7 @@ function creatingReading(p5, fn) { * * */ - + // fn.lerpColor = function(c1, c2, amt) { // p5._validateParameters('lerpColor', arguments); @@ -1059,6 +1059,64 @@ function creatingReading(p5, fn) { return new p5.Color(lerpColor, this._colorMode, this._colorMaxes); }; + /** + * Blends multiple colors to find a color between them. + * + * The `amt` parameter specifies the amount to interpolate between the color + * stops which are colors at each `amt` value "location" with `amt` values + * that are between 2 color stops interpolating between them based on its relative + * distance to both. + * + * The way that colors are interpolated depends on the current + * colorMode(). + * + * @method paletteLerp + * @param {[p5.Color, Number][]} colors_stops color stops to interpolate from + * @param {Number} amt number to use to interpolate relative to color stops + * @return {p5.Color} interpolated color. + * + * @example + *
+ * + * function setup() { + * createCanvas(400, 400); + * } + * + * function draw() { + * // The background goes from white to red to green to blue fill + * background(paletteLerp([ + * ['white', 0], + * ['red', 0.05], + * ['green', 0.25], + * ['blue', 1] + * ], millis() / 10000 % 1)); + * } + * + *
+ */ + + fn.paletteLerp = function (color_stops, amt) { + const first_color_stop = color_stops[0]; + console.log ("This is first color stop", first_color_stop); + + if (amt < first_color_stop[1]) + return this.color(first_color_stop[0]); + + for (let i = 1; i < color_stops.length; i++) { + const color_stop = color_stops[i]; + if (amt < color_stop[1]) { + const prev_color_stop = color_stops[i - 1]; + return this.lerpColor( + this.color(prev_color_stop[0]), + this.color(color_stop[0]), + (amt - prev_color_stop[1]) / (color_stop[1] - prev_color_stop[1]) + ); + } + } + + return this.color(color_stops[color_stops.length - 1][0]); + }; + /** * Gets the lightness value of a color. * From 5c651979caea8542b02139610dff914f8e979ffb Mon Sep 17 00:00:00 2001 From: Diana Galindo Date: Mon, 18 Nov 2024 16:28:44 +0000 Subject: [PATCH 11/14] implementing toString() within Culori constraints --- preview/index.html | 27 +++++++++++++++++++-------- src/color/p5.Color.js | 12 ++++++------ 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/preview/index.html b/preview/index.html index 896050f477..10d2786a9e 100644 --- a/preview/index.html +++ b/preview/index.html @@ -17,15 +17,32 @@