balance_wheel/views/userspace/index.hbs
2023-03-26 14:40:47 +07:00

410 lines
No EOL
13 KiB
Handlebars
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<div class="h-screen d-flex flex-column">
<header class="navbar navbar-expand-md navbar-dark bd-navbar">
<ul class="nav nav-pills container flex-wrap flex-md-nowrap gap-2">
<h4>Привет, {{user.full_name}}!</h4>
<div class="flex-grow-1"></div>
<li class="nav-item">
<a class="nav-link active" href="/userspace/votes">История</a>
</li>
<li class="nav-item">
<a class="nav-link active" href="/gateway/logout">Выйти</a>
</li>
</ul>
</header>
<div x-data="{loading: false}" class="align-items-center container d-flex flex-grow-1 flex-row justify-content-center">
{{#if user.vgroup_id includeZero=true}}
<canvas id="wheel" style="height: 600"></canvas>
<form class="col m-4 h-fit-content">
<div class="d-flex flex-row gap-2">
<label class="w-15">Здоровье</label>
<input x-bind:disabled="loading" type="range" id="a0" class="flex-grow-1" min="0" max="10" step="1" value="0" oninput="paramChange(this, 0)">
<input x-bind:disabled="loading" type="number" class="dubler" id="b0" min="0" max="10" step="1" value="0" oninput="param2Change(this, 0)">
</div>
<div class="d-flex flex-row gap-2">
<label class="w-15">Любовь</label>
<input x-bind:disabled="loading" type="range" id="a1" class="flex-grow-1" min="0" max="10" step="1" value="0" oninput="paramChange(this, 1)">
<input x-bind:disabled="loading" type="number" class="dubler" id="b1" min="0" max="10" step="1" value="0" oninput="param2Change(this, 1)">
</div>
<div class="d-flex flex-row gap-2">
<label class="w-15">Секс</label>
<input x-bind:disabled="loading" type="range" id="a2" class="flex-grow-1" min="0" max="10" step="1" value="0" oninput="paramChange(this, 2)">
<input x-bind:disabled="loading" type="number" class="dubler" id="b2" min="0" max="10" step="1" value="0" oninput="param2Change(this, 2)">
</div>
<div class="d-flex flex-row gap-2">
<label class="w-15">Работа</label>
<input x-bind:disabled="loading" type="range" id="a3" class="flex-grow-1" min="0" max="10" step="1" value="0" oninput="paramChange(this, 3)">
<input x-bind:disabled="loading" type="number" class="dubler" id="b3" min="0" max="10" step="1" value="0" oninput="param2Change(this, 3)">
</div>
<div class="d-flex flex-row gap-2">
<label class="w-15">Отдых</label>
<input x-bind:disabled="loading" type="range" id="a4" class="flex-grow-1" min="0" max="10" step="1" value="0" oninput="paramChange(this, 4)">
<input x-bind:disabled="loading" type="number" class="dubler" id="b4" min="0" max="10" step="1" value="0" oninput="param2Change(this, 4)">
</div>
<div class="d-flex flex-row gap-2">
<label class="w-15">Деньги</label>
<input x-bind:disabled="loading" type="range" id="a5" class="flex-grow-1" min="0" max="10" step="1" value="0" oninput="paramChange(this, 5)">
<input x-bind:disabled="loading" type="number" class="dubler" id="b5" min="0" max="10" step="1" value="0" oninput="param2Change(this, 5)">
</div>
<div class="d-flex flex-row gap-2">
<label class="w-15">Отношения</label>
<input x-bind:disabled="loading" type="range" id="a6" class="flex-grow-1" min="0" max="10" step="1" value="0" oninput="paramChange(this, 6)">
<input x-bind:disabled="loading" type="number" class="dubler" id="b6" min="0" max="10" step="1" value="0" oninput="param2Change(this, 6)">
</div>
<div class="d-flex flex-row gap-2">
<label class="w-15">Личн. рост</label>
<input x-bind:disabled="loading" type="range" id="a7" class="flex-grow-1" min="0" max="10" step="1" value="0" oninput="paramChange(this, 7)">
<input x-bind:disabled="loading" type="number" class="dubler" id="b7" min="0" max="10" step="1" value="0" oninput="param2Change(this, 7)">
</div>
<div class="d-flex flex-row gap-2">
<label class="w-15">Смысл жизни</label>
<input x-bind:disabled="loading" type="range" id="a8" class="flex-grow-1" min="0" max="10" step="1" value="0" oninput="paramChange(this, 8)">
<input x-bind:disabled="loading" type="number" class="dubler" id="b8" min="0" max="10" step="1" value="0" oninput="param2Change(this, 8)">
</div>
<div class="d-flex flex-row gap-2">
<label class="w-15">Тревожность</label>
<input x-bind:disabled="loading" type="range" id="a9" class="flex-grow-1" min="0" max="10" step="1" value="0" oninput="paramChange(this, 9)">
<input x-bind:disabled="loading" type="number" class="dubler" id="b9" min="0" max="10" step="1" value="0" oninput="param2Change(this, 9)">
</div>
<button x-bind:disabled="loading" type="button" id="sendBtn" class="btn btn-outline-primary w-100 pt-2">Отправить</button>
</form>
{{else}}
<div class="text-center">
<h1>Вы не состоите в группе</h1>
<p>Повторите попытку, когда администратор привяжет вас к группе</p>
</div>
{{/if}}
</div>
</div>
{{#if user.vgroup_id includeZero=true}}
<script>
let myCanvas, ctx;
let param = [{
name: "ЗДОРОВЬЕ",
dbmap: "health",
value: 0
},
{
name: "ЛЮБОВЬ",
dbmap: "love",
value: 0
},
{
name: "СЕКС",
dbmap: "sex",
value: 0
},
{
name: "РАБОТА",
dbmap: "work",
value: 0
},
{
name: "ОТДЫХ",
dbmap: "rest",
value: 0
},
{
name: "ДЕНЬГИ",
dbmap: "finances",
value: 0
},
{
name: "ОТНОШЕНИЯ",
dbmap: "relations",
value: 0
},
{
name: "ЛИЧН. РОСТ",
dbmap: "pers_growth",
value: 0
},
{
name: "СМЫСЛ ЖИЗНИ",
dbmap: "meaning_of_life",
value: 0
},
{
name: "СПОКОЙСТВИЕ",
dbmap: "serenity",
value: 0
},
];
document.addEventListener("DOMContentLoaded", () => {
myCanvas = document.getElementById("wheel");
myCanvas.width = 480;
myCanvas.height = 600;
ctx = myCanvas.getContext("2d");
drawWheel();
const sendBtn = document.getElementById("sendBtn");
sendBtn.addEventListener("click", async () => {
Alpine.$data(sendBtn).loading = true;
try {
let res = await fetch(`${location.href}/vote`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(param),
});
let json = await res.json();
console.log(json);
if (json.status == "ok") {
alert("Спасибо за голосование!");
} else {
alert(("Ошибка голосования!\n" + (json.message || "")).trim());
console.log(json);
}
} catch (e) {
console.error(e.message);
alert(e.message);
return;
}
resetWheel();
Alpine.$data(sendBtn).loading = false;
location.reload();
});
});
const resetWheel = () => {
document.querySelectorAll(".dubler").forEach((el) => {
el.value = 0;
});
document.querySelector(".dubler").dispatchEvent(new Event("input"));
}
// отрисовка линии
function drawLine(ctx, startX, startY, endX, endY) {
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(endX, endY);
ctx.stroke();
}
// отрисовка дуги
function drawArc(ctx, centerX, centerY, radius, startAngle, endAngle) {
ctx.beginPath();
ctx.arc(centerX, centerY, radius, startAngle, endAngle);
ctx.stroke();
}
// отрисовка сектора
function drawPieSlice(ctx, centerX, centerY, radius, startAngle, endAngle, color) {
ctx.fillStyle = color;
ctx.globalAlpha = 0.8;
ctx.beginPath();
ctx.moveTo(centerX, centerY);
ctx.arc(centerX, centerY, radius, startAngle, endAngle);
ctx.closePath();
ctx.fill();
}
// проставка временной отметки
function drawTimestamp(ctx) {
let now = new Date();
let day, month, hour, minute, second;
if (now.getDate() < 10) {
day = "0" + now.getDate();
} else {
day = now.getDate();
}
if (now.getMonth() < 10) {
month = "0" + (now.getMonth() + 1);
} else {
month = (now.getMonth() + 1);
}
if (now.getHours() < 10) {
hour = "0" + now.getHours();
} else {
hour = now.getHours();
}
if (now.getMinutes() < 10) {
minute = "0" + now.getMinutes();
} else {
minute = now.getMinutes();
}
if (now.getSeconds() < 10) {
second = "0" + now.getSeconds();
} else {
second = now.getSeconds();
}
let timestamp = day + "-" + month + "-" + now.getFullYear() + " " + hour + ":" + minute + ":" + second;
ctx.fillStyle = "darkgray";
ctx.globalAlpha = 1;
ctx.font = "10pt Roboto";
ctx.fillText(timestamp, myCanvas.width - 127, 15);
}
// отрисовка текста
function drawText(ctx) {
ctx.fillStyle = "#222";
name = " " + param[6].name + " " + param[7].name + " " + param[0].name + " " + param[1].name + " ";
drawTextAlongArc(ctx, name, 240, 240, 208, Math.PI);
name = " " + param[5].name + " " + param[4].name + " " + param[3].name + " " + param[2].name + " ";
drawTextAlongArc(ctx, name, 240, 240, -220, Math.PI * -1);
ctx.fillText(param[0].value, 283, 126);
ctx.fillText(param[1].value, 354, 196);
ctx.fillText(param[2].value, 354, 296);
ctx.fillText(param[3].value, 283, 366);
ctx.fillText(param[4].value, 190, 366);
ctx.fillText(param[5].value, 115, 296);
ctx.fillText(param[6].value, 115, 196);
ctx.fillText(param[7].value, 190, 126);
ctx.fillText(param[8].name + " - " + param[8].value, 45, 490);
ctx.fillText(param[9].name + " - " + (10 - param[9].value), 45, 550);
ctx.fillText("ТРЕВОЖНОСТЬ - " + param[9].value, 315, 550);
}
// отрисовка всего колеса
function drawWheel() {
ctx.clearRect(0, 0, myCanvas.width, myCanvas.height);
ctx.strokeStyle = "#999999";
ctx.fillStyle = "white";
ctx.rect(0, 0, myCanvas.width, myCanvas.height);
ctx.fill();
ctx.stroke();
ctx.fillStyle = "black";
ctx.globalAlpha = 1;
ctx.font = "11pt Roboto";
// отрисовка опорных кругов колеса
for (let i = 1; i <= 10; i++)
drawArc(ctx, 240, 240, i * 20, 0, 360);
// отрисовка опорных линий колеса
drawLine(ctx, 240, 40, 240, 440);
drawLine(ctx, 382, 98, 98, 382);
drawLine(ctx, 98, 98, 382, 382);
drawLine(ctx, 40, 240, 440, 240);
// отрисовка секторов колеса
for (let i = -0.5; i < 1.5; i = i + 0.25) {
value = param[(i + 0.5) / 0.25].value;
name = param[(i + 0.5) / 0.25].name;
if (value <= 4)
color = "#ea4335"; // красный
else if (value >= 8)
color = "#34a853"; // зеленый
else
color = "#fbbc05"; // желтый
drawPieSlice(ctx, 240, 240, 20 * value, Math.PI * i, Math.PI * (i + 0.25), color);
}
ctx.strokeStyle = "#999999";
for (let i = 0; i < 10; i = i + 1) {
ctx.rect(45 + i * 40, 500, 30, 20);
ctx.rect(45 + i * 40, 560, 30, 20);
ctx.stroke();
}
for (let i = 0; i < 10; i = i + 1) {
if (param[8].value < i + 1)
color = "white";
else
if (param[8].value <= 4)
color = "#ea4335" // красный
else if (param[8].value >= 8)
color = "#34a853"; // зеленый
else
color = "#fbbc05"; // желтый
ctx.fillStyle = color;
ctx.fillRect(45 + i * 40, 500, 30, 20);
////////////////////////////////////////////////////
if ((10 - param[9].value) < i + 1)
color = "white";
else
if ((10 - param[9].value) <= 4)
color = "#ea4335" // красный
else if ((10 - param[9].value) >= 8)
color = "#34a853"; // зеленый
else
color = "#fbbc05"; // желтый
ctx.fillStyle = color;
ctx.fillRect(45 + i * 40, 560, 30, 20);
}
drawTimestamp(ctx);
drawText(ctx);
}
// создание подписей вокруг внешнего круга
function drawTextAlongArc(context, str, centerX, centerY, radius, angle) {
let len = str.length,
s;
context.save();
context.translate(centerX, centerY);
context.rotate(-1 * angle / 2);
context.rotate(-1 * (angle / len) / 2);
for (let n = 0; n < len; n++) {
context.rotate(angle / len);
context.save();
context.translate(0, -1 * radius);
s = str[n];
context.fillText(s, 0, 0);
context.restore();
}
context.restore();
}
// действия при сдвиге ползунка
function paramChange(block, id) {
param[id].value = parseInt(block.value) || 0;
document.getElementById("b" + id).value = block.value;
drawWheel();
}
// действия при изменении значения дублирующего input
function param2Change(block, id) {
param[id].value = block.value;
document.getElementById("a" + id).value = block.value;
drawWheel();
}
</script>
{{/if}}