gka / chroma.js

JavaScript library for all kinds of color manipulations
https://gka.github.io/chroma.js/
Other
10.08k stars 543 forks source link

[NewFeaure] getDifferenceColor #247

Open Daniel4Digital opened 3 years ago

Daniel4Digital commented 3 years ago

Hi there,

Would be great to have a library where we could first check the difference between 2 colors.

Let say: ('#EDF0FC', '#B2C3F9'), that would generate a value or object where we could then pass to another function that would have the new color let say we pass the same ('#EDF0FC'), it should return the "#B2C3F9" color;

If we pass: '#1CA085' it should return '#007382'. So basically we would have the same difference applied to a new color. With that in mind, with 1 single color I can calculate many others variations automatically.

I was able to do this manually:

`chroma.distance('#ED0000', '#B20000', 'rgb'); //Only way to get the r difference chroma.distance('#00F000', '#00C300', 'rgb'); //Only way to get the g difference chroma.distance('#0000FC', '#0000F9', 'rgb'); //Only way to get the b difference

chroma.distance('#EDF0FC', '#B2C3F9', 'rgb'); // this should return imo an object { r:0, g:0, b:0 } with each difference

a = chroma('EDF0FC'); b = chroma('B2C3F9'); c = chroma('EDF0FC'); //NewColor //c = chroma('1CA085'); //NewColor Test

dr = a.get('rgb.r') - b.get('rgb.r'); dg = a.get('rgb.g') - b.get('rgb.g'); db = a.get('rgb.b') - b.get('rgb.b');

cr = c.get('rgb.r') - dr; cg = c.get('rgb.g') - dg; cb = c.get('rgb.b') - db;

//if the difference of rgb is negative it should recalculate the color correctly. //With 1CA085 the difference is -31 and that 31 should be divided by 2 (=-15.5) and sum up to g and b so we could get the correct color. chroma(cr,cg,cb);`

At the moment we have some problems:

I need to manually divide the hex color to check the distances of r, g, b. A solution for that would be to be able to use: chroma.distance('#EDF0FC', '#B2C3F9', 'rgb.r') to get the r.

Then we should have a new function to calculate the new color(newColor, object), where the object could be: { r:0, g:0, b:0 } where each of the r, g,b would have the difference and it would return the new color with the same difference. It could be a darken color or a lighten one depending on the difference.

I wasnt able to find any way with the library to do this easely.

Artoria2e5 commented 3 years ago

Won't this do?

var chroma = require("chroma-js")

function asArray(a, mode='rgb') {
  return Array.isArray(a) ? a : chroma(a)[mode]()
}

/** Per-element arithmetic */
function colorArith(a, b, f, mode='rgb') {
  const ma = asArray(a, mode), mb = asArray(b, mode)
  return ma.map((_, i) => f(ma[i], mb[i]))
}

const colorDiff = (a, b, mode='rgb') => colorArith(a, b, (a, b) => a - b, mode)
const colorSum = (a, b, mode='rgb') => colorArith(a, b, (a, b) => a + b, mode)

let d = colorDiff('#EDF0FC', '#B2C3F9')
console.log(chroma(colorSum('#B2C3F9', d)).hex())

let d2 = colorDiff('#EDF0FC', '#B2C3F9', 'lch')
console.log(chroma(colorSum('#B2C3F9', d2, 'lch'), 'lch').hex())

wrt the adjustment for negative values you mentioned... well colors just don't work like that.