PageSourceSearch

https://elearning.ucse.edu.ar//lib/javascript/Educativa/Modules/Aula/Components/ColorContrast.js?v=1787049104

js ucse.edu.ar collected 2026-10-02 11:54:56 UTC 5,307 bytes, 142 lines download raw bytes

1/***********************************************************/
2/*                                                         */
3/* Plataforma e-ducativa - Argentina                       */
4/*                                                         */
5/* Copyright (c) 2026 de e-ducativa Educación Virtual S.A. */
6/*                                                         */
7/***********************************************************/
8/**
9 * A partir de una variable CSS con un color, calcula el contraste y lo establece en otra variable CSS
10 *
11 * @param {string} css_variable - El nombre de la variable CSS que contiene el color principal.
12 * @param {string} css_contrast_variable - El nombre de la variable CSS que se actualizara con el valor de contraste calculado.
13 *
14 */
15export function updateCssContrastVariable(css_variable, css_contrast_variable, algorithm = "apca") {
16    const chatMainColor = getComputedStyle(document.documentElement).getPropertyValue(css_variable).trim();
17    document.documentElement.style.setProperty(
18        css_contrast_variable,
19        contrastColor({ cssColor: chatMainColor, algorithm })
20    );
21}
22
23/**
24 * Calcula el color de contraste para el color CSS dado.
25 *
26 * Para hacer esto, se crea un elemento <div> temporal en el documento, se le establece el color de fondo
27 * con el valor pasado como argumento y se obtiene el color computado por el navegador.
28 *
29 * Se puede calcular el contraste optimo mediante dos algoritmos:
30 *  WCAG (Web Content Accessibility Guidelines)
31 *  YIQ (YIQ color space)
32 *
33 * @param {object}
34 * @prop {string} cssColor - El color CSS para el que se va a calcular el contraste.
35 * @prop {string} algorithm - El algoritmo a utilizar para calcular el contraste. Puede ser "luminance", "yiq" o "apca".
36 *
37 * @return {string} El color de contraste para el color CSS dado, que sera #000000 o #FFFFFF.
38 */
39export function contrastColor({ cssColor, algorithm = "apca" }) {
40    const temp = document.createElement("div");
41    temp.style.color = cssColor;
42    document.body.appendChild(temp);
43
44    const computedColor = getComputedStyle(temp).color;
45    document.body.removeChild(temp);
46
47    const [r, g, b] = computedColor.match(/\d+/g).map(Number).slice(0, 3);
48
49    if (algorithm === "apca") {
50        return apca(r, g, b);
51    } else if (algorithm === "yiq") {
52        return yiq(r, g, b);
53    } else if (algorithm === "luminance") {
54        return luminance(r, g, b);
55    }
56}
57
58// Luminance (WCAG 2.1)
59function luminance(r, g, b) {
60    function _luminance(rr, gg, bb) {
61        const a = [rr, gg, bb].map((v) => {
62            v /= 255;
63            return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
64        });
65        return 0.2126 * a[0] + 0.7152 * a[1] + 0.0722 * a[2];
66    }
67    const bgLuminance = _luminance(r, g, b);
68
69    const contrastWithBlack = (bgLuminance + 0.01) / 0.01;
70    const contrastWithWhite = 1.01 / (bgLuminance + 0.01);
71
72    return contrastWithBlack > contrastWithWhite ? "#000000" : "#FFFFFF";
73}
74
75function yiq(r, g, b) {
76    const yiq = (r * 299 + g * 587 + b * 114) / 1000;
77    return yiq >= 128 ? "#000000" : "#FFFFFF";
78}
79
80// APCA-W3 (version 0.0.98G-4g)
81function apca(r, g, b) {
82    // APCA-W3 constants
83    const mainTRC = 2.4;
84
85    // sRGB coefficients
86    const sRco = 0.2126729;
87    const sGco = 0.7151522;
88    const sBco = 0.0721750;
89
90    // Normalization exponents (polarity aware)
91    const normBG = 0.56;
92    const normTXT = 0.57;
93    const revBG = 0.65;
94    const revTXT = 0.62;
95
96    // Soft clamp for very dark colors
97    const blkThrs = 0.022;
98    const blkClmp = 1.414;
99
100    // Scalers and offsets
101    const scaleBoW = 1.14;
102    const loBoWoffset = 0.027;
103    const scaleWoB = 1.14;
104    const loWoBoffset = 0.027;
105    const loClip = 0.1;
106
107    // Linearize sRGB (simple gamma, as per APCA-W3)
108    function toLinear(c) {
109        return Math.pow(c / 255, mainTRC);
110    }
111
112    const R = toLinear(r);
113    const G = toLinear(g);
114    const B = toLinear(b);
115    const bgY = sRco * R + sGco * G + sBco * B;
116
117    const txtY_white = 1.0;
118    const txtY_black = 0.0;
119
120    const contrastWhite = contrastAPCA_W3(txtY_white, bgY, normBG, normTXT, revBG, revTXT, blkThrs, blkClmp, scaleBoW, loBoWoffset, scaleWoB, loWoBoffset, loCl
120ip);
121    const contrastBlack = contrastAPCA_W3(txtY_black, bgY, normBG, normTXT, revBG, revTXT, blkThrs, blkClmp, scaleBoW, loBoWoffset, scaleWoB, loWoBoffset, loClip);
122
123    return Math.abs(contrastBlack) > Math.abs(contrastWhite) ? "#000000" : "#FFFFFF";
124}
125
126// APCA-W3 contrast calculation
127function contrastAPCA_W3(txtY, bgY, normBG, normTXT, revBG, revTXT, blkThrs, blkClmp, scaleBoW, loBoWoffset, scaleWoB, loWoBoffset, loClip) {
128    // Soft clamp for very dark colors
129    txtY = txtY > blkThrs ? txtY : txtY + Math.pow(blkThrs - txtY, blkClmp);
130    bgY = bgY > blkThrs ? bgY : bgY + Math.pow(blkThrs - bgY, blkClmp);
131
132    let SAPC;
133    if (bgY > txtY) {
134        // Normal polarity: dark text on light background
135        SAPC = (Math.pow(bgY, normBG) - Math.pow(txtY, normTXT)) * scaleBoW;
136        return SAPC < loClip ? 0 : (SAPC - loBoWoffset) * 100;
137    } else {
138        // Reverse polarity: light text on dark background
139        SAPC = (Math.pow(bgY, revBG) - Math.pow(txtY, revTXT)) * scaleWoB;
140        return SAPC > -loClip ? 0 : (SAPC + loWoBoffset) * 100;
141    }
142}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.