На некоторых сайтах можно встретить колесо фортуны с призами. Работает так: нажимаете кнопку, колесо начинает крутиться, и на что показывает стрелка после остановки — это и есть ваш приз. Есть сервисы, которые предоставляют такое колесо как платную услугу, а мы сделаем своё и бесплатно:
❗️ В этом проекте довольно люто используется CSS 3. Мы о нём ещё не писали, но мы исправимся и напишем. Многие штуки в CSS-коде будут выглядеть непривычно, поэтому мы их объясним прямо в комментариях. Крепитесь.
Готовим страницу
Как обычно в наших проектах, на странице будет только разметка невидимых блоков — всё содержимое появится потом, из скрипта. Внутреннее устройство будет такое:
- делаем главный блок deal-wheel, внутри которого будут находиться все элементы;
- внутрь этого блока добавляем список spinner — это будут наши надписи на секторах;
- туда же кладём блок с язычком барабана ticker, который укажет на приз и кнопку с классом btn-spin — она запустит колесо.
За остальное будет отвечать скрипт.
Колесо удачи Испытай удачу
Сразу добавим стили в отдельный файл style.css:
/* делаем везде так, чтобы свойства width и height задавали не размеры контента, а размеры блока */ * { box-sizing: border-box; } /* общие настройки страницы */ body { /* подключаем сетку */ display: grid; /* ставим всё по центру */ place-items: center; /* если что-то не помещается на своё место — скрываем то, что не поместилось */ overflow: hidden; }
Настраиваем общий блок
Задача общего блока — установить связи между элементами, распределить их внутри виртуальной сетки и настроить параметры отображения внутренних элементов.
Чтобы не перегружать код одними и теми же параметрами, будем использовать CSS-переменные. Они начинаются с двух дефисов и работают внутри того блока, в котором прописаны. Также эти переменные понадобятся нам при настройке анимации в скрипте.
Зачем нужны переменные в CSS
Добавим стили в файл style.css. Читайте комментарии, тут всё подробно объяснено:
/* общий блок для всех элементов */ .deal-wheel { /* задаём переменные блока, внутри которого всё будет рисоваться */ /* размеры колеса */ —size: clamp(250px, 80vmin, 700px); /* clamp — функция CSS, которая задаёт три размера: минимальное, предпочтительное и максимальное. В данном случае мы хотим, чтобы колесо было не меньше 250 пикселей, не больше 700 пикселей, но в идеале — 80% от безопасно малой высоты окна браузера */ /* настройки яркости и заливки фона секторов. Нам понадобится описать поведение градиента, это у нас делается через много переменных */ —lg-hs: 0 3%; —lg-stop: 50%; —lg: linear-gradient( hsl(var(—lg-hs) 0%) 0 var(—lg-stop), hsl(var(—lg-hs) 20%) var(—lg-stop) 100% ); /* добавляем позиционирование относительно других элементов */ position: relative; /* подключаем стандартную CSS-сетку */ display: grid; grid-gap: calc(var(—size) / 20); /* выравниваем содержимое блока по центру */ align-items: center; /* задаём имена областей внутри сетки — в CSS теперь можно прямо назвать эти области */ grid-template-areas: «spinner» «trigger»; /* устанавливаем размер шрифта */ font-size: calc(var(—size) / 21); } /* всё, что относится ко внутренним элементам главного блока, будет находиться в области сетки с названием spinner */ .deal-wheel > * { grid-area: spinner; } /* сам блок и кнопка будут находиться в области сетки с названием trigger и будут выровнены по центру */ .deal-wheel .btn-spin { grid-area: trigger; justify-self: center; }
Готовим переменные в скрипте
Так как на самой странице у нас только блоки, всё остальное содержимое будем делать и добавлять через скрипт script.js.
Первое, что нам понадобится, — завести все переменные, которые будем использовать в проекте. Начнём со списка призов. Обратите внимание, что цвета здесь указаны в системе HSL — hue, saturation, lightness (оттенок, насыщенность, яркость). Это не необходимость, можно было указать и в RGB, и в hex-значениях:
// надписи и цвета на секторах const prizes = [ { text: «Скидка 10%», color: «hsl(197 30% 43%)», }, { text: «Дизайн в подарок», color: «hsl(173 58% 39%)», }, { text: «Второй сайт бесплатно», color: «hsl(43 74% 66%)», }, { text: «Скидка 50%», color: «hsl(27 87% 67%)», }, { text: «Блог в подарок», color: «hsl(12 76% 61%)», }, { text: «Скидок нет», color: «hsl(350 60% 52%)», }, { text: «Таргет в подарок», color: «hsl(91 43% 54%)», }, { text: «Скидка 30% на всё», color: «hsl(140 36% 74%)», } ];
Теперь создадим переменные, через которые будем работать со всеми элементами на странице:
// создаём переменные для быстрого доступа ко всем объектам на странице — блоку в целом, колесу, кнопке и язычку const wheel = document.querySelector(«.deal-wheel»); const spinner = wheel.querySelector(«.spinner»); const trigger = wheel.querySelector(«.btn-spin»); const ticker = wheel.querySelector(«.ticker»);
Следующий шаг — переменные для разбивки блока на разноцветные секторы. Так как мы заранее не знаем, сколько у нас призов, то будем сразу всё высчитывать:
// на сколько секторов нарезаем круг const prizeSlice = 360 / prizes.length; // на какое расстояние смещаем сектора друг относительно друга const prizeOffset = Math.floor(180 / prizes.length); // прописываем CSS-классы, которые будем добавлять и убирать из стилей const spinClass = «is-spinning»; const selectedClass = «selected»; // получаем все значения параметров стилей у секторов const spinnerStyles = window.getComputedStyle(spinner);
Осталось добавить переменные, которые будут меняться в ходе работы скрипта:
// переменная для анимации⠀ let tickerAnim;⠀ // угол вращения let rotation = 0;⠀ // текущий сектор⠀ let currentSlice = 0;⠀ // переменная для текстовых подписей let prizeNodes;
Добавляем секторы и призы на экран
Теперь, когда у нас есть все нужные переменные, добавим призы в блок со списком «.spinner». Логика такая:
- Перебираем весь список с призами, один за одним, по очереди.
- Сразу считаем угол поворота для каждой надписи.
- Добавляем в конец списка HTML-код, чтобы у нас появился новый элемент маркированного списка.
- В этом же коде добавляем ему стиль для поворота на нужный угол.
// расставляем текст по секторам const createPrizeNodes = () => { // обрабатываем каждую подпись prizes.forEach(({ text, color, reaction }, i) => { // каждой из них назначаем свой угол поворота const rotation = ((prizeSlice * i) * -1) — prizeOffset; // добавляем код с размещением текста на страницу в конец блока spinner spinner.insertAdjacentHTML( «beforeend», // текст при этом уже оформлен нужными стилями `
` ); }); };
Также сделаем разбивку по цветным секторам: просто добавим нужные параметры к стилю у класса «.spinner»:
// рисуем разноцветные секторы const createConicGradient = () => { // устанавливаем нужное значение стиля у элемента spinner spinner.setAttribute( «style», `background: conic-gradient( from -90deg, ${prizes // получаем цвет текущего сектора .map(({ color }, i) => `${color} 0 ${(100 / prizes.length) * (prizes.length — i)}%`) .reverse() } );` ); };
Теперь соберём всё вместе и сразу создадим объект с призами, чтобы потом было из чего выбирать:
// создаём функцию, которая нарисует колесо в сборе const setupWheel = () => { // сначала секторы createConicGradient(); // потом текст createPrizeNodes(); // а потом мы получим список всех призов на странице, чтобы работать с ними как с объектами prizeNodes = wheel.querySelectorAll(«.prize»); }; // подготавливаем всё к первому запуску setupWheel();
После запуска вам может показаться, что наш код не работает. Но на самом деле это не так: код работает как нужно, просто мы не добавили в стили новые параметры, которые использовали в коде — spinner и prize. Исправим это на следующем шаге.
Сохраняем файлы и открываем страницу в браузере.
Как сделать амулет удачи?
В магазинах можно купить любой амулет или талисман удачи, но лучше всего изготовить его самостоятельно. Когда человек создает амулет или талисман собственными руками, его энергетика пропитывает каждый участочек артефакта, соединяясь с материалом.
В этом случае артефакт становится частью самого человека, входит в его ауру. При создании артефакта важно точно воспроизвести рисунок, а материал-носитель имеет второстепенную роль. Носитель может быть любым:
Носитель может быть любым:
- дерево;
- камень;
- глина;
- металл;
- картон;
- плотная бумага.
Если вы сделаете амулет из бумаги и картона (пентакль), то можно залить его расплавленным воском.
Но также допускается заклеить артефакт скотчем, чтобы символ не стерлись и бумага не помялась. Активируется артефакт верой в его силу.
Бывали случаи, когда нарисованный символ начинал работать сразу же после его изображения на простом листе бумаги.
Исправляем внешний вид колеса
Сейчас блок с колесом выглядит как прямоугольник, потому что зависит от содержимого с текстом. Чтобы это стало похоже на круг, добавим стили специально для секторов колеса:
/* сектор колеса */ .spinner { /* добавляем относительное позиционирование */ position: relative; /* подключаем сетку */ display: grid; /* выравниваем всё по центру */ align-items: center; /* добавляем элемент в сетку */ grid-template-areas: «spinner»; /* устанавливаем размеры */ width: var(—size); height: var(—size); /* поворачиваем элемент */ transform: rotate(calc(var(—rotate, 25) * 1deg)); /* рисуем круглую обводку, а всё, что не поместится, — будет скрыто за кругом */ border-radius: 50% }; /* всё, что внутри этого блока, будет находиться в области сетки с названием spinner */ .spinner * { grid-area: spinner; }
У нас появились нормальное деление круга на цветные секторы, но все надписи слиплись. Всё дело в относительном позиционировании. Так как мы ещё не задавали правила расстановки текста, каждый элемент получился на одном и том же месте. Чтобы их разнести по секторам, добавим стили для текста:
/* текст на секторах */ .prize { /* включаем «гибкую» вёрстку */ display: flex; align-items: center; /* задаём отступы от краёв блока */ padding: 0 calc(var(—size) / 6) 0 calc(var(—size) / 20); /* устанавливаем размеры */ width: 50%; height: 50%; /* устанавливаем координаты, относительно которых будем вращать текст */ transform-origin: center right; /* поворачиваем текст */ transform: rotate(var(—rotate)); /* запрещаем пользователю выделять мышкой текст на секторах */ user-select: none; }
Стало лучше, но кнопка теперь слишком мелкая. Нужно исправить.
Мастер-класс по изготовлению амулета
Чтобы изготовить талисман “Колесо Фортуны”, вам понадобятся бумага желтого или зеленого цвета, такие же фломастер и свеча, ножницы, а также пинцет, воск и карандаш. Если рисуете колесо на желтой бумаге, возьмите зелёный фломастер, и наоборот. Цвет свечи роли не играет. Останьтесь в одиночестве, предварительно потренировавшись в нанесении рисунка.
- Начните с изображения круга. Обведите монету, чашку или блюдце — размер не важен, но слишком большой амулет неудобно носить.
- Расплавьте воск. Осторожно нанесите изображение, сначала карандашом, подом обведите фломастером. Ни в коем случае не допускайте искажений рисунка. Пропорции важнее красоты. Именно поэтому мы посоветовали вам сначала потренироваться.
- Нанесите картинку с двух сторон. Вырежьте колесо. Окуните на минуту в расплавленный воск. Осторожно вытащите его пинцетом и дайте воску застыть. Амулет готов, осталось только зарядить его, и можно пользоваться.
Кнопка запуска
Сделаем текст на кнопке того же размера, что и надписи на секторах. Заодно пропишем внешний вид неактивной кнопки: пусть она будет полупрозрачной и с другим курсором. Тогда сразу будет понятно — кнопка работает, нажимать пока нельзя.
/* кнопка запуска колеса */ .btn-spin { color: white; background: black; border: none; /* берём размер шрифта такой же, как в колесе */ font-size: inherit; /* добавляем отступы от текста внутри кнопки */ padding: 0.9rem 2rem 1rem; /* скругляем углы */ border-radius: 0.5rem; /* меняем внешний вид курсора над кнопкой на руку*/ cursor: pointer; } /* если кнопка нажата и неактивна */ .btn-spin:disabled { /* меняем внешний вид курсора */ cursor: progress; /* делаем кнопку полупрозрачной */ opacity: 0.25; }
Так кнопка выглядит гораздо лучше.
Кому подойдет оберег
В отличие от некоторых славянских оберегов, Колесо Фортуны подойдет любому, кто верит в его магическую силу. Он защищает учащихся, бизнесменов, спортсменов, путешественников — тех, чья деятельность связана с риском, кто кроме собственных способностей нуждается в благосклонности судьбы.
Кроме того, как можно скорее амулет необходимо приобрести тому, кто:
- часто болеет или рискует здоровьем (например, на работе);
- потерял работу и стабильный доход;
- имеет проблемы с общением, не может устроить личную жизнь;
- не уверен в себе, испытывает страх, думает о самоубийстве;
- запутался в себе, не знает, что делать дальше.
Оберег нужен и тем, у кого все хорошо — в качестве профилактики. Он приумножит хорошее, поможет достичь спокойствия, процветания, стабильности и гармонии.
Добавляем язычок
Язычок — это такой указатель на колесе, который всё время указывает на какой-то сектор. При вращении настоящего колеса фортуны металлический язычок касается столбиков на границе секторов и отклоняется в сторону. Так легко можно определить — перескочил язычок на новый сектор или скорости колеса не хватило и он остался на столбике, указывая на предыдущее значение.
Пока просто нарисуем язычок, а механику добавим чуть позже:
/* язычок */ .ticker { /* добавляем относительное позиционирование */ position: relative; /* устанавливаем размеры */ left: calc(var(—size) / -15); width: calc(var(—size) / 10); height: calc(var(—size) / 20); /* фон язычка */ background: var(—lg); /* делаем так, чтобы язычок был выше колеса */ z-index: 1; /* форма язычка */ clip-path: polygon(20% 0, 100% 50%, 20% 100%, 0% 50%); /* устанавливаем точку, относительно которой будет вращаться язычок при движении колеса */ transform-origin: center left; }
Теперь всё на месте.
Амулет Колесо Фортуны: значение
Одним привлечением удачи символизм колеса не исчерпывается. Круглый амулет напомнит вам, что жизнь — это дорога без конца и края. Конец одного этапа — лишь начало следующего, не стоит отчаиваться и бросать начатое на полпути. Что толку от благосклонности судьбы, если вы не знаете, куда и зачем “идете”? Медитация на заветный оберег поможет вам, если вы чувствуете, что потеряли направление в жизни.
Помимо колеса, талисман часто содержит определенный набор символов. По сути, он как бы говорит энергии: “Собирайся здесь!”. Удача и богатство придут в вашу жизнь вместе с позитивными магическими силами. Причем речь идет не только о деньгах или другом имуществе. Владелец Колеса Фортуны может стать более богатым духовно, достичь успехов в творчестве, личной жизни, науке и магии.
На самом глубинном, сакральном уровне, о котором задумываются только мудрейшие из магов, амулет символизирует всю Вселенную. В древности люди считали, что земля имеет форму диска или колеса. В данном контексте её настоящий вид значения не имеет. Куда важнее мистическое значение — вы как будто носите на груди маленькую модель всей нашей планеты, на которой миллионы лет живут люди, познавая и радость, и боль.
Задаём количество оборотов
Если мы в жизни запустим такое колесо, то оно постепенно будет замедляться. За это отвечает сила трения и разные физические факторы. Чтобы нам реализовать такую же механику, мы заранее определим количество градусов, на которое повернётся колесо. Для этого добавим функцию, которая вернёт нам случайным образом некоторое число в зависимости от минимального и максимального параметра вращения:
// функция запуска вращения с плавной остановкой const spinertia = (min, max) => { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max — min + 1)) + min; };
Запускаем колесо
Чтобы запустить колесо, нужно нажать на кнопку. Но так как мы в HTML-файле не прописывали обработчик нажатия, добавим такой обработчик в JS-файле. Читайте комментарии, чтобы разобраться подробнее, что происходит в этом блоке:
// отслеживаем нажатие на кнопку trigger.addEventListener(«click», () => { // делаем её недоступной для нажатия trigger.disabled = true; // задаём начальное вращение колеса rotation = Math.floor(Math.random() * 360 + spinertia(2000, 5000)); // убираем прошлый приз prizeNodes.forEach((prize) => prize.classList.remove(selectedClass)); // добавляем колесу класс is-spinning, с помощью которого реализуем нужную отрисовку wheel.classList.add(spinClass); // через CSS говорим секторам, как им повернуться spinner.style.setProperty(«—rotate», rotation); // возвращаем язычок в горизонтальную позицию ticker.style.animation = «none»; // запускаем анимацию вращение runTickerAnimation(); });