171 lines
4.1 KiB
HTML
171 lines
4.1 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>Graphs</title>
|
|
<link rel="stylesheet" href="/static/style.css">
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<div class="layout">
|
|
|
|
<!-- SIDEBAR (optional placeholder - remove if not needed) -->
|
|
<div class="sidebar">
|
|
<div class="nav-item active">Graphs</div>
|
|
<div class="nav-item">Dashboard</div>
|
|
<div class="nav-item">Settings</div>
|
|
</div>
|
|
|
|
<!-- MAIN CONTENT -->
|
|
<div class="content">
|
|
|
|
<div class="page">
|
|
|
|
<h2 class="section-title">Graphs</h2>
|
|
<a href="/">Back</a>
|
|
|
|
<div class="chart-container" style="height: calc(100vh - 140px);">
|
|
<canvas id="chart"></canvas>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function getParams() {
|
|
const url = new URL(window.location.href);
|
|
|
|
return {
|
|
tickers: url.searchParams.get("ticker"),
|
|
limit: parseInt(url.searchParams.get("limit") || 28)
|
|
};
|
|
}
|
|
|
|
async function loadGraph() {
|
|
const { tickers, limit } = getParams();
|
|
|
|
if (!tickers) {
|
|
document.body.innerHTML = "<h3>Missing ?ticker= parameter</h3>";
|
|
return;
|
|
}
|
|
|
|
const tickerList = tickers.split(",").map(t => t.trim());
|
|
|
|
const res = await fetch(
|
|
`/api/graphs?ticker=${tickers}&limit=${limit}`
|
|
);
|
|
|
|
const data = await res.json();
|
|
|
|
const datasets = [];
|
|
let basePrices = [];
|
|
|
|
tickerList.forEach((ticker, index) => {
|
|
|
|
const raw = data[ticker] || [];
|
|
|
|
if (raw.length === 0) return;
|
|
|
|
const companyName = `${raw[0].CompanyName} (${ticker})` || ticker;
|
|
|
|
const prices = raw
|
|
.map(r => parseFloat(r.NewPrice))
|
|
.reverse();
|
|
|
|
if (index === 0) basePrices = prices;
|
|
|
|
const color = `hsl(${(index * 360) / tickerList.length}, 70%, 50%)`;
|
|
|
|
const pointColors = prices.map((_, i) =>
|
|
i % 4 === 0 ? "rgba(255, 99, 132, 1)" : color
|
|
);
|
|
|
|
const pointSizes = prices.map((_, i) =>
|
|
i % 4 === 0 ? 5 : 3
|
|
);
|
|
|
|
datasets.push({
|
|
label: companyName,
|
|
data: prices,
|
|
borderColor: color,
|
|
backgroundColor: color,
|
|
borderWidth: 2,
|
|
fill: false,
|
|
pointBackgroundColor: pointColors,
|
|
pointBorderColor: pointColors,
|
|
pointRadius: pointSizes,
|
|
pointHoverRadius: 6
|
|
});
|
|
});
|
|
|
|
const labels = [];
|
|
const totalDays = Math.ceil(basePrices.length / 4);
|
|
let dayCounter = totalDays;
|
|
|
|
for (let i = 0; i < basePrices.length; i++) {
|
|
if (i % 4 === 0) {
|
|
labels.push(String(dayCounter));
|
|
dayCounter--;
|
|
} else {
|
|
labels.push("");
|
|
}
|
|
}
|
|
|
|
new Chart(document.getElementById("chart"), {
|
|
type: "line",
|
|
data: {
|
|
labels: labels,
|
|
datasets: datasets
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
|
|
plugins: {
|
|
tooltip: {
|
|
callbacks: {
|
|
label: function(context) {
|
|
return `${context.dataset.label}: $${context.parsed.y}`;
|
|
}
|
|
}
|
|
},
|
|
legend: {
|
|
display: true
|
|
}
|
|
},
|
|
|
|
scales: {
|
|
x: {
|
|
title: {
|
|
display: true,
|
|
text: "Days"
|
|
},
|
|
ticks: {
|
|
autoSkip: false,
|
|
maxRotation: 0
|
|
}
|
|
},
|
|
y: {
|
|
title: {
|
|
display: true,
|
|
text: "Price ($)"
|
|
},
|
|
ticks: {
|
|
callback: function(value) {
|
|
return `$${value}`;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
loadGraph();
|
|
</script>
|
|
|
|
</body>
|
|
</html> |