Skip to content

Instantly share code, notes, and snippets.

@Munawwar
Created January 16, 2020 07:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Munawwar/6df560f2027f5ecb65a4281797e9ab03 to your computer and use it in GitHub Desktop.
Save Munawwar/6df560f2027f5ecb65a4281797e9ab03 to your computer and use it in GitHub Desktop.
leonardocolor.io contrast distribution
const d3 = require('d3');
const d3hsluv = require('d3-hsluv');
const { generateContrastColors } = require('./leonardo');
Object.assign(d3, d3hsluv);
function interpolateLumArray(newColors) {
const lums = [];
for (let i = 0; i < newColors.length; i += 1) {
lums.push(d3.hsluv(newColors[i]).v);
}
const startLum = Math.min(...lums);
const endLum = Math.max(...lums);
const interpolator = d3.interpolateNumber(startLum, endLum);
for (let i = 1; i < lums.length - 1; i += 1) {
lums[i] = interpolator((i) / (lums.length));
}
lums.sort((a, b) => b - a);
return lums;
}
function returnRatioCube(lum) {
const a = 1.45;
const b = 0.7375;
const c = 2.5;
const x = lum / 100;
const exp = ((x * -1 / a) + b);
const y = (exp ** 3) * c;
const r = y * 20 + 1;
if (r > 1) {
return r;
}
if (r < 1 && r >= 0) {
return 1;
}
return -1;
}
export const distributeRatios = (newColors) => {
const lums = interpolateLumArray(newColors);
return lums.map(lum => Number(returnRatioCube(lum).toFixed(2)));
};
const cache = {};
export default function generateColors({
numberOfColors = 5,
colorKeys = ['#38b2ac', '#112135'],
base = '#ffffff',
firstRatio = 3,
lastRatio = 18,
}) {
const cacheKey = [
numberOfColors,
colorKeys.join(','),
base,
firstRatio,
lastRatio,
].join('|');
if (cache[cacheKey]) {
return cache[cacheKey];
}
const uniformspace = (lastRatio - firstRatio) / numberOfColors;
const initialRatios = [];
for (let i = 0; i < numberOfColors; i += 1) {
initialRatios.push(
i === numberOfColors - 1 && i !== 0
? lastRatio
: Number((firstRatio + uniformspace * i).toFixed(2)),
);
}
const firstColors = generateContrastColors({
colorKeys,
base,
ratios: initialRatios,
colorspace: 'CAM02',
});
const distributedColors = generateContrastColors({
colorKeys,
base,
ratios: distributeRatios(firstColors),
colorspace: 'CAM02',
});
cache[cacheKey] = distributedColors;
return distributedColors;
}
@Munawwar
Copy link
Author

Credits: Code ripped off from leonardocolor.io website's source.

To generate leonardo.js used in this example do:

git clone @adobe/leonardo
cd leonardo
npm install
npm install -g rollup
rollup packages/contrast-colors/index.js --file leonardo.js --format cjs 

Copy leonardo.js to your front-end source directory and also install following modules

npm install d3 d3-cam02 d3-hsluv d3-hsv

I couldn't get direct ESM format working with React CRA/webpack.. so I took this rollup route.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment