Creating a Roulette Wheel Using HTML5 Canvas

From: http://tech.pro/tutorial/1008/creating-a-roulette-wheel-using-html5-canvas


HTML5 is really hot all over the web right now so I figured I would dropsome HTML5 knowledge on y'all. I have worked with Flash and Flexconsistently for the last few years so I can easily drop and manipulategraphics in it, but I haven't done much with HTML5. This lead me to tryand challenge myself to recreate something I built in Flash in HTML5.That is what we are going to look at and learn to build in thistutorial.

A few things should be mentioned. First IE simply doesn't implement thecanvas tag which means it won't work in IE, Google has released ExplorerCanvas which fixes this tosome extent. I, however, didn't worry about adding that to this tutorialbecause this post is about creating the content. Also, there are somesmall things that don't work in other browsers. Finally, Mobile Safari(iPhone, iPod Touch, and iPad) doesn't implement text renderingcorrectly.


To get things rolling we'll first put some simple html down. Thisincludes thecanvas tag which is what we're using for this tutorial. The only other element we are going to use is an input button to spin our wheel. I also added a little bit of inline style to place the button.


<input type="button" value="spin" style="float:left;" />
<canvas id="canvas" width="500" height="500"></canvas>

The next thing we are going to do is begin drawing some stuff on to ourcanvas. This is going to be done in JavaScript in a function I nameddrawRouletteWheel. The basics of drawing on the canvasin 2D at least involve grabbing a drawing context and then drawing ontoit. Sounds complicated doesn't it. Let's look at a little bit of code.


var colors = ["#B8D430", "#3AB745", "#029990", "#3501CB",
                 "#2E2C75", "#673A7E", "#CC0071", "#F80120",
                 "#F35B20", "#FB9A00", "#FFCC00", "#FEF200"];

var startAngle = 0;
var arc = Math.PI / 6;
var ctx;

function drawRouletteWheel() {
  var canvas = document.getElementById("canvas");
  if (canvas.getContext) {
    var outsideRadius = 200;
    var insideRadius = 125;

    ctx = canvas.getContext("2d");
    ctx.clearRect(0,0,500,500);

    ctx.strokeStyle = "black";
    ctx.lineWidth = 2;

    for(var i = 0; i < 12; i++) {
      var angle = startAngle + i * arc;
      ctx.fillStyle = colors[i];

      ctx.beginPath();
      ctx.arc(250, 250, outsideRadius, angle, angle + arc, false);
      ctx.arc(250, 250, insideRadius, angle + arc, angle, true);
      ctx.stroke();
      ctx.fill();
    } 
  }
}



Okay, looking at the start of the function we grab a reference to ourcanvas object by id - nothing new here. Then we check to make sure thebrowser supports grabbing a drawing context, this is important to makesure we don't throw errors in browsers that don't support the features.Then we set a couple of variables for the inner and outer radius of ourwheel. Now, we get into the meat. The first thing we do is grab a 2Ddrawing context by callinggetContext. From here we clear the canvas, so we have a blank slate to draw onto.Then we set the stroke color and width which in this case is "black" and2.

The next part takes a little bit of explaining, we are going to loopthrough 12 sections (the number of sides we are going to draw). For eachsection we determine the angle of where each section is going to start.The startAngle is a global variable in which we are going to use toanimate the wheel, for now, it is set to 0. The following line sets thefill color by pulling a value from the global colors array. Drawingbegins after that with starting a path drawing two arcs, using the 'arc(x, y, radius, startAngle, endAngle, anticlockwise)' function. We then tell the context to stroke the path and fill the path, these will use the previously set parameters.

Now, we are going to add the restaurant text to our drawing code. Also,to finish off the drawing function we'll add the nice little arrow atthe top. The text drawing is done using thefillText(text, x, y [, maxWidth ]) function. Let's take a look at the updated code.


var restaraunts = ["Wendy's", "McDonalds", "Chick-fil-a", "Five Guys",
                       "Gold Star", "La Mexicana", "Chipotle", "Tazza Mia",
                       "Panera", "Just Crepes", "Arby's", "Indian"];

function drawRouletteWheel() {
  var canvas = document.getElementById("canvas");
  if (canvas.getContext) {
    var outsideRadius = 200;
    var textRadius = 160;
    var insideRadius = 125;

    ctx = canvas.getContext("2d");
    ctx.clearRect(0,0,500,500);


    ctx.strokeStyle = "black";
    ctx.lineWidth = 2;

    ctx.font = 'bold 12px Helvetica, Arial';

    for(var i = 0; i < 12; i++) {
      var angle = startAngle + i * arc;
      ctx.fillStyle = colors[i];

      ctx.beginPath();
      ctx.arc(250, 250, outsideRadius, angle, angle + arc, false);
      ctx.arc(250, 250, insideRadius, angle + arc, angle, true);
      ctx.stroke();
      ctx.fill();

      ctx.save();
      ctx.shadowOffsetX = -1;
      ctx.shadowOffsetY = -1;
      ctx.shadowBlur    = 0;
      ctx.shadowColor   = "rgb(220,220,220)";
      ctx.fillStyle = "black";
      ctx.translate(250 + Math.cos(angle + arc / 2) * textRadius, 
                    250 + Math.sin(angle + arc / 2) * textRadius);
      ctx.rotate(angle + arc / 2 + Math.PI / 2);
      var text = restaraunts[i];
      ctx.fillText(text, -ctx.measureText(text).width / 2, 0);
      ctx.restore();
    } 

    //Arrow
    ctx.fillStyle = "black";
    ctx.beginPath();
    ctx.moveTo(250 - 4, 250 - (outsideRadius + 5));
    ctx.lineTo(250 + 4, 250 - (outsideRadius + 5));
    ctx.lineTo(250 + 4, 250 - (outsideRadius - 5));
    ctx.lineTo(250 + 9, 250 - (outsideRadius - 5));
    ctx.lineTo(250 + 0, 250 - (outsideRadius - 13));
    ctx.lineTo(250 - 9, 250 - (outsideRadius - 5));
    ctx.lineTo(250 - 4, 250 - (outsideRadius - 5));
    ctx.lineTo(250 - 4, 250 - (outsideRadius + 5));
    ctx.fill();
  }
}



Looking at the new text drawing we start by saving the current contextstate - this is going to allow us to rotate and translate the textwithout affecting everything else. We then set some shadow stuff, whichwill put a drop shadow on the text. Translating and rotating the text istackled next, we first translate the text to the correct placement onthe wheel and then rotate it. Drawing the text follows this but with theadded effect of centering the text by measuring it and dividing that by2 to offset it. You'll notice we grab the restaurant name from a globalarray. Lastly we restore to our initial state we saved to, this makessure the transformations do not affect later drawing. The arrow is eveneasier to explain, we just move to one corner and draw lines to createthe shape and fill it with black.

Below I have the complete code for this demo. I'll explain the spinningand animating code right after.


var colors = ["#B8D430", "#3AB745", "#029990", "#3501CB",
             "#2E2C75", "#673A7E", "#CC0071", "#F80120",
             "#F35B20", "#FB9A00", "#FFCC00", "#FEF200"];
var restaraunts = ["Wendy's", "McDonalds", "Chick-fil-a", "Five Guys",
                   "Gold Star", "La Mexicana", "Chipotle", "Tazza Mia",
                   "Panera", "Just Crepes", "Arby's", "Indian"];

var startAngle = 0;
var arc = Math.PI / 6;
var spinTimeout = null;

var spinArcStart = 10;
var spinTime = 0;
var spinTimeTotal = 0;

var ctx;

function drawRouletteWheel() {
  var canvas = document.getElementById("canvas");
  if (canvas.getContext) {
    var outsideRadius = 200;
    var textRadius = 160;
    var insideRadius = 125;

    ctx = canvas.getContext("2d");
    ctx.clearRect(0,0,500,500);


    ctx.strokeStyle = "black";
    ctx.lineWidth = 2;

    ctx.font = 'bold 12px Helvetica, Arial';

    for(var i = 0; i < 12; i++) {
      var angle = startAngle + i * arc;
      ctx.fillStyle = colors[i];

      ctx.beginPath();
      ctx.arc(250, 250, outsideRadius, angle, angle + arc, false);
      ctx.arc(250, 250, insideRadius, angle + arc, angle, true);
      ctx.stroke();
      ctx.fill();

      ctx.save();
      ctx.shadowOffsetX = -1;
      ctx.shadowOffsetY = -1;
      ctx.shadowBlur    = 0;
      ctx.shadowColor   = "rgb(220,220,220)";
      ctx.fillStyle = "black";
      ctx.translate(250 + Math.cos(angle + arc / 2) * textRadius, 
                    250 + Math.sin(angle + arc / 2) * textRadius);
      ctx.rotate(angle + arc / 2 + Math.PI / 2);
      var text = restaraunts[i];
      ctx.fillText(text, -ctx.measureText(text).width / 2, 0);
      ctx.restore();
    } 

    //Arrow
    ctx.fillStyle = "black";
    ctx.beginPath();
    ctx.moveTo(250 - 4, 250 - (outsideRadius + 5));
    ctx.lineTo(250 + 4, 250 - (outsideRadius + 5));
    ctx.lineTo(250 + 4, 250 - (outsideRadius - 5));
    ctx.lineTo(250 + 9, 250 - (outsideRadius - 5));
    ctx.lineTo(250 + 0, 250 - (outsideRadius - 13));
    ctx.lineTo(250 - 9, 250 - (outsideRadius - 5));
    ctx.lineTo(250 - 4, 250 - (outsideRadius - 5));
    ctx.lineTo(250 - 4, 250 - (outsideRadius + 5));
    ctx.fill();
  }
}

function spin() {
  spinAngleStart = Math.random() * 10 + 10;
  spinTime = 0;
  spinTimeTotal = Math.random() * 3 + 4 * 1000;
  rotateWheel();
}

function rotateWheel() {
  spinTime += 30;
  if(spinTime >= spinTimeTotal) {
    stopRotateWheel();
    return;
  }
  var spinAngle = spinAngleStart - easeOut(spinTime, 0, spinAngleStart, spinTimeTotal);
  startAngle += (spinAngle * Math.PI / 180);
  drawRouletteWheel();
  spinTimeout = setTimeout('rotateWheel()', 30);
}

function stopRotateWheel() {
  clearTimeout(spinTimeout);
  var degrees = startAngle * 180 / Math.PI + 90;
  var arcd = arc * 180 / Math.PI;
  var index = Math.floor((360 - degrees % 360) / arcd);
  ctx.save();
  ctx.font = 'bold 30px Helvetica, Arial';
  var text = restaraunts[index]
  ctx.fillText(text, 250 - ctx.measureText(text).width / 2, 250 + 10);
  ctx.restore();
}

function easeOut(t, b, c, d) {
  var ts = (t/=d)*t;
  var tc = ts*t;
  return b+c*(tc + -3*ts + 3*t);
}

drawRouletteWheel();




It's a lot to take in but we'll take it slow. At the bottom of the codeyou'll see we calldrawRouletteWheel, this is too draw the initial wheel when the page loads. We have toupdate the input button we put on the screen to now call our spinfunction, which handles spinning the wheel, of course. The updated inputfollows.
<input type="button" value="spin" onclick="spin();" style="float:left;" />

Taking a look at the spin function we set a couple global variables that decide how fast we aregoing to spin and how long we are going to spin. These have a little bitof randomness in them to make things more interesting. Lastly, we call rotateWheel.

The rotateWheel function updates the amount of time we have been spinning, checks to seeif we should stop, updates spinning speed, draws the wheel, and thencalls itself in 30 milliseconds. After checking the time we change thespinning angle, startAngle, this is done using an easing function to slow down the spinning. Thenwe call our drawing function and usesetTimeoutand keeps a reference to call our rotate again.

The last function we need look at is stopping the wheel,stopRotateWheel. This starts with clearing the timeout which will stop the code fromrotating the wheel. Then we use some math to figure out what restaurantis at the top. Finally, we draw the large name of the of the selectedrestaurant in the middle of the wheel.

Well, that's pretty much a wrap on this post. I really like how HTML5and the canvas tag are coming along. Although it's not quite ready forprimetime production work yet. I look forward to the next couple yearsof web development.

Source Files:


1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REaDME.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值