button desing

This commit is contained in:
p-wojt 2022-01-06 19:54:59 +01:00
parent 861b9e34af
commit ef26f5849b
5 changed files with 163 additions and 109 deletions

33
app.css
View File

@ -1,6 +1,6 @@
body { body {
background-color: #121212; background-color: #121212;
color: snow; color: #FAF9F6;
transition-duration: 3s; transition-duration: 3s;
} }
@ -31,6 +31,20 @@ ul {
height: 2rem; height: 2rem;
width: 15.5rem; width: 15.5rem;
margin-top: 0.5rem; margin-top: 0.5rem;
background-color: #6495ED;
border: 0.05rem solid black;
box-shadow: 0 0.7rem 0 -0.1rem #6082B6, 0 0.75rem 0 -0.05rem black;
border-radius: 0.5rem;
}
.add-item-button:hover {
transform: translate(0, 0.25rem);
box-shadow: 0 0.5rem 0 -0.1rem #6082B6, 0 0.55rem 0 -0.05rem black;
}
.add-item-button:active {
transform: translate(0, 0.5rem);
box-shadow: 0 0.1rem 0 -0.1rem #6082B6, 0 0.15rem 0 -0.05rem black;
} }
.close-arrow { .close-arrow {
@ -69,6 +83,21 @@ ul {
.remove-all-items-button { .remove-all-items-button {
width: 5.4rem; width: 5.4rem;
height: 2rem;
background-color: #6495ED;
border: 0.05rem solid black;
box-shadow: 0 0.7rem 0 -0.1rem #6082B6, 0 0.75rem 0 -0.05rem black;
border-radius: 0.5rem;
}
.remove-all-items-button:hover {
transform: translate(0, 0.25rem);
box-shadow: 0 0.5rem 0 -0.1rem #6082B6, 0 0.55rem 0 -0.05rem black;
}
.remove-all-items-button:active {
transform: translate(0, 0.5rem);
box-shadow: 0 0.1rem 0 -0.1rem #6082B6, 0 0.15rem 0 -0.05rem black;
} }
.roulette-wheel { .roulette-wheel {
@ -76,7 +105,6 @@ ul {
top: 50%; top: 50%;
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
z-index: -1;
margin-left: 5rem; margin-left: 5rem;
text-align: center; text-align: center;
} }
@ -89,6 +117,7 @@ ul {
.winner { .winner {
font-size: 32; font-size: 32;
margin-bottom: 1rem; margin-bottom: 1rem;
height: 28px;
} }
@media screen and (max-width: 940px) { @media screen and (max-width: 940px) {

View File

@ -28,24 +28,32 @@ const modeEl = lightDarkModeEl.querySelector("img")! as HTMLImageElement;
const canvasWrapper = document.getElementsByClassName( const canvasWrapper = document.getElementsByClassName(
"roulette-wheel" "roulette-wheel"
)[0]! as HTMLDivElement; )[0]! as HTMLDivElement;
const winnerEl = document.getElementsByClassName('winner')[0]! as HTMLDivElement; const winnerEl = document.getElementsByClassName(
"winner"
)[0]! as HTMLDivElement;
const MAXIMUM_SIZE = 16;
canvasEl.width = canvasWrapper.offsetWidth; canvasEl.width = canvasWrapper.offsetWidth;
canvasEl.height = canvasWrapper.offsetHeight; canvasEl.height = canvasWrapper.offsetHeight;
const x = canvasEl.width / 2;
const y = canvasEl.height / 2;
const radius = canvasEl.height / 2 - 5;
const animationFPSRate = 30;
counterEl.textContent = `0/${MAXIMUM_SIZE}`; const MAXIMUM_SIZE = 16;
const ROTATIONS = 20;
const ANIMATION_FPS = 60;
const WHEEL_OFFSET = 5;
const X_CENTER = canvasEl.width / 2;
const Y_CENTER = canvasEl.height / 2;
const RADIUS = canvasEl.height / 2 - WHEEL_OFFSET;
const itemsList = new ItemList(MAXIMUM_SIZE); const itemsList = new ItemList(MAXIMUM_SIZE);
const items: MenuItem[] = []; const items: MenuItem[] = [];
let rotate_by = 50;
configure(); configure();
function configure() { function configure() {
counterEl.textContent = `0/${MAXIMUM_SIZE}`;
winnerEl.style.fontSize = "32px";
LightDarkMode.currentMode = "dark"; LightDarkMode.currentMode = "dark";
IdPool.initializeIdsPool(MAXIMUM_SIZE); IdPool.initializeIdsPool(MAXIMUM_SIZE);
addRemoveItem(); addRemoveItem();
@ -53,15 +61,17 @@ function configure() {
removeAllItems(); removeAllItems();
lightDarkMode(); lightDarkMode();
drawRouletteWheel(0); drawRouletteWheel(0);
canvasEl.addEventListener("click", startRoulette);
} }
function addRemoveItem() { function addRemoveItem() {
addButtonEl.addEventListener("click", () => { addButtonEl.addEventListener("click", () => {
const name = inputEl.value; const name = inputEl.value;
if (name) {
const id = IdPool.getAnId(); const id = IdPool.getAnId();
if (name && id) { if (id) {
const color = avaliableRGBs[id % avaliableRGBs.length]; const color = avaliableRGBs[id % avaliableRGBs.length];
const item = new Item(id, name, color); const item = new Item(id, name, color);
const menuItem = new MenuItem(id, name, color); const menuItem = new MenuItem(id, name, color);
@ -81,18 +91,17 @@ function addRemoveItem() {
itemListEl.appendChild(menuItem.el); itemListEl.appendChild(menuItem.el);
updateCounter(); updateCounter();
guessItemIndex = Math.floor(Math.random() * items.length); guessItemIndex = Math.floor(Math.random() * items.length);
maxAngle = 360 * rotations + segmentAngle * guessItemIndex;
segmentAngle = 360 / items.length; segmentAngle = 360 / items.length;
maxAngle = 360 * ROTATIONS + segmentAngle * guessItemIndex;
drawRouletteWheel(0); drawRouletteWheel(0);
} }
}
}); });
} }
function addItemByEnter() { function addItemByEnter() {
bodyEl.addEventListener("keyup", (event: KeyboardEvent) => { bodyEl.addEventListener("keyup", (event: KeyboardEvent) => {
if (event.key !== "Enter") { if (event.key !== "Enter") return;
return;
}
addButtonEl.click(); addButtonEl.click();
}); });
} }
@ -107,7 +116,7 @@ function registerChangeColorByClick(item: Item, menuItem: MenuItem) {
avaliableRGBs[(actualColorIndex + 1) % avaliableRGBs.length]; avaliableRGBs[(actualColorIndex + 1) % avaliableRGBs.length];
menuItem.el.style.backgroundColor = color; menuItem.el.style.backgroundColor = color;
item.color = color; item.color = color;
drawRouletteWheel(0); if (!animationId) drawRouletteWheel(0);
} }
}); });
} }
@ -132,13 +141,27 @@ function updateCounter() {
function animateCounter() { function animateCounter() {
counterEl.animate( counterEl.animate(
[{ transform: "scale(1.25)" }, { transform: "scale(1.00)" }], [
{ transform: "scale(1.5)" },
{ transform: "scale(1.00)" },
{ transform: "" },
],
{ {
duration: 500, duration: 500,
} }
); );
} }
function animateWinner() {
winnerEl.animate(
{
opacity: [0.5, 1],
easing: ["ease-in", "ease-out"],
},
1000
);
}
function lightDarkMode() { function lightDarkMode() {
lightDarkModeEl.addEventListener("click", () => { lightDarkModeEl.addEventListener("click", () => {
modeEl.animate([{ transform: "rotate(360deg)" }], { modeEl.animate([{ transform: "rotate(360deg)" }], {
@ -147,75 +170,61 @@ function lightDarkMode() {
if (LightDarkMode.currentMode == "dark") { if (LightDarkMode.currentMode == "dark") {
modeEl.src = "static/sun.png"; modeEl.src = "static/sun.png";
bodyEl.style.backgroundColor = "snow"; bodyEl.style.backgroundColor = "#FAF9F6";
bodyEl.style.color = "black"; bodyEl.style.color = "black";
} else { } else {
modeEl.src = "static/moon.png"; modeEl.src = "static/moon.png";
bodyEl.style.backgroundColor = "#121212"; bodyEl.style.backgroundColor = "#121212";
bodyEl.style.color = "white"; bodyEl.style.color = "white";
} }
LightDarkMode.changeMode(); LightDarkMode.changeMode();
}); });
} }
const arrowImage = document.createElement("img");
arrowImage.src = "static/arrow-down.png";
arrowImage.alt = "arrow";
function drawRouletteWheel(angle: number) { function drawRouletteWheel(angle: number) {
const segmentWidth = 360 / items.length; const segmentWidth = 360 / items.length;
let startAngle = angle; let startAngle = angle;
let endAngle = segmentWidth + startAngle; let endAngle = segmentWidth + startAngle;
ctx.clearRect(0, 0, canvasEl.width, canvasEl.height); ctx.clearRect(0, 0, canvasEl.width, canvasEl.height);
ctx.beginPath(); ctx.beginPath();
// let xtemp = x + Math.cos(totalAngle/2) * radius/2;
// let ytemp = y + Math.sin(totalAngle/2) * radius/2;
ctx.save(); ctx.save();
ctx.translate(x + radius + 50, y); ctx.translate(X_CENTER + RADIUS + 50, Y_CENTER);
ctx.lineTo(0, -20); ctx.lineTo(0, -20);
ctx.lineTo(0, 20); ctx.lineTo(0, 20);
ctx.lineTo(-50, 0); ctx.lineTo(-50, 0);
ctx.fillStyle = 'white'; ctx.fillStyle = "#C4B454";
ctx.fill(); ctx.fill();
ctx.stroke(); ctx.stroke();
ctx.restore(); ctx.restore();
ctx.arc(x, y, radius, 0, Math.PI * 2, true); ctx.arc(X_CENTER, Y_CENTER, RADIUS, 0, Math.PI * 2, true);
ctx.stroke(); ctx.stroke();
for (let i = 0; i < items.length; i++) { for (let i = 0; i < items.length; i++) {
ctx.beginPath(); ctx.beginPath();
ctx.lineTo(x, y); ctx.lineTo(X_CENTER, Y_CENTER);
ctx.font = "bold 24px verdana, sans-serif"; ctx.font = "bold 24px verdana, sans-serif";
ctx.arc( ctx.arc(
x, X_CENTER,
y, Y_CENTER,
radius, RADIUS,
(startAngle * Math.PI) / 180, (startAngle * Math.PI) / 180,
(endAngle * Math.PI) / 180, (endAngle * Math.PI) / 180,
false false
); );
ctx.lineTo(x, y); ctx.lineTo(X_CENTER, Y_CENTER);
ctx.fillStyle = itemsList.items[i].color; ctx.fillStyle = itemsList.items[i].color;
ctx.fill(); ctx.fill();
ctx.save(); ctx.save();
ctx.fillStyle = "black"; ctx.fillStyle = "black";
const text = itemsList.items[i].name; const text = itemsList.items[i].name;
if (items.length > 1) { if (items.length > 1) {
const xT = const angleVal = ((startAngle + segmentWidth / 2) * Math.PI) / 180;
x + const xT = X_CENTER + (Math.cos(angleVal) * RADIUS) / 2;
(Math.cos((startAngle + segmentWidth / 2) * Math.PI / 180) * radius) / const xY = Y_CENTER + (Math.sin(angleVal) * RADIUS) / 2;
2;
const xY =
y +
(Math.sin((startAngle + segmentWidth / 2) * Math.PI / 180) * radius) /
2;
ctx.translate(xT, xY); ctx.translate(xT, xY);
console.log(totalAngle); ctx.rotate(Math.PI / items.length + (Math.PI / 180) * startAngle);
ctx.rotate(Math.PI / items.length + Math.PI/180 * startAngle);
ctx.fillText(text, -ctx.measureText(text).width / 2, 0); ctx.fillText(text, -ctx.measureText(text).width / 2, 0);
} else {
}else{ ctx.fillText(text, X_CENTER, Y_CENTER);
ctx.fillText(text, x, y);
} }
ctx.restore(); ctx.restore();
if (items.length !== 1) { if (items.length !== 1) {
@ -223,63 +232,62 @@ function drawRouletteWheel(angle: number) {
} }
startAngle += segmentWidth; startAngle += segmentWidth;
endAngle += segmentWidth; endAngle += segmentWidth;
// xtemp += Math.cos(totalAngle/2) * radius/2;
// ytemp += Math.sin(totalAngle/2) * radius/2;
// console.log(ytemp);
} }
} }
let guessItemIndex = Math.floor(Math.random() * items.length); let guessItemIndex = Math.floor(Math.random() * items.length);
let segmentAngle = 360 / items.length; let segmentAngle = 360 / items.length;
const rotations = 1; let maxAngle = 360 * ROTATIONS + segmentAngle * guessItemIndex;
let maxAngle = 360 * rotations + segmentAngle * guessItemIndex;
let angleSpeed = 0;
let totalAngle = 0;
let animationId: number | null; let animationId: number | null;
let startAngle = 2; let winner: string;
// const maxAngleSpeed = segmentAngle; let endTime: number;
function startRoulette() { function easeOut(
if (animationId) { time: number,
//resetRouletteAnimation(); beginningVal: number,
} else { toChange: number,
guessItemIndex = Math.floor(Math.random() * items.length); duration: number
console.log(guessItemIndex); ) {
segmentAngle = 360 / items.length; return time == duration
maxAngle = ? beginningVal + toChange
360 * rotations + : toChange * (-Math.pow(2, (-10 * time) / duration) + 1) + beginningVal;
(items.length - 1 - guessItemIndex) * segmentAngle +
Math.random() * segmentAngle;
beginAnimateRoulette();
}
} }
function startRoulette() {
if (!animationId) {
if (winner) {
winner = "";
winnerEl.textContent = "";
drawRouletteWheel(0);
} else {
guessItemIndex = Math.floor(Math.random() * items.length);
winner = itemsList.items[guessItemIndex].name;
segmentAngle = 360 / items.length;
totalTime = 0;
maxAngle =
360 * ROTATIONS +
(items.length - 1 - guessItemIndex) * segmentAngle +
Math.random() * segmentAngle;
console.log(maxAngle);
endTime = (maxAngle / rotate_by) * (1000 / ANIMATION_FPS);
console.log(endTime);
beginAnimateRoulette();
}
}
}
let totalTime = 0;
function beginAnimateRoulette() { function beginAnimateRoulette() {
if (totalAngle < maxAngle) { //TODO: animations doesn't work as expected (endTime too low or totalTime incrementing faster than expected)
drawRouletteWheel(angleSpeed); if (totalTime < endTime) {
angleSpeed += startAngle; drawRouletteWheel(easeOut(totalTime, 0, maxAngle, endTime));
totalAngle += startAngle;
setTimeout(() => { setTimeout(() => {
animationId = window.requestAnimationFrame(beginAnimateRoulette); animationId = window.requestAnimationFrame(beginAnimateRoulette);
}, 1000 / animationFPSRate); totalTime += 1000 / ANIMATION_FPS;
}, 1000 / ANIMATION_FPS);
} else { } else {
window.cancelAnimationFrame(animationId!); window.cancelAnimationFrame(animationId!);
animationId = null; animationId = null;
angleSpeed = 1; winnerEl.textContent = `Winner: ${winner}`;
totalAngle = 0; animateWinner();
winnerEl.textContent = `Winner: ${itemsList.items[guessItemIndex].name}`;
} }
} }
// function resetRouletteAnimation(){
// if(animationId){
// window.cancelAnimationFrame(animationId!)
// }
// drawRouletteWheel(0);
// animationId = null;
// angleSpeed = 1;
// totalAngle = 0;
// delta = 0.2;
// }
canvasEl.addEventListener("click", startRoulette);

View File

@ -1 +1,18 @@
export const avaliableRGBs = ["rgba(255, 0, 0, 0.5)", "rgba(0, 255, 0, 0.5)", "rgba(0, 0, 255, 0.5)", "rgba(255, 255, 0, 0.5)"]; export const avaliableRGBs = [
"rgba(255, 0, 0, 0.5)",
"rgba(0, 255, 0, 0.5)",
"rgba(0, 0, 255, 0.5)",
"rgba(255, 255, 0, 0.5)",
"rgba(0, 255, 255, 0.5)",
"rgba(205, 127, 50, 0.5)",
"rgba(115, 147, 179, 0.5)",
"rgba(255, 117, 24, 0.5)",
"rgba(255, 0, 255, 0.5)",
"rgba(191, 64, 191, 0.5)",
"rgba(47, 197, 114, 0.5)",
"rgba(255, 222, 173, 0.5)",
"rgba(204, 204, 255, 0.5)",
"rgba(93, 63, 211, 0.5)",
"rgba(250, 128, 114, 0.5)",
"rgba(0, 255, 127, 0.5)",
];

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB