我在想办法在js中创建一个类似这样的色轮:javascript - 使用JavaScript创建色轮-LMLPHP。色轮应该有大约4096(*)个像素大小的元素,它们的颜色通过CSSbackground规则设置。
我知道这不是创建颜色选择器的方式,通常情况下,任何东西都不应该有这么多的单像素DOM元素你不需要告诉我这些,也不需要想别的办法来完成。
我还想让每个像素大小的元素左对齐,而不是绝对定位。
(X):4096是所有速记十六进制代码(x x x)的数目,但是色轮没有单色值,除了白色。所以唯一颜色的实际数目是4081(?)
这是我想出来的代码(几乎什么都没有):

var p = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
for(var i = 0; i < p.length; i++)
{
    for(var j = 0; j < p.length; j++)
    {
        for(var k = 0; k < p.length; k++)
        {
            document.write('<div style="background:#' + p[i] + p[j] + p[k] +'"></div>');
        }
    }
}

javascript - 使用JavaScript创建色轮-LMLPHP是我得到的结果(放大10倍),使用以下CSS:
div
{
    float: left;
    width: 10px;
    height: 10px;
}

如你所见,这与我想要的相去甚远。因此,任何帮助都将非常感谢,因为我对如何实现这一点非常迷茫。我有颜色,但我不知道怎么把它们放在轮子里。
编辑:
除非有人碰巧给了我一个非常完整的解决方案,目前看来这比我的技术水平要高一点所以我愿意接受(我想)更容易实现的东西。
基本上,另一种可以接受的输出形式是这样的:javascript - 使用JavaScript创建色轮-LMLPHP

最佳答案

我之前发布了一个答案,它依赖于浏览器将颜色从hsl颜色空间转换为rgb颜色空间。不幸的是,这是一种方法,虽然简单,但没有产生所显示的图像。
为了正确地产生所需的输出,一个更简单的方法是使用HSV颜色模型-一个非常类似于HSL的模型。
当我们使用正确的颜色空间时,为任何给定的像素确定正确的颜色是一个简单的插值3个值-所有这些值都是线性变化的(变化量保持不变)。一端为0,另一端为1,表示中间某点为0.5)
首先,让我们看看您想要的输出,以及我们的hsv输入是如何相对于x和y坐标变化的。我们将从更易于可视化和创建的平面条开始。
扁钢
javascript - 使用JavaScript创建色轮-LMLPHP
关于这张图片,我们可以观察到以下情况:
色调范围从左边缘的0到右边缘的360。
sat的范围从上边缘的0到1,在顶部之间的中间
&底部边缘。超过1的点,它被夹在1。
VAL的范围从顶部和底部之间的0到顶部和底部之间的1
底部。在点为0之前,它被钳制为0。
现在,让我们看看同一张图片的轮子表示。
色轮
javascript - 使用JavaScript创建色轮-LMLPHP
如果你仔细看,你会发现,当包装成一个圆圈时,色带会产生色轮。车轮中心对应于带材的上边缘,外缘对应于下边缘。
这也是为什么我们可以显示,原来的车轮,你显示的是一个有点不准确的颜色空间表示,因为它有红色的左边缘基本上,你的图像是水平翻转的。;)
好的,这就显示了图像与HSV颜色空间的关系接下来,我们真的需要能够在飞行中创造它们。这是相当直接的,现在我们有计划如何去做。
完成后,我们将得到两张画布-这些是我用于注释的图像从那以后,你可以有几种方法来解决这个问题。
您可以:允许用户选择任何他们喜欢的颜色,然后再从短手十六进制值集中返回最接近的颜色。
或者你可以:备份一点,只在画布上设置那些在同一组短手值中的颜色。
一个需要更长的时间来计算所选的颜色,而另一个则需要更长的时间来计算初始图像。
我把实现的那一部分留给了您,而不是选择:避开这么多DOM元素的想法,只使用2个画布,而且,根据我链接到@MDN的代码,简单地按照选择的颜色选择。

function newEl(tag){return document.createElement(tag)}

window.addEventListener('load', onDocLoaded, false);
function onDocLoaded(evt)
{
	var strip = makeCanvas();
	strip.addEventListener('mousemove', pick);
	document.body.appendChild( strip );

	var wheel = makeWheel(256);
	wheel.addEventListener('mousemove', pick);
	document.body.appendChild( wheel );
}


var hsv2rgb = function(hsv) {
  var h = hsv.hue, s = hsv.sat, v = hsv.val;
  var rgb, i, data = [];
  if (s === 0) {
    rgb = [v,v,v];
  } else {
    h = h / 60;
    i = Math.floor(h);
    data = [v*(1-s), v*(1-s*(h-i)), v*(1-s*(1-(h-i)))];
    switch(i) {
      case 0:
        rgb = [v, data[2], data[0]];
        break;
      case 1:
        rgb = [data[1], v, data[0]];
        break;
      case 2:
        rgb = [data[0], v, data[2]];
        break;
      case 3:
        rgb = [data[0], data[1], v];
        break;
      case 4:
        rgb = [data[2], data[0], v];
        break;
      default:
        rgb = [v, data[0], data[1]];
        break;
    }
  }
  return rgb;
};

function clamp(min, max, val)
{
	if (val < min) return min;
	if (val > max) return max;
	return val;
}

function makeCanvas()
{
	var can, ctx;
	can = newEl('canvas');
	ctx = can.getContext('2d');
	can.width = 360;
	can.height = 100;
	var span = newEl('span');

	var imgData = ctx.getImageData(0,0,360,100);
	var xPos, yPos, index;
	var height=imgData.height, width=imgData.width;


	for (yPos=0; yPos<height; yPos++)
	{
		for (xPos=0; xPos<width; xPos++)
		{
			// this is the point at which the S & V values reach
            // the peaks or start to change. 2 means height/2
            // so a divisor of 3 would mean the 'break-points'
            // were at the 1/3 and 2/3 positions
            // while a divisor of 4 would imply 1/4 and 3/4
            //
            // Have a look at the generated images using the eye-
            // dropper tool of an image program (Gimp, Photoshop,
            // etc) that allows you to choose the HSV colour
            // model, to get a better idea of what I'm saying
            // here.
            var divisor = 2;

			var hue = xPos;
			var sat = clamp(0, 1, yPos / (height/divisor) );
			var val = clamp(0, 1, (height-yPos) / (height/divisor) );
			var rgb = hsv2rgb( {hue:hue, sat:sat, val:val} );

			index = 4 * (xPos + yPos*360);

            imgData.data[ index + 0 ] = rgb[0] * 255;	// r
			imgData.data[ index + 1 ] = rgb[1] * 255;	// g
			imgData.data[ index + 2 ] = rgb[2] * 255;	// b
			imgData.data[ index + 3 ] = 255;	// a
		}
	}
	ctx.putImageData(imgData, 0, 0);
	return can;
}

// see the comment in the above function about the divisor. I've
// hard-coded it here, to 2
// diameter/2 corresponds to the max-height of a strip image
function makeWheel(diameter)
{
	var can = newEl('canvas');
	var ctx = can.getContext('2d');
	can.width = diameter;
	can.height = diameter;
	var imgData = ctx.getImageData(0,0,diameter,diameter);
	var maxRange = diameter / 2;

	for (var y=0; y<diameter; y++)
	{
		for (var x=0; x<diameter; x++)
		{
			var xPos = x - (diameter/2);
			var yPos = (diameter-y) - (diameter/2);


			var polar = pos2polar( {x:xPos, y:yPos} );
			var sat = clamp(0,1,polar.len / ((maxRange/2)));
			var val = clamp(0,1, (maxRange-polar.len) / (maxRange/2) );

			var rgb = hsv2rgb( {hue:polar.ang, sat:sat, val:val} );

			var index = 4 * (x + y*diameter);
			imgData.data[index + 0] = rgb[0]*255;
			imgData.data[index + 1] = rgb[1]*255;
			imgData.data[index + 2] = rgb[2]*255;
			imgData.data[index + 3] = 255;
		}
	}
	ctx.putImageData(imgData, 0,0);
	return can;
}

function deg2rad(deg)
{
	return (deg / 360) * ( 2 * Math.PI );
}
function rad2deg(rad)
{
	return (rad / (Math.PI * 2)) * 360;
}

function pos2polar(inPos)
{
	var vecLen = Math.sqrt( inPos.x*inPos.x + inPos.y*inPos.y );
	var something = Math.atan2(inPos.y,inPos.x);
	while (something < 0)
		something += 2*Math.PI;

	return { ang: rad2deg(something), len: vecLen };
}



function pick(event)
{
	var can = this;
	var ctx = can.getContext('2d');
	var color = document.getElementById('color');

  var x = event.layerX;
  var y = event.layerY;
  var pixel = ctx.getImageData(x, y, 1, 1);
  var data = pixel.data;
  var rgba = 'rgba(' + data[0] + ',' + data[1] +
             ',' + data[2] + ',' + (data[3] / 255) + ')';
  color.style.background =  rgba;
  color.textContent = rgba;
}

canvas
{
	border: solid 1px red;
}

<div id="color" style="width: 200px; height: 50px; float: left;"></div>

09-28 03:19