javascript - 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
(纯绿色)。您可以使用颜色选择器自己查看。
有没有办法制作可用于调色板的完美线性渐变?
解决方案
不,渐变返回正确的结果。右上角的像素位于渐变的起点和终点之间,并有一个插值来反映这一点。
想象一下具有单个水平或垂直渐变的单个像素画布。渐变的起点是 [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>
如果我们有一个 10 x 10 像素的画布,渐变从 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>
随着画布变大,应用渐变的第一个/最后一个值与渐变开始/结束值之间的差异会减小。如果您将示例中的画布更改为 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>
推荐阅读
- angular - 如何将表单发送到父组件
- react-admin - 如何支持在资源显示布局上查看其他资源数据
- uwp - 适用于 UWP 应用程序的 Google Cloud Speech API
- c# - 模型类与 DTO 的 Post Action
- tensorflow - 如何在 Mac 上安装 TensorFlow?
- mysql - 尝试将分数分配给列时接收空值
- python - Discord API 401:未经授权的错误
- scala - 适用于 Apache Spark 的 BigQuery 连接器 - 更新分区表
- r - 如何从 rvest 中的元素中刮取 id?
- spring-boot - 春季启动测试,无法加载junit测试的属性文件