Как реализовать палитру цветов

JavaScript
Как реализовать палитру цветов

В процессе разработки библиотеки компонентов пользовательского интерфейса компании цветовой компонент ColorPicker не был подробно изучен из-за нехватки времени.Глядя на цветную хроматограмму, я подумал, что это будет очень сложно реализовать, поэтому я напрямую инкапсулировал палитру цветов с открытым исходным кодом. . Это было где-то пол года назад, и эта статья тоже есть в черновике у меня в блоге (только заголовок не имеет содержания, запись я сделал тогда, думая, что потом успею ее изучить, там еще много такие сквозняки на данный момент 😂) Хранится пол года. Некоторое время назад я спросил у коллег из компании по пользовательскому интерфейсу некоторые концепции, связанные с цветом, и искал знания в этой области.Урожай все еще довольно большой, особенно Zhihu.В чем разница между HSL, HSV, HSB в цветовом пространстве?В этом вопросе@ForrestОтвет почти на просторечии, отлично 👍.


После понимания концепций иди посмотри на этот компонент, у нас не было бы такого странного чувства конфликта промышленности. В конце концов понял, что этот компонент,DEMO, и запишите процесс реализации следующим образом:

[Анализ Photoshop Colorizer] Небольшая глава представляет собой краткое изложение некоторых концепций цвета, основанное на статьях Wikipedia и Zhihu. Краткое изложение перспективы развития может быть не очень профессиональным, просто поймите это.

Разбор тонеров Photoshop

PhotoShop拾色器

Разница между HSL, HSV, HSB

Как внешний интерфейс, мы знаем HEX и RGB, но цветовые понятия HSL, HSV и HSB часто расплывчаты. Как показано на картинке выше, цветовая палитра Photoshop, нижняя часть имеетH,S,B,R,G,BПодождите несколько полей ввода,R,G,BПредставляя цветовые каналы трех основных цветов красного, зеленого и синего, различные цвета могут быть получены путем изменения трех цветовых каналов и наложения друг на друга, что нам хорошо известно. ТакH,S,BЧто это такое?

Фактически,HSBтакой жеRGBТочно так же это также цветовой режим, где H (оттенок) представляет оттенок (какой цвет), S (насыщенность) представляет насыщенность (чистоту цвета), а B (яркость) представляет яркость (яркость цвета). ). По сравнению с режимом RGB цветовой режим HSB более удобен для пользователя.Он определяет цвет "какой цвет? Цвет яркий? Цвет яркий?".

что такое оттенок

Оттенок – это цвет, воспринимаемый человеческим глазом при различных условиях освещения.«Красные, оранжевые, желтые, зеленые, синие, синие и фиолетовые, кто занимается танцами в небе с цветом?», - давно описаны стихи великих людей. В цветовом режиме HSV/HSL оттенок составляет 0 градусов (360 градусов) для красного, 60 градусов для желтого, 120 градусов для зеленого, 180 градусов для голубого, 240 градусов для синего и 300 градусов для пурпурного.Его диапазон значений составляет 0 - 360 градусов.,Как показано ниже:

色相

что такое насыщенность

Насыщенность относится к интенсивности или чистоте цвета.. Насыщенность представляет собой долю компонентов цвета в оттенке, измеряемую в процентах от 0 (прозрачный) до 100% (полностью насыщенный). Чистота является признаком силы восприятия цвета.Цвета с высокой чистотой кажутся человеческому глазу более яркими.

Что такое легкость

Светлота – это относительная светлота и темнота цвета. Обычно измеряется в процентах от 0 (черный) до 100% (белый).


такой же,HSL,HSVа такжеHSBТочно так же интерпретация цвета основана на трех аспектах оттенка, насыщенности и светлоты. Среди них HSB и HSV — это одно и то же, но название другое. Мы будем использовать HSV для его представления позже.

Разница между тремя цветовыми рисунком, почти известным (конец прилагаемой ссылке) имеет очень легко понять ответы:

В принципе и производительности H (оттенок) в HSL и HSB абсолютно одинаковы, но S (насыщенность) у них разные, а также L и B (яркость):

  • S в HSB контролирует количество белого, смешиваемого с сплошным цветом, чем больше значение, тем меньше белого и тем чище цвет;
  • B в HSB управляет количеством черного, подмешанного к сплошному цвету, чем больше значение, тем меньше черного и выше яркость.
  • S в HSL не имеет ничего общего с черным и белым, и насыщенность не контролирует количество черного и белого, смешанных с цветом;
  • L в HSL управляет смешиванием черного и белого цветов в сплошном цвете.

Три диапазона выражений значений HSV: H [0-360] float S [0-1] float V [0-1] float

Приведенные выше концепции могут быть не очень профессиональными, просто поймите.Если мы используем процедурное мышление для объяснения вышеупомянутых концепций, это означает, что если мы смешаем различные степени черного и белого в цвет, мы можем изменить его на другое значение цвета, как показано ниже:

PhotoShop拾色器
То есть отпуститьR,G,BВ дополнение к трем цветовым каналам вы также можете передать оттенокH,насыщенностьS, яркостьVОстальные три канала используются для передачи цвета.

Процесс реализации

color-picker效果图
Как показано на приведенном выше изображении, это окончательный эффект селектора цвета, который необходимо реализовать. Весь макет состоит из трех компонентов: панель насыщенности/яркости, панель оттенков и панель прозрачности. Все три панели являются моделями ползунков. Ползунки на панели насыщенности/яркости могут свободно перемещаться по своим панелям, а ползунок оттенка и прозрачности на панель позволяет только проводить пальцем влево и вправо. Окончательное значение координаты скольжения ползунка будет использоваться для расчетаHSVоснование для стоимости. «Мой муж в руках, у меня есть мир». Исходя из изложенных выше концепций и идей, нам нужно только рассчитать цветовую фазу через координатыH,насыщенностьS, яркостьVТри значения, вы можете преобразовать его в цвет в указанном формате.
流程图

  • Насыщенность/яркость, насыщенность и значение из панели, состоящей из двух слоев. Значения левой координаты, используемые для расчета значений насыщенности ползунка, Верхнее значение, используемое для расчета яркости;
  • Левое значение значения координат слайдера цветной фазной панели используется для расчета значения цветного фазы;
  • Левое значение координаты ползунка панели прозрачности используется для расчета прозрачности.Прозрачность является дополнением к цвету и не имеет ничего общего с самим цветом;
  • в конечном итоге произвелHSVAЧетыре значения будут преобразованы в разные цветовые форматы по разным алгоритмам;

Реализация панели насыщенности/яркости

С точки зрения непрофессионала, насыщенность — это то, сколько белого «примешано» к сплошному цвету, а яркость — это то, сколько черного «примешано» к сплошному цвету; эти величины выражаются в процентах, а их значения варьируются в0% ~ 100%.

Насыщенность идет слева направо, чем меньше белого примешивается, тем выше чистота цвета. То есть белый, смешанный в крайнем левом углу панели, достигает пика чистого белого, в то время как белый, смешанный в крайнем правом углу, почти прозрачен, что представляет собой радиальный градиент слева направо, от белого к прозрачному; по той же причине можно получить Out, легкость может быть представлена ​​радиальным градиентом снизу вверх, от чисто черного до полностью прозрачного. Поскольку большинство областей этих двух градиентов прозрачны, когда различные оттенки, такие как красный, оранжевый, желтый, зеленый, синий, синий и фиолетовый, устанавливаются ниже этих двух слоев, вся область будет формировать цветовой спектр. Как показано ниже:

饱和度/亮度面板的实现原理
Для того, чтобы было проще понять, я записал небольшое видео, в котором, регулируя цвет фона элементов панели, можно более четко показать эффект этих двух радиальных градиентов, наложенных на сплошной цвет фона. После того, как процесс формирования цветового спектра понятен, реализация панели насыщенности/яркости становится намного проще.Чтобы упростить структуру, прямое использование::before/::afterПсевдоэлементы для реализации слоев насыщенности и осветления.

макет
<div class="mo-color-sat-val">
  <!-- 饱和度渐变元素 -->
  ::before
  <!-- 滑块 -->
  <div class="mo-color-thumb" role="slider" tabindex="0">
    <span></span>
  </div>
  <!-- 明度渐变元素 -->
  ::after
</div>
.mo-color-sat-val {
  position: relative;
  // 色相将直接作用于面板的背景色上
  background: transparent;

  &::before,
  &::after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
  }

  // 饱和度 一条从左往右,由纯白到透明的径向渐变
  &::before {
    background: linear-gradient(to right, white, transparent);
  }

  // 明度 一条从下往上,由纯黑到透明的径向渐变
  &::after {
    background: linear-gradient(to top, black, transparent);
  }
}
Рассчитать значения S и V по координатам

Когда ползунок свободно скользит по панели, положение ползунка является значением координат, необходимым для вычисления значений S и V. Как скользить и вычислять координаты не является предметом этой статьи, вы можете напрямуюСправочный исходный код, который я инкапсулировал какDraggableКласс, который генерирует координату во время процесса скольжения и возвращает экземпляр через ряд функций-ловушек.

// 初始化$sat面板的Draggable类
states.satDragIns = new Draggable(states.$sat, {
  drag: satDrag,
  end: satDrag
})

function satDrag (coordinate: Coordinate) {
  // satWidth 面板的宽度
  // satHeight 面板的高度
  // 饱和度和明度的范围都是从 0 - 100 的一个百分比值,为了便于计算,这里直接保存为小数, 坐标原点是左下角
  const saturation = Math.round(coordinate.left / satWidth * 100) / 100
  const value = Math.round((1 - coordinate.top / satHeight) * 100) / 100
}

Сбросить цвет фона панели при изменении оттенка

Последнее кольцо панели «Насыщенность/Яркость» предназначено для установки цвета фона панели при изменении оттенка таким образом, чтобы формировался окончательный цветовой спектр (как на видео выше). Вам нужно только сгенерировать цвет в формате hsl из значения H, сгенерированного после изменения оттенка (обратитесь к реализации оттенка):

 states.$sat.style.background = `hsl(${h}, 100%, 50%)`

реализация оттенка

色相
Можно видеть, что в цветовом пространстве HSV полоса оттенков формируется путем постепенного перехода шести цветов: красного, желтого, зеленого, голубого, синего и пурпурного, и, наконец, переходов от плоского красного к красному с обратной связью. Возможно, это будет легче понять, уменьшив его до формы кольца (маленькие черные точки обозначают углы):
色相环
Затем эту полосу градиента можно реализовать, если вычислить угол каждого цвета.Градиент начинается с красного (0 градусов) и замыкает цикл с красного (360 градусов); средние 5 значений цвета делятся поровну угол в свою очередь:

0 deg: 红色
1/6 deg: 黄色
2/6 deg: 绿色
...
5/6 deg: 品红色
360 deg: 红色
макет

Преобразуется в окончательный код CSS следующим образом:

// 色相
.mo-color-hue>.mo-color-rail {
  background: linear-gradient(to right, #f00 0%, #ff0 16.66%, #0f0 33.33%, #0ff 50%, #00f 66.66%, #f0f 83.33%, #f00 100%);
}
<div class="mo-color-hue">
  <!-- 渐变条 -->
  <div class="mo-color-rail"></div>
  <!-- 滑块 -->
  <div class="mo-color-thumb" role="slider" tabindex="0">
    <span></span>
  </div>
</div>
Рассчитать значение H по координатам
// 通过left坐标和hue元素宽度计算出比例值,然后乘以360度计算出当前位置所处的度数
hue = Math.round((left / hueWidth) * 360 * 100) / 100

Достижение прозрачности

Реализация панели прозрачности самая простая, а фоновая сетка также генерируется с помощью CSS-градиентов.Подробности можно найти в этой статье CSS God Zhang Xinxu "Введение в CSS Paint API".

макет
<!-- 格子背景直接作用在容器上 -->
<div class="mo-color-alpha">
  <!-- 颜色背景层 -->
  <div class="mo-color-rail"></div>
  <div class="mo-color-thumb" role="slider" tabindex="0">
    <span></span>
  </div>
</div>
.mo-color-alpha {
  background-color: white;
  background-image: linear-gradient(45deg, #c5c5c5 25%, transparent 0, transparent 75%, #c5c5c5 0, #c5c5c5), linear-gradient(45deg, #c5c5c5 25%, transparent 0, transparent 75%, #c5c5c5 0, #c5c5c5);
  background-size: 10px 10px;
  background-position: 0 0, 5px 5px;
}
Рассчитать значение прозрачности по координатам
alpha = Math.round(left / alpWidth * 100) / 100
Измените цвет фона цветного слоя при изменении оттенка
const hsl = hsv2hsl(h, s, v)
states.$alpRail.style.background = `linear-gradient(to right, transparent, hsl(${hsl.h}, ${hsl.s * 100}%, ${hsl.l * 100}%))`

Как и выше, мы получаем то, что необходимо для генерации цветаH,S,VТри важных параметра. С этими тремя параметрами можно передать алгоритм преобразования цвета, такой какhsv2rgbи т. д., конвертировать три параметра hsv в значения цвета в разных форматах.Что касается алгоритма конвертации, то эта статья расширяться не будет.этот сайтПодробный список алгоритмов преобразования различных цветов можно найти здесь.

Совет: как проверить допустимость цвета

Нельзя не учитывать, что палитра цветов может получать входящие значения от пользователя, а сам компонент ColorPicker имеет встроенныйsetValueметод, мы не можем гарантировать, что пользователь передал допустимое значение цвета, так как же проверить, является ли цвет допустимым? Сначала я рассматривал возможность использования регулярных выражений для проверки, но, поскольку это потребовало бы передачиrgb(260, 260, 260)Такое значение, выходящее за пределы допустимого диапазона для определенного канала, сложнее проверить. Затем я установил неправильный цвет для элемента в браузере Chrome и обнаружил, что Chrome автоматически понизил цвет до белого, затем, если цветовому стилю DOM назначен неправильный цвет, а затем получить цвет, а затем проверить, полученный цвет соответствует входящему цвету, можно ли его использовать как основу для проверки? Chrome прошел этот тест, другие браузеры — нет.

При меньшем количестве тестов этот трюк может быть проблематичным.

/**
 * 校验颜色是否合法
 * 测试用例较少,该技巧可能存在问题
 * 
 * 原理,如果颜色不合法,将会被转换为rgb(255,255,255)
 * 只需验证设置后的颜色是否等于传入的颜色
 * @param color 
 */
function checkColor(color: string) {
  // todo
  const style = new Option().style
  style.color = color
  return style.color === color 
}

// 只负责将传入的值转换为 h, s, v 三个通道值,而不去校验值是否超出范围或有效
function parseColor(color) {
  // hex2hsv
  if (HEX_REG.test(color)) {}
  // rgb2hsv
  if (RGB_REG.test(color)) {}
  // ...

  return {
    h,
    s,
    v,
    a
  }
}

setValue (color) {
  const { h, s, v, a } = parseColor(color)
  const {r, g, b} = hsv2rgb(h, s, v,)
  if (checkColor(`rgb(${r},${g},${b})`)) {
    // todo
  }
}

исходный код

Эта статья была впервые опубликована вмой блог

использованная литература