410 lines
No EOL
13 KiB
Handlebars
410 lines
No EOL
13 KiB
Handlebars
<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}} |