HSV を RGB に変換するのってどうやるんだっけというのを確認しながらコードに落とし込んだ。
しかも詳細を把握してない状態で入出力についてふわっとした状態で書いた。
なので全然間違ってるかもしれん。
何がふわっとしているのかというと
hue が 0 から 359 なのか 0.0 から 0.999 なのかどうかとか、
RGB の要素だって 0 から 255 までとも限らず、
出力されるのも要素の配列なのか、HTML での色指定の文字列なのかどうか辺り。
ちょっと何言ってるかわからねーと思うし、まだちゃんとしてないが一応それっぽいやつの片鱗を味あわせるぜ。
hsvToRgb.js
const hsvToRgb = function(hue, saturation, value, prophet) {
if (prophet == null) {
prophet = {
saturationIsZero: function(saturation) {
return !(saturation > 0) && !(saturation < 0);
},
saturationRate: function(saturation) {
return saturation / this.maxSaturation;
},
maxSaturation: 255,
valueRate: function(value) {
return value / this.maxValue;
},
maxValue: 255,
hueStageAndRate: function(hue) {
const hueNormalized = hue % 360;
const hueStage = parseInt(hueNormalized / 60, 10);
const hueTmp = (parseInt(hue % 60, 10) / 60);
const hueRate = (hueStage % 2 == 0) ? hueTmp : 1 - hueTmp;
return [hueStage, hueRate];
},
newResult: function(r, g, b) {
return [r * 255, g * 255, b * 255];
}
};
}
const valueRate = prophet.valueRate(value);
if (prophet.saturationIsZero(saturation)) {
return prophet.newResult(valueRate, valueRate, valueRate);
}
const saturationRate = prophet.saturationRate(saturation);
const min = valueRate - (saturationRate * valueRate);
const [hueStage, hueRate] = prophet.hueStageAndRate(hue);
switch (hueStage) {
case 0: {
const r = valueRate;
const g = hueRate * (valueRate - min) + min;
const b = min;
return prophet.newResult(r, g, b);
} break;
case 1: {
const r = hueRate * (valueRate - min) + min;
const g = valueRate;
const b = min;
return prophet.newResult(r, g, b);
} break;
case 2: {
const r = min;
const g = valueRate;
const b = hueRate * (valueRate - min) + min;
return prophet.newResult(r, g, b);
} break;
case 3: {
const r = min;
const g = hueRate * (valueRate - min) + min;
const b = valueRate;
return prophet.newResult(r, g, b);
} break;
case 4: {
const r = hueRate * (valueRate - min) + min;
const g = min;
const b = valueRate;
return prophet.newResult(r, g, b);
} break;
case 5: {
const r = valueRate;
const g = min;
const b = hueRate * (valueRate - min) + min;
return prophet.newResult(r, g, b);
} break;
}
// unexpected
return null;
};
const myProphet = {
saturationIsZero: function(saturation) {
return !(saturation > 0) && !(saturation < 0);
},
saturationRate: function(saturation) {
return saturation / this.maxSaturation;
},
maxSaturation: 1,
valueRate: function(value) {
return value / this.maxValue;
},
maxValue: 1,
hueStageAndRate: function(hue) {
const hueNormalized = hue % 360;
const hueStage = parseInt(hueNormalized / 60, 10);
const hueTmp = (parseInt(hue % 60, 10) / 60);
const hueRate = (hueStage % 2 == 0) ? hueTmp : 1 - hueTmp;
return [hueStage, hueRate];
},
newResult: function(r, g, b) {
// return [r * 255, g * 255, b * 255];
const toHex = function(val) {
const num = parseInt(val, 10);
const hex = num.toString(16);
const padded = hex.padStart(2, '0');
return padded;
};
return `#${toHex(r * 255)}${toHex(g * 255)}${toHex(b * 255)}`;
}
};
console.log(`red? ${hsvToRgb(0, 0.5, 1, myProphet)}`);
console.log(`yellow? ${hsvToRgb(60, 0.5, 1, myProphet)}`);
console.log(`green? ${hsvToRgb(120, 0.5, 1, myProphet)}`);
console.log(`cyan? ${hsvToRgb(180, 0.5, 1, myProphet)}`);
console.log(`blue? ${hsvToRgb(240, 0.5, 1, myProphet)}`);
console.log(`magenta? ${hsvToRgb(300, 0.5, 1, myProphet)}`);