Skip to content

Commit

Permalink
* added alpha functionality to bezier interpolation (n-degree compati…
Browse files Browse the repository at this point in the history
…bility)

* added tests for alpha bezier interpolation

Based on https://github.com/gka/chroma.js/pull/228/files
But adding n-degree polynomials

Signed-off-by: regorxxx <regorxxx@protonmail.com>
  • Loading branch information
regorxxx committed Nov 7, 2023
1 parent 24cbe87 commit 48a86d2
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 13 deletions.
24 changes: 16 additions & 8 deletions src/generator/bezier.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,29 @@ const bezier = function(colors) {
// linear interpolation
[lab0, lab1] = colors.map(c => c.lab());
I = function(t) {
const lab = ([0, 1, 2].map((i) => lab0[i] + (t * (lab1[i] - lab0[i]))));
return new Color(lab, 'lab');
const linearInterpolation = (x0, x1) => x0 + (t * (x1 - x0));
const lab = ([0, 1, 2].map((i) => linearInterpolation(lab0[i], lab1[i])));
const alpha = linearInterpolation(colors[0].alpha(), colors[1].alpha());
return new Color(lab, 'lab').alpha(alpha);
};
} else if (colors.length === 3) {
// quadratic bezier interpolation
[lab0, lab1, lab2] = colors.map(c => c.lab());
I = function(t) {
const lab = ([0, 1, 2].map((i) => ((1-t)*(1-t) * lab0[i]) + (2 * (1-t) * t * lab1[i]) + (t * t * lab2[i])));
return new Color(lab, 'lab');
const quadraticInterpolation = (x0, x1, x2) => ((1-t)*(1-t) * x0) + (2 * (1-t) * t * x1) + (t * t * x2)
const lab = ([0, 1, 2].map((i) => quadraticInterpolation(lab0[i], lab1[i], lab2[i])));
const alpha = quadraticInterpolation(colors[0].alpha(), colors[1].alpha(), colors[2].alpha());
return new Color(lab, 'lab').alpha( alpha );
};
} else if (colors.length === 4) {
// cubic bezier interpolation
let lab3;
[lab0, lab1, lab2, lab3] = colors.map(c => c.lab());
I = function(t) {
const lab = ([0, 1, 2].map((i) => ((1-t)*(1-t)*(1-t) * lab0[i]) + (3 * (1-t) * (1-t) * t * lab1[i]) + (3 * (1-t) * t * t * lab2[i]) + (t*t*t * lab3[i])));
return new Color(lab, 'lab');
const cubicInterpolation = (x0, x1, x2, x3) => ((1-t)*(1-t)*(1-t) * x0) + (3 * (1-t) * (1-t) * t * x1) + (3 * (1-t) * t * t * x2) + (t*t*t * x3);
const lab = ([0, 1, 2].map((i) => cubicInterpolation(lab0[i], lab1[i], lab2[i], lab3[i])));
const alpha = cubicInterpolation(colors[0].alpha(), colors[1].alpha(), colors[2].alpha(), colors[3].alpha());
return new Color(lab, 'lab').alpha(alpha);
};
} else if (colors.length >= 5) {
// general case (degree n bezier)
Expand All @@ -53,8 +59,10 @@ const bezier = function(colors) {
row = binom_row(n);
I = function (t) {
const u = 1 - t;
const lab = ([0, 1, 2].map((i) => labs.reduce((sum, el, j) => (sum + row[j] * u ** (n - j) * t ** j * el[i]), 0)))
return new Color(lab, 'lab');
const nInterpolation = (i, labs) => labs.reduce((sum, el, j) => (sum + row[j] * u ** (n - j) * t ** j * el[i]), 0);
const lab = ([0, 1, 2].map((i) => nInterpolation(i, labs)))
const alpha = nInterpolation(0, colors.map(c => [c.alpha()]));
return new Color(lab, 'lab').alpha(alpha);
};
} else {
throw new RangeError("No point in running bezier with only one color.")
Expand Down
82 changes: 77 additions & 5 deletions test/bezier.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,22 @@ vows
assert.equal(topic.f(0.5).hex(), "#777777");
},
},


"two color linear interpolation with alpha": {
topic: {
f: chroma.bezier(['white', chroma('black').alpha(0)])
},
"starts from white"(topic) {
assert.equal(topic.f(0).hex(), "#ffffff");
},
"ends in transparent black"(topic) {
assert.equal(topic.f(1).hex(), "#00000000");
},
"center is transluscent grey"(topic) {
assert.equal(topic.f(0.5).hex(), "#77777780");
},
},

"three color quadratic bezier interpolation": {
topic: {
f: chroma.bezier(["white", "red", "black"]),
Expand All @@ -36,7 +51,22 @@ vows
assert.equal(topic.f(0.5).hex(), "#c45c44");
},
},


"three color quadratic bezier interpolation with alpha": {
topic: {
f: chroma.bezier(["white", chroma("red").alpha(.5), chroma("black").alpha(0)])
},
"starts from white"(topic) {
assert.equal(topic.f(0).hex(), "#ffffff");
},
"ends in transparent black"(topic) {
assert.equal(topic.f(1).hex(), "#00000000");
},
"center is a transluscent greyish red"(topic) {
assert.equal(topic.f(0.5).hex(), "#c45c4480");
}
},

"four color cubic bezier interpolation": {
topic: {
f: chroma.bezier(["white", "yellow", "red", "black"]),
Expand All @@ -57,8 +87,29 @@ vows
assert.equal(topic.f(0.75).hex(), "#914213");
},
},

"five color diverging quadratic bezier interpolation": {

"four color cubic bezier interpolation with alpha": {
topic: {
f: chroma.bezier(["white", chroma("yellow").alpha(1/3), chroma("red").alpha(2/3), chroma("black").alpha(0)])
},
"starts from white"(topic) {
assert.equal(topic.f(0).hex(), "#ffffff");
},
"ends in transparent black"(topic) {
assert.equal(topic.f(1).hex(), "#00000000");
},
"1st quarter"(topic) {
assert.equal(topic.f(0.25).hex(), "#ffe085a7");
},
"center"(topic) {
assert.equal(topic.f(0.5).hex(), "#e6973580");
},
"3rd quarter"(topic) {
assert.equal(topic.f(0.75).hex(), "#91421358");
}
},

"five color diverging n-1-degree bezier interpolation": {
topic: {
f: chroma.bezier([
"darkred",
Expand All @@ -84,7 +135,28 @@ vows
assert.equal(topic.f(0.75).hex(), "#a7c1bd");
},
},


"five color diverging n-1-degree bezier interpolation with alpha": {
topic: {
f: chroma.bezier(["darkred", chroma("orange").alpha(.75), chroma("snow").alpha(.5), chroma("lightgreen").alpha(.25), chroma("royalblue").alpha(0)])
},
"starts from darkred"(topic) {
assert.equal(topic.f(0).hex(), "#8b0000");
},
"ends in transparent royalblue"(topic) {
assert.equal(topic.f(1).hex(), "#4169e100");
},
"center is snow"(topic) {
assert.equal(topic.f(0.5).hex(), "#dfcb9880");
},
"1st quarter"(topic) {
assert.equal(topic.f(0.25).hex(), "#dd8d49bf");
},
"3rd quarter"(topic) {
assert.equal(topic.f(0.75).hex(), "#a7c1bd40");
}
},

"using bezier in a chroma.scale": {
topic: {
f: chroma
Expand Down

0 comments on commit 48a86d2

Please sign in to comment.