12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758 |
- const jab2hex = jab => d3.jab(...jab).formatHex();
- const rgb2hex = rgb => d3.rgb(...rgb).formatHex();
- const jab2hue = jab => d3.jch(d3.jab(...jab)).h || 0;
- const rgb2hue = rgb => d3.hsl(d3.rgb(...rgb)).h || 0;
- const jab2lit = ([j]) => j / 100;
- const rgb2lit = rgb => d3.hsl(d3.rgb(...rgb)).l || 0;
- const jab2chroma = jab => d3.jch(d3.jab(...jab)).C / 100;
- const rgb2chroma = rgb => d3.jch(d3.rgb(...rgb)).C / 100;
- const buildVectorData = (vector, toHue, toLightness, toChroma, toHex) => {
- const sqMag = vectorDot(vector, vector);
- const mag = Math.sqrt(sqMag);
- const unit = vector.map(c => c / mag);
- const hue = toHue(vector);
- const lightness = toLightness(vector);
- const chroma = toChroma(vector);
- const hex = toHex(vector);
- return { vector, sqMag, mag, unit, hue, lightness, chroma, hex };
- };
- const calcImportance = (chroma, lightness, proportion) =>
- chroma // used linearly
- - Math.abs((lightness / 0.75) - 1) // reduce contribution for overly light color - probably a highlight
- + 0.5 * Math.tanh(10 * (proportion - 0.25)) // steep ramp centered around 25%
- const buildClusterData = (size, inertia, mu1, mu2, mu3, nu1, nu2, nu3, totalSize, toHue, toLightness, toChroma, toHex) => {
- const mu = buildVectorData([mu1, mu2, mu3], toHue, toLightness, toChroma, toHex);
- const nu = [nu1, nu2, nu3];
- const proportion = size / totalSize;
- const importance = calcImportance(mu.chroma, mu.lightness, proportion);
- return {
- size, inertia, mu, nu,
- proportion, importance,
- muNuAngle: rad2deg * Math.acos(vectorDot(mu.unit, nu) / vectorMag(nu)),
- };
- };
- const buildPokemonData = ([name, size, ...values]) => ({
- name,
- jab: {
- total: buildClusterData(size, ...values.slice(0, 7), size, jab2hue, jab2lit, jab2chroma, jab2hex),
- clusters: [
- buildClusterData(...values.slice(7, 15), size, jab2hue, jab2lit, jab2chroma, jab2hex),
- buildClusterData(...values.slice(15, 23), size, jab2hue, jab2lit, jab2chroma, jab2hex),
- buildClusterData(...values.slice(23, 31), size, jab2hue, jab2lit, jab2chroma, jab2hex),
- ],
- },
- rgb: {
- total: buildClusterData(size, ...values.slice(31, 38), size, rgb2hue, rgb2lit, rgb2chroma, rgb2hex),
- clusters: [
- buildClusterData(...values.slice(38, 46), size, rgb2hue, rgb2lit, rgb2chroma, rgb2hex),
- buildClusterData(...values.slice(46, 54), size, rgb2hue, rgb2lit, rgb2chroma, rgb2hex),
- buildClusterData(...values.slice(54, 62), size, rgb2hue, rgb2lit, rgb2chroma, rgb2hex),
- ],
- },
- });
- const pokemonData = databaseV2.map(row => buildPokemonData(row));
|