javascript - 如何在没有画布的情况下创建颜色选择器?
问题描述
我想创建一个没有画布或 JavaScript 库的自定义颜色选择器。我找到了一些使用画布的网站,但是否可以只使用背景图片?这是我的代码:
#rainbow{
height: 15px;
background-color: red;
background-image: linear-gradient(to right, Red , Orange, Yellow, Green, Blue, Indigo, Violet);
border-radius: 3px;
border: 1px solid black;
margin: 5px;
}
#saturation{
height:15px;
background-color:red;
background-image: linear-gradient(to left, red, gray);
border-radius: 3px;
border: 1px solid black;
margin: 5px;
}
#grayscale{
height:15px;
background-color:gray;
background-image: linear-gradient(to right, black, white);
margin: 5px;
border-radius: 3px;
border:1px solid black;
}
#color-picker{
background-color:whitesmoke;
box-shadow:lightgray 2px 2px;
padding: 10px;
border-radius: 7px;
<!DOCTYPE html>
<html>
<body>
<div id="color-picker">
<div id="rainbow"></div>
<div id="grayscale"></div>
<div id="saturation"></div>
<label for="hex">HEX:</label>
<input id="hex" type="text" value="#ffffff"/>
<label for="rgb">RGB:</label>
<input id="rgb" type="text" value="255,255,255"/>
<label for="hsl">HSL:</label>
<input id="hsl" type="text" value="0,0,100"/>
</div>
</body>
</html>
解决方案
该问题使用线性渐变来填充颜色选择器图表。这会在 x 方向(但不是 y)上给出颜色,并且由于渐变是线性的,我们可以通过在开始它所在部分的颜色(例如红色)和结束其所在部分的颜色(橙色)取决于鼠标沿该部分的距离。
我们要使用的组件是:
listening for a mouse move event
event.clientX - this gives the x offset of the mouse within an element
a formula for calculating the rgb values (see code in the snippet)
conversions from rgb to hex and hsl so the relevant input elements can be updated
cursor as a semi transparent svg circle
请注意,我们在 rgb 中工作,因为选择了线性一维颜色图表,然后转换为 hsl 和 hex,因此可以显示所有 3 种颜色。
let rgbRainbow= [[255,0,0], [255, 255, 0], [255, 165, 0], [0, 128, 0], [0, 0, 255], [75, 0, 130], [238, 130, 238]];
let rainbow = document.getElementById('rainbow');
let rainbowWidth = rainbow.offsetWidth;
let sectionWidth = rainbowWidth /(rgbRainbow.length - 1);
// adapted from https://stackoverflow.com/questions/22218140/calculate-the-color-at-a-given-point-on-a-gradient-between-two-colors
function colorAt(x) {
let section = Math.floor(x / sectionWidth);
let pc = (x%sectionWidth)/sectionWidth;
let c1 = rgbRainbow[section];
let c2 = (section >= (rgbRainbow.length-1)) ? c1 : rgbRainbow[section + 1]; // there appears to be an end affect
return [Math.floor(c1[0] + pc*(c2[0]-c1[0])), Math.floor(c1[1] + pc*(c2[1]-c1[1])), Math.floor(c1[2] + pc*(c2[2]-c1[2]))];
}
// adapted from https://gmigdos.wordpress.com/2011/01/13/javascript-convert-rgb-values-to-hsl/
function rgb2hsl(rgbArr){ //returns a string of this form 'H,S,L
var r1 = rgbArr[0] / 255;
var g1 = rgbArr[1] / 255;
var b1 = rgbArr[2] / 255;
var maxColor = Math.max(r1,g1,b1);
var minColor = Math.min(r1,g1,b1);
var L = (maxColor + minColor) / 2 ;
var S = 0;
var H = 0;
if(maxColor != minColor){
if(L < 0.5){
S = (maxColor - minColor) / (maxColor + minColor);
}else{
S = (maxColor - minColor) / (2.0 - maxColor - minColor);
}
if(r1 == maxColor){
H = (g1-b1) / (maxColor - minColor);
}else if(g1 == maxColor){
H = 2.0 + (b1 - r1) / (maxColor - minColor);
}else{
H = 4.0 + (r1 - g1) / (maxColor - minColor);
}
}
L = Math.floor(L * 100);
S = Math.floor(S * 100);
H = Math.floor(H * 60);
if(H<0){
H += 360;
}
return H + ',' + S + ',' + L;
}
function rgb2hex(rgbArr) {
function intToHex(i) {
let hex = i.toString(16);
return hex.length == 1 ? "0" + hex : hex;
}
return "#" + intToHex(rgbArr[0]) + intToHex(rgbArr[1]) + intToHex(rgbArr[2]);
}
function mouseMovedTo(x) {
let c = colorAt(x);
document.getElementById('color').style.backgroundColor = 'rgb('+c[0]+','+c[1]+','+c[2]+')';
document.getElementById('rgb').value = c;
document.getElementById('hsl').value = rgb2hsl(c);
document.getElementById('hex').value = rgb2hex(c);
}
#rainbow{
height: 150px;
background-color: red;
background-image: linear-gradient(to right, Red , Orange, Yellow, Green, Blue, Indigo, Violet);
border-radius: 3px;
border: 1px solid black;
cursor: url("data:image/svg+xml,%3Csvg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='16px' height='16px' xml:space='preserve'%3E %3Ccircle cx='8' cy='8' r='8' fill='rgba(0,0,0,0.2)' /%3E %3C/svg%3E") 8 8, auto;
}
#grayscale{
height:15px;
background-color:gray;
background-image: linear-gradient(to right, black, white);
margin-top: 5px;
border-radius: 3px;
border:1px solid black;
}
#color-picker{
background-color:whitesmoke;
box-shadow:lightgray 2px 2px;
padding: 10px;
border-radius: 7px;
}
<div id="color-picker" >
<div id="rainbow" onmousemove="mouseMovedTo(event.clientX);"></div>
<div id="grayscale"></div>
<label for="hex">HEX:</label>
<input id="hex" type="text" value="#ffffff"/>
<label for="rgb">RGB:</label>
<input id="rgb" type="text" value="255,255,255"/>
<label for="hsl">HSL:</label>
<input id="hsl" type="text" value="0,0,100"/>
<div id="color" style="width:100px; height: 2em; border: 1px solid black;">Current color</div>
</div>
推荐阅读
- python - 带有 RPi (python3) RuntimeError 的 AlarmSystem:已为此 GPIO 通道启用冲突边缘检测
- php - Mod重写问题 - 网址/路径可以输入两次
- c - xdp 代码计算 icmp 校验和的验证程序失败?
- python - How to use 'Polyline'
- arrays - CastError:路径“_id”处的值“xxx”转换为 ObjectId 失败
- kotlin - Kotlin/Native Basic Image manipulation
- amazon-web-services - 基于 AWS 中主机的传出规则
- php - 正在从 productcolours 表中获取颜色 ID,但如何从颜色表中获取颜色名称
- python - 无法写入 jupyter 服务器中的文件
- php - How to Add Order Number, Order Date and Hour in a Woocommerce Email Template