275 lines
9.5 KiB
HTML
275 lines
9.5 KiB
HTML
<!doctype html>
|
|
<html>
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
|
|
<script>
|
|
const priceColorMap = {
|
|
0: "bg-lime-200",
|
|
1: "bg-lime-300",
|
|
2: "bg-lime-400",
|
|
3: "bg-lime-500",
|
|
4: "bg-lime-600",
|
|
5: "bg-lime-700",
|
|
6: "bg-amber-200",
|
|
7: "bg-amber-300",
|
|
8: "bg-amber-400",
|
|
9: "bg-amber-500",
|
|
10: "bg-amber-600",
|
|
11: "bg-amber-700",
|
|
12: "bg-orange-300",
|
|
13: "bg-orange-400",
|
|
14: "bg-orange-500",
|
|
15: "bg-orange-600",
|
|
16: "bg-rose-400",
|
|
17: "bg-rose-500",
|
|
18: "bg-rose-600",
|
|
19: "bg-rose-700",
|
|
20: "bg-rose-800",
|
|
21: "bg-fuchsia-500",
|
|
22: "bg-fuchsia-700",
|
|
23: "bg-fuchsia-800",
|
|
24: "bg-fuchsia-950",
|
|
}
|
|
|
|
function getBgColor(value) {
|
|
// Clamp value between 0 and 24, round down
|
|
let v = Math.max(0, Math.min(24, Math.floor(value)));
|
|
return priceColorMap[v] || "";
|
|
}
|
|
|
|
function formatDate(date) {
|
|
const year = date.getFullYear();
|
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
const day = String(date.getDate()).padStart(2, '0');
|
|
return `${year}-${month}-${day}`;
|
|
}
|
|
|
|
function loadData(date, today) {
|
|
let prefix = today ? 'today' : 'tomorrow';
|
|
|
|
if(prefix == 'today') {
|
|
document.getElementById(prefix).innerText = "Dnes ("+date+")";
|
|
} else {
|
|
document.getElementById(prefix).innerText = "Zítra ("+date+")";
|
|
}
|
|
|
|
fetch('/price/day/'+date+'?num_cheapest_hours=8')
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if(data.detail == "prices not found") {
|
|
for (let i = 0; i < 24; i++) {
|
|
document.getElementById(prefix + i).innerText = "-";
|
|
}
|
|
return;
|
|
}
|
|
|
|
for (let i = 0; i < 24; i++) {
|
|
let extra_class = "";
|
|
let border = "border-dotted"
|
|
if(today && i == new Date().getHours()) {
|
|
extra_class = " font-bold text-xl";
|
|
border = "border-solid"
|
|
}
|
|
|
|
let value = Math.round(data.total.hours[i]*100)/100;
|
|
|
|
if(data.cheapest_hours_by_average.hours.includes(i)) {
|
|
document.getElementById(prefix + i).className = "px-1 "+border+" border-4 border-lime-400 "+ getBgColor(value) + extra_class;
|
|
} else if (data.most_expensive_hours_by_average.hours.includes(i)) {
|
|
document.getElementById(prefix + i).className = "px-1 "+border+" border-4 border-rose-400 "+ getBgColor(value) + extra_class;
|
|
} else {
|
|
if(extra_class != "") {
|
|
extra_class = " border-4 border-solid border-gray-500";
|
|
}
|
|
document.getElementById(prefix + i).className = "px-1 "+ getBgColor(value) + extra_class;
|
|
}
|
|
document.getElementById(prefix + i).innerText = value;
|
|
}
|
|
})
|
|
}
|
|
|
|
function loadAllData() {
|
|
const currentDate = new Date();
|
|
const tomorrowDate = new Date(currentDate);
|
|
tomorrowDate.setDate(currentDate.getDate() + 1);
|
|
|
|
const currentDateString = formatDate(currentDate);
|
|
const tomorrowDateString = formatDate(tomorrowDate);
|
|
|
|
loadData(currentDateString, true);
|
|
loadData(tomorrowDateString, false);
|
|
}
|
|
|
|
window.onload = function() {
|
|
loadAllData();
|
|
// Reload data every hour (3600000 milliseconds)
|
|
setInterval(loadAllData, 3600000);
|
|
};
|
|
async function createTableRows() {
|
|
const tbody = document.getElementById('prices-table-body');
|
|
tbody.innerHTML = '';
|
|
const today = new Date();
|
|
const tomorrow = new Date(today);
|
|
tomorrow.setDate(today.getDate() + 1);
|
|
const tomorrowString = formatDate(tomorrow);
|
|
// Check if tomorrow's data is available
|
|
let tomorrowAvailable = false;
|
|
try {
|
|
const resp = await fetch('/price/day/' + tomorrowString + '?num_cheapest_hours=8');
|
|
const data = await resp.json();
|
|
if (!data.detail || data.detail !== "prices not found") {
|
|
tomorrowAvailable = true;
|
|
}
|
|
} catch (e) {}
|
|
|
|
let rowCount = tomorrowAvailable ? 15 : 14;
|
|
for (let offset = 0; offset < rowCount; offset++) {
|
|
let date;
|
|
let label;
|
|
if (tomorrowAvailable && offset === 0) {
|
|
date = tomorrow;
|
|
label = `Zítra (${tomorrowString})`;
|
|
} else {
|
|
date = new Date(today);
|
|
date.setDate(today.getDate() - (tomorrowAvailable ? offset - 1 : offset));
|
|
const dateString = formatDate(date);
|
|
label = offset === (tomorrowAvailable ? 1 : 0) ? `Dnes (${dateString})` : dateString;
|
|
}
|
|
const dateString = formatDate(date);
|
|
const rowId = `row-${dateString}`;
|
|
const tr = document.createElement('tr');
|
|
tr.id = rowId;
|
|
// Date cell
|
|
const dateCell = document.createElement('td');
|
|
let dateCellClass = 'px-1 w-16 ';
|
|
// Weekend: Saturday (6) or Sunday (0)
|
|
if (date.getDay() === 0 || date.getDay() === 6) {
|
|
dateCellClass += 'bg-neutral-500';
|
|
} else {
|
|
dateCellClass += 'bg-neutral-200';
|
|
}
|
|
dateCell.className = dateCellClass;
|
|
dateCell.id = `date-${dateString}`;
|
|
dateCell.innerText = label;
|
|
tr.appendChild(dateCell);
|
|
// Hour cells
|
|
for (let i = 0; i < 24; i++) {
|
|
const td = document.createElement('td');
|
|
td.className = 'px-1';
|
|
td.id = `${dateString}-${i}`;
|
|
td.innerText = '-';
|
|
tr.appendChild(td);
|
|
}
|
|
tbody.appendChild(tr);
|
|
}
|
|
}
|
|
|
|
function loadData(date, isToday) {
|
|
fetch('/price/day/' + date + '?num_cheapest_hours=8')
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.detail == "prices not found") {
|
|
for (let i = 0; i < 24; i++) {
|
|
document.getElementById(`${date}-${i}`).innerText = "-";
|
|
}
|
|
return;
|
|
}
|
|
for (let i = 0; i < 24; i++) {
|
|
let extra_class = "";
|
|
let border = "border-dotted";
|
|
if (isToday && i == new Date().getHours()) {
|
|
extra_class = " font-bold text-xl";
|
|
border = "border-solid";
|
|
}
|
|
let value = Math.round(data.total.hours[i] * 100) / 100;
|
|
let td = document.getElementById(`${date}-${i}`);
|
|
if (data.cheapest_hours_by_average.hours.includes(i)) {
|
|
td.className = `px-1 ${border} border-4 border-lime-400 ${getBgColor(value)}${extra_class}`;
|
|
} else if (data.most_expensive_hours_by_average.hours.includes(i)) {
|
|
td.className = `px-1 ${border} border-4 border-rose-400 ${getBgColor(value)}${extra_class}`;
|
|
} else {
|
|
if (extra_class != "") {
|
|
extra_class = " border-4 border-solid border-gray-500";
|
|
}
|
|
td.className = `px-1 ${getBgColor(value)}${extra_class}`;
|
|
}
|
|
td.innerText = value;
|
|
}
|
|
});
|
|
}
|
|
|
|
async function loadAllData() {
|
|
await createTableRows();
|
|
const today = new Date();
|
|
const tomorrow = new Date(today);
|
|
tomorrow.setDate(today.getDate() + 1);
|
|
const tomorrowString = formatDate(tomorrow);
|
|
// Check if tomorrow's data is available
|
|
let tomorrowAvailable = false;
|
|
try {
|
|
const resp = await fetch('/price/day/' + tomorrowString + '?num_cheapest_hours=8');
|
|
const data = await resp.json();
|
|
if (!data.detail || data.detail !== "prices not found") {
|
|
tomorrowAvailable = true;
|
|
}
|
|
} catch (e) {}
|
|
let rowCount = tomorrowAvailable ? 15 : 14;
|
|
for (let offset = 0; offset < rowCount; offset++) {
|
|
let date;
|
|
if (tomorrowAvailable && offset === 0) {
|
|
date = tomorrow;
|
|
} else {
|
|
date = new Date(today);
|
|
date.setDate(today.getDate() - (tomorrowAvailable ? offset - 1 : offset));
|
|
}
|
|
const dateString = formatDate(date);
|
|
loadData(dateString, (tomorrowAvailable ? offset === 1 : offset === 0));
|
|
}
|
|
}
|
|
|
|
window.onload = function() {
|
|
loadAllData();
|
|
setInterval(loadAllData, 3600000);
|
|
};
|
|
</script>
|
|
</head>
|
|
<body class="bg-neutral-800">
|
|
<table class="table border-collapse border border-slate-500 text-center w-full" id="prices-table">
|
|
<thead>
|
|
<tr class="bg-neutral-400">
|
|
<th class="px-1">Datum</th>
|
|
<th class="px-1">00</th>
|
|
<th class="px-1">01</th>
|
|
<th class="px-1">02</th>
|
|
<th class="px-1">03</th>
|
|
<th class="px-1">04</th>
|
|
<th class="px-1">05</th>
|
|
<th class="px-1">06</th>
|
|
<th class="px-1">07</th>
|
|
<th class="px-1">08</th>
|
|
<th class="px-1">09</th>
|
|
<th class="px-1">10</th>
|
|
<th class="px-1">11</th>
|
|
<th class="px-1">12</th>
|
|
<th class="px-1">13</th>
|
|
<th class="px-1">14</th>
|
|
<th class="px-1">15</th>
|
|
<th class="px-1">16</th>
|
|
<th class="px-1">17</th>
|
|
<th class="px-1">18</th>
|
|
<th class="px-1">19</th>
|
|
<th class="px-1">20</th>
|
|
<th class="px-1">21</th>
|
|
<th class="px-1">22</th>
|
|
<th class="px-1">23</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="prices-table-body">
|
|
</tbody>
|
|
</table>
|
|
|
|
</body>
|
|
</html>
|