英文:
How to get the color at the top in a roulette built with canvas?
问题
我使用Canvas创建了一个轮盘赌游戏,因为我对它不太熟悉,所以无法得到我需要的颜色。轮盘赌游戏的顶部有一个箭头,我想记录箭头下面的颜色。
这里应该是紫色,但实际上是黄色:
我应该怎么做呢?
我相信可以使用坐标来获取这些信息,但我迄今为止无法做到。
如果需要的话,可以在黄色箭头的位置添加一些参考箭头。
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;
// 生成1到360之间的随机数
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;
}
if (progress >= spinTime - 2000) velocity = velocity - 2;
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) {
requestAnimationFrame(animation);
} else {
// 计算轮盘停止时所在的部分
let stopDegree = (degree - rotation / Math.PI * 180) % 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(
"轮盘停在第" +
segmentNumber +
"部分(颜色:" +
colors[segmentNumber - 1] +
")"
);
}
}
requestAnimationFrame(animation);
}
// 绘制初始轮盘
drawRoulette();
spinButton.addEventListener("click", spin);
.roulette-wrapper {
position: relative;
background: #ccc;
height: 720px;
width: 720px;
}
#spin-button {
position: absolute;
}
.roulette-wrapper .top-image {
position: absolute;
left: 50%;
top: -30px;
transform: translateX(-50%);
z-index: 777;
}
.roulette-wrapper .center-image {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.roulette-wrapper canvas {
position: absolute;
background-color: white;
border-radius: 50%;
}
<div class="roulette-wrapper">
<button id="spin-button">旋转</button>
<img class="top-image" src="https://sonhodospes.vteximg.com.br/arquivos/top-arrow.svg" alt="顶部图像"/>
<canvas id="roulette-canvas" width="720" height="720"></canvas>
<img class="center-image" src="https://sonhodospes.vteximg.com.br/arquivos/coupon-spin-center-full.svg" alt="中心图像"/>
</div>
<details>
<summary>英文:</summary>
I built a roulette using canvas, since I'm new at it I'm not being able to get the color I need.
The roulette has an arrow at its top, I want to log the color that are below the arrow.
Here should be purple but it is yellow:
[![enter image description here][1]][1]
How can I do that?
I believe that there is a way to use coordinates to get this info, but I couldn't do it so far.
If it is necessary there is no problem adding some reference arrow at the same position of the golden one.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
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; // Spin time in milliseconds
const decelerationRate = 0.97; // Rate at which velocity decreases
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"; // Golden color
ctx.lineWidth = 12;
ctx.stroke();
// Draw the segments
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;
// Random number between 1 and 360
degree = Math.floor(Math.random() * 360) + 1;
velocity = 10; // Initial velocity
let start = null;
let stopAnimation = false;
function animation(timestamp) {
if (!start) start = timestamp;
let progress = timestamp - start;
rotation += (velocity * Math.PI) / 180 / 20; // Increase rotation based on velocity
velocity *= decelerationRate; // Decrease velocity based on deceleration rate
// Stop the animation when velocity becomes too low
if (velocity < 0.1) {
velocity = 0;
spinning = false;
}
if (!stopAnimation && progress >= spinTime - 1500) {
// Start gradually slowing down the animation one second before it stops
velocity *= decelerationRate;
stopAnimation = true;
}
if (progress >= spinTime - 2000) velocity = velocity - 2;
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) {
requestAnimationFrame(animation);
} else {
// Calculate the segment that the roulette stopped at
let stopDegree = (degree - rotation / Math.PI * 180) % 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);
}
// Draw the initial roulette
drawRoulette();
spinButton.addEventListener("click", spin);
<!-- language: lang-css -->
.roulette-wrapper {
position: relative;
background: #ccc;
height: 720px;
width: 720px;
}
#spin-button {
position: absolute;
}
.roulette-wrapper .top-image {
position: absolute;
left: 50%;
top: -30px;
transform: translateX(-50%);
z-index: 777;
}
.roulette-wrapper .center-image {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.roulette-wrapper canvas {
position: absolute;
background-color: white;
border-radius: 50%;
}
<!-- language: lang-html -->
<div class="roulette-wrapper">
<button id="spin-button">Spin</button>
<img class="top-image" src="https://sonhodospes.vteximg.com.br/arquivos/top-arrow.svg" alt="top-image"/>
<canvas id="roulette-canvas" width="720" height="720"></canvas>
<img class="center-image" src="https://sonhodospes.vteximg.com.br/arquivos/coupon-spin-center-full.svg" alt="center-image"/>
</div>
<!-- end snippet -->
[1]: https://i.stack.imgur.com/o1OaH.png
</details>
# 答案1
**得分**: 2
以下是您要翻译的代码部分的内容:
```javascript
There are these issues:
* The rotation you apply to the canvas is cumulative. I'm not referring to `rotation +=`, but to `ctx.rotate`: that **adds** the given rotation argument value to the current transformation of the canvas. So here you lose track of the **absolute** rotation that is in effect explaining why you get the wrong color notification at the end. To avoid this accumulation, *reset* the transformation before you call `ctx.rotation`. When you do this, you'll notice you'll need to increase the initial velocity to compensate for this correction.
* The variable `degree` is only used in determining the final color, which makes no sense as it is a random number. So remove this variable.
* The initial `velocity` is always the same. It would make more sense to make it a random value, like between 20 and 100.
* When you add to the `rotation`, you divide by some "magic" number 20. Don't do this. Instead choose a more appropriate velocity.
* The `if` block that tests `progress >= spinTime - 1500` will only execute once, since it sets `stopAnimation` to `true`. So the effect of this block is negligible. Remove it.
* The assignment `velocity = velocity - 2;` will also be executed when the velocity is already tiny, making it negative. This is not right: a negative velocity would signify a backwards movement. You'll want to always have a non-negative velocity. So remove this.
* You have several stop conditions, like `spinning`, `spinTime`, `stopAnimation`, ... Just use `spinning` only.
* The `stopDegree` calculation could give a negative value, because `%` in JavaScript is a *remainder* operator, not a *modulo* operator. So subtract from 360 to make sure the result remains non-negative.
Here is your snippet with the above changes. Comments in Capitals indicate where changes were made:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
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; // Spin time in milliseconds
const decelerationRate = 0.97; // Rate at which velocity decreases
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"; // Golden color
ctx.lineWidth = 12;
ctx.stroke();
// Draw the segments
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;
// Random number between 1 and 360
// NOT USED IN MEANINGFUL WAY: degree = Math.floor(Math.random() * 360) + 1;
// NOT RANDOM: velocity = 10; // Initial velocity
velocity = Math.floor(Math.random() * 80) + 20; // Initial velocity (20-100)
let start = null;
let stopAnimation = false;
function animation(timestamp) {
if (!start) start = timestamp;
let progress = timestamp - start;
// NO MAGIC NUMBERS (20): rotation += (velocity * Math.PI) / 180 / 20;
rotation += (velocity * Math.PI) / 180; // Increase rotation based on velocity
velocity *= decelerationRate; // Decrease velocity based on deceleration rate
// Stop the animation when velocity becomes too low
if (velocity < 0.1) {
velocity = 0;
spinning = false;
}
/*
// NOT ONE EXTRA DECELERATION
if (!stopAnimation && progress >= spinTime - 1500) {
// Start gradually slowing down the animation one second before it stops
velocity *= decelerationRate;
stopAnimation = true;
}
// NO NEGATIVE VELOCITY
if (progress >= spinTime - 2000) velocity = velocity - 2;
*/
// RESET ROTATION:
ctx.resetTransform();
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();
// ONLY USE spinning FOR ENDING: if (progress < spinTime) {
if (spinning) {
requestAnimationFrame(animation);
} else {
// Calculate the segment that the roulette stopped at
// DON'T USE degree: let stopDegree = (degree - rotation / Math.PI * 180) % 360;
let stopDegree = 360 - (rotation / Math.PI * 180) % 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);
}
// Draw the initial roulette
drawRoulette();
spinButton.addEventListener("click", spin);
希望这对您有所帮助!如果您有任何其他翻译需求,请随时告诉我。
英文:
There are these issues:
-
The rotation you apply to the canvas is cumulative. I'm not referring to
rotation +=
, but toctx.rotate
: that adds the given rotation argument value to the current transformation of the canvas. So here you lose track of the absolute rotation that is in effect explaining why you get the wrong color notification at the end. To avoid this accumulation, reset the transformation before you callctx.rotation
. When you do this, you'll notice you'll need to increase the initial velocity to compensate for this correction. -
The variable
degree
is only used in determining the final color, which makes no sense as it is a random number. So remove this variable. -
The initial
velocity
is always the same. It would make more sense to make it a random value, like between 20 and 100. -
When you add to the
rotation
, you divide by some "magic" number 20. Don't do this. Instead choose a more appropriate velocity. -
The
if
block that testsprogress >= spinTime - 1500
will only execute once, since it setsstopAnimation
totrue
. So the effect of this block is negligible. Remove it. -
The assignment
velocity = velocity - 2;
will also be executed when the velocity is already tiny, making it negative. This is not right: a negative velocity would signify a backwards movement. You'll want to always have a non-negative velocity. So remove this. -
You have several stop conditions, like
spinning
,spinTime
,stopAnimation
, ... Just usespinning
only. -
The
stopDegree
calculation could give a negative value, because%
in JavaScript is a remainder operator, not a modulo operator. So subtract from 360 to make sure the result remains non-negative.
Here is your snippet with the above changes. Comments in Capitals indicate where changes were made:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
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; // Spin time in milliseconds
const decelerationRate = 0.97; // Rate at which velocity decreases
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"; // Golden color
ctx.lineWidth = 12;
ctx.stroke();
// Draw the segments
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;
// Random number between 1 and 360
// NOT USED IN MEANINGFUL WAY: degree = Math.floor(Math.random() * 360) + 1;
// NOT RANDOM: velocity = 10; // Initial velocity
velocity = Math.floor(Math.random() * 80) + 20; // Initial velocity (20-100)
let start = null;
let stopAnimation = false;
function animation(timestamp) {
if (!start) start = timestamp;
let progress = timestamp - start;
// NO MAGIC NUMBERS (20): rotation += (velocity * Math.PI) / 180 / 20;
rotation += (velocity * Math.PI) / 180; // Increase rotation based on velocity
velocity *= decelerationRate; // Decrease velocity based on deceleration rate
// Stop the animation when velocity becomes too low
if (velocity < 0.1) {
velocity = 0;
spinning = false;
}
/*
// NOT ONE EXTRA DECELERATION
if (!stopAnimation && progress >= spinTime - 1500) {
// Start gradually slowing down the animation one second before it stops
velocity *= decelerationRate;
stopAnimation = true;
}
// NO NEGATIVE VELOCITY
if (progress >= spinTime - 2000) velocity = velocity - 2;
*/
// RESET ROTATION:
ctx.resetTransform();
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();
// ONLY USE spinning FOR ENDING: if (progress < spinTime) {
if (spinning) {
requestAnimationFrame(animation);
} else {
// Calculate the segment that the roulette stopped at
// DON'T USE degree: let stopDegree = (degree - rotation / Math.PI * 180) % 360;
let stopDegree = 360 - (rotation / Math.PI * 180) % 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);
}
// Draw the initial roulette
drawRoulette();
spinButton.addEventListener("click", spin);
<!-- language: lang-css -->
.roulette-wrapper {
position: relative;
background: #ccc;
height: 720px;
width: 720px;
}
#spin-button {
position: absolute;
}
.roulette-wrapper .top-image {
position: absolute;
left: 50%;
top: -30px;
transform: translateX(-50%);
z-index: 777;
}
.roulette-wrapper .center-image {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.roulette-wrapper canvas {
position: absolute;
background-color: white;
border-radius: 50%;
}
<!-- language: lang-html -->
<div class="roulette-wrapper">
<button id="spin-button">Spin</button>
<img class="top-image" src="https://sonhodospes.vteximg.com.br/arquivos/top-arrow.svg" alt="top-image"/>
<canvas id="roulette-canvas" width="720" height="720"></canvas>
<img class="center-image" src="https://sonhodospes.vteximg.com.br/arquivos/coupon-spin-center-full.svg" alt="center-image"/>
</div>
<!-- end snippet -->
答案2
得分: 1
以下是代码部分的翻译:
One "dirty" solution is to use getImageData.data to get the RGB at position X,Y just below the bottom center of the arrow.
Then use that to determine the name of the color. I'm sure there is another way to get the name from the RGB, just this is simple and works.
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; // Spin time in milliseconds
const decelerationRate = 0.97; // Rate at which velocity decreases
let colorRGB = {
"255,0,0" : "red",
"0,0,255" : "blue",
"255,255,0" : "yellow",
"128,0,128" : "purple",
"255,165,0" : "orange"
};
let arrow = document.querySelector(".top-image");
const rect = arrow.getBoundingClientRect();
const arrowCenter = rect.left + window.scrollX - arrow.offsetWidth
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"; // Golden color
ctx.lineWidth = 12;
ctx.stroke();
// Draw the segments
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;
// Random number between 1 and 360
degree = Math.floor(Math.random() * 360) + 1;
velocity = 10; // Initial velocity
let start = null;
let stopAnimation = false;
function animation(timestamp) {
if (!start) start = timestamp;
let progress = timestamp - start;
rotation += (velocity * Math.PI) / 180 / 20; // Increase rotation based on velocity
velocity *= decelerationRate; // Decrease velocity based on deceleration rate
// Stop the animation when velocity becomes too low
if (velocity < 0.1) {
velocity = 0;
spinning = false;
}
if (!stopAnimation && progress >= spinTime - 1500) {
// Start gradually slowing down the animation one second before it stops
velocity *= decelerationRate;
stopAnimation = true;
}
if (progress >= spinTime - 2000) velocity = velocity - 2;
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) {
requestAnimationFrame(animation);
} else {
// Calculate the segment that the roulette stopped at
let stopDegree = (degree - rotation / Math.PI * 180) % 360;
let segmentNumber = 0;
for (let i = 0; i < segments; i++) {
if (
stopDegree >= segmentSize * i &&
stopDegree < segmentSize * (i + 1)
) {
segmentNumber = i + 1;
break;
}
}
var data = ctx.getImageData(arrowCenter, arrow.offsetHeight, 1, 1).data;
let selColor = data[0] + "," + data[1] + "," + data[2];
console.log(
"The roulette stopped at segment " +
colorRGB[selColor]
);
}
}
requestAnimationFrame(animation);
}
// Draw the initial roulette
drawRoulette();
spinButton.addEventListener("click", spin);
请注意,以上翻译包括JavaScript代码部分。如果您有其他部分需要翻译,请告诉我。
英文:
One "dirty" solution is to use getImageData.data to get the RGB at position X,Y just below the bottom center of the arrow.
Then use that to determine the name of the color. I'm sure there is another way to get the name from the RGB, just this is simple and works.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
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; // Spin time in milliseconds
const decelerationRate = 0.97; // Rate at which velocity decreases
let colorRGB = {
"255,0,0" : "red",
"0,0,255" : "blue",
"255,255,0" : "yellow",
"128,0,128" : "purple",
"255,165,0" : "orange"
};
let arrow = document.querySelector(".top-image");
const rect = arrow.getBoundingClientRect();
const arrowCenter = rect.left + window.scrollX - arrow.offsetWidth
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"; // Golden color
ctx.lineWidth = 12;
ctx.stroke();
// Draw the segments
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;
// Random number between 1 and 360
degree = Math.floor(Math.random() * 360) + 1;
velocity = 10; // Initial velocity
let start = null;
let stopAnimation = false;
function animation(timestamp) {
if (!start) start = timestamp;
let progress = timestamp - start;
rotation += (velocity * Math.PI) / 180 / 20; // Increase rotation based on velocity
velocity *= decelerationRate; // Decrease velocity based on deceleration rate
// Stop the animation when velocity becomes too low
if (velocity < 0.1) {
velocity = 0;
spinning = false;
}
if (!stopAnimation && progress >= spinTime - 1500) {
// Start gradually slowing down the animation one second before it stops
velocity *= decelerationRate;
stopAnimation = true;
}
if (progress >= spinTime - 2000) velocity = velocity - 2;
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) {
requestAnimationFrame(animation);
} else {
// Calculate the segment that the roulette stopped at
let stopDegree = (degree - rotation / Math.PI * 180) % 360;
let segmentNumber = 0;
for (let i = 0; i < segments; i++) {
if (
stopDegree >= segmentSize * i &&
stopDegree < segmentSize * (i + 1)
) {
segmentNumber = i + 1;
break;
}
}
var data = ctx.getImageData(arrowCenter, arrow.offsetHeight, 1, 1).data;
let selColor = data[0] + "," + data[1] + "," + data[2];
console.log(
"The roulette stopped at segment " +
colorRGB[selColor]
);
}
}
requestAnimationFrame(animation);
}
// Draw the initial roulette
drawRoulette();
spinButton.addEventListener("click", spin);
<!-- language: lang-css -->
.roulette-wrapper {
position: relative;
background: #ccc;
height: 720px;
width: 720px;
}
#spin-button {
position: absolute;
}
.roulette-wrapper .top-image {
position: absolute;
left: 50%;
top: -30px;
transform: translateX(-50%);
z-index: 777;
}
.roulette-wrapper .center-image {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.roulette-wrapper canvas {
position: absolute;
background-color: white;
border-radius: 50%;
}
<!-- language: lang-html -->
<div class="roulette-wrapper">
<button id="spin-button">Spin</button>
<img class="top-image" src="https://sonhodospes.vteximg.com.br/arquivos/top-arrow.svg" alt="top-image"/>
<canvas id="roulette-canvas" width="720" height="720"></canvas>
<img class="center-image" src="https://sonhodospes.vteximg.com.br/arquivos/coupon-spin-center-full.svg" alt="center-image"/>
</div>
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论