nojiko
nojiko copied to clipboard
函数 - hsv... - 一套用于处理 HSV 模式的函数
/// 构建一个 HSV 数据集合
///
/// @param {number/deg} $h - 色相,值须在 [0deg, 360deg] 区间内,否则将以 360deg 取模;
/// @param {number/%} $s - 对比度,值须在 [0%, 100%] 区间内,否则将抛出异常;
/// @param {number/%} $v - 明度,值须在 [0%, 100%] 区间内,否则将抛出异常;
///
/// @return {Map}
///
/// 一个包含三个键值对的集合,分别为:
///
/// - `h` `{number/deg}` 色相;
/// - `s` `{number/%}` 饱和度;
/// - `v` `{number/%}` 明度;
@function hsv($h, $s, $v) {
@if $s < 0 or $s > 100 or $v < 0 or $v > 100 {
@error "must be between 0 and 100.";
}
@return (
h: $h % 360deg,
s: $s + 0%,
v: $v + 0%,
__is-hsv: true
)
}
/// 将一个色值转换为 HSV 模式
///
/// TODO 不支持含有不透明度的色值,转换后将丢失其不透明度。
///
/// @link http://ariya.blogspot.com/2008/07/converting-between-hsl-and-hsv.html Converting between HSL and HSV
///
/// @param {Color} $color - 待转换的色值;
///
/// @return {Map}
///
/// 一个包含三个键值对的集合,分别为:
///
/// - `h` `{number/deg}` 色相;
/// - `s` `{number/%}` 饱和度;
/// - `v` `{number/%}` 明度;
@function to-hsv($color) {
@if (is-hsv($color)) {
@return $color;
}
$h: hue($color);
$s: saturation($color);
$l: lightness($color);
@if (unit($s) == '%') {
$s: strip-unit($s) / 100;
}
@if (unit($l) == '%') {
$l: strip-unit($l) / 100;
}
$l: $l * 2;
$s: $s * ( if($l <= 1, $l, 2 - $l) );
@return hsv(
$h,
percentage(limit( 2 * $s / ( $l + $s ), 0, 1 )),
percentage(limit( ($l + $s) / 2, 0, 1)),
);
}
/// 判断所传入的数据是否是由 `to-hsv` 方法所生成的 HSV 色值数据;
/// @param {Map} $val - 待判断的值;
/// @return {boolean}
@function is-hsv($val) {
@return type-of($val) == 'map' and map-get($val, __is-hsv) == true;
}
/// 获取一个色值所对应 HSV 模式中的色相值;
/// @param {Color} $color - 一个颜色值(RGB,HSL 或是由 to-hsv 生成的 HSV 数据);
/// @return {number/deg}
///
/// @example scss
/// $hue: hsv-hue(#f 0); // --> 0deg
/// $hue: hsv-hue(hsl(120deg, 100%, 50%); // --> 120deg
/// $hue: hsv-hue(to-hsv(#00f)); // --> 240deg
@function hsv-hue($color) {
@return map-get(to-hsv($color), h);
}
/// 获取一个色值所对应 HSV 模式中的饱和度值;
/// @param {Color} $color - 一个颜色值(RGB,HSL 或是由 to-hsv 生成的 HSV 数据);
/// @return {number/%}
///
/// @example scss
/// $hue: hsv-saturation(#f00); // --> 100%
/// $hue: hsv-saturation(hsl(240deg, 60%, 50%); // --> 75%
/// $hue: hsv-saturation(to-hsv(#ff8080)); // --> 49.8039215686%
@function hsv-saturation($color) {
@return map-get(to-hsv($color), s);
}
/// 获取一个色值所对应 HSV 模式中的明度值;
/// @param {Color} $color - 一个颜色值(RGB,HSL 或是由 to-hsv 生成的 HSV 数据);
/// @return {number/%}
///
/// @example scss
/// $hue: hsv-value(#f00); // --> 100%
/// $hue: hsv-value(hsl(0deg, 100%, 37.5%); // --> 75%
/// $hue: hsv-value(to-hsv(#800000)); // --> 50.1960784314%
@function hsv-value($color) {
@return map-get(to-hsv($color), v);
}
/// 将 hsv 转换为 hsl
/// @param {Map} $val - 待转换的 HSV 色值数据;
/// @return {Color<HSL>}
@function hsv-to-hsl($hsv) {
$h: hsv-hue($hsv);
$s: hsv-saturation($hsv);
$v: hsv-value($hsv);
$s: 0 + ($s / 100%);
$v: 0 + ($v / 100%);
$l: (2 - $s) * $v;
@return hsl(
$h,
percentage(limit($s * $v / (if($l <= 1, $l, 2 - $l)), 0, 1)),
percentage(limit($l / 2, 0, 1))
);
}
/// 将 hsv 转换为 rgb
/// @link https://www.rapidtables.com/convert/color/hsv-to-rgb.html HSV to RGB
/// @param {Map} $val - 待转换的 HSV 色值数据;
/// @return {Color<RGB>}
@function hsv-to-rgb($hsv) {
$h: hsv-hue($hsv);
$s: hsv-saturation($hsv);
$v: hsv-value($hsv);
$h: strip-unit($h);
$s: strip-unit($s) / 100;
$v: strip-unit($v) / 100;
$c: $v * $s;
$x: $c * (1 - abs(($h / 60) % 2 - 1));
$m: $v - $c;
$rgb: ();
@if 0 <= $h and $h < 60 {
$rgb: ($c, $x, 0);
}
@else if 60 <= $h and $h < 120 {
$rgb: ($x, $c, 0);
}
@else if 120 <= $h and $h < 180 {
$rgb: (0, $c, $x);
}
@else if 180 <= $h and $h < 240 {
$rgb: (0, $x, $c);
}
@else if 240 <= $h and $h < 300 {
$rgb: ($x, 0, $c);
}
@else if 300 <= $h and $h < 360 {
$rgb: ($c, 0, $x);
}
@return rgb(
(nth($rgb, 1) + $m) * 255,
(nth($rgb, 2) + $m) * 255,
(nth($rgb, 3) + $m) * 255
);
}