Skip to content

Commit

Permalink
wheel spinner
Browse files Browse the repository at this point in the history
  • Loading branch information
asmaamostafa74 committed Jul 30, 2024
0 parents commit a9df4ef
Show file tree
Hide file tree
Showing 12 changed files with 500 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions .idea/prj.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added images/il_570xN.3812195829_4zqo.avif
Binary file not shown.
13 changes: 13 additions & 0 deletions images/washing-machine.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/zmm20d38gb-fr-1500x1500 (1) (1).png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/zwf8240sb5-1500x1500.avif
Binary file not shown.
28 changes: 28 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./styles.css">
</head>
<body>
<div class="deal-wheel">
<div class="spinner"></div>
<button class="btn-spin">Spin</button>

<div class="ticker"></div>
<div class="grim-reaper"></div>

</div>
<div class="power-indicator">
<div class="power-rectangle"></div>
</div>


<script src="./script.js">

</script>

</body>
</html>
193 changes: 193 additions & 0 deletions script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
const prizes = [
{
text: "Microwave 10",
color: "hsl(197 30% 43%)",
reaction: "dancing",
image: "./images/zmm20d38gb-fr-1500x1500 (1) (1).png"
},
{
text: "Microwave 15",
color: "hsl(173 58% 39%)",
reaction: "shocked",
image: "./images/zmm20d38gb-fr-1500x1500 (1) (1).png"
},
{
text: "Microwave 20",
color: "hsl(43 74% 66%)",
reaction: "shocked",
image: "./images/zmm20d38gb-fr-1500x1500 (1) (1).png"
},
{
text: "Microwave 25",
color: "hsl(27 87% 67%)",
reaction: "shocked",
image: "./images/zmm20d38gb-fr-1500x1500 (1) (1).png"
},
{
text: "Microwave 30 pro",
color: "hsl(12 76% 61%)",
reaction: "dancing",
image: "./images/zmm20d38gb-fr-1500x1500 (1) (1).png"
},
{
text: "10% Off",
color: "hsl(350 60% 52%)",
reaction: "laughing",
image: "./images/zmm20d38gb-fr-1500x1500 (1) (1).png"
},
{
text: "10% Off",
color: "hsl(91 43% 54%)",
reaction: "laughing",
image: "./images/zmm20d38gb-fr-1500x1500 (1) (1).png"
},
{
text: "10% Off",
color: "hsl(140 36% 74%)",
reaction: "dancing",
image: "./images/zmm20d38gb-fr-1500x1500 (1) (1).png"
}
];

const wheel = document.querySelector(".deal-wheel");
const spinner = wheel.querySelector(".spinner");
const trigger = wheel.querySelector(".btn-spin");
const ticker = wheel.querySelector(".ticker");
const reaper = wheel.querySelector(".grim-reaper");
const prizeSlice = 360 / prizes.length;
const prizeOffset = Math.floor(180 / prizes.length);
const spinClass = "is-spinning";
const selectedClass = "selected";
const spinnerStyles = window.getComputedStyle(spinner);
let tickerAnim;
let rotation = 0;
let currentSlice = 0;
let prizeNodes;

const createPrizeNodes = () => {
prizes.forEach(({ text, color, reaction, image }, i) => {
const rotation = ((prizeSlice * i) * -1) - prizeOffset;

spinner.insertAdjacentHTML(
"beforeend",
`<li class="prize" data-reaction=${reaction} style="--rotate: ${rotation}deg">
<span class="text">${text}</span>
<img src="${image}" alt="${text}" />
</li>`
);
});
};

const createConicGradient = () => {
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");
};

const spinertia = (min, max) => {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
};

const runTickerAnimation = () => {
// https://css-tricks.com/get-value-of-css-rotation-through-javascript/
const values = spinnerStyles.transform.split("(")[1].split(")")[0].split(",");
const a = values[0];
const b = values[1];
let rad = Math.atan2(b, a);

if (rad < 0) rad += (2 * Math.PI);

const angle = Math.round(rad * (180 / Math.PI));
const slice = Math.floor(angle / prizeSlice);

if (currentSlice !== slice) {
ticker.style.animation = "none";
setTimeout(() => ticker.style.animation = null, 10);
currentSlice = slice;
}

tickerAnim = requestAnimationFrame(runTickerAnimation);
};

const selectPrize = () => {
const selected = Math.floor(rotation / prizeSlice);
prizeNodes[selected].classList.add(selectedClass);
reaper.dataset.reaction = prizeNodes[selected].dataset.reaction;
};

trigger.addEventListener("click", () => {
if (reaper.dataset.reaction !== "resting") {
reaper.dataset.reaction = "resting";
}

trigger.disabled = true;
rotation = Math.floor(Math.random() * 360 + spinertia(2000, 5000));
prizeNodes.forEach((prize) => prize.classList.remove(selectedClass));
wheel.classList.add(spinClass);
spinner.style.setProperty("--rotate", rotation);
ticker.style.animation = "none";
runTickerAnimation();
});

spinner.addEventListener("transitionend", () => {
cancelAnimationFrame(tickerAnim);
trigger.disabled = false;
trigger.focus();
rotation %= 360;
selectPrize();
wheel.classList.remove(spinClass);
spinner.style.setProperty("--rotate", rotation);
});

setupWheel();

// Power
const button = document.querySelector(".btn-spin");
const powerRectangle = document.querySelector(".power-rectangle");

let holdStartTime = 0;
let intervalId = null;

const updatePowerIndicator = () => {
const maxHoldDuration = 2000;
const holdDuration = Date.now() - holdStartTime;
const power = Math.min(100, (holdDuration / maxHoldDuration) * 100);

powerRectangle.style.width = `${power}%`;
powerRectangle.style.backgroundColor = `rgba(0, 128, 0, ${power / 100})`;
};

button.addEventListener("mousedown", () => {
holdStartTime = Date.now();
powerRectangle.style.width = '0';
powerRectangle.style.backgroundColor = 'rgba(0, 128, 0, 0)';

intervalId = setInterval(updatePowerIndicator, 50);
});

button.addEventListener("mouseup", () => {
clearInterval(intervalId);
powerRectangle.style.width = '0';
powerRectangle.style.backgroundColor = 'rgba(0, 128, 0, 0)';
});

button.addEventListener("mouseleave", () => {
clearInterval(intervalId);
powerRectangle.style.width = '0';
powerRectangle.style.backgroundColor = 'rgba(0, 128, 0, 0)';
});
Loading

0 comments on commit a9df4ef

Please sign in to comment.