javascript - CSS线性渐变不准确?

标签 javascript html css

对于我的应用程序,我希望制作一个可以提供从 0 度到 360 度的任何色调的调色板。我目前正在使用此代码制作调色板。我们以色调 120(纯绿色)为例:

function drawPalette(hue) {
  var ctx = document.querySelector("canvas").getContext("2d");

  let w = ctx.canvas.width;
  let h = ctx.canvas.height;

  var grH = ctx.createLinearGradient(0, 0, w, 0);
  grH.addColorStop(0, '#fff');
  grH.addColorStop(1, 'hsl(' + hue + ', 100%, 50%)');

  ctx.fillStyle = grH;
  ctx.fillRect(0, 0, w, h);

  var grV = ctx.createLinearGradient(0, 0, 0, h);
  grV.addColorStop(0, 'rgba(0,0,0,0)');
  grV.addColorStop(1, '#000');

  ctx.fillStyle = grV;
  ctx.fillRect(0, 0, w, h);
}

drawPalette(120);
<canvas></canvas>

我遇到的问题是这似乎不是一个完美的渐变。例如,右上角的颜色是 #02FF02 而不是 #00FF00(纯绿色)。您可以使用颜色选择器亲自查看。

有什么方法可以制作可用于调色板的完美线性渐变?

最佳答案

不,梯度返回正确的结果。右上角的像素位于渐变的起点和终点之间,并有一个内插值来反射(reflect)这一点。

想象一下具有单个水平或垂直渐变的单个像素 Canvas 。梯度的起点是[0,0],梯度的终点是[1,0]。我们唯一像素的中间值应该介于起始值和结束值之间。如果我们的起始值为 255,255,255,结束值为 0,255,0,那么唯一的像素应该是 128,255,128,如下所示:

function drawPalette(hue) {
  var ctx = document.querySelector("canvas").getContext("2d");

  let w = ctx.canvas.width;
  let h = ctx.canvas.height;

  var grH = ctx.createLinearGradient(0, 0, w, 0);
  grH.addColorStop(0, '#fff');
  grH.addColorStop(1, 'hsl(' + hue + ', 100%, 50%)');

  ctx.fillStyle = grH;
  ctx.fillRect(0, 0, w, h);

  
  let data = ctx.getImageData(w-1,0, 1, 1).data;
  console.log(data);

}

drawPalette(120);
<canvas width="1" height="1"></canvas>

如果我们有一个十像素乘十像素的 Canvas ,渐变从 0 延伸到 10,最后一列像素的中间超过 9.5 像素。这意味着,渐变的插值应该是渐变起始值和结束值之间的 95%。使用与上面相同的梯度,应该是:13, 255, 13:

function drawPalette(hue) {
  var ctx = document.querySelector("canvas").getContext("2d");

  let w = ctx.canvas.width;
  let h = ctx.canvas.height;

  var grH = ctx.createLinearGradient(0, 0, w, 0);
  grH.addColorStop(0, '#fff');
  grH.addColorStop(1, 'hsl(' + hue + ', 100%, 50%)');

  ctx.fillStyle = grH;
  ctx.fillRect(0, 0, w, h);

  
  let data = ctx.getImageData(w-1,0, 1, 1).data;
  console.log(data);

}

drawPalette(120);
<canvas width="10" height="10"></canvas>

随着 Canvas 变大,应用渐变的第一个/最后一个值与渐变开始/结束值之间的差异会减小。如果您将示例中的 Canvas 更改为 1000x1000 的大小,则由于四舍五入,右上角像素的值为 0,255,0:

function drawPalette(hue) {
  var ctx = document.querySelector("canvas").getContext("2d");

  let w = ctx.canvas.width;
  let h = ctx.canvas.height;

  var grH = ctx.createLinearGradient(0, 0, w, 0);
  grH.addColorStop(0, '#fff');
  grH.addColorStop(1, 'hsl(' + hue + ', 100%, 50%)');

  ctx.fillStyle = grH;
  ctx.fillRect(0, 0, w, h);

  var grV = ctx.createLinearGradient(0, 0, 0, h);
  grV.addColorStop(0, 'rgba(0,0,0,0)');
  grV.addColorStop(1, '#000');

  ctx.fillStyle = grV;
  ctx.fillRect(0, 0, w, h);
  
  let data = ctx.getImageData(w-1,0, 1, 1).data;
  console.log(data);
  
}

drawPalette(120);
<canvas width="1000" height="1000"></canvas>

渐变包括起点和终点之间的像素。如果您不希望它们被渐变化,则必须修改渐变,使其晚一个像素开始,早一个像素结束:

function drawPalette(hue) {
  var ctx = document.querySelector("canvas").getContext("2d");

  let w = ctx.canvas.width;
  let h = ctx.canvas.height;
  
  // to ensure we know we're covering the whole thing:
  ctx.fillRect(0,0,w,h)
  //

  var grH = ctx.createLinearGradient(1, 0, w-2, 0);
  grH.addColorStop(0, '#fff');
  grH.addColorStop(1, 'hsl(' + hue + ', 100%, 50%)');

  ctx.fillStyle = grH;
  ctx.fillRect(0, 0, w, h);

  
  let data = ctx.getImageData(w-1,0, 1, 1).data;
  console.log(data);

}

drawPalette(120);
<canvas width="100" height="100"></canvas>

关于javascript - CSS线性渐变不准确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65639332/

相关文章:

javascript - 如何为两个动态路由创建一个页面?

html - Github Pages 不会从 Git LFS 加载视频

html - 如何水平列出DIV框

css - 在悬停时用图像周围的灰色和文本填充 div 框

html - 如何在 Bootstrap 中垂直居中高度未知的 float 元素?

javascript - 如何确定文本输入中的值偏移?

javascript - 回调 - ReferenceError : Variable is not defined

javascript - 将评分计算为数字

html - 如何在不影响输入的宽度和高度的情况下,将svg图像作为背景图标添加到具有宽度和高度的输入右侧

html - CSS 过渡中的文本