Published
Edited
May 13, 2020
Importers
1 star
Insert cell
md`# ColorBlindLib`
Insert cell
convertRGB = function (){
// Following Code is adapted from hcirn_colorblind_simulation.js available from
// https://github.com/MaPePeR/jsColorblindSimulator.
// The file needed a couple of missing declaration of varying variables and the functions in the file has been encapsulated into a single function covertRGB.
// ....
// The original code in github repository itself has been grabbed from http://web.archive.org/web/20090318054431/http://www.nofunc.com/Color_Blindness_Library
// Added 2 missing } to fix code.
// Used Lookup table for Math.pow(<>/255, gamma)
/*

This function allows you to see what colors look like to those who are color blind.

Use the fBlind[] in order to convert. For instance: fBlind['Tritanomaly'](RGB) would convert RGB[] into Tritanomaly.

*/
/*

The Color Blind Simulation function is
copyright (c) 2000-2001 by Matthew Wickline and the
Human-Computer Interaction Resource Network ( http://hcirn.com/ ).

It is used with the permission of Matthew Wickline and HCIRN,
and is freely available for non-commercial use. For commercial use, please
contact the Human-Computer Interaction Resource Network ( http://hcirn.com/ ).

*/

const rBlind = {
protan: {cpu: 0.735, cpv: 0.265, am: 1.273463, ayi: -0.073894},
deutan: {cpu: 1.14, cpv: -0.14, am: 0.968437, ayi: 0.003331},
tritan: {cpu: 0.171, cpv: -0.003, am: 0.062921, ayi: 0.292119}};

const fBlind = {
Normal: function (v) { return (v); },
Protanopia: function (v) { return (blindMK(v, 'protan')); },
Protanomaly: function (v) { return (anomylize(v, blindMK(v, 'protan'))); },
Deuteranopia: function (v) { return (blindMK(v, 'deutan')); },
Deuteranomaly: function (v) { return (anomylize(v, blindMK(v, 'deutan'))); },
Tritanopia: function (v) { return (blindMK(v, 'tritan')); },
Tritanomaly: function (v) { return (anomylize(v, blindMK(v, 'tritan'))); },
Achromatopsia: function (v) { return (monochrome(v)); },
Achromatomaly: function (v) { return (anomylize(v, monochrome(v))); }
};

const powGammaLookup = Array(256);
(function () {
for (let i = 0; i < 256; i++) {
powGammaLookup[i] = Math.pow(i / 255, 2.2);
}

})();

function blindMK(rgb,t) {
const gamma = 2.2;
const wx = 0.312713;
const wy = 0.329016;
const wz = 0.358271;

const b = rgb[2];
const g = rgb[1];
const r = rgb[0];

const cr = powGammaLookup[r];
const cg = powGammaLookup[g];
const cb = powGammaLookup[b];
// rgb -> xyz
const cx = (0.430574 * cr + 0.341550 * cg + 0.178325 * cb);
const cy = (0.222015 * cr + 0.706655 * cg + 0.071330 * cb);
const cz = (0.020183 * cr + 0.129553 * cg + 0.939180 * cb);

const sum_xyz = cx + cy + cz;
var cu = 0;
var cv = 0;

if (sum_xyz != 0) {
cu = cx / sum_xyz;
cv = cy / sum_xyz;
}

var nx = wx * cy / wy;
var nz = wz * cy / wy;
var clm;
var dy = 0;

if (cu < rBlind[t].cpu) {
clm = (rBlind[t].cpv - cv) / (rBlind[t].cpu - cu);
} else {
clm = (cv - rBlind[t].cpv) / (cu - rBlind[t].cpu);
}

var clyi = cv - cu * clm;
var du = (rBlind[t].ayi - clyi) / (clm - rBlind[t].am);
var dv = (clm * du) + clyi;

var sx = du * cy / dv;
var sy = cy;
var sz = (1 - (du + dv)) * cy / dv;
// xzy->rgb
var sr = (3.063218 * sx - 1.393325 * sy - 0.475802 * sz);
var sg = (-0.969243 * sx + 1.875966 * sy + 0.041555 * sz);
var sb = (0.067871 * sx - 0.228834 * sy + 1.069251 * sz);

var dx = nx - sx;
var dz = nz - sz;
// xzy->rgb
let dr = (3.063218 * dx - 1.393325 * dy - 0.475802 * dz);
let dg = (-0.969243 * dx + 1.875966 * dy + 0.041555 * dz);
let db = (0.067871 * dx - 0.228834 * dy + 1.069251 * dz);

var adjr = dr ? ((sr < 0 ? 0 : 1) - sr) / dr : 0;
var adjg = dg ? ((sg < 0 ? 0 : 1) - sg) / dg : 0;
var adjb = db ? ((sb < 0 ? 0 : 1) - sb) / db : 0;

var adjust = Math.max(
((adjr > 1 || adjr < 0) ? 0 : adjr),
((adjg > 1 || adjg < 0) ? 0 : adjg),
((adjb > 1 || adjb < 0) ? 0 : adjb)
);

sr = sr + (adjust * dr);
sg = sg + (adjust * dg);
sb = sb + (adjust * db);

return ([inversePow(sr),inversePow(sg),inversePow(sb)]);

}

function inversePow(v) {
return (255 * (v <= 0 ? 0 : v >= 1 ? 1 : Math.pow(v, 1 / 2.2)));
}

function anomylize(a,b) {
const v = 1.75, d = v * 1 + 1;

return ([
(v * b[0] + a[0] * 1) / d,
(v * b[1] + a[1] * 1) / d,
(v * b[2] + a[2] * 1) / d
]);

}

function monochrome(r) {
const z = Math.round(r[0] * 0.299 + r[1] * 0.587 + r[2] * 0.114);
return ([z,z,z]);
}
return fBlind;
}()
Insert cell
md`NOTE:<br\>This page uses the Color Blind Simulation function
by Matthew Wickline and the
Human-Computer Interaction Resource Network (http://hcirn.com/) copyright (c) 2000-2001.<br/>
The code is adapted from hcirn_colorblind_simulation.js available in https://github.com/MaPePeR/jsColorblindSimulator with slight modification.
The modifications are: A couple of missing declaration of varying variables and the code is encapsulated in a function.`
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more