We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
本文意在记录一次个人实践,背景是最近公司新起了一个 React 技术栈的项目,因此没有历史包袱,可以尝试使用框架的新特性 React hook 来实现 React 组件。
在考虑做什么时候,正好看到 Ant-Design 的色彩设计,相信使用 React 的童鞋对 Ant-Design 的设计语言和风格是比较清楚的,本文实践的 Demo 是使用 React hook 新特性编写了一个帮助设计童鞋生成平滑色彩渐变的设计工具 Color-Design-Helper 。 生成规则是参考 Ant-Design色彩 ,有兴趣的童鞋可以先行阅读官方文档。
仓库:https://github.com/zerolty/color-design-helper
体验地址: http://zerolty.com/color-design-helper/
记得几个月前阅读过一篇介绍 Ant-Design 调色板演进的文章《 Ant Design 色板生成算法演进之路》,阅读完之后,想对现有的调色板进行增强,因此做这个工具实践方向上的需求和实现是
不知道这样描述是否准确,Ant Design 的基础色板共计 120 个颜色,包含 12 个主色以及衍生色。如果我使用平均法和 tint-shade 法,工具可以通过设计人员自己定制step得到更多级的过渡色,从而更好的满足视觉需求。下图是 Ant-Design 提供的色板生成工具和工具tint-shade 25色的对比。
step
这是 Ant-Design 提供的色板生成工具已经支持的了,除了官方推荐的共计 120 个颜色,你也可以自己定义主色。
平均法、tint-shade 法、和 HSV 递进算法(antd现在使用的)
顾名思义,我可以选择两种颜色,设置好步骤数,等量平均地从第一种颜色向第二种颜色过渡。 比如我们选取的颜色分别是#ffffff和#000000,我们先将HEX转化为RGB,分别是(255, 255, 255)和(0, 0, 0),在将0-255按照选择的step依次平均获得相应的色带。
#ffffff
#000000
这是第一版 Ant-Design 的实现,思路上是把纯黑和纯白和主色分别混合,生成一条常规的渐变色带。比如我们的主色是#1890ff,“色级”是10,将其转化为 RGB 后与#000000按照平均法混合,得到一条色带,取 20%、40%、60%、80%、100%五种色和#fffffff按照平均法混合,得到一条色带,取 20%、40%、60%、80%、100%五种色拼接组成我们的tint-shade色带。
#1890ff
#fffffff
tint-shade
import avgMix from './avg-color'; // 平均函数 function tintShade(color, granularity) { granularity = Number(granularity); const mid = Math.round(granularity/2); // 取中间的值 const mixWithWhite = granularity % 2 === 0 // 奇偶情况 ? avgMix([255, 255, 255], color, mid).slice(1, mid+1) : avgMix([255, 255, 255], color, mid).slice(1, mid); const mixWithBlack = granularity % 2 === 0 ? avgMix(color, [0, 0, 0], mid).slice(1, mid+1) : avgMix(color, [0, 0, 0], mid).slice(0, mid); return [...mixWithWhite, ...mixWithBlack]; // 合并黑白混合 }
选定主色后,我们使用 HSV 模型,将HEX格式的主色转化成H、S、V。
const hsv = new TinyColor({ r: color[0], g: color[1], b: color[2] }).toHsv();
第二步是生成我们色带需要数量的“生成色”数组,并将明暗线设置在60%的位置
for(let i = 1, len = granularity; i <= len; i++) { // “生成色”数 colors.push( colorPalette(color, i, Math.round((granularity)*0.6)) // 明暗线设置在60%的位置 ); } // HSV的优化 const isLight = index <= num; // 判断明暗
第三步 直接跟着代码看对H、S、V的处理,也可以直接看官方实现源码
const getHue = function (hsv, i, isLight) { let hue; if (hsv.h >= 60 && hsv.h <= 240) { // 冷色调 // 减淡变亮 色相顺时针旋转 更暖 // 加深变暗 色相逆时针旋转 更冷 hue = isLight ? hsv.h - hueStep * i : hsv.h + hueStep * i; } else { // 暖色调 // 减淡变亮 色相逆时针旋转 更暖 // 加深变暗 色相顺时针旋转 更冷 hue = isLight ? hsv.h + hueStep * i : hsv.h - hueStep * i; } if (hue < 0) { hue += 360; } else if (hue >= 360) { hue -= 360; } return Math.round(hue); }; // 每个生成颜色的S(饱和)计算,饱和在一定范围内折中,还原比较真实的视觉感受 const getSaturation = function (hsv, i, isLight) { let saturation; if (isLight) { // 减淡变亮 饱和度迅速降低 saturation = Math.round(hsv.s * 100) - saturationStep * i; } else if (i === darkColorCount) { // 加深变暗-最暗 饱和度提高 saturation = Math.round(hsv.s * 100) + saturationStep; } else { // 加深变暗 饱和度缓慢提高 saturation = Math.round(hsv.s * 100) + saturationStep2 * i; } if (saturation > 100) { saturation = 100; } if (isLight && i === lightColorCount && saturation > 10) { saturation = 10; } if (saturation < 6) { saturation = 6; } return Math.round(saturation); }; // 每个生成颜色的V计算,冷色调,变亮;暖色反之 const getValue = function (hsv, i, isLight) { if (isLight) { // 减淡变亮 return Math.round(hsv.v * 100) + brightnessStep1 * i; } // 加深变暗幅度更大 return Math.round(hsv.v * 100) - brightnessStep2 * i; };
在编写这个工具的时候,通过组件拆分是非常简单的三部分,Step 显示和色带是两个纯的render,因此我们很容易想到把状态都放在顶部组件。另外我们的颜色输入框、range选择器、算法选择器三个控件是有状态的,value和setValue需要从顶部组件下发下去,而在以往不使用 React Hooks 的主组件应该是这样
render
颜色输入框、range选择器、算法选择器
value
setValue
<input type="color" value="state,xxx" onChange="onXXXChange" />
这里可以用 State Hooks 抽象 Input 组件的状态和状态控制逻辑,Hooks 是React 16.7.0-alpha.0尝试使用的新特性,官方文档是最好的参考 React hook ,英文阅读不适可以看秋风翻译的React Hooks详解翻译。这个工具按照范式只使用一个函数,没有 class 和 state ,非常顺滑。
使用 react-hook ,全局有三个控制型组件使用 input ,我们也可以把 input 不要看成是原生组件而是一个render-props,useInputValue第一个参数是初始值,第二个参数setOr是供筛选使用暴露出的设置方法,可以在外层手动修改状态,如果不加筛选,setDisabled, setValue将被传到input的props上, React 会抛出Warning提示 Input 没有定义对应的 Props 。
useInputValue
setOr
setDisabled, setValue
input
props
Warning
// define hook function import { useState, useCallback } from "react"; export default function useInputValue(initiateValue, setOr) { const [value, setValue] = useState(initiateValue); const [disabled, setDisabled] = useState(false); let onChange = useCallback(e => setValue(e.target.value), []); if(setOr) return { value, onChange, disabled, setDisabled, setValue }; return { value, onChange, disabled }; } // usage const startInputHook = useInputValue('#ffffff', true); const endInputHook = useInputValue('#1890ff'); const stepInputHook = useInputValue(1); const radiosHook = useInputValue('avg'); ... <input type="color" {...filterStartInputHook} disabled={startInputHook.disabled} /> <input type="text" {...filterStartInputHook} disabled={startInputHook.disabled}/> <input type="range" min={MIN} max={MAX} {...stepInputHook} />
先明确我们用到的三种颜色格式
RGB 与 HEX 之间转化使用toString(16)和parseInt(x, 16)即可
toString(16)
parseInt(x, 16)
// HEX to RGB const hexArray = hex => /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); // 正则取出rgb的十六进制 const rgbObjectFromHex = hex => { var result = hexArray(hex) return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16), } : null; } const rgbArrayFromHex = hex => { const rgb = rgbObjectFromHex(hex); return [rgb.r, rgb.g, rgb.b]; // rgb的数组 } // RGB to HEX function rgbChannelToHex (channel) { const hex = channel.toString(16); return hex.length === 1 ? `0${hex}` : hex; } function rgbToHex (r, g, b) { return `#${rgbChannelToHex(r)}${rgbChannelToHex(g)}${rgbChannelToHex(b)}`; } function rgbArrayToHex (color) { return rgbToHex(color[0], color[1], color[2]); }
RGB 与 HSV 的转化可以参考公式算法,源码可见:HSV-RGB
rgb to hsv
我在实践后,发现一些浮点情况边界处理的不好,之后使用这个颜色转化的库来实践,省去部分成本tinycolor
暗底白字与明底黑字实现是通过计算 RGB 判断明暗,从而显示白色或黑色
export default function brightness(c) { const color = ((c[0] * 299 + c[1] * 587 + c[2] * 114) / 1000) < 154 ? '#ffffff' : '#000000'; return color; }
欢迎小伙伴们,点评和指出不足一起探讨问题,另外我和@蓝色的秋风大佬正在共建一个偏 handsome 的小工具最佳实践,如果你是热爱技术、并有想法参与技术共建欢迎和我们联系。
无影er 秋风 阿米狗
The text was updated successfully, but these errors were encountered:
顶!
Sorry, something went wrong.
No branches or pull requests
React Hooks 起手式,实现一个「高颜值实用」的色彩设计工具
本文意在记录一次个人实践,背景是最近公司新起了一个 React 技术栈的项目,因此没有历史包袱,可以尝试使用框架的新特性 React hook 来实现 React 组件。
调色板Pro
在考虑做什么时候,正好看到 Ant-Design 的色彩设计,相信使用 React 的童鞋对 Ant-Design 的设计语言和风格是比较清楚的,本文实践的 Demo 是使用 React hook 新特性编写了一个帮助设计童鞋生成平滑色彩渐变的设计工具 Color-Design-Helper 。 生成规则是参考 Ant-Design色彩 ,有兴趣的童鞋可以先行阅读官方文档。
需求与实现
记得几个月前阅读过一篇介绍 Ant-Design 调色板演进的文章《 Ant Design 色板生成算法演进之路》,阅读完之后,想对现有的调色板进行增强,因此做这个工具实践方向上的需求和实现是
自定义“色级”,更细的粒度,更多的可能
不知道这样描述是否准确,Ant Design 的基础色板共计 120 个颜色,包含 12 个主色以及衍生色。如果我使用平均法和 tint-shade 法,工具可以通过设计人员自己定制
step
得到更多级的过渡色,从而更好的满足视觉需求。下图是 Ant-Design 提供的色板生成工具和工具tint-shade 25色的对比。自定义主色
这是 Ant-Design 提供的色板生成工具已经支持的了,除了官方推荐的共计 120 个颜色,你也可以自己定义主色。
三种算法
平均法、tint-shade 法、和 HSV 递进算法(antd现在使用的)
平均法
顾名思义,我可以选择两种颜色,设置好步骤数,等量平均地从第一种颜色向第二种颜色过渡。
比如我们选取的颜色分别是
#ffffff
和#000000
,我们先将HEX转化为RGB,分别是(255, 255, 255)和(0, 0, 0),在将0-255按照选择的step依次平均获得相应的色带。tint-shade
这是第一版 Ant-Design 的实现,思路上是把纯黑和纯白和主色分别混合,生成一条常规的渐变色带。比如我们的主色是
#1890ff
,“色级”是10,将其转化为 RGB 后与#000000
按照平均法混合,得到一条色带,取 20%、40%、60%、80%、100%五种色和#fffffff
按照平均法混合,得到一条色带,取 20%、40%、60%、80%、100%五种色拼接组成我们的tint-shade
色带。HSV 递进算法(antd现在使用的)
选定主色后,我们使用 HSV 模型,将HEX格式的主色转化成H、S、V。
第二步是生成我们色带需要数量的“生成色”数组,并将明暗线设置在60%的位置
第三步
直接跟着代码看对H、S、V的处理,也可以直接看官方实现源码
React-Hooks
在编写这个工具的时候,通过组件拆分是非常简单的三部分,Step 显示和色带是两个纯的
render
,因此我们很容易想到把状态都放在顶部组件。另外我们的颜色输入框、range选择器、算法选择器
三个控件是有状态的,value
和setValue
需要从顶部组件下发下去,而在以往不使用 React Hooks 的主组件应该是这样这里可以用 State Hooks 抽象 Input 组件的状态和状态控制逻辑,Hooks 是React 16.7.0-alpha.0尝试使用的新特性,官方文档是最好的参考 React hook ,英文阅读不适可以看秋风翻译的React Hooks详解翻译。这个工具按照范式只使用一个函数,没有 class 和 state ,非常顺滑。
使用 react-hook ,全局有三个控制型组件使用 input ,我们也可以把 input 不要看成是原生组件而是一个render-props,
useInputValue
第一个参数是初始值,第二个参数setOr
是供筛选使用暴露出的设置方法,可以在外层手动修改状态,如果不加筛选,setDisabled, setValue
将被传到input
的props
上, React 会抛出Warning
提示 Input 没有定义对应的 Props 。颜色转化
先明确我们用到的三种颜色格式
#000000
这类,rgb 的16进制组合表达RGB 与 HEX、HSV之间的转化
RGB 与 HEX 之间转化使用
toString(16)
和parseInt(x, 16)
即可RGB 与 HSV 的转化可以参考公式算法,源码可见:HSV-RGB
rgb to hsv
我在实践后,发现一些浮点情况边界处理的不好,之后使用这个颜色转化的库来实践,省去部分成本tinycolor
反差色文字颜色
暗底白字与明底黑字实现是通过计算 RGB 判断明暗,从而显示白色或黑色
写在最后
欢迎小伙伴们,点评和指出不足一起探讨问题,另外我和@蓝色的秋风大佬正在共建一个偏 handsome 的小工具最佳实践,如果你是热爱技术、并有想法参与技术共建欢迎和我们联系。
打赏
友情链接
无影er
秋风
阿米狗
The text was updated successfully, but these errors were encountered: