JSFiddle - React, Tailwind, and code Playground

blendColors

by tonytlwu

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
<table>
  <thead><tr>
    <th>Result</th>
    <th>Input</th>
    <th>Output</th>
  </tr></thead>
  <tbody id="target">
  </tbody>
</table>

CSS

.pass {
  color: green;
}

.fail {
  color: red;
}

td {
  border: 1px solid #ccc;
}

JavaScript

function blendColors(colors) {
  colors = Array.isArray(colors) ? colors : [];
  var base = [0, 0, 0, 0];
  var mix;
  var added;
  while (added = colors.shift()) {
    if (typeof added[3] === 'undefined') {
      added[3] = 1;
    }
    // check if both alpha channels exist.
    if (typeof base[3] === 'number' && typeof added[3] === 'number') {
      mix = [0, 0, 0, 0];
      // alpha
      mix[3] = 1 - (1 - added[3]) * (1 - base[3]);
      // red
      mix[0] = Math.round((added[0] * added[3] / mix[3]) + (base[0] * base[3] * (1 - added[3]) / mix[3]));
      // green
      mix[1] = Math.round((added[1] * added[3] / mix[3]) + (base[1] * base[3] * (1 - added[3]) / mix[3]));
      // blue
      mix[2] = Math.round((added[2] * added[3] / mix[3]) + (base[2] * base[3] * (1 - added[3]) / mix[3]));
    } else if (added) {
      mix = added;
    } else {
      mix = base;
    }
    base = mix;
  }

  return mix;
}

var scenarios = [
  {
  	input: [
      [0, 0, 0, 0],
      [255, 255, 255, 0],
      [255, 0, 0, .5],
      [0, 255, 0, .5]
    ],
    output: [85, 170, 0, 0.75]
  },
  {
  	input: [
      [255, 255, 255, 1],
      [0, 0, 0, 0],
      [0, 0, 0, 0]
    ],
    output: [255, 255, 255, 1]
  }
];

var output = [];

for (var i = 0, l = scenarios.length; i < l; i++) {
	output.push('<tr>');
  output.push((_.isEqual(blendColors(_.cloneDeep(scenarios[i].input)), scenarios[i].output) ? '<td class="pass">Pass' : '<td class="fail">Fail') + '</td>');
  output.push('<td><pre>' + JSON.stringify(scenarios[i].input) + '</pre></td>');
  output.push('<td><pre>' + JSON.stringify(scenarios[i].output) + '</pre></td>');
  output.push('</tr>');
}

document.querySelector('#target').innerHTML = output.join('');