colorpicker
文章目录
需求分析:
以下四种方案, 前三种为点击色块选择颜色, 第四种为滑动/拖拽选颜色, 所以分为两种实现类型-色块或者色带, 做出两种colorpicker.
第一种方案的颜色选择器: 点击色块选择颜色
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>第一种方法:点击方块选择颜色</title>
<style>
* {
margin: 0;
padding: 0;
}
#colorpicker {
width: 230px;
height: 350px;
margin: auto;
padding: 2px;
background-color: #f1f1f1;
border: 1px solid black;
text-align: center;
}
.color_container {
display: flex;
width: 220px;
height: 210px;
margin: 5px;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
align-items: center;
background-color: #cec7c7;
}
.rgb_value {
margin: 10px;
}
.rgb_value input {
display: inline-block;
width: 70px;
}
</style>
</head>
<body>
<div id="colorpicker">
无颜色
<div class="color_container"></div>
<div class="rgb_value">
RGB值为 <input type="text" value="">
</div>
</div>
<script>
let colorpicker = document.getElementById('colorpicker');
let color_container = document.querySelector('.color_container');
/* 创建颜色代码数组 */
// 因为找不到这个案例的颜色变化的规律, 所以用了笨方法, 写死了颜色数组
let color_array = [
"#ffffff", "#e5e4e4", "#d9d8d8", "#c0bdbd", "#a7a4a4", "#8e8a8b", "#827e7f", "#767173", "#5c585a", "#000000",
"#fefcdf", "#fef4c4", "#feed9b", "#fee573", "#ffed43", "#f6cc0b", "#f6cc0b", "#c9a601", "#ad8e00", "#8c7301",
"#ffded3", "#ffc4b0", "#ff9d7d", "#ff7a4e", "#ff6600", "#e95d00", "#d15502", "#ba4b01", "#a44201", "#8d3901",
"#ffd2d0", "#ffbab7", "#fe9a95", "#ff7a73", "#ff483f", "#fe2419", "#f10b00", "#d40a00", "#940000", "#6d201b",
"#ffdaed", "#ffb7dc", "#ffa1d1", "#ff84c3", "#ff57ac", "#fd1289", "#ec0078", "#d6006d", "#bb005f", "#9b014f",
"#fcd6fe", "#fbbcff", "#f9a1fe", "#f784fe", "#f564fe", "#f546ff", "#f328ff", "#d801e5", "#c001cb", "#8f0197",
"#e2f0fe", "#c7e2fe", "#add5fe", "#92c7fe", "#6eb5ff", "#48a2ff", "#2690fe", "#0162f4", "#013add", "#0021b0",
"#d3fdff", "#acfafd", "#7cfaff", "#4af7fe", "#1de6fe", "#01deff", "#00cdec", "#01b6de", "#00a0c2", "#0084a0",
"#edffcf", "#dffeaa", "#d1fd88", "#befa5a", "#a8f32a", "#8fd80a", "#79c101", "#3fa701", "#307f00", "#156200",
"#d4c89f", "#daad88", "#c49578", "#c2877e", "#ac8295", "#c0a5c4", "#969ac2", "#92b7d7", "#80adaf", "#9ca53b",
];
// 遍历数组,添加对应颜色的小方块
for (let color of color_array) {
color_container.innerHTML += `<div value="${
color}" style="background: ${
color}; width: 15px; height: 15px; margin: 3px; cursor: pointer;"></div>`
}
//加点击事件
let color_squares = document.querySelectorAll('.color_square');
let rgb_value = document.querySelector('.rgb_value').querySelector('input');
color_container.addEventListener('click', function(event) {
//console.log(event.target);
//div直接获取name和value属性获取不到, 得用getAttribute()
rgb_value.value = event.target.getAttribute('value');
})
</script>
</body>
</html>
效果如下:
进行了改进, 把整个颜色选择器封装到js文件里, 通过appendChild的形式添加盒子和样式, 使用的时候就只需要添加js文件即可:
/* 1. 整体的父盒子部分 */
let colorpicker = document.createElement("div");
colorpicker.style = `
width: 230px;
height: 300px;
margin: auto;
padding: 2px;
background-color: #f1f1f1;
border: 1px solid black;
text-align: center;
`;
colorpicker.innerText = '点击选择颜色';
/* 2. 选色盒子部分 */
let color_container = document.createElement("div");
color_container.style = `
display: flex;
width: 220px;
height: 210px;
margin: 5px;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
align-items: center;
background-color: #cec7c7;
`;
/* 创建颜色代码数组 */
let color_array = [
"#ffffff", "#e5e4e4", "#d9d8d8", "#c0bdbd", "#a7a4a4", "#8e8a8b", "#827e7f", "#767173", "#5c585a", "#000000",
"#fefcdf", "#fef4c4", "#feed9b", "#fee573", "#ffed43", "#f6cc0b", "#f6cc0b", "#c9a601", "#ad8e00", "#8c7301",
"#ffded3", "#ffc4b0", "#ff9d7d", "#ff7a4e", "#ff6600", "#e95d00", "#d15502", "#ba4b01", "#a44201", "#8d3901",
"#ffd2d0", "#ffbab7", "#fe9a95", "#ff7a73", "#ff483f", "#fe2419", "#f10b00", "#d40a00", "#940000", "#6d201b",
"#ffdaed", "#ffb7dc", "#ffa1d1", "#ff84c3", "#ff57ac", "#fd1289", "#ec0078", "#d6006d", "#bb005f", "#9b014f",
"#fcd6fe", "#fbbcff", "#f9a1fe", "#f784fe", "#f564fe", "#f546ff", "#f328ff", "#d801e5", "#c001cb", "#8f0197",
"#e2f0fe", "#c7e2fe", "#add5fe", "#92c7fe", "#6eb5ff", "#48a2ff", "#2690fe", "#0162f4", "#013add", "#0021b0",
"#d3fdff", "#acfafd", "#7cfaff", "#4af7fe", "#1de6fe", "#01deff", "#00cdec", "#01b6de", "#00a0c2", "#0084a0",
"#edffcf", "#dffeaa", "#d1fd88", "#befa5a", "#a8f32a", "#8fd80a", "#79c101", "#3fa701", "#307f00", "#156200",
"#d4c89f", "#daad88", "#c49578", "#c2877e", "#ac8295", "#c0a5c4", "#969ac2", "#92b7d7", "#80adaf", "#9ca53b",
];
// 遍历数组,添加pick按钮至容器
for (let color of color_array) {
color_container.innerHTML += `<div value="${
color}" style="background: ${
color}; width: 15px; height: 15px; margin: 3px; cursor: pointer;"></div>`
}
/* 3. 显示颜色RGB数值的部分 */
let show_rgb = document.createElement('div');
show_rgb.innerHTML = `RGB值为 <input type="text" value="">`;
/* 4. 最后加上点击事件 */
let rgb_value = show_rgb.querySelector('input');
color_container.addEventListener('click', function(event) {
console.log(event.target);
//div直接获取name属性获取不到, 得用getAttribute()
rgb_value.value = event.target.getAttribute('value');
})
/* append进body里 */
colorpicker.appendChild(color_container);
colorpicker.appendChild(show_rgb);
document.body.appendChild(colorpicker);
第二种方案颜色选择器:拖拽或者点击色带进行选择
第二种方案的功能分析(根据Photoshop功能分析):
- 左边色块从左到右为可见光光谱, 右边为明暗色带;
- 同时输出HSL和RGB值, 所以获取HSL后再转换为RGB: HSL和RGB值互相转换
- 右侧明暗发生变化时, 左边色块整体的颜色明暗也会随之发生变化;
- 左边色块中的圆形可以点击/拖拽选择颜色, 右边明暗带的三角形可以点击/拖拽改变明暗;
色带部分用如下css的linear-gradient实现:
.color_wheel {
/* 【红0%,黄17%,青34%,天蓝50%,蓝67%,紫84%,红100%】 */
background: linear-gradient(to bottom, transparent, rgba(255, 255, 255, 1) 100%), linear-gradient(to right, rgb(255, 0, 0) 0%, rgb(255, 255, 0) 17%, rgb(0, 255, 0)34%, rgb(0, 255, 255) 50%, rgb(0, 0, 255) 67%, rgb(255, 0, 255) 84%, rgb(255, 0, 0) 100%);
}
样式补充完成后效果如下:
接下来实现既可以点击选择颜色,又可以拖拽选色圆形的功能:
/* 下面实现: 点击后drag移动到鼠标位置 && 拖拽功能, 并且控制drag在色块区域内 */
let color_wheel = document.querySelector('.color_wheel');
let drag_circle = document.querySelector('.circle');
//获取原点在页面中的坐标
let basepointX = color_wheel.offsetLeft;
let basepointY = color_wheel.offsetTop;
//封装一个函数,控制drag在色块内
function changeDragPosition(dragX, dragY) {
if (dragX >= 0 && dragX <= 200) {
drag_circle.style.left = dragX - 5 + 'px';
}
if (dragY >= 0 && dragY <= 250) {
drag_circle.style.top = dragY - 5 + 'px';
}
if (dragX <= 0) {
drag_circle.style.left = '0px';
}
if (dragY <= 0) {
drag_circle.style.top = '0px';
}
if (dragX >= 190) {
drag_circle.style.left = '190px';
}
if (dragY >= 240) {
drag_circle.style.top = '240px';
}
}
//点击时,drag移动到鼠标位置,6+4=10是圆drag的直径
color_wheel.addEventListener('mouseup', function(event) {
let dragX = event.pageX - basepointX;
let dragY = event.pageY - basepointY;
changeDragPosition(dragX, dragY);
})
//drag可以拖拽
drag_circle.addEventListener('mousedown', function(event) {
//当鼠标按下, 就获得鼠标在drag内的坐标
let initX = (event.pageX - basepointX) - drag_circle.offsetLeft;
let initY = (event.pageY - basepointY) - drag_circle.offsetTop;
console.log(initX);
//鼠标移动的时候,把鼠标在color_wheel中的坐标,减去 鼠标在drag内的坐标就是模态框drag的left和top值
document.addEventListener('mousemove', moveDrag);
function moveDrag(event) {
let dragX = (event.pageX - basepointX) - initX + 5;
let dragY = (event.pageY - basepointY) - initY + 5;
console.log(dragX, dragY);
changeDragPosition(dragX, dragY);
}
//鼠标弹起,就让鼠标移动事件移除
document.addEventListener('mouseup', function() {
document.removeEventListener('mousemove', moveDrag);
})
});
同理完成点击/拖拽三角形,控制明暗的功能;
接下来完成根据坐标,输出HSL和RGB颜色的功能: 练习es6语法和面向对象的思想
观察可得容易从坐标得到HSL的值: 可见光色块部分,从左到右改变横坐标时SL不变,H(色相hue)从0°变为360°;从上到下改变纵坐标时, HL不变, S从100%变为0%; 所以,先获得HSL比较容易,最后转化成RGB一起输出.
class ColorValue {
constructor(h, s, l, r, g, b) {
this.H = h; //(h∈[0,1])*[0°,360°]
this.S = s; //(s∈[0,1])*100%
this.L = l; //(l∈[0,1])*100%
this.R = r;
this.G = g;
this.B = b;
}
position2Hsl(x, y, z) {
//x,y是相对色块左上角的坐标,z是明暗带往下滑动的相对距离
this.H = (x / 200); //x∈[0,200px]
this.S = (1 - (y / 250)); //y∈[0,250px]
this.L = (1 - (z / 250)); //z∈[0,250px]
}
HSL2RGB() {
//H, S and L input range = 0 ÷ 1.0
//R, G and B output range = 0 ÷ 255
if (this.S == 0) {
this.R = this.L;
this.G = this.L;
this.B = this.L;
} else {
var hue2rgb = function hue2rgb(p, q, t) {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
return p;
}
let q = this.L < 0.5 ? this.L * (1 + this.S) : (this.L + this.S) - (this.S * this.L);
let p = 2 * this.L - q;
this.R = 255 * hue2rgb(p, q, this.H + (1 / 3))
this.G = 255 * hue2rgb(p, q, this.H)
this.B = 255 * hue2rgb(p, q, this.H - (1 / 3))
}
}
}
document.addEventListener('mouseup', outputColor);
let hslrgb = document.querySelectorAll('input'); //伪数组[h,s,l,r,g,b]
/* 根据坐标输出颜色值 */
function outputColor(event) {
//x,y是相对色块左上角的坐标,z是明暗带往下滑动的相对距离
let x = drag_circle.offsetLeft + 5;
let y = drag_circle.offsetTop + 5;
let z = drag_triangle.offsetTop;
let color_value = new ColorValue();
color_value.position2Hsl(x, y, z);
color_value.HSL2RGB();
console.log(color_value);
hslrgb[0].value = color_value.H * 360;
hslrgb[1].value = color_value.S * 100;
hslrgb[2].value = color_value.L * 100;
hslrgb[3].value = color_value.R;
hslrgb[4].value = color_value.G;
hslrgb[5].value = color_value.B;
}
最后完成: 拉动右侧明暗带, 左侧色块整体的明暗发生变化
let L = (1 - this.offsetTop / 240);
document.addEventListener('mousemove', changeColorL(L));
/* 每次改变light,都会更改拾色区整体亮度 */
function changeColorL(L) {
let rgb = L * 255;
color_wheel.style.background = 'linear-gradient(to bottom, rgba(' + rgb + ', ' + rgb + ', ' + rgb + ', .6) 0%, rgba(' + rgb + ', ' + rgb + ', ' + rgb + ', 1) 100%), linear-gradient(to right, rgb(255, 0, 0) 0%, rgb(255, 255, 0) 17%, rgb(0, 255, 0)34%, rgb(0, 255, 255) 50%, rgb(0, 0, 255) 67%, rgb(255, 0, 255) 84%, rgb(255, 0, 0) 100%)';
//`linear-gradient(to bottom, rgba(${rgb}, ${rgb}, ${rgb}, .3) 0%, rgba(${rgb}, ${rgb}, ${rgb}, 1) 100%), linear-gradient(to right, rgb(255, 0, 0) 0%, rgb(255, 255, 0) 17%, rgb(0, 255, 0)34%, rgb(0, 255, 255) 50%, rgb(0, 0, 255) 67%, rgb(255, 0, 255) 84%, rgb(255, 0, 0) 100%)`;
}