Статьи

Создание колеса рулетки с использованием HTML5 Canvas

HTML5 сейчас очень популярен во всем Интернете, поэтому я решил, что я поделюсь с вами некоторыми знаниями HTML5. Я работал с Flash и Flex последовательно в течение последних нескольких лет, поэтому я могу легко удалять и манипулировать графикой в ​​нем, но я мало что сделал с HTML5. Это побудило меня попытаться воссоздать что-то, что я построил во Flash в HTML5. Вот на что мы будем смотреть и учиться строить в этом уроке.

Несколько вещей должны быть упомянуты. Во-первых, IE просто не реализует тег < canvas >, что означает, что он не будет работать в IE, Google выпустил Explorer Canvas, который в некоторой степени исправляет это. Я, однако, не беспокоился о добавлении этого в этот учебник, потому что этот пост о создании контента. Кроме того, есть некоторые мелочи, которые не работают в других браузерах. Наконец, в Mobile Safari (iPhone, iPod Touch и iPad) неправильно реализован рендеринг текста.

Чтобы все пошло как по маслу, мы сначала добавим простой HTML. Это включает тег < canvas >, который мы используем для этого урока. Единственный другой элемент, который мы собираемся использовать, это кнопка ввода, чтобы вращать колесо. Я также добавил немного встроенного стиля для размещения кнопки.

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

Следующее, что мы собираемся сделать, это начать рисовать некоторые вещи на нашем холсте. Это будет сделано в JavaScript в функции, которую я назвал drawRouletteWheel . Основы рисования на < canvas > в 2D, по крайней мере, включают захват контекста рисования и последующее рисование на нем. Звучит сложно, не правда ли? Давайте посмотрим на немного кода.

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();
}
}
}

Хорошо, глядя на начало функции, мы берем ссылку на наш объект canvas по id — здесь ничего нового. Затем мы проверяем, поддерживает ли браузер захват контекста рисования, важно убедиться, что мы не генерируем ошибок в браузерах, которые не поддерживают эти функции. Затем мы устанавливаем пару переменных для внутреннего и внешнего радиуса нашего колеса. Теперь мы попадаем в мясо. Первое, что мы делаем, это получаем контекст 2D-рисования, вызывая getContext . Отсюда мы очищаем холст, поэтому у нас есть чистый лист для рисования. Затем мы устанавливаем цвет и ширину обводки, которая в данном случае равна «черный» и 2.

Следующая часть требует небольшого объяснения, мы собираемся пройти через 12 секций (количество сторон, которые мы собираемся нарисовать). Для каждого раздела мы определяем угол начала каждого раздела. StartAngle — это глобальная переменная, в которой мы собираемся использовать анимацию колеса, на данный момент она установлена ​​на 0. Следующая строка устанавливает цвет заливки путем извлечения значения из массива глобальных цветов. Рисование начинается после этого, начиная траекторию прорисовки двух дуг, используя функцию arc ( x , y , radius , startAngle , endAngle , против часовой стрелки ), Затем мы сообщаем контексту обводку пути и заполнение пути, они будут использовать ранее установленные параметры.

Теперь мы собираемся добавить текст ресторана в наш код для рисования. Кроме того, чтобы завершить функцию рисования, мы добавим симпатичную маленькую стрелку вверху. Текст чертежа выполняется с помощью fillText ( текст , х , у [ , 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();
}
}

Глядя на новый текстовый чертеж, мы начинаем с сохранения текущего состояния контекста — это позволит нам вращать и переводить текст, не затрагивая все остальное. Затем мы устанавливаем некоторые теневые элементы, которые добавят тень на текст. Далее мы переходим к переводу и повороту текста, сначала мы переводим текст в правильное положение на колесе, а затем поворачиваем его. Рисование текста следует за этим, но с дополнительным эффектом центрирования текста путем его измерения и деления на 2, чтобы сместить его. Вы заметите, что мы берем название ресторана из глобального массива. Наконец, мы возвращаемся к нашему исходному состоянию, в котором мы сохранили, это гарантирует, что преобразования не влияют на последующее рисование. Стрелку еще проще объяснить, мы просто перемещаемся в один угол и рисуем линии, чтобы создать форму, и заливаем ее черным.

Ниже у меня есть полный код для этой демонстрации. Я объясню код вращения и анимации сразу после.

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();

Это много, но мы пойдем медленно. Внизу кода, который вы увидите, мы вызываем drawRouletteWheel , это также рисует начальное колесо при загрузке страницы. Мы должны обновить кнопку ввода, которую мы помещаем на экран, чтобы теперь вызывать нашу функцию вращения, которая, конечно, обрабатывает вращение колеса. Обновленный ввод следует.

<input type="button" value="spin" onclick="spin();" style="float:left;" />

Взглянув на функцию вращения, мы установили пару глобальных переменных, которые определяют, как быстро мы будем вращаться и как долго мы будем вращаться. В них есть немного случайности, чтобы сделать вещи более интересными. Наконец, мы вызываем rotateWheel .

Функция rotateWheel обновляет количество времени, которое мы вращали , проверяет, должны ли мы остановиться, обновляет скорость вращения, рисует колесо и затем вызывает себя за 30 миллисекунд. После проверки времени, когда мы меняем угол вращения, startAngle , это делается с помощью функции замедления, чтобы замедлить вращение. Затем мы вызываем нашу функцию рисования и используем setTimeout и сохраняем ссылку для повторного вызова нашего вращения.

Последняя функция, на которую мы должны обратить внимание — это остановка колеса, stopRotateWheel . Это начинается с очистки тайм-аута, который остановит вращение колеса. Затем мы используем некоторую математику, чтобы выяснить, какой ресторан находится на вершине. Наконец, мы рисуем большое название выбранного ресторана в середине колеса.

Ну, это в значительной степени завершение этого поста. Мне очень нравится, как идут дела с HTML5 и тегом canvas. Хотя он еще не совсем готов к работе в прайм-тайм. Я с нетерпением жду следующих нескольких лет веб-разработки.

Если у вас есть какие-либо вопросы по учебнику или вы просто хотите отмахнуться от моих навыков кодирования, не стесняйтесь оставлять комментарии.