Skip to content

Commit

Permalink
docs: add blog (ant-design#44698)
Browse files Browse the repository at this point in the history
* docs: add blog

* docs: update blog

* docs: update blog title
  • Loading branch information
RedJue authored Sep 8, 2023
1 parent 59366da commit ec607dd
Show file tree
Hide file tree
Showing 2 changed files with 226 additions and 0 deletions.
113 changes: 113 additions & 0 deletions docs/blog/color-picker.en-US.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
---
title: Color Models and Color Picker
date: 2023-09-07
author: Redjue
---

Hello everyone, I'm [Redjue](https://github.com/Redjue), and I'm honored to have the opportunity to contribute the [ColorPicker](/components/color-picker) component to **Ant Design** this year. It's been a great learning experience and has given me a deeper understanding of the development process of **Ant Design**. In this article, I will share the specific implementation process.

## Color Models

Before we start implementing, we need to understand a concept: color models. A color model is a mathematical model used to describe colors. Common color models include `RGB`, `HSV`, `HEX`, etc. Among these color models, `RGB` is the most common and easiest to understand, so let's start with the `RGB` color model.

### RGB Color Model

The `RGB` color model represents colors by the combination of three primary colors (red, green, and blue). The value range of each primary color is 0-255, and the combination of the three primary colors can represent 256<sup>3</sup> colors. These colors can form a cube, as shown in the following figure: ![RGB](https://user-images.githubusercontent.com/21119589/266228482-f1ff94b1-e7ca-40c5-8512-1bc5ab79c388.jpg)

In the `RGB` color model, each color can be represented by a triplet `(R, G, B)`, where `R` represents the value of red, `G` represents the value of green, and `B` represents the value of blue. For example, red can be represented as `(255, 0, 0)`, green can be represented as `(0, 255, 0)`, and blue can be represented as `(0, 0, 255)`.

### HSV/HSB Color Model

The `HSV` color model represents colors by hue, saturation, and value. The value range of hue is 0-360, and the value range of saturation and value is 0-100. The `HSV` color model can be represented by a cone, as shown in the following figure: ![HSV](https://user-images.githubusercontent.com/21119589/266231236-d68ad9d7-9654-4bc5-8489-7cc52f2aabb1.png)

In the `HSV` color model, each color can be represented by a triplet `(H, S, V)`, where `H` represents the value of hue, `S` represents the value of saturation, and `V` represents the value of value. For example, red can be represented as `(0, 100, 100)`, green can be represented as `(120, 100, 100)`, and blue can be represented as `(240, 100, 100)`.

### HEX Color Model

The `HEX` color model represents colors by hexadecimal numbers. The first two digits represent the value of red, the middle two digits represent the value of green, and the last two digits represent the value of blue. For example, red can be represented as `#FF0000`, green can be represented as `#00FF00`, and blue can be represented as `#0000FF`. As shown in the following figure: ![HEX](https://user-images.githubusercontent.com/21119589/266235167-fa4e9362-6b97-4966-b43f-14b6f7eb62a3.png)

This is also the most common way of representing colors because it can be used directly in CSS. Moreover, the representation is very simple, just convert the three numbers in the RGB color model to hexadecimal numbers.

## Conversion of Color Models

Different algorithms are needed for the conversion of color models. There are many mature libraries on the market that can be selected. In the implementation, we chose the library [tinycolor](https://github.com/scttcper/tinycolor), which supports the conversion of multiple color models such as `RGB`, `HSL`, `HSV`, `HEX`, etc. Moreover, its size is very small, only about 10KB, which is very suitable for use in browsers.

## Selection of Color Models

Since we need to implement a color picker, we need to choose a color model to represent colors. In terms of complexity, the `RGB` color model is the simplest because it only needs three numbers to represent a color, and its value range is 0-255, which is very easy to understand. However, the disadvantage of the `RGB` color model is also very obvious. Its color space is a cube, and the color change at the edge of the cube is very obvious. This color space is not suitable for human visual perception.

Therefore, we need to choose a color model that is more suitable for human visual perception. Here we chose the `HSV` color model, which represents colors through hue, saturation, and value. This color space is more in line with human visual perception, and the color change at the edge of the color space is not too obvious.

## Implementation Details

The implementation mainly consists of three parts: the color panel, the selection anchor, and sliders.

### Color Panel

Since we are using the `HSV` color model, we need to represent hue, saturation, and value on the panel.

1. Hue

```css
background-color: rgb(0, 106, 255);
```

This way we get a blue color with both saturation and brightness set to 100% <img style="width:auto" src="https://user-images.githubusercontent.com/21119589/266240524-e40a2df7-c3c8-4ecc-aff9-10a4b2d645d7.png"/>

2. Add brightness overlay

```css
background-color: rgb(0, 106, 255);
background-image: linear-gradient(0deg, rgb(0, 0, 0), transparent);
```

After adding the brightness overlay, we get a blue color with brightness variation <img style="width:auto" src="https://user-images.githubusercontent.com/21119589/266242191-e31fd6e2-675b-455c-bc98-9df3b3c8be7f.png"/>

3. Add saturation overlay

```css
background-color: rgb(0, 106, 255);
background-image: linear-gradient(0deg, rgb(0, 0, 0), transparent), linear-gradient(90deg, rgb(255, 255, 255), rgba(255, 255, 255, 0));
```

After adding the saturation overlay, we get a blue color with brightness variation <img style="width:auto" src="https://user-images.githubusercontent.com/21119589/266243231-6d682bf5-fb74-4a8e-9930-19a604d1203f.png"/>

So far, we have obtained a color panel with complete hue, saturation, and brightness.

### Selection Anchor

The implementation of the selection anchor is relatively simple. We only need to correspond the offset position of the anchor to the saturation and brightness of the color panel.

```ts
...
const { width, height } = containerRef.current.getBoundingClientRect();
const { width: targetWidth, height: targetHeight } = targetRef.current.getBoundingClientRect();
const centerOffsetX = targetWidth / 2;
const centerOffsetY = targetHeight / 2;
// Saturation
const saturation = (offset.x + centerOffsetX) / width;
// Brightness
const bright = 1 - (offset.y + centerOffsetY) / height;
```

### Hue and Alpha Sliders

The logic is the same as above, we just need to correspond the offset position of the sliders to the hue or alpha of the color.

```ts
...
const { width, height } = containerRef.current.getBoundingClientRect();
const { width: targetWidth, height: targetHeight } = targetRef.current.getBoundingClientRect();
const centerOffsetX = targetWidth / 2;
const centerOffsetY = targetHeight / 2;
// Hue
const hue = ((offset.x + centerOffsetX) / width) * 360;
// Opacity
const alpha = (offset.x + centerOffsetX) / width;
```

So far, we have obtained a color picker with complete hue, saturation, and brightness, as shown in the following figure: <img style="width:auto" src="https://user-images.githubusercontent.com/21119589/266269086-3dacf4e6-f799-4cb1-b81a-fd4930d7063f.png"/>

## Summary

Through this development journey, I have gained a deeper understanding of color models and the development process of Ant Design. Thanks to the Ant Design team for giving me this opportunity, and thank you all for reading. If you are interested in the implementation details, you can check out the source code implementation at [@rc-component/color-picker](https://github.com/react-component/color-picker).
113 changes: 113 additions & 0 deletions docs/blog/color-picker.zh-CN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
---
title: 色彩模型与颜色选择器
date: 2023-09-07
author: Redjue
---

大家好,我是 [Redjue(红果汁)](https://github.com/Redjue),很荣幸今年有机会向 **Ant Design** 贡献了颜色选择器组件 [ColorPicker](/components/color-picker-cn),这是一次很棒的学习机会,也让我对 **Ant Design** 的开发流程有了更深入的了解。在这篇文章中,我将分享一下具体的实现过程。

## 色彩模型

在实现之前我们需要了解一个概念:色彩模型。色彩模型是一种用于描述色彩的数学模型,常见的色彩模型有 `RGB``HSV``HEX` 等。在这些色彩模型中,`RGB` 是最常见的色彩模型,也是最容易理解的色彩模型,因此我们先来看一下 `RGB` 色彩模型。

### RGB 色彩模型

`RGB` 色彩模型是通过三原色(红、绿、蓝)的不同组合来表示色彩的,每个原色的取值范围是 0-255,三原色的组合可以表示 256<sup>3</sup> 种颜色,这些颜色可以组成一个立方体,如下图所示: ![RGB](https://user-images.githubusercontent.com/21119589/266228482-f1ff94b1-e7ca-40c5-8512-1bc5ab79c388.jpg)

`RGB` 色彩模型中,每个颜色都可以用一个三元组 `(R, G, B)` 来表示,其中 `R` 表示红色的取值,`G` 表示绿色的取值,`B` 表示蓝色的取值。例如,红色可以表示为 `(255, 0, 0)`,绿色可以表示为 `(0, 255, 0)`,蓝色可以表示为 `(0, 0, 255)`

### HSV/HSB 色彩模型

`HSV` 色彩模型是通过色相(Hue)、饱和度(Saturation)、明度(Value)来表示色彩的,其中色相的取值范围是 0-360,饱和度和明度的取值范围是 0-100。HSV 色彩模型可以用一个圆锥体来表示,如下图所示: ![HSV](https://user-images.githubusercontent.com/21119589/266231236-d68ad9d7-9654-4bc5-8489-7cc52f2aabb1.png)

`HSV` 色彩模型中,每个颜色都可以用一个三元组 `(H, S, V)` 来表示,其中 `H` 表示色相的取值,`S` 表示饱和度的取值,`V` 表示明度的取值。例如,红色可以表示为 `(0, 100, 100)`,绿色可以表示为 `(120, 100, 100)`,蓝色可以表示为 `(240, 100, 100)`

### HEX 色彩模型

`HEX` 色彩模型是通过十六进制数来表示色彩的,其中前两位表示红色的取值,中间两位表示绿色的取值,后两位表示蓝色的取值。例如,红色可以表示为 `#FF0000`,绿色可以表示为 `#00FF00`,蓝色可以表示为 `#0000FF`。如下图所示: ![HEX](https://user-images.githubusercontent.com/21119589/266235167-fa4e9362-6b97-4966-b43f-14b6f7eb62a3.png)

这也是我们最常见的颜色表示方式,因为它可以直接在 CSS 中使用。而且表示方式非常简单,只需要将 RGB 色彩模型中的三个数字转换为十六进制数即可。

## 色彩模型的转换

颜色模型的转换需要不同的算法,市面上已经有很多成熟的类库可以进行选择,在实现上我们选择了 [tinycolor](https://github.com/scttcper/tinycolor) 这个类库,它支持 `RGB``HSL``HSV``HEX` 等多种色彩模型的转换,而且它的体积非常小,只有 10KB 左右,非常适合在浏览器中使用。

## 色彩模型的选择

由于我们需要实现一个颜色选择器,因此我们需要选择一个色彩模型来表示颜色。从复杂度来说,`RGB` 色彩模型是最简单的,因为它只需要三个数字就可以表示一个颜色,而且它的取值范围是 0-255,非常容易理解。但是 `RGB` 色彩模型的缺点也很明显,它的色彩空间是一个立方体,而且在立方体的边缘颜色的变化非常明显,这样的色彩空间并不适合人类的视觉感知。

因此,我们需要选择一个更适合人类视觉感知的色彩模型,这里我们选择了 `HSV` 色彩模型,通过色相、饱和度、明度三个维度来表示颜色,这样的色彩空间更加符合人类的视觉感知,而且在色彩空间的边缘颜色的变化也不会太明显。

## 具体实现

主要分为三部分实现:颜色面板、选择锚点和滑块。

### 颜色面板

由于我们用了 `HSV` 的色彩模型,所以我们的需要将色相、饱和度、明度在面板上表示出来。

1. 色相

```css
background-color: rgb(0, 106, 255);
```

这样我们就得到一个明度和饱和度都为 100% 的蓝色 <img style="width:auto" src="https://user-images.githubusercontent.com/21119589/266240524-e40a2df7-c3c8-4ecc-aff9-10a4b2d645d7.png"/>

2. 叠加明度

```css
background-color: rgb(0, 106, 255);
background-image: linear-gradient(0deg, rgb(0, 0, 0), transparent);
```

叠加明度图层后,我们得到了具有明度变化的蓝色 <img style="width:auto" src="https://user-images.githubusercontent.com/21119589/266242191-e31fd6e2-675b-455c-bc98-9df3b3c8be7f.png"/>

3. 叠加饱和度

```css
background-color: rgb(0, 106, 255);
background-image: linear-gradient(0deg, rgb(0, 0, 0), transparent), linear-gradient(90deg, rgb(255, 255, 255), rgba(255, 255, 255, 0));
```

叠加饱和度图层后,我们得到了具有明度变化和饱和度变化的蓝色 <img style="width:auto" src="https://user-images.githubusercontent.com/21119589/266243231-6d682bf5-fb74-4a8e-9930-19a604d1203f.png"/>

至此我们就得到了一个拥有完整色相、饱和度、明度的颜色面板。

### 选择锚点

选择锚点的实现比较简单,我们只需要将锚点的偏移位置对应到颜色面板的饱和度、明度即可。

```ts
...
const { width, height } = containerRef.current.getBoundingClientRect();
const { width: targetWidth, height: targetHeight } = targetRef.current.getBoundingClientRect();
const centerOffsetX = targetWidth / 2;
const centerOffsetY = targetHeight / 2;
// 饱和度
const saturation = (offset.x + centerOffsetX) / width;
// 明度
const bright = 1 - (offset.y + centerOffsetY) / height;
```

### 色相和不透明度滑块

逻辑同上,我们只需要将滑块的偏移位置对应到颜色的色相或不透明度即可。

```ts
...
const { width, height } = containerRef.current.getBoundingClientRect();
const { width: targetWidth, height: targetHeight } = targetRef.current.getBoundingClientRect();
const centerOffsetX = targetWidth / 2;
const centerOffsetY = targetHeight / 2;
// 色相
const hue = ((offset.x + centerOffsetX) / width) * 360;
// 不透明度
const alpha = (offset.x + centerOffsetX) / width;
```

至此我们得到了一个完整的颜色选择器,如下图所示: <img style="width:auto" src="https://user-images.githubusercontent.com/21119589/266269086-3dacf4e6-f799-4cb1-b81a-fd4930d7063f.png"/>

## 总结

通过这次开发之旅,我对色彩模型有了更深入的了解,也对 **Ant Design** 的开发流程有了更深入的了解。感谢 **Ant Design** 团队给我这次机会,也感谢大家的阅读。如果对细节实现感兴趣的童鞋,可以移步 [@rc-component/color-picker](https://github.com/react-component/color-picker) 查看源码实现。

0 comments on commit ec607dd

Please sign in to comment.