您的位置:首页 > Web前端 > HTML5

使用html5的canvas实现大转盘抽奖

2015-07-23 14:33 621 查看
To get things rolling we'll first put some simple html down. This includes the canvas tag which is what we're using forthis tutorial. The only other element we are going to use is an input button tospin our wheel. I also added a little bit of inline style
to place the button.

首先我们写一些简单的html,其中包括这次用到的canvas标签。要使用的其他元素是一个输入按钮,按下可以旋转转盘。我加入了一些内联的样式来放置按钮。

<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 our canvas. This is going to be done in JavaScript ina function I named drawRouletteWheel. The basics of drawing on the canvas in 2D at least involve grabbing a drawing context and then
drawing onto it. Sounds complicated doesn't it. Let's look at a little bit of code.

接下来需要在canvas上画一些东西。我将在一个名为drawRouletteWheel的方法中实现。在canvas上画2d的基本是至少包括context并在上面画。听起来复杂而已,看看代码先。

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 our canvas object by id - nothing new here. Then we check to make sure the browser supports grabbing a drawing context, this is important to make sure 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 our wheel. Now, we get into the meat. The first thing we do is grab a 2Ddrawing context by calling getContext. 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" and 2.

好了,看看函数开始时,我们通过id获取了canvas对象-依旧老套。然后检查确认浏览器是支持这个可画的context的,当浏览器不支持这个特性时,我们没有抛出异常,所以检查很重要。随后我们定义了一些转盘的内外弧度的变量。现在到干货的时候了,首先使用getContext方法获取ctx,首先清空这个canvas,得到一个空的画板。然后设置边框颜色为黑色,线条宽度为2.

The next part takes a little bit of explaining, we are going to loop through 12 sections (the number of sides we are going to draw). For each section we determine the angle of where each section is going to start.The start Angle is a global variable in which
we are going to use to animate the wheel, for now, it is set to 0. The following line sets the fill color by pulling a value from the global colors array. Drawing begins 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.

接下来的部分需要进行一下说明,我们将循环这12个区域(即将要画的区域),每个区域我们决定其开始的角度,开始角度是全局变量,用来使转盘旋转,现在这个变量设为0。接下来一行代码从全局定义的颜色中设置了填充颜色。然后开始画两个弧线,使用arc(x, y, radius, startAngle, endAngle, anticlockwise)函数。然后告诉context画线并填充这个路径,使用的是之前设置的参数。

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 at the top. The text drawing is done using the fillText(text,x, y [, maxWidth ]) function. Let's take a look at the
updated code.

现在我们将餐馆文字加入到其中,再添加一个小箭头在顶部,文字的绘制是使用fillText(text,x, y [, maxWidth ])函数,接下来看看更新的代码。

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 context state - this is going to allow us to rotate and translate the text without affecting everything else. We then set some shadow stuff, which will put a drop shadow on the text. Translating
and rotating the text is tackled next, we first translate the text to the correct placement on the wheel and then rotate it. Drawing the text follows this but with the added effect of centering the text by measuring it and dividing that by 2 to offset it.
You'll notice we grab the restaurant name from a global array. Lastly were store to our initial state we saved to, this makes sure the transformations do not affect later drawing. The arrow is even easier to explain, we just move to one corner and draw lines
to create the shape and fill it with black.

注意看绘制文字之前我们保存了当前context的状态-这将使我们可以在不影响其他东西的情况下旋转和变换文字。然后设置了一下文字阴影。接下来处理文字的变换和旋转,首先将文字变换到大转盘正确的位置上,再旋转。按此绘制文字后再通过计算并除以2以加入居中效果。注意我们是从全局数组中获取的餐馆名。最后我们恢复到之前保存的状态,这将保证接下来的绘制不受变换的影响。箭头比较简单了,移动到一角,画线,填充为黑色即可。

Below I have the complete code for this demo. I'll explain the spinning and 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,

af83
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 code you'll see we call drawRouletteWheel, this is too draw the initial wheel when the page loads. We have to update the input button we put on the screen to now call our spin function, which
handles spinning the wheel,of course. The updated input follows.

接下来我慢一点解释,在代码的最后可以看见调用了drawRouletteWheel方法,这是用来在页面加载是初始化绘制转盘。我们需要更新屏幕上的输入按钮来调用旋转的方法,作用是旋转转盘,如下。

<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 are going to spin and how long we are going to spin. These have a little bit of randomness in them to make things more interesting. Lastly, we call rotateWheel.

在spin方法中我们设置了一些全局变量,如旋转速度和旋转时间。为了有趣一点,使用了一些随机数。最后再调用rotateWheel方法。

The rotateWheel function updates the amount of time we have been spinning, checks to see if we should stop, updates spinning speed, draws the wheel, and then calls itself in 30 milliseconds. After checking the time we change the spinning angle, startAngle,
this is done using an easing function to slow down the spinning. Then we call our drawing function and use setTimeout and keeps a reference to call our rotate again.

rotateWheel函数更新了已经旋转的时间,检查是否应该停止,更新旋转速度,绘制转盘,延时30ms再调用自己本身。检查旋转角度startAngle后,使用一个宽松的方法来使转盘慢下来,然后调用绘制方法,使用延时方法使旋转继续。

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

最后来看看停止转盘的方法stopRotateWheel。首先清除延时使旋转转盘的代码停止,然后使用一些数学计算出位于顶部的餐馆。最后,在转盘中心绘制出餐馆的大名。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  翻译 html5 canvas