From a79b653331a9603f2616529a19591819a71fe76c Mon Sep 17 00:00:00 2001 From: FerrinThreatt Date: Fri, 27 Jun 2025 11:37:48 -0400 Subject: [PATCH 1/2] contrast function first PR --- src/color/p5.Color.js | 64 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/color/p5.Color.js b/src/color/p5.Color.js index d258bf10e2..4aa4a6bf81 100644 --- a/src/color/p5.Color.js +++ b/src/color/p5.Color.js @@ -28,6 +28,7 @@ import { P3 } from 'colorjs.io/fn'; + import HSBSpace from './color_spaces/hsb.js'; const map = (n, start1, stop1, start2, stop2, clamp) => { @@ -41,6 +42,17 @@ const map = (n, start1, stop1, start2, stop2, clamp) => { const serializationMap = {}; +const SRGB_THRESHOLD = 0.03928; +const SRGB_DIVISOR = 12.92; +const GAMMA_OFFSET = 0.055; +const GAMMA_DIVISOR = 1.055; +const GAMMA_EXPONENT = 2.4; +const LUMINANCE_RED = 0.2126; +const LUMINANCE_GREEN = 0.7152; +const LUMINANCE_BLUE = 0.0722; +const EPSILON = 0.05; +const THRESHOLD = 4.5; + class Color { // Reference to underlying color object depending on implementation // Not meant to be used publicly unless the implementation is known for sure @@ -291,6 +303,58 @@ class Color { return colorString; } +/** + * Checks if two colors contrast ratio is WCAG 2.1 compliant and returns the ratio + * + * @param {Color} other + * @returns {{ ratio: Number, passes: boolean }} + * @example + *
+ * + * + * function setup() { + * // Define colors + * let color1 = color(255, 255, 255); + * let color2 = color(0); + * + * // Test for contrast + * let result = color1.contrast(color2) + * + * console.log(result) + * + * } + * + *
+ */ + + contrast(new_other) { + //Constants for contrast ratio cutoffs + const CONTRAST_AA_NORMAL = 4.5; + const CONTRAST_AA_LARGE = 3.0; + const CONTRAST_AAA_NORMAL = 7.0; + const CONTRAST_AAA_LARGE = 4.5; + + //helper function for luminance aka brightness + let luminance = (c) => { + //putting RGB values into array and convert colors to value between 0-1 + let rgb = [red(c), green(c), blue(c)].map(v => { + v /= 255; + return v <= SRGB_THRESHOLD + ? v / SRGB_DIVISOR + : Math.pow((v + GAMMA_OFFSET) / GAMMA_DIVISOR, GAMMA_EXPONENT); + }); + return LUMINANCE_RED * rgb[0] + LUMINANCE_GREEN * rgb[1] + LUMINANCE_BLUE * rgb[2]; + }; + + let l1 = luminance(this); + let l2 = luminance(new_other); + //Epsilon to avoid dividing by zero + let ratio = (Math.max(l1, l2) + EPSILON) / (Math.min(l1, l2) + EPSILON); + + return { ratio, pass: ratio >= THRESHOLD }; + + }; + /** * Sets the red component of a color. * From 5fe2c719f789904e9951b8808f05ba2df5b9035d Mon Sep 17 00:00:00 2001 From: FerrinThreatt Date: Fri, 27 Jun 2025 13:39:45 -0400 Subject: [PATCH 2/2] contrast function and AA/AAA constants --- src/color/p5.Color.js | 48 ++++++++----------------------------------- src/core/constants.js | 15 ++++++++++++++ 2 files changed, 23 insertions(+), 40 deletions(-) diff --git a/src/color/p5.Color.js b/src/color/p5.Color.js index 4aa4a6bf81..185a703aeb 100644 --- a/src/color/p5.Color.js +++ b/src/color/p5.Color.js @@ -8,6 +8,7 @@ import { RGB, RGBHDR, HSL, HSB, HWB, LAB, LCH, OKLAB, OKLCH } from './creating_reading'; + import { ColorSpace, to, @@ -25,10 +26,9 @@ import { OKLab, OKLCH as OKLCHSpace, - + contrast, P3 } from 'colorjs.io/fn'; - import HSBSpace from './color_spaces/hsb.js'; const map = (n, start1, stop1, start2, stop2, clamp) => { @@ -42,16 +42,8 @@ const map = (n, start1, stop1, start2, stop2, clamp) => { const serializationMap = {}; -const SRGB_THRESHOLD = 0.03928; -const SRGB_DIVISOR = 12.92; -const GAMMA_OFFSET = 0.055; -const GAMMA_DIVISOR = 1.055; -const GAMMA_EXPONENT = 2.4; -const LUMINANCE_RED = 0.2126; -const LUMINANCE_GREEN = 0.7152; -const LUMINANCE_BLUE = 0.0722; -const EPSILON = 0.05; -const THRESHOLD = 4.5; + + class Color { // Reference to underlying color object depending on implementation @@ -302,7 +294,6 @@ class Color { } return colorString; } - /** * Checks if two colors contrast ratio is WCAG 2.1 compliant and returns the ratio * @@ -326,35 +317,12 @@ class Color { * * */ - - contrast(new_other) { - //Constants for contrast ratio cutoffs - const CONTRAST_AA_NORMAL = 4.5; - const CONTRAST_AA_LARGE = 3.0; - const CONTRAST_AAA_NORMAL = 7.0; - const CONTRAST_AAA_LARGE = 4.5; - - //helper function for luminance aka brightness - let luminance = (c) => { - //putting RGB values into array and convert colors to value between 0-1 - let rgb = [red(c), green(c), blue(c)].map(v => { - v /= 255; - return v <= SRGB_THRESHOLD - ? v / SRGB_DIVISOR - : Math.pow((v + GAMMA_OFFSET) / GAMMA_DIVISOR, GAMMA_EXPONENT); - }); - return LUMINANCE_RED * rgb[0] + LUMINANCE_GREEN * rgb[1] + LUMINANCE_BLUE * rgb[2]; + contrast(new_other) { + const contrast_method = 'WCAG21'; + const ratio = contrast(this._color, new_other._color, contrast_method); + return ratio; }; - let l1 = luminance(this); - let l2 = luminance(new_other); - //Epsilon to avoid dividing by zero - let ratio = (Math.max(l1, l2) + EPSILON) / (Math.min(l1, l2) + EPSILON); - - return { ratio, pass: ratio >= THRESHOLD }; - - }; - /** * Sets the red component of a color. * diff --git a/src/core/constants.js b/src/core/constants.js index 942b48c9ad..c51bae9306 100644 --- a/src/core/constants.js +++ b/src/core/constants.js @@ -1371,3 +1371,18 @@ export const EXCLUDE = Symbol('exclude'); * @private */ export const JOIN = Symbol('join'); + +/** + * @typedef {'color-contrast-threshold-aa'} COLOR_CONTRAST_THRESHOLD_AA + * @property {COLOR_CONTRAST_THRESHOLD_AA} COLOR_CONTRAST_THRESHOLD_AA + * @final + */ +export const COLOR_CONTRAST_THRESHOLD_AA = 4.5; + + +/** + * @typedef {'color-contrast-threshold-aaa'} COLOR_CONTRAST_THRESHOLD_AAA + * @property {COLOR_CONTRAST_THRESHOLD_AAA} COLOR_CONTRAST_THRESHOLD_AAA + * @final + */ +export const COLOR_CONTRAST_THRESHOLD_AAA = 7.0;