阅读 121

不用框架,复刻一个VS Code的调色板

前言

那天在codepen看到了别人做的color picker就突发奇想自己复刻一个VS Code的调色板,我也是刚开始学前端嘛,看见啥都想试着写一个。

说干就干,花了几个小时写了一个,bug贼多,就是一个想法,也懒得改了,菜鸡一个,大佬勿喷。

我们先来看看原版长啥样(颜色过多的话gif会失真,大概看看):

2.gif

可以看到上方用来显示颜色和色值,点击可以切换三种色彩显示方式,分别是rgba,hsla和hex8;然后下方左侧一个色谱来选择颜色,右侧两个滑块选择透明度和色相。

右上角的显示原来的颜色和最下方的文字提示这次就先不写了????

然后看看我几个小时复刻的结果(在线预览):

112.gif

HTML+CSS

HTML没啥好说的,就div套div

我大概画了一下整体布局:

image-20211025162348883

透明背景

image-20211025163217663

这背景的黑白格子上来就给我整蒙了,还得是万能的搜索啊,最后用线性渐变解决了:

background: linear-gradient(                 45deg,                  rgba(0, 0, 0, 0.4) 25%,                  transparent 25%,                  transparent 75%,                  rgba(0, 0, 0, 0.4) 75%,                  rgba(0, 0, 0, 0.4)                 ),             linear-gradient(                 45deg,                  rgba(0, 0, 0, 0.4) 25%,                  transparent 25%,                  transparent 75%,                  rgba(0, 0, 0, 0.4) 75%,                  rgba(0, 0, 0, 0.4)             ); background-size: 10px 10px; background-position: 0 0, 5px 5px; 复制代码

下半部分

透明度和色相选择部分都用线性渐变解决:

// 透明度 background: linear-gradient(to bottom, rgba(0, 0, 0, 1), rgba(0, 0, 0, 0)); // 色相 background: linear-gradient(to bottom,     hsl(0, 100%, 50%),     hsl(60, 100%, 50%),     hsl(120, 100%, 50%),     hsl(180, 100%, 50%),     hsl(240, 100%, 50%),     hsl(300, 100%, 50%),     hsl(360, 100%, 50%) ); 复制代码

滑块左右要各超出去1px:

.slide {     width: 27px;     height: 5px;     border: 1px solid #eee;     position: absolute;     left: -2px;     top: 0; } 复制代码

成果

CSS写完后就是这个样子:

image.png

JS

先把要用到的变量都定义出来:

const container = document.querySelector('.container') const value = document.querySelector('.value') const opacity = document.querySelector('.opacity') const hue = document.querySelector('.hue') const opaSlide = document.querySelector('#opa-slide') const hueSlide = document.querySelector('#hue-slide') const spectrum = document.querySelector('.spectrum') const cursor = document.querySelector('.color-cursor') const canvas = document.querySelector('canvas') const ctx = canvas.getContext('2d') const speRect = canvas.getBoundingClientRect() let bg_color = {   h: 0,   s: "100%",   l: "50%",   a: 1 }; 复制代码

canvas

canvas也就是色谱部分用两个黑白透明渐变覆盖画出来的:

function draw(color) {     ctx.clearRect(0, 0, canvas.width, canvas.height);     if (!color) color = '#f00';     ctx.fillStyle = color;     ctx.fillRect(0, 0, canvas.width, canvas.height);     let whiteGradient = ctx.createLinearGradient(0, 0, canvas.width, 0);     whiteGradient.addColorStop(0, "#fff");     whiteGradient.addColorStop(1, "transparent");     ctx.fillStyle = whiteGradient;     ctx.fillRect(0, 0, canvas.width, canvas.height);     let blackGradient = ctx.createLinearGradient(0, 0, 0, canvas.height);     blackGradient.addColorStop(0, "transparent");     blackGradient.addColorStop(1, "#000");     ctx.fillStyle = blackGradient;     ctx.fillRect(0, 0, canvas.width, canvas.height); } draw(); 复制代码

image.png

鼠标事件

检测鼠标按下、移动、抬起事件,然后更改信息:

let isDraw = false; container.onmousedown = () => (isDraw = true); container.onmousemove = (e) => {   if (!isDraw) return;   if (检测到鼠标移动到目标区域) {       更改显示位置;       更改颜色;   }      更改全部颜色及文本信息; }; container.onmouseup = () => (isDraw = false); // 避免一些bug,但这样影响效果 canvas.onmouseout = () => (isDraw = false); 复制代码

移动改变透明度及色相

通过鼠标位置计算滑块位置,然后计算比例修改透明度和色相值,用到了TinyColor来解析颜色。

let bg_color = {   h: 0,   s: "100%",   l: "50%",   a: 1 }; container.onmousemove = (e) => {   if (!isDraw) return;   if (e.target === opacity || e.target.parentNode === opacity) {     let y = e.pageY - opacity.getBoundingClientRect().top;     if (y < 0) y = 0.1;     if (y > 150) y = 145;     opaSlide.style.top = y + "px";     bg_color.a = 1 - y / opacity.offsetHeight;   }   if (e.target === hue || e.target.parentNode === hue) {     let y = e.pageY - hue.getBoundingClientRect().top;     if (y < 0) y = 0.1;     if (y > 150) y = 145;     hueSlide.style.top = y + "px";     bg_color.h = (y / hue.offsetHeight) * 360;     draw(tinycolor(bg_color));   } }; 复制代码

移动改变颜色

在stackoverflow上找到了一个公式,通过x,y在画布上的比例计算颜色的亮度和饱和度:

 if (e.target === spectrum || e.target.parentNode === spectrum) {     let x = e.pageX - speRect.left - cursor.offsetWidth / 2;     let y = e.pageY - speRect.top - cursor.offsetHeight / 2;     let r = cursor.offsetHeight;     if (x < 0) x = 0;     if (x > speRect.width - r) x = speRect.width - r;     if (y < 0) y = 0.1;     if (y > speRect.height - r) y = speRect.height - r;     cursor.style.left = x + "px";     cursor.style.top = y + "px";     // from stackoverflow     let hsvValue = 1 - y / speRect.height;     let hsvSaturation = x / speRect.width;     let lightness = (hsvValue / 2) * (2 - hsvSaturation);     let saturation =       (hsvValue * hsvSaturation) / (1 - Math.abs(2 * lightness - 1));     bg_color.l = lightness * 100 + "%";     bg_color.s = saturation * 100 + "%"; } 复制代码

显示文字及背景颜色

这里就是tinycolor的用法,可以看一下官方文档。

let method = "toRgbString"; function changeBg() {   let color = tinycolor(bg_color)[method]();   value.style.background = color;   value.style.color = parseInt(bg_color.l) >= 50 ? "black" : "white";   value.innerHTML = color;   document.body.style.background = `linear-gradient(to top, transparent, ${color})`   cursor.style.background = color; } 复制代码

点击上方切换颜色显示方式

let index = 0; function changeType() {   switch (index % 3) {     case 0:       method = "toRgbString";       break;     case 1:       method = "toHex8String";       break;     case 2:       method = "toHslString";       break;   }   index++; } value.onclick = () => {   changeType();   changeBg(); }; 复制代码

源代码

bug巨多无比,我还是太菜了,源码放到了codepen上,想看的话可以看看

Color Picker (codepen.io)

总结

canvas挺好用,线性渐变更好用,但我太菜了。。。


作者:Mancuoj
链接:https://juejin.cn/post/7023255955546570766


文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐