You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

二维带角度线性渐变特定点颜色计算问题求助

线性渐变角度参数失效的修复方案

我需要实现一个函数,计算指定宽度、高度、起止颜色及角度的线性渐变中某像素的颜色。目前编写的getColorAtCoordinate函数无法正确处理角度参数——测试时设置0°和135°绘制Canvas,结果完全一致。推测是角度非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});

问题根源

原代码的核心错误是完全忽略了角度参数:distanceFromStart和distanceFromEnd计算的是点到固定两点(0,0)和(width,height)的距离,与传入的angle无关,导致所有角度下的渐变逻辑都等同于对角线渐变,自然输出一致。

修复方案

要正确实现角度化线性渐变,需要:

  1. 根据角度计算渐变的方向向量
  2. 计算画布上所有点在该方向上的投影值,确定渐变的覆盖范围
  3. 通过当前点的投影值归一化得到颜色混合比例

修正后的getColorAtCoordinate函数:

function getColorAtCoordinate(x, y, width, height, angle, startColor, endColor) {
  // 将角度转换为弧度,适配Canvas y轴向下的坐标系
  const angleRad = (angle * Math.PI) / 180;
  // 计算渐变方向的单位向量,用于投影计算
  const dirX = Math.cos(angleRad);
  const dirY = Math.sin(angleRad);

  // 计算画布四个顶点在渐变方向上的投影值
  const projections = [
    dirX * 0 + dirY * 0,          // 左上角(0,0)
    dirX * width + dirY * 0,      // 右上角(width,0)
    dirX * 0 + dirY * height,     // 左下角(0,height)
    dirX * width + dirY * height  // 右下角(width,height)
  ];

  // 确定投影的极值,保证渐变覆盖整个画布
  const minProj = Math.min(...projections);
  const maxProj = Math.max(...projections);

  // 计算当前点的投影值并归一化,得到颜色混合比例
  const pointProj = dirX * x + dirY * y;
  const position = (pointProj - minProj) / (maxProj - minProj);

  // 计算最终RGB颜色值
  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})`;
}

关键逻辑说明

  • 方向向量:dirX和dirY是角度对应的单位向量,用于将画布上的点投影到渐变方向线上,是实现角度渐变的核心。
  • 投影范围:通过画布四个顶点的投影值确定渐变的起止边界,确保渐变完全覆盖画布区域。
  • 归一化比例:将当前点的投影值映射到[0,1]区间,直接对应起止颜色的混合比例,保证渐变效果随角度正确变化。

替换原函数后,0°(水平渐变)和135°(从右上到左下渐变)的效果会呈现明显差异,符合预期。

内容的提问来源于stack exchange,提问作者SQRCAT

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 16:53:14