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

如何获取Canvas实现的轮盘顶部箭头下方的颜色?

解决Canvas轮盘箭头下方颜色判断错误的问题

问题分析

你的轮盘绘制时,每个扇形的起始角度是基于**向上方向(-90度偏移)的,但停止角度计算时用的是Canvas默认的向右方向(0度)**作为基准,导致角度和扇形的对应关系错位,所以日志输出的颜色和实际箭头下方的颜色不符。另外,减速逻辑里的velocity = velocity - 2会导致速度骤降,影响最终停止位置的准确性,需要调整。


解决方案一:修正角度计算逻辑

调整停止角度的计算,让它和绘制轮盘时的角度基准一致:

  1. 把计算出的stopDegree减去90度,转换为绘制时的坐标系
  2. 处理负数角度(加360度取模),确保在0-360范围内
  3. 重新匹配对应的扇形

同时优化减速逻辑,去掉导致速度突变的代码,保持平滑减速。

修改后的核心代码片段

// 替换原停止角度计算部分
let stopDegree = (degree - rotation / Math.PI * 180 - 90) % 360;
// 处理负数角度
if (stopDegree < 0) stopDegree += 360;

// 去掉这行速度突变的代码
// if (progress >= spinTime - 2000) velocity = velocity - 2;

解决方案二:通过像素颜色直接获取(更直观)

如果觉得角度计算容易出错,可以直接获取箭头位置的像素颜色,步骤如下:

  1. 确定箭头在Canvas上的坐标:箭头位于Canvas顶部中心,坐标为(canvas.width/2, 30)(避开边框)
  2. 使用ctx.getImageData获取该点的像素颜色
  3. 对比颜色数组,找到匹配的颜色

修改后的核心代码片段

// 替换原角度计算逻辑
const arrowX = canvas.width / 2;
const arrowY = 30;
// 重置画布变换,确保获取正确像素
ctx.save();
ctx.setTransform(1, 0, 0, 1, 0, 0);
const pixel = ctx.getImageData(arrowX, arrowY, 1, 1).data;
ctx.restore();

// 匹配RGB值到颜色名称
function getColorName(r, g, b) {
  if (r === 255 && g === 0 && b === 0) return "red";
  if (r === 255 && g === 255 && b === 0) return "yellow";
  if (r === 0 && g === 0 && b === 255) return "blue";
  if (r === 255 && g === 165 && b === 0) return "orange";
  if (r === 128 && g === 0 && b === 128) return "purple";
  return "unknown";
}

const color = getColorName(pixel[0], pixel[1], pixel[2]);
const segmentNumber = colors.indexOf(color) + 1;

console.log(
  "The roulette stopped at segment " +
    segmentNumber +
    " (color: " +
    color +
    ")"
);

完整修正版JavaScript代码(方案一)

const canvas = document.getElementById("roulette-canvas");
const ctx = canvas.getContext("2d");
const spinButton = document.getElementById("spin-button");
const segments = 5;
const segmentSize = 360 / segments;
const colors = ["red", "yellow", "blue", "orange", "purple"];
const spinTime = 4500;
const decelerationRate = 0.97;
let degree = 0;
let rotation = 0;
let velocity = 0;
let spinning = false;

function drawRoulette() {
  ctx.beginPath();
  ctx.arc(canvas.width / 2, canvas.height / 2, 353, 0, 2 * Math.PI);
  ctx.strokeStyle = "#D3A466";
  ctx.lineWidth = 12;
  ctx.stroke();

  for (let i = 0; i < segments; i++) {
    ctx.fillStyle = colors[i];
    ctx.beginPath();
    ctx.moveTo(canvas.width / 2, canvas.height / 2);
    ctx.arc(
      canvas.width / 2,
      canvas.height / 2,
      350,
      (segmentSize * i - 90) * Math.PI / 180,
      (segmentSize * (i + 1) - 90) * Math.PI / 180
    );
    ctx.lineTo(canvas.width / 2, canvas.height / 2);
    ctx.fill();
  }
}

function spin() {
  if (spinning) return;

  spinning = true;
  degree = Math.floor(Math.random() * 360) + 1;
  velocity = 10;

  let start = null;
  let stopAnimation = false;

  function animation(timestamp) {
    if (!start) start = timestamp;
    let progress = timestamp - start;
    rotation += (velocity * Math.PI) / 180 / 20;
    velocity *= decelerationRate;

    if (velocity < 0.1) {
      velocity = 0;
      spinning = false;
    }

    if (!stopAnimation && progress >= spinTime - 1500) {
      velocity *= decelerationRate;
      stopAnimation = true;
    }

    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.translate(canvas.width / 2, canvas.height / 2);
    ctx.rotate(rotation);
    ctx.translate(-canvas.width / 2, -canvas.height / 2);
    drawRoulette();

    if (progress < spinTime && velocity > 0) {
      requestAnimationFrame(animation);
    } else {
      let stopDegree = (degree - rotation / Math.PI * 180 - 90) % 360;
      if (stopDegree < 0) stopDegree += 360;
      let segmentNumber = 0;

      for (let i = 0; i < segments; i++) {
        if (stopDegree >= segmentSize * i && stopDegree < segmentSize * (i + 1)) {
          segmentNumber = i + 1;
          break;
        }
      }

      console.log(
        "The roulette stopped at segment " +
          segmentNumber +
          " (color: " +
          colors[segmentNumber - 1] +
          ")"
      );
    }
  }

  requestAnimationFrame(animation);
}

drawRoulette();
spinButton.addEventListener("click", spin);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 23:09:26