136 lines
3.2 KiB
JavaScript
136 lines
3.2 KiB
JavaScript
/**
|
|
* Chart utilities for activity visualization
|
|
*/
|
|
|
|
class ActivityChart {
|
|
constructor(canvasId) {
|
|
this.canvasId = canvasId;
|
|
this.chart = null;
|
|
this.initChart();
|
|
}
|
|
|
|
initChart() {
|
|
// Check if Chart.js is available
|
|
if (typeof Chart === "undefined") {
|
|
console.error("Chart.js is not loaded");
|
|
return;
|
|
}
|
|
|
|
const chartElement = document.getElementById(this.canvasId);
|
|
if (!chartElement) {
|
|
console.error(
|
|
`Chart canvas element with id "${this.canvasId}" not found`
|
|
);
|
|
return;
|
|
}
|
|
|
|
this.ctx = chartElement.getContext("2d");
|
|
}
|
|
|
|
/**
|
|
* Render the activity chart with provided data
|
|
* @param {Array} data - Chart data array
|
|
*/
|
|
render(data) {
|
|
if (!this.ctx) {
|
|
console.error("Chart context not available");
|
|
return;
|
|
}
|
|
|
|
// Extract the data for the chart
|
|
const labels = data.map((item) => `${item.hour}:00`);
|
|
const successData = data.map((item) => item.success);
|
|
const errorData = data.map((item) => item.error);
|
|
const pendingData = data.map((item) => item.pending);
|
|
|
|
// Destroy existing chart if it exists
|
|
if (this.chart) {
|
|
this.chart.destroy();
|
|
}
|
|
|
|
this.chart = new Chart(this.ctx, {
|
|
type: "bar",
|
|
data: {
|
|
labels: labels,
|
|
datasets: [
|
|
{
|
|
label: "Success",
|
|
data: successData,
|
|
backgroundColor: "#28a745",
|
|
stack: "Stack 0",
|
|
},
|
|
{
|
|
label: "Error",
|
|
data: errorData,
|
|
backgroundColor: "#dc3545",
|
|
stack: "Stack 0",
|
|
},
|
|
{
|
|
label: "Pending",
|
|
data: pendingData,
|
|
backgroundColor: "#ffc107",
|
|
stack: "Stack 0",
|
|
},
|
|
],
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
scales: {
|
|
x: {
|
|
stacked: true,
|
|
title: {
|
|
display: true,
|
|
text: "Hour",
|
|
},
|
|
},
|
|
y: {
|
|
stacked: true,
|
|
beginAtZero: true,
|
|
title: {
|
|
display: true,
|
|
text: "Papers Scraped",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Load and render chart data for specified time range
|
|
* @param {number} hours - Number of hours to show data for
|
|
*/
|
|
async loadData(hours) {
|
|
try {
|
|
const response = await fetch(`/scraper/stats?hours=${hours}`);
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
const data = await response.json();
|
|
console.log("Stats data loaded:", data);
|
|
this.render(data);
|
|
} catch (error) {
|
|
console.error("Failed to load activity stats:", error);
|
|
// Hide the chart or show an error message
|
|
const chartContainer = document.getElementById(
|
|
this.canvasId
|
|
).parentElement;
|
|
if (chartContainer) {
|
|
chartContainer.innerHTML =
|
|
'<p class="text-muted">Chart data unavailable</p>';
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Destroy the chart instance
|
|
*/
|
|
destroy() {
|
|
if (this.chart) {
|
|
this.chart.destroy();
|
|
this.chart = null;
|
|
}
|
|
}
|
|
}
|