如何在使用Canvas构建的轮盘中获取顶部的颜色?

huangapple go评论97阅读模式
英文:

How to get the color at the top in a roulette built with canvas?

问题

我使用Canvas创建了一个轮盘赌游戏,因为我对它不太熟悉,所以无法得到我需要的颜色。轮盘赌游戏的顶部有一个箭头,我想记录箭头下面的颜色。

这里应该是紫色,但实际上是黄色:

如何在使用Canvas构建的轮盘中获取顶部的颜色?

我应该怎么做呢?

我相信可以使用坐标来获取这些信息,但我迄今为止无法做到。

如果需要的话,可以在黄色箭头的位置添加一些参考箭头。

  1. const canvas = document.getElementById("roulette-canvas");
  2. const ctx = canvas.getContext("2d");
  3. const spinButton = document.getElementById("spin-button");
  4. const segments = 5;
  5. const segmentSize = 360 / segments;
  6. const colors = ["red", "yellow", "blue", "orange", "purple"];
  7. const spinTime = 4500; // 旋转时间(毫秒)
  8. const decelerationRate = 0.97; // 速度减小的速率
  9. let degree = 0;
  10. let rotation = 0;
  11. let velocity = 0;
  12. let spinning = false;
  13. function drawRoulette() {
  14. ctx.beginPath();
  15. ctx.arc(canvas.width / 2, canvas.height / 2, 353, 0, 2 * Math.PI);
  16. ctx.strokeStyle = "#D3A466"; // 金色
  17. ctx.lineWidth = 12;
  18. ctx.stroke();
  19. // 绘制各个部分
  20. for (let i = 0; i < segments; i++) {
  21. ctx.fillStyle = colors[i];
  22. ctx.beginPath();
  23. ctx.moveTo(canvas.width / 2, canvas.height / 2);
  24. ctx.arc(
  25. canvas.width / 2,
  26. canvas.height / 2,
  27. 350,
  28. (segmentSize * i - 90) * Math.PI / 180,
  29. (segmentSize * (i + 1) - 90) * Math.PI / 180
  30. );
  31. ctx.lineTo(canvas.width / 2, canvas.height / 2);
  32. ctx.fill();
  33. }
  34. }
  35. function spin() {
  36. if (spinning) return;
  37. spinning = true;
  38. // 生成1到360之间的随机数
  39. degree = Math.floor(Math.random() * 360) + 1;
  40. velocity = 10; // 初始速度
  41. let start = null;
  42. let stopAnimation = false;
  43. function animation(timestamp) {
  44. if (!start) start = timestamp;
  45. let progress = timestamp - start;
  46. rotation += (velocity * Math.PI) / 180 / 20; // 根据速度增加旋转
  47. velocity *= decelerationRate; // 根据减速率减小速度
  48. // 当速度变得太低时停止动画
  49. if (velocity < 0.1) {
  50. velocity = 0;
  51. spinning = false;
  52. }
  53. if (!stopAnimation && progress >= spinTime - 1500) {
  54. // 在动画停止前一秒逐渐减速动画
  55. velocity *= decelerationRate;
  56. stopAnimation = true;
  57. }
  58. if (progress >= spinTime - 2000) velocity = velocity - 2;
  59. ctx.clearRect(0, 0, canvas.width, canvas.height);
  60. ctx.translate(canvas.width / 2, canvas.height / 2);
  61. ctx.rotate(rotation);
  62. ctx.translate(-canvas.width / 2, -canvas.height / 2);
  63. drawRoulette();
  64. if (progress < spinTime) {
  65. requestAnimationFrame(animation);
  66. } else {
  67. // 计算轮盘停止时所在的部分
  68. let stopDegree = (degree - rotation / Math.PI * 180) % 360;
  69. let segmentNumber = 0;
  70. for (let i = 0; i < segments; i++) {
  71. if (
  72. stopDegree >= segmentSize * i &&
  73. stopDegree < segmentSize * (i + 1)
  74. ) {
  75. segmentNumber = i + 1;
  76. break;
  77. }
  78. }
  79. console.log(
  80. "轮盘停在第" +
  81. segmentNumber +
  82. "部分(颜色:" +
  83. colors[segmentNumber - 1] +
  84. ")"
  85. );
  86. }
  87. }
  88. requestAnimationFrame(animation);
  89. }
  90. // 绘制初始轮盘
  91. drawRoulette();
  92. spinButton.addEventListener("click", spin);
  1. .roulette-wrapper {
  2. position: relative;
  3. background: #ccc;
  4. height: 720px;
  5. width: 720px;
  6. }
  7. #spin-button {
  8. position: absolute;
  9. }
  10. .roulette-wrapper .top-image {
  11. position: absolute;
  12. left: 50%;
  13. top: -30px;
  14. transform: translateX(-50%);
  15. z-index: 777;
  16. }
  17. .roulette-wrapper .center-image {
  18. position: absolute;
  19. left: 50%;
  20. top: 50%;
  21. transform: translate(-50%, -50%);
  22. }
  23. .roulette-wrapper canvas {
  24. position: absolute;
  25. background-color: white;
  26. border-radius: 50%;
  27. }
  1. <div class="roulette-wrapper">
  2. <button id="spin-button">旋转</button>
  3. <img class="top-image" src="https://sonhodospes.vteximg.com.br/arquivos/top-arrow.svg" alt="顶部图像"/>
  4. <canvas id="roulette-canvas" width="720" height="720"></canvas>
  5. <img class="center-image" src="https://sonhodospes.vteximg.com.br/arquivos/coupon-spin-center-full.svg" alt="中心图像"/>
  6. </div>
  1. <details>
  2. <summary>英文:</summary>
  3. I built a roulette using canvas, since I&#39;m new at it I&#39;m not being able to get the color I need.
  4. The roulette has an arrow at its top, I want to log the color that are below the arrow.
  5. Here should be purple but it is yellow:
  6. [![enter image description here][1]][1]
  7. How can I do that?
  8. I believe that there is a way to use coordinates to get this info, but I couldn&#39;t do it so far.
  9. If it is necessary there is no problem adding some reference arrow at the same position of the golden one.
  10. &lt;!-- begin snippet: js hide: false console: true babel: false --&gt;
  11. &lt;!-- language: lang-js --&gt;
  12. const canvas = document.getElementById(&quot;roulette-canvas&quot;);
  13. const ctx = canvas.getContext(&quot;2d&quot;);
  14. const spinButton = document.getElementById(&quot;spin-button&quot;);
  15. const segments = 5;
  16. const segmentSize = 360 / segments;
  17. const colors = [&quot;red&quot;, &quot;yellow&quot;, &quot;blue&quot;, &quot;orange&quot;, &quot;purple&quot;];
  18. const spinTime = 4500; // Spin time in milliseconds
  19. const decelerationRate = 0.97; // Rate at which velocity decreases
  20. let degree = 0;
  21. let rotation = 0;
  22. let velocity = 0;
  23. let spinning = false;
  24. function drawRoulette() {
  25. ctx.beginPath();
  26. ctx.arc(canvas.width / 2, canvas.height / 2, 353, 0, 2 * Math.PI);
  27. ctx.strokeStyle = &quot;#D3A466&quot;; // Golden color
  28. ctx.lineWidth = 12;
  29. ctx.stroke();
  30. // Draw the segments
  31. for (let i = 0; i &lt; segments; i++) {
  32. ctx.fillStyle = colors[i];
  33. ctx.beginPath();
  34. ctx.moveTo(canvas.width / 2, canvas.height / 2);
  35. ctx.arc(
  36. canvas.width / 2,
  37. canvas.height / 2,
  38. 350,
  39. (segmentSize * i - 90) * Math.PI / 180,
  40. (segmentSize * (i + 1) - 90) * Math.PI / 180
  41. );
  42. ctx.lineTo(canvas.width / 2, canvas.height / 2);
  43. ctx.fill();
  44. }
  45. }
  46. function spin() {
  47. if (spinning) return;
  48. spinning = true;
  49. // Random number between 1 and 360
  50. degree = Math.floor(Math.random() * 360) + 1;
  51. velocity = 10; // Initial velocity
  52. let start = null;
  53. let stopAnimation = false;
  54. function animation(timestamp) {
  55. if (!start) start = timestamp;
  56. let progress = timestamp - start;
  57. rotation += (velocity * Math.PI) / 180 / 20; // Increase rotation based on velocity
  58. velocity *= decelerationRate; // Decrease velocity based on deceleration rate
  59. // Stop the animation when velocity becomes too low
  60. if (velocity &lt; 0.1) {
  61. velocity = 0;
  62. spinning = false;
  63. }
  64. if (!stopAnimation &amp;&amp; progress &gt;= spinTime - 1500) {
  65. // Start gradually slowing down the animation one second before it stops
  66. velocity *= decelerationRate;
  67. stopAnimation = true;
  68. }
  69. if (progress &gt;= spinTime - 2000) velocity = velocity - 2;
  70. ctx.clearRect(0, 0, canvas.width, canvas.height);
  71. ctx.translate(canvas.width / 2, canvas.height / 2);
  72. ctx.rotate(rotation);
  73. ctx.translate(-canvas.width / 2, -canvas.height / 2);
  74. drawRoulette();
  75. if (progress &lt; spinTime) {
  76. requestAnimationFrame(animation);
  77. } else {
  78. // Calculate the segment that the roulette stopped at
  79. let stopDegree = (degree - rotation / Math.PI * 180) % 360;
  80. let segmentNumber = 0;
  81. for (let i = 0; i &lt; segments; i++) {
  82. if (
  83. stopDegree &gt;= segmentSize * i &amp;&amp;
  84. stopDegree &lt; segmentSize * (i + 1)
  85. ) {
  86. segmentNumber = i + 1;
  87. break;
  88. }
  89. }
  90. console.log(
  91. &quot;The roulette stopped at segment &quot; +
  92. segmentNumber +
  93. &quot; (color: &quot; +
  94. colors[segmentNumber - 1] +
  95. &quot;)&quot;
  96. );
  97. }
  98. }
  99. requestAnimationFrame(animation);
  100. }
  101. // Draw the initial roulette
  102. drawRoulette();
  103. spinButton.addEventListener(&quot;click&quot;, spin);
  104. &lt;!-- language: lang-css --&gt;
  105. .roulette-wrapper {
  106. position: relative;
  107. background: #ccc;
  108. height: 720px;
  109. width: 720px;
  110. }
  111. #spin-button {
  112. position: absolute;
  113. }
  114. .roulette-wrapper .top-image {
  115. position: absolute;
  116. left: 50%;
  117. top: -30px;
  118. transform: translateX(-50%);
  119. z-index: 777;
  120. }
  121. .roulette-wrapper .center-image {
  122. position: absolute;
  123. left: 50%;
  124. top: 50%;
  125. transform: translate(-50%, -50%);
  126. }
  127. .roulette-wrapper canvas {
  128. position: absolute;
  129. background-color: white;
  130. border-radius: 50%;
  131. }
  132. &lt;!-- language: lang-html --&gt;
  133. &lt;div class=&quot;roulette-wrapper&quot;&gt;
  134. &lt;button id=&quot;spin-button&quot;&gt;Spin&lt;/button&gt;
  135. &lt;img class=&quot;top-image&quot; src=&quot;https://sonhodospes.vteximg.com.br/arquivos/top-arrow.svg&quot; alt=&quot;top-image&quot;/&gt;
  136. &lt;canvas id=&quot;roulette-canvas&quot; width=&quot;720&quot; height=&quot;720&quot;&gt;&lt;/canvas&gt;
  137. &lt;img class=&quot;center-image&quot; src=&quot;https://sonhodospes.vteximg.com.br/arquivos/coupon-spin-center-full.svg&quot; alt=&quot;center-image&quot;/&gt;
  138. &lt;/div&gt;
  139. &lt;!-- end snippet --&gt;
  140. [1]: https://i.stack.imgur.com/o1OaH.png
  141. </details>
  142. # 答案1
  143. **得分**: 2
  144. 以下是您要翻译的代码部分的内容:
  145. ```javascript
  146. There are these issues:
  147. * 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.
  148. * 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.
  149. * The initial `velocity` is always the same. It would make more sense to make it a random value, like between 20 and 100.
  150. * When you add to the `rotation`, you divide by some "magic" number 20. Don't do this. Instead choose a more appropriate velocity.
  151. * 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.
  152. * 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.
  153. * You have several stop conditions, like `spinning`, `spinTime`, `stopAnimation`, ... Just use `spinning` only.
  154. * 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.
  155. Here is your snippet with the above changes. Comments in Capitals indicate where changes were made:
  156. <!-- begin snippet: js hide: false console: true babel: false -->
  157. <!-- language: lang-js -->
  158. const canvas = document.getElementById("roulette-canvas");
  159. const ctx = canvas.getContext("2d");
  160. const spinButton = document.getElementById("spin-button");
  161. const segments = 5;
  162. const segmentSize = 360 / segments;
  163. const colors = ["red", "yellow", "blue", "orange", "purple"];
  164. const spinTime = 4500; // Spin time in milliseconds
  165. const decelerationRate = 0.97; // Rate at which velocity decreases
  166. let degree = 0;
  167. let rotation = 0;
  168. let velocity = 0;
  169. let spinning = false;
  170. function drawRoulette() {
  171. ctx.beginPath();
  172. ctx.arc(canvas.width / 2, canvas.height / 2, 353, 0, 2 * Math.PI);
  173. ctx.strokeStyle = "#D3A466"; // Golden color
  174. ctx.lineWidth = 12;
  175. ctx.stroke();
  176. // Draw the segments
  177. for (let i = 0; i < segments; i++) {
  178. ctx.fillStyle = colors[i];
  179. ctx.beginPath();
  180. ctx.moveTo(canvas.width / 2, canvas.height / 2);
  181. ctx.arc(
  182. canvas.width / 2,
  183. canvas.height / 2,
  184. 350,
  185. (segmentSize * i - 90) * Math.PI / 180,
  186. (segmentSize * (i + 1) - 90) * Math.PI / 180
  187. );
  188. ctx.lineTo(canvas.width / 2, canvas.height / 2);
  189. ctx.fill();
  190. }
  191. }
  192. function spin() {
  193. if (spinning) return;
  194. spinning = true;
  195. // Random number between 1 and 360
  196. // NOT USED IN MEANINGFUL WAY: degree = Math.floor(Math.random() * 360) + 1;
  197. // NOT RANDOM: velocity = 10; // Initial velocity
  198. velocity = Math.floor(Math.random() * 80) + 20; // Initial velocity (20-100)
  199. let start = null;
  200. let stopAnimation = false;
  201. function animation(timestamp) {
  202. if (!start) start = timestamp;
  203. let progress = timestamp - start;
  204. // NO MAGIC NUMBERS (20): rotation += (velocity * Math.PI) / 180 / 20;
  205. rotation += (velocity * Math.PI) / 180; // Increase rotation based on velocity
  206. velocity *= decelerationRate; // Decrease velocity based on deceleration rate
  207. // Stop the animation when velocity becomes too low
  208. if (velocity < 0.1) {
  209. velocity = 0;
  210. spinning = false;
  211. }
  212. /*
  213. // NOT ONE EXTRA DECELERATION
  214. if (!stopAnimation && progress >= spinTime - 1500) {
  215. // Start gradually slowing down the animation one second before it stops
  216. velocity *= decelerationRate;
  217. stopAnimation = true;
  218. }
  219. // NO NEGATIVE VELOCITY
  220. if (progress >= spinTime - 2000) velocity = velocity - 2;
  221. */
  222. // RESET ROTATION:
  223. ctx.resetTransform();
  224. ctx.clearRect(0, 0, canvas.width, canvas.height);
  225. ctx.translate(canvas.width / 2, canvas.height / 2);
  226. ctx.rotate(rotation);
  227. ctx.translate(-canvas.width / 2, -canvas.height / 2);
  228. drawRoulette();
  229. // ONLY USE spinning FOR ENDING: if (progress < spinTime) {
  230. if (spinning) {
  231. requestAnimationFrame(animation);
  232. } else {
  233. // Calculate the segment that the roulette stopped at
  234. // DON'T USE degree: let stopDegree = (degree - rotation / Math.PI * 180) % 360;
  235. let stopDegree = 360 - (rotation / Math.PI * 180) % 360;
  236. let segmentNumber = 0;
  237. for (let i = 0; i < segments; i++) {
  238. if (
  239. stopDegree >= segmentSize * i && stopDegree < segmentSize * (i + 1)
  240. ) {
  241. segmentNumber = i + 1;
  242. break;
  243. }
  244. }
  245. console.log(
  246. "The roulette stopped at segment " +
  247. segmentNumber +
  248. " (color: " +
  249. colors[segmentNumber - 1] +
  250. ")"
  251. );
  252. }
  253. }
  254. requestAnimationFrame(animation);
  255. }
  256. // Draw the initial roulette
  257. drawRoulette();
  258. spinButton.addEventListener("click", spin);

希望这对您有所帮助!如果您有任何其他翻译需求,请随时告诉我。

英文:

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 &gt;= 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 -->

  1. const canvas = document.getElementById(&quot;roulette-canvas&quot;);
  2. const ctx = canvas.getContext(&quot;2d&quot;);
  3. const spinButton = document.getElementById(&quot;spin-button&quot;);
  4. const segments = 5;
  5. const segmentSize = 360 / segments;
  6. const colors = [&quot;red&quot;, &quot;yellow&quot;, &quot;blue&quot;, &quot;orange&quot;, &quot;purple&quot;];
  7. const spinTime = 4500; // Spin time in milliseconds
  8. const decelerationRate = 0.97; // Rate at which velocity decreases
  9. let degree = 0;
  10. let rotation = 0;
  11. let velocity = 0;
  12. let spinning = false;
  13. function drawRoulette() {
  14. ctx.beginPath();
  15. ctx.arc(canvas.width / 2, canvas.height / 2, 353, 0, 2 * Math.PI);
  16. ctx.strokeStyle = &quot;#D3A466&quot;; // Golden color
  17. ctx.lineWidth = 12;
  18. ctx.stroke();
  19. // Draw the segments
  20. for (let i = 0; i &lt; segments; i++) {
  21. ctx.fillStyle = colors[i];
  22. ctx.beginPath();
  23. ctx.moveTo(canvas.width / 2, canvas.height / 2);
  24. ctx.arc(
  25. canvas.width / 2,
  26. canvas.height / 2,
  27. 350,
  28. (segmentSize * i - 90) * Math.PI / 180,
  29. (segmentSize * (i + 1) - 90) * Math.PI / 180
  30. );
  31. ctx.lineTo(canvas.width / 2, canvas.height / 2);
  32. ctx.fill();
  33. }
  34. }
  35. function spin() {
  36. if (spinning) return;
  37. spinning = true;
  38. // Random number between 1 and 360
  39. // NOT USED IN MEANINGFUL WAY: degree = Math.floor(Math.random() * 360) + 1;
  40. // NOT RANDOM: velocity = 10; // Initial velocity
  41. velocity = Math.floor(Math.random() * 80) + 20; // Initial velocity (20-100)
  42. let start = null;
  43. let stopAnimation = false;
  44. function animation(timestamp) {
  45. if (!start) start = timestamp;
  46. let progress = timestamp - start;
  47. // NO MAGIC NUMBERS (20): rotation += (velocity * Math.PI) / 180 / 20;
  48. rotation += (velocity * Math.PI) / 180; // Increase rotation based on velocity
  49. velocity *= decelerationRate; // Decrease velocity based on deceleration rate
  50. // Stop the animation when velocity becomes too low
  51. if (velocity &lt; 0.1) {
  52. velocity = 0;
  53. spinning = false;
  54. }
  55. /*
  56. // NOT ONE EXTRA DECELERATION
  57. if (!stopAnimation &amp;&amp; progress &gt;= spinTime - 1500) {
  58. // Start gradually slowing down the animation one second before it stops
  59. velocity *= decelerationRate;
  60. stopAnimation = true;
  61. }
  62. // NO NEGATIVE VELOCITY
  63. if (progress &gt;= spinTime - 2000) velocity = velocity - 2;
  64. */
  65. // RESET ROTATION:
  66. ctx.resetTransform();
  67. ctx.clearRect(0, 0, canvas.width, canvas.height);
  68. ctx.translate(canvas.width / 2, canvas.height / 2);
  69. ctx.rotate(rotation);
  70. ctx.translate(-canvas.width / 2, -canvas.height / 2);
  71. drawRoulette();
  72. // ONLY USE spinning FOR ENDING: if (progress &lt; spinTime) {
  73. if (spinning) {
  74. requestAnimationFrame(animation);
  75. } else {
  76. // Calculate the segment that the roulette stopped at
  77. // DON&#39;T USE degree: let stopDegree = (degree - rotation / Math.PI * 180) % 360;
  78. let stopDegree = 360 - (rotation / Math.PI * 180) % 360;
  79. let segmentNumber = 0;
  80. for (let i = 0; i &lt; segments; i++) {
  81. if (
  82. stopDegree &gt;= segmentSize * i &amp;&amp;
  83. stopDegree &lt; segmentSize * (i + 1)
  84. ) {
  85. segmentNumber = i + 1;
  86. break;
  87. }
  88. }
  89. console.log(
  90. &quot;The roulette stopped at segment &quot; +
  91. segmentNumber +
  92. &quot; (color: &quot; +
  93. colors[segmentNumber - 1] +
  94. &quot;)&quot;
  95. );
  96. }
  97. }
  98. requestAnimationFrame(animation);
  99. }
  100. // Draw the initial roulette
  101. drawRoulette();
  102. spinButton.addEventListener(&quot;click&quot;, spin);

<!-- language: lang-css -->

  1. .roulette-wrapper {
  2. position: relative;
  3. background: #ccc;
  4. height: 720px;
  5. width: 720px;
  6. }
  7. #spin-button {
  8. position: absolute;
  9. }
  10. .roulette-wrapper .top-image {
  11. position: absolute;
  12. left: 50%;
  13. top: -30px;
  14. transform: translateX(-50%);
  15. z-index: 777;
  16. }
  17. .roulette-wrapper .center-image {
  18. position: absolute;
  19. left: 50%;
  20. top: 50%;
  21. transform: translate(-50%, -50%);
  22. }
  23. .roulette-wrapper canvas {
  24. position: absolute;
  25. background-color: white;
  26. border-radius: 50%;
  27. }

<!-- language: lang-html -->

  1. &lt;div class=&quot;roulette-wrapper&quot;&gt;
  2. &lt;button id=&quot;spin-button&quot;&gt;Spin&lt;/button&gt;
  3. &lt;img class=&quot;top-image&quot; src=&quot;https://sonhodospes.vteximg.com.br/arquivos/top-arrow.svg&quot; alt=&quot;top-image&quot;/&gt;
  4. &lt;canvas id=&quot;roulette-canvas&quot; width=&quot;720&quot; height=&quot;720&quot;&gt;&lt;/canvas&gt;
  5. &lt;img class=&quot;center-image&quot; src=&quot;https://sonhodospes.vteximg.com.br/arquivos/coupon-spin-center-full.svg&quot; alt=&quot;center-image&quot;/&gt;
  6. &lt;/div&gt;

<!-- end snippet -->

答案2

得分: 1

以下是代码部分的翻译:

  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.
  2. 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.
  3. const canvas = document.getElementById("roulette-canvas");
  4. const ctx = canvas.getContext("2d");
  5. const spinButton = document.getElementById("spin-button");
  6. const segments = 5;
  7. const segmentSize = 360 / segments;
  8. const colors = ["red", "yellow", "blue", "orange", "purple"];
  9. const spinTime = 4500; // Spin time in milliseconds
  10. const decelerationRate = 0.97; // Rate at which velocity decreases
  11. let colorRGB = {
  12. "255,0,0" : "red",
  13. "0,0,255" : "blue",
  14. "255,255,0" : "yellow",
  15. "128,0,128" : "purple",
  16. "255,165,0" : "orange"
  17. };
  18. let arrow = document.querySelector(".top-image");
  19. const rect = arrow.getBoundingClientRect();
  20. const arrowCenter = rect.left + window.scrollX - arrow.offsetWidth
  21. let degree = 0;
  22. let rotation = 0;
  23. let velocity = 0;
  24. let spinning = false;
  25. function drawRoulette() {
  26. ctx.beginPath();
  27. ctx.arc(canvas.width / 2, canvas.height / 2, 353, 0, 2 * Math.PI);
  28. ctx.strokeStyle = "#D3A466"; // Golden color
  29. ctx.lineWidth = 12;
  30. ctx.stroke();
  31. // Draw the segments
  32. for (let i = 0; i < segments; i++) {
  33. ctx.fillStyle = colors[i];
  34. ctx.beginPath();
  35. ctx.moveTo(canvas.width / 2, canvas.height / 2);
  36. ctx.arc(
  37. canvas.width / 2,
  38. canvas.height / 2,
  39. 350,
  40. (segmentSize * i - 90) * Math.PI / 180,
  41. (segmentSize * (i + 1) - 90) * Math.PI / 180
  42. );
  43. ctx.lineTo(canvas.width / 2, canvas.height / 2);
  44. ctx.fill();
  45. }
  46. }
  47. function spin() {
  48. if (spinning) return;
  49. spinning = true;
  50. // Random number between 1 and 360
  51. degree = Math.floor(Math.random() * 360) + 1;
  52. velocity = 10; // Initial velocity
  53. let start = null;
  54. let stopAnimation = false;
  55. function animation(timestamp) {
  56. if (!start) start = timestamp;
  57. let progress = timestamp - start;
  58. rotation += (velocity * Math.PI) / 180 / 20; // Increase rotation based on velocity
  59. velocity *= decelerationRate; // Decrease velocity based on deceleration rate
  60. // Stop the animation when velocity becomes too low
  61. if (velocity < 0.1) {
  62. velocity = 0;
  63. spinning = false;
  64. }
  65. if (!stopAnimation && progress >= spinTime - 1500) {
  66. // Start gradually slowing down the animation one second before it stops
  67. velocity *= decelerationRate;
  68. stopAnimation = true;
  69. }
  70. if (progress >= spinTime - 2000) velocity = velocity - 2;
  71. ctx.clearRect(0, 0, canvas.width, canvas.height);
  72. ctx.translate(canvas.width / 2, canvas.height / 2);
  73. ctx.rotate(rotation);
  74. ctx.translate(-canvas.width / 2, -canvas.height / 2);
  75. drawRoulette();
  76. if (progress < spinTime) {
  77. requestAnimationFrame(animation);
  78. } else {
  79. // Calculate the segment that the roulette stopped at
  80. let stopDegree = (degree - rotation / Math.PI * 180) % 360;
  81. let segmentNumber = 0;
  82. for (let i = 0; i < segments; i++) {
  83. if (
  84. stopDegree >= segmentSize * i &&
  85. stopDegree < segmentSize * (i + 1)
  86. ) {
  87. segmentNumber = i + 1;
  88. break;
  89. }
  90. }
  91. var data = ctx.getImageData(arrowCenter, arrow.offsetHeight, 1, 1).data;
  92. let selColor = data[0] + "," + data[1] + "," + data[2];
  93. console.log(
  94. "The roulette stopped at segment " +
  95. colorRGB[selColor]
  96. );
  97. }
  98. }
  99. requestAnimationFrame(animation);
  100. }
  101. // Draw the initial roulette
  102. drawRoulette();
  103. 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 -->

  1. const canvas = document.getElementById(&quot;roulette-canvas&quot;);
  2. const ctx = canvas.getContext(&quot;2d&quot;);
  3. const spinButton = document.getElementById(&quot;spin-button&quot;);
  4. const segments = 5;
  5. const segmentSize = 360 / segments;
  6. const colors = [&quot;red&quot;, &quot;yellow&quot;, &quot;blue&quot;, &quot;orange&quot;, &quot;purple&quot;];
  7. const spinTime = 4500; // Spin time in milliseconds
  8. const decelerationRate = 0.97; // Rate at which velocity decreases
  9. let colorRGB = {
  10. &quot;255,0,0&quot; : &quot;red&quot;,
  11. &quot;0,0,255&quot; : &quot;blue&quot;,
  12. &quot;255,255,0&quot; : &quot;yellow&quot;,
  13. &quot;128,0,128&quot; : &quot;purple&quot;,
  14. &quot;255,165,0&quot; : &quot;orange&quot;
  15. };
  16. let arrow = document.querySelector(&quot;.top-image&quot;);
  17. const rect = arrow.getBoundingClientRect();
  18. const arrowCenter = rect.left + window.scrollX - arrow.offsetWidth
  19. let degree = 0;
  20. let rotation = 0;
  21. let velocity = 0;
  22. let spinning = false;
  23. function drawRoulette() {
  24. ctx.beginPath();
  25. ctx.arc(canvas.width / 2, canvas.height / 2, 353, 0, 2 * Math.PI);
  26. ctx.strokeStyle = &quot;#D3A466&quot;; // Golden color
  27. ctx.lineWidth = 12;
  28. ctx.stroke();
  29. // Draw the segments
  30. for (let i = 0; i &lt; segments; i++) {
  31. ctx.fillStyle = colors[i];
  32. ctx.beginPath();
  33. ctx.moveTo(canvas.width / 2, canvas.height / 2);
  34. ctx.arc(
  35. canvas.width / 2,
  36. canvas.height / 2,
  37. 350,
  38. (segmentSize * i - 90) * Math.PI / 180,
  39. (segmentSize * (i + 1) - 90) * Math.PI / 180
  40. );
  41. ctx.lineTo(canvas.width / 2, canvas.height / 2);
  42. ctx.fill();
  43. }
  44. }
  45. function spin() {
  46. if (spinning) return;
  47. spinning = true;
  48. // Random number between 1 and 360
  49. degree = Math.floor(Math.random() * 360) + 1;
  50. velocity = 10; // Initial velocity
  51. let start = null;
  52. let stopAnimation = false;
  53. function animation(timestamp) {
  54. if (!start) start = timestamp;
  55. let progress = timestamp - start;
  56. rotation += (velocity * Math.PI) / 180 / 20; // Increase rotation based on velocity
  57. velocity *= decelerationRate; // Decrease velocity based on deceleration rate
  58. // Stop the animation when velocity becomes too low
  59. if (velocity &lt; 0.1) {
  60. velocity = 0;
  61. spinning = false;
  62. }
  63. if (!stopAnimation &amp;&amp; progress &gt;= spinTime - 1500) {
  64. // Start gradually slowing down the animation one second before it stops
  65. velocity *= decelerationRate;
  66. stopAnimation = true;
  67. }
  68. if (progress &gt;= spinTime - 2000) velocity = velocity - 2;
  69. ctx.clearRect(0, 0, canvas.width, canvas.height);
  70. ctx.translate(canvas.width / 2, canvas.height / 2);
  71. ctx.rotate(rotation);
  72. ctx.translate(-canvas.width / 2, -canvas.height / 2);
  73. drawRoulette();
  74. if (progress &lt; spinTime) {
  75. requestAnimationFrame(animation);
  76. } else {
  77. // Calculate the segment that the roulette stopped at
  78. let stopDegree = (degree - rotation / Math.PI * 180) % 360;
  79. let segmentNumber = 0;
  80. for (let i = 0; i &lt; segments; i++) {
  81. if (
  82. stopDegree &gt;= segmentSize * i &amp;&amp;
  83. stopDegree &lt; segmentSize * (i + 1)
  84. ) {
  85. segmentNumber = i + 1;
  86. break;
  87. }
  88. }
  89. var data = ctx.getImageData(arrowCenter, arrow.offsetHeight, 1, 1).data;
  90. let selColor = data[0] + &quot;,&quot; + data[1] + &quot;,&quot; + data[2];
  91. console.log(
  92. &quot;The roulette stopped at segment &quot; +
  93. colorRGB[selColor]
  94. );
  95. }
  96. }
  97. requestAnimationFrame(animation);
  98. }
  99. // Draw the initial roulette
  100. drawRoulette();
  101. spinButton.addEventListener(&quot;click&quot;, spin);

<!-- language: lang-css -->

  1. .roulette-wrapper {
  2. position: relative;
  3. background: #ccc;
  4. height: 720px;
  5. width: 720px;
  6. }
  7. #spin-button {
  8. position: absolute;
  9. }
  10. .roulette-wrapper .top-image {
  11. position: absolute;
  12. left: 50%;
  13. top: -30px;
  14. transform: translateX(-50%);
  15. z-index: 777;
  16. }
  17. .roulette-wrapper .center-image {
  18. position: absolute;
  19. left: 50%;
  20. top: 50%;
  21. transform: translate(-50%, -50%);
  22. }
  23. .roulette-wrapper canvas {
  24. position: absolute;
  25. background-color: white;
  26. border-radius: 50%;
  27. }

<!-- language: lang-html -->

  1. &lt;div class=&quot;roulette-wrapper&quot;&gt;
  2. &lt;button id=&quot;spin-button&quot;&gt;Spin&lt;/button&gt;
  3. &lt;img class=&quot;top-image&quot; src=&quot;https://sonhodospes.vteximg.com.br/arquivos/top-arrow.svg&quot; alt=&quot;top-image&quot;/&gt;
  4. &lt;canvas id=&quot;roulette-canvas&quot; width=&quot;720&quot; height=&quot;720&quot;&gt;&lt;/canvas&gt;
  5. &lt;img class=&quot;center-image&quot; src=&quot;https://sonhodospes.vteximg.com.br/arquivos/coupon-spin-center-full.svg&quot; alt=&quot;center-image&quot;/&gt;
  6. &lt;/div&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年2月24日 04:37:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/75550068.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定