计算二维角度线性渐变上特定点的颜色

问题描述 投票:0回答:1

我需要计算具有指定宽度、长度、开始和结束颜色以及特定角度的线性渐变上像素的颜色。

经过几天的研究并试图理解其中的机制,以及一些 AI 的帮助(顺便说一句,经过 30 多次修改后没有产生有效的结果),我想出了这个方法:

function getColorAtCoordinate(x, y, width, height, angle, startColor, endColor) {

   // angle to radians
  const angleRad = (angle * Math.PI) / 180; 

   // get diagonal length of rectangle
  const diagonalLength = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)); 

   // calculate distance from start (top-left) of rectangle
  const distanceFromStart = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));

   // calculate distance from end (bottom-right corner) of rectangle
  const distanceFromEnd = Math.sqrt(Math.pow(x - width, 2) + Math.pow(y - height, 2)); 

   // calculate position of point between start and end of gradient
  const position = distanceFromStart / (distanceFromStart + distanceFromEnd); 

   // calculate color components
  const red = Math.round(startColor.r + (endColor.r - startColor.r) * position);
  const green = Math.round(startColor.g + (endColor.g - startColor.g) * position);
  const blue = Math.round(startColor.b + (endColor.b - startColor.b) * position);

   // return string
  return "rgb(" + red + ", " + green + ", " + blue + ")";

}         
      

问题是函数似乎没有正确考虑角度。

为了测试它,我写了一个小函数,使用

getColorAtCoordinate
函数逐个像素地在画布上绘制渐变。

我提供了一个片段和一个 链接到 jsFiddle

我正在绘制两个具有相同颜色和尺寸但角度不同(分别为 0 和 135)的画布元素。如您所见,两个画布元素结果完全相同。我试图找出原因,我认为这是因为对于 0 或 180 度以外的角度,起点和终点的距离计算不正确。

数学不是我的强项。也许有人可以启发我。

function getColorAtCoordinate(x, y, width, height, angle, startColor, endColor) {
  const angleRad = (angle * Math.PI) / 180;
  const diagonalLength = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));
  const distanceFromStart = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
  const distanceFromEnd = Math.sqrt(Math.pow(x - width, 2) + Math.pow(y - height, 2));
  const position = distanceFromStart / (distanceFromStart + distanceFromEnd);
  const red = Math.round(startColor.r + (endColor.r - startColor.r) * position);
  const green = Math.round(startColor.g + (endColor.g - startColor.g) * position);
  const blue = Math.round(startColor.b + (endColor.b - startColor.b) * position);
  return "rgb(" + red + ", " + green + ", " + blue + ")";
}         

function drawGradientCanvas(width, height, angle, startColor, endColor) {
  const canvas = document.createElement('canvas');
  canvas.width = width;
  canvas.height = height;
  const ctx = canvas.getContext('2d');
  for (let y = 0; y < height; y++) {
    for (let x = 0; x < width; x++) {
      const color = getColorAtCoordinate(x, y, width, height, angle, startColor, endColor);
      ctx.fillStyle = color;
      ctx.fillRect(x, y, 1, 1);
    }
  }
  document.addEventListener('DOMContentLoaded', function() {
    document.body.appendChild(canvas);
  });
}

drawGradientCanvas(1057,404,0,{r:87,g:154,b:209},{r:31,g:103,b:157});
drawGradientCanvas(1057,404,135,{r:87,g:154,b:209},{r:31,g:103,b:157});

javascript math interpolation gradient linear-gradients
1个回答
0
投票

事实证明,这比我预期的要棘手。以下功能仅供参考。您需要进行一些错误检查以确保输出不会超出范围并决定如何避免被零除等。

function getColorAtCoordinate(x, y, width, height, angle, startColor, endColor) {
  const angleRad = (angle * Math.PI) / 180;
  const sinangle = Math.sin(angleRad);
  const cosangle = Math.cos(angleRad);
  const D = width * cosangle + height * sinangle;
  const s = x * cosangle + y * sinangle;  
  const colorgradr = (endColor.r - startColor.r)/D;
  const red = Math.round(startColor.r + s*colorgradr);
  const colorgradg = (endColor.g - startColor.g)/D;
  const green = Math.round(startColor.g + s*colorgradg);
  const colorgradb = (endColor.b - startColor.b)/D;
  const blue = Math.round(startColor.b + s*colorgradb);
  return "rgb(" + red + ", " + green + ", " + blue + ")";
}          

我测试了你在 jsfiddle 链接中给我的预期输出,但由于某种原因,渐变没有出现在图形中。代码的另一部分肯定有问题。我的数学比 Javascript 好,所以剩下的就交给你吧。

getColorAtCoordinate(200, 300, 1057, 404, 30, {r:87,g:154,b:209},{r:31,g:103,b:157}) = rgb(71, 139, 194) 
© www.soinside.com 2019 - 2024. All rights reserved.