Published
Edited
Jan 25, 2021
2 forks
Importers
99 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
getColorSpaceMarkdown = (id) => {
return {
CIELAB: 'L\\*a\\*b\\*',
RGB: 'RGB',
Oklab: 'Oklab',
LinearRGB: 'Linear RGB',
Jzazbz: 'J<sub>z</sub>a<sub>z</sub>b<sub>z</sub>',
XYB: 'XYB'
}[id];
};
Insert cell
drawSplineGradient = (colors, opts = {}) => {
const {
space = 'CIELAB', // 'RGB', 'LinearRGB', 'CIELAB', 'Jzazbz' or 'XYB'
jitter = true, // using some fudged gaussian jittering
closed = false,
tension = 0.5,
type = 'uniform'
} = opts;
let from = (a) => a;
let to = (a) => a;
let jitterInSpace = a => a.map(n => n + randomGaussian(0, 0.5));
if (space === 'LinearRGB') {
from = rgb => rgb.map(n => sRGB.gammaToLinear(n / 255));
to = srgb => srgb.map(n => Math.round(255 * sRGB.linearToGamma(n)));
jitterInSpace = a => a.map(n => n + randomGaussian(0, 0.002));
} else if (space === 'CIELAB') {
from = rgb => LabConvert.rgb2lab(rgb);
to = lab => LabConvert.lab2rgb(lab);
jitterInSpace = lab => jitterLab(lab, 0.5);
} else if (space === 'Oklab') {
from = rgb => {
const srgb = rgb.map(n => sRGB.gammaToLinear(n / 255));
const { L, a, b } = oklab.sRGBToOklab({ r: srgb[0], g: srgb[1], b: srgb[2] });
return [ L, a, b ];
};
to = ([ L, a, b ]) => {
const rgb = oklab.oklabTosRGB({ L, a, b });
const srgb = [ rgb.r, rgb.g, rgb.b ];
return srgb.map(n => Math.round(255 * sRGB.linearToGamma(n)));
};
jitterInSpace = (lab) => jitterLab(lab, 0.005);
} else if (space === 'XYB') {
from = rgb => XYBConvert.rgb2xyb(rgb);
to = xyb => XYBConvert.xyb2rgb(xyb);
jitterInSpace = xyb => xyb.map(n => n + randomGaussian(0, 0.0005));
} else if (space === 'Jzazbz') {
const displayWhiteLuminance = 10000; // nits
from = rgb => {
const srgb = rgb.map(n => n / 255);
const xyz_abs = srgb_to_xyz(srgb).map(n => n * displayWhiteLuminance / 100);
return Jzazbz.forward(xyz_abs);
};
to = Jab => {
const xyz_abs = Jzazbz.inverse(Jab);
const srgb = xyz_to_srgb(xyz_abs.map(n => n / displayWhiteLuminance * 100));
return srgb.map(n => Math.max(0, Math.min(255, Math.round(n * 255))));
};
jitterInSpace = Jab => Jab.map(n => n + randomGaussian(0, 0.0025));
}

const points = colors.map(rgb => from(rgb));
const spline = CatmullRomSpline(points, {
closed,
tension,
type
});
return ramp(u => {
const sample = spline.getPoint(u);
let point = jitter ? jitterInSpace(sample) : sample;
return to(point);
});
};
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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