旋转后如何在正确的位置停止HTML5画布轮? [英] How can we stop this HTML5 Canvas wheel at exact points after spin?

查看:142
本文介绍了旋转后如何在正确的位置停止HTML5画布轮?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在下面的代码中链接HTML5画布自转轮游戏。我想将此画布停在用户定义的位置,就像用户希望始终停在200个文本或类似的100个文本一样。

In the Below code link HTML5 canvas spin wheel game. I want to stop this canvas at a user-defined position as if the user wants to stop always at 200 texts or 100 texts like that.

当前,它在随机点处停止,我想控制停在哪里,就像我想在任何时候将圆停在100或200或0处一样。

Currently, it is stopping at random points I want to control where to stop as in if I want to stop circle at 100 or 200 or 0 whenever I want.

我们如何实现这一目标???任何人都可以帮忙!!!!!

How can we achieve that??? Can anyone Help!!!!!

附加的Codepen链接。

Attached Codepen link also.

HTML文件

<div>
  <canvas class="spin-wheel" id="canvas" width="300" height="300"></canvas>
</div>

JS文件

var color    = ['#ca7','#7ac','#77c','#aac','#a7c','#ac7', "#caa"];
var label    = ['10', '200','50','100','5','500',"0"];
var slices = color.length;
var sliceDeg = 360/slices;
var deg = 270;
var speed = 5;
var slowDownRand = 0;
var ctx = canvas.getContext('2d');
var width = canvas.width; // size
var center = width/2;      // center
var isStopped = false;
var lock = false;

function rand(min, max) {
  return Math.random() * (max - min) + min;
}


function deg2rad(deg){ return deg * Math.PI/180; }

function drawSlice(deg, color){
  ctx.beginPath();
  ctx.fillStyle = color;
  ctx.moveTo(center, center);
  ctx.arc(center, center, width/2, deg2rad(deg), deg2rad(deg+sliceDeg));
  console.log(center, center, width/2, deg2rad(deg), deg2rad(deg+sliceDeg))
  ctx.lineTo(center, center);
  ctx.fill();
}

function drawText(deg, text) {
  ctx.save();
  ctx.translate(center, center);
  ctx.rotate(deg2rad(deg));
  ctx.textAlign = "right";
  ctx.fillStyle = "#fff";
  ctx.font = 'bold 30px sans-serif';
  ctx.fillText(text, 130, 10);
  ctx.restore();
}

function drawImg() {
  ctx.clearRect(0, 0, width, width);
  for(var i=0; i<slices; i++){
    drawSlice(deg, color[i]);
    drawText(deg+sliceDeg/2, label[i]);
    deg += sliceDeg;
  }
}

  // ctx.rotate(360);

function anim() {
   isStopped = true;
  deg += speed;
  deg %= 360;

  // Increment speed
  if(!isStopped && speed<3){
    speed = speed+1 * 0.1;
  }
  // Decrement Speed
  if(isStopped){
    if(!lock){
      lock = true;
      slowDownRand = rand(0.994, 0.998);
    } 
    speed = speed>0.2 ? speed*=slowDownRand : 0;
  }
  // Stopped!
  if(lock && !speed){
    var ai = Math.floor(((360 - deg - 90) % 360) / sliceDeg); // deg 2 Array Index
    console.log(slices)
    ai = (slices+ai)%slices; // Fix negative index
    return alert("You got:\n"+ label[ai] ); // Get Array Item from end Degree
    // ctx.arc(150,150,150,8.302780584487312,9.200378485512967);
    //   ctx.fill();
  }

  drawImg();
  window.requestAnimationFrame(anim);
}

function start() {
  anim()
}

drawImg();

转盘密码笔

推荐答案

缓和曲线



如果您在随时间变化的位置上绘制车轮位置,您会看到一条曲线,看起来像是一条抛物线的一半。

Ease curves

If you where to plot the wheel position over time as it slows to a stop you would see a curve, a curve that looks like half a parabola.

如果在下一个代码段中绘制x的值在0到1范围内平方,则可以获得相同的曲线,红线显示 f(x)=>的图。 x * x 其中 0< = x< = 1

You can get the very same curve if you plot the value of x squared in the range 0 to 1 as in the next snippet, the red line shows the plot of f(x) => x * x where 0 <= x <= 1

不幸的是绘图是错误的方法,需要在x和y中进行镜像。通过将函数更改为 f(x)=>很简单。 1-(1-x)** 2 (单击画布以获取黄线)

Unfortunately the plot is the wrong way round and needs to be mirrored in x and y. That is simple by changing the function to f(x) => 1 - (1 - x) ** 2 (Click the canvas to get the yellow line)

const size = 200;
const ctx = Object.assign(document.createElement("canvas"),{width: size, height: size / 2}).getContext("2d");
document.body.appendChild(ctx.canvas);
ctx.canvas.style.border = "2px solid black";

plot(getData());
plot(unitCurve(x => x * x), "#F00");
ctx.canvas.addEventListener("click",()=>plot(unitCurve(x => 1 - (1 - x) ** 2), "#FF0"), {once: true});


function getData(chart = []) {
    var pos = 0, speed = 9, deceleration = 0.1;
    while(speed > 0) {
        chart.push(pos);
        pos += speed;
        speed -= deceleration;    
    }
    return chart;
}
function unitCurve(f,chart = []) {
    const step = 1 / 100;
    var x = 0;
    while(x <= 1) {
        chart.push(f(x));
        x += step
    }
    return chart;
}
function plot(chart, col = "#000") {
    const xScale = size / chart.length, yScale = size / 2 / Math.max(...chart);
    ctx.setTransform(xScale, 0, 0, yScale, 0, 0);
    ctx.strokeStyle = col;
    ctx.beginPath();
    chart.forEach((y,x) => ctx.lineTo(x,y));
    ctx.setTransform(1, 0, 0, 1, 0, 0);
    ctx.stroke();
}

在动画中,此曲线是

我们可以创建使用easy函数的函数,它会花费时间并返回车轮的位置。我们可以提供一些附加值,这些值控制车轮将花费多长时间才能停止,开始位置以及所有重要的停止位置。

We can create function that uses the ease function, takes the time and returns the position of the wheel. We can provide some additional values that controls how long the wheel will take to stop, the starting position and the all important stop position.

function wheelPos(currentTime, startTime, endTime, startPos, endPos) {
    // first scale the current time to a value from 0 to 1
    const x = (currentTime - startTime) / (endTime - startTime);
    // rather than the square, we will use the square root (this flips the curve)
    const xx = x ** (1 / 2);
    // convert the value to a wheel position
    return xx * (endPos - startPos) + startPos;
}

演示程序将其付诸实践。演示中的函数没有使用平方根,而是将根定义为常量 slowDownRate = 2.6 。该值越小,开始速度越大,结束速度越慢。值为1表示它将以恒定速度移动然后停止。该值必须> 0且< 1

The demo puts it in action. Rather than using the square root the function in the demo defines the root as the constant slowDownRate = 2.6. The smaller this value the greater start speed and the slower the end speed. A value of 1 means it will move at a constant speed and then stop. The value must be > 0 and < 1

>
requestAnimationFrame(mainLoop);
Math.TAU = Math.PI * 2;
const size = 160;
const ctx = Object.assign(document.createElement("canvas"),{width: size, height: size}).getContext("2d");
document.body.appendChild(ctx.canvas);
const stopAt = document.createElement("div")
document.body.appendChild(stopAt);
ctx.canvas.style.border = "2px solid black";


var gTime;   // global time
const wheelSteps = 12;
const minSpins = 4 * Math.TAU;  // min number of spins before stopping
const spinTime = 6000;          // in ms
const slowDownRate = 1 / 2.6;   // smaller this value the greater the ease in. 
                                // Must be > 0 and < 1

const wheel = {  // hold wheel related variables
    img: createWheel(wheelSteps),
    endTime: performance.now() - 2000,
    set currentPos(val) {
      this.speed = (val - this.pos) / 2;  // for the wobble at stop
      this.pos = val;
    },
    set endAt(pos) {
       this.endPos = (Math.TAU - (pos / wheelSteps) * Math.TAU) + minSpins;
       this.startPos = 0;
       this.endTime = gTime + spinTime;
       this.startTime = gTime;
       stopAt.textContent = "Spin to: "+(pos + 1);
    }
 };
 function wheelPos(currentTime, startTime, endTime, startPos, endPos) {
    const x = ((currentTime - startTime) / (endTime - startTime)) ** slowDownRate;
    return x * (endPos - startPos) + startPos;
 } 

function mainLoop(time) {
  gTime = time;
  ctx.setTransform(1,0,0,1,0,0);
  ctx.clearRect(0, 0, size, size);

  if (time > wheel.endTime + 2000) { // spin again
      wheel.endAt =  Math.random() * wheelSteps | 0;
  } else if (time <= wheel.endTime) { // wheel is spinning get pos
      wheel.currentPos = wheelPos(time, wheel.startTime, wheel.endTime, wheel.startPos, wheel.endPos);
  } else { // wobble at stop
      wheel.speed += (wheel.endPos - wheel.pos) * 0.25;
      wheel.speed *= 0.9;
      wheel.pos += wheel.speed;
  }

  // draw wheel
  ctx.setTransform(1,0,0,1,size / 2, size / 2);
  ctx.rotate(wheel.pos);
  ctx.drawImage(wheel.img, -size / 2 , - size / 2);

  // draw marker
  ctx.setTransform(1,0,0,1,0,0);
  ctx.fillStyle = "#F00";
  ctx.beginPath();
  ctx.lineTo(size - 13, size / 2);
  ctx.lineTo(size, size / 2 - 7);
  ctx.lineTo(size, size / 2 + 7);
  ctx.fill();
  
  requestAnimationFrame(mainLoop);
}

   

function createWheel(steps) {
    const ctx = Object.assign(document.createElement("canvas"),{width: size, height: size}).getContext("2d");
    const s = size, s2 = s / 2, r = s2 - 4;
    ctx.fillStyle = "#EEE";
    ctx.beginPath();
    ctx.lineWidth = 2;
    ctx.arc(s2, s2, r, 0, Math.TAU);
    ctx.moveTo(s2 + 12, s2);
    ctx.arc(s2, s2, 12, 0, Math.TAU);
    for (let a = 0; a < Math.TAU; a += Math.TAU / steps) {
        const aa = a - Math.PI / steps;
        ctx.moveTo(Math.cos(aa) * 12 + s2, Math.sin(aa) * 12 + s2);
        ctx.lineTo(Math.cos(aa) * r + s2, Math.sin(aa) * r + s2);
    }
    ctx.fill("evenodd");
    ctx.stroke();
    ctx.fillStyle = "#000";
    ctx.font = "13px arial";
    ctx.textAlign = "center";
    ctx.textBaseline = "middle";
    const tr = r - 8;
    var idx = 1;        
    for (let a = 0; a < Math.TAU; a += Math.TAU / steps) {
        const dx = Math.cos(a);
        const dy = Math.sin(a);
        ctx.setTransform(dy, -dx, dx, dy, dx * (tr - 4) + s2, dy * (tr - 4) + s2);
        ctx.fillText(""+ (idx ++), 0, 0);
    }
    return ctx.canvas;
}

body { font-family: arial }

这篇关于旋转后如何在正确的位置停止HTML5画布轮?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆