Fooocus/web/assets/js/chart-settings.js

553 lines
16 KiB
JavaScript

// VARS AND CONST
const hostname = "localhost"; // Gets the host without port
const baseUrl = `http://${hostname}:5000`; // Append the port 5000
const apiUrl = `${baseUrl}/gpu_usage/`;
const colorPalette = [
"rgb(240, 193, 90, 0.2)",
"rgb(240, 142, 219, 0.2)",
"rgb(24, 90, 219, 0.2)",
"rgb(127, 161, 195, 0.2)",
"rgb(128, 239, 145, 0.2)",
"rgb(245, 245, 245, 0.2)",
"rgb(240, 142, 219, 0.2)",
"rgb(159, 238, 209, 0.2)",
];
const borderColors = [
"rgb(240, 193, 90)",
"rgb(240, 142, 219)",
"rgb(24, 90, 219)",
"rgb(127, 161, 195)",
"rgb(128, 239, 145)",
"rgb(245, 245, 245)",
"rgb(240, 142, 219)",
"rgb(159, 238, 209)",
];
let currentChart = null; // Track the current chart instance
const MAX_DATA_POINTS = 50; // Number of data points to keep
// Custom plugin to draw fixed labels in the middle of the chart area
const fixedLabelPlugin = {
id: "fixedLabelPlugin",
afterDatasetsDraw(chart) {
const { ctx, scales, data } = chart;
ctx.save();
const centerX = scales.x.left + scales.x.width / 2;
const labelPositions = [];
data.datasets[0].data.forEach((value, index) => {
const yPos = chart.getDatasetMeta(0).data[index].y;
// Store yPos for positioning labels
labelPositions.push({
x: centerX,
y: yPos,
value: `${+value.toFixed(2)}` + `${index == 5 ? "\u00B0" : "%"}`,
});
});
const size = localStorage.getItem("chart-size") ?? "small";
let fontSize = 10; // Default font size
switch (size) {
case "small":
fontSize = "10px";
break;
case "medium":
fontSize = "16px";
break;
default:
fontSize = "18px";
break;
}
ctx.font = fontSize;
ctx.fillStyle = "#FFFFFF";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
labelPositions.forEach((label) => {
ctx.fillText(label.value, label.x, label.y);
});
ctx.restore();
},
};
// Initialize the bar chart
function initializeBarChart() {
localStorage.setItem("active-chart", "bar");
const chartContainer = document.getElementById("chart-container");
const existingCanvas = document.getElementById("usage-chart");
const chartWrapper = document.getElementById("chart-wrapper");
if (existingCanvas) {
chartContainer.removeChild(existingCanvas);
}
const size = localStorage.getItem("chart-size") ?? "small";
let fontSize = 10; // Default font size
switch (size) {
case "small":
fontSize = "10px";
break;
case "medium":
fontSize = "16px";
break;
default:
fontSize = "18px";
break;
}
// Create a new canvas element
const newCanvas = document.createElement("canvas");
newCanvas.id = "usage-chart";
newCanvas.classList.add("bar"); // Add the class directly to the canvas element
chartContainer.appendChild(newCanvas);
const ctx = newCanvas.getContext("2d");
$(chartWrapper).hide();
currentChart = new Chart(ctx, {
type: "bar",
data: {
labels: ["CPU", "RAM", "GPU", "VRAM", "HDD", "TEMP"],
datasets: [
{
label: "Usage",
data: [0, 0, 0, 0, 0],
barPercentage: 0.8, // Adjust space occupied by bars
categoryPercentage: 1, // Adjust space between bars
backgroundColor: function (context) {
const value = context.dataset.data[context.dataIndex];
return value > 90 ? "#D9534F" : colorPalette[context.dataIndex];
},
borderColor: function (context) {
const value = context.dataset.data[context.dataIndex];
return value > 90 ? "#D9534F" : borderColors[context.dataIndex];
},
borderWidth: 1.5,
},
],
},
options: {
indexAxis: "y", // Horizontal bars
scales: {
x: {
grid: {
display: false, // Hide all grid lines
},
border: {
display: false, // Hide all grid lines
},
beginAtZero: true,
max: 100,
ticks: {
color: "#ffffff",
font: {
size: fontSize,
weight: 600,
},
align: "center",
callback: function (value, index, ticks) {
return value + "%";
},
},
},
y: {
grid: {
display: false,
},
border: {
color: "#ffffff30",
width: 1, // Width of the axis border
},
ticks: {
color: "#FFFFFF",
crossAlign: "far",
font: {
weight: 600,
size: fontSize,
},
// Specify the maximum number of ticks to show
maxTicksLimit: 10,
// Control the step size between ticks
stepSize: 1,
// Optional: Set font size and other style properties
},
},
},
plugins: {
legend: {
display: false,
},
tooltip: {
enabled: false,
},
},
responsive: true,
maintainAspectRatio: false,
},
plugins: [fixedLabelPlugin], // Register the custom plugins
});
currentChart.options.animation = true;
const legendContainer = document.getElementById("custom-legend");
legendContainer.innerHTML = "";
document.getElementById("settingsMenu").classList.remove("show"); // Hide the menu
document.querySelectorAll("canvas").forEach((row) => {
row.classList.remove("no-drag");
row.classList.add("drag");
});
window.addEventListener("resize", () => {
currentChart.resize();
});
$(chartWrapper).fadeIn(300);
}
// Initialize the line chart
function initializeLineChart() {
localStorage.setItem("active-chart", "line");
const existingCanvas = document.getElementById("usage-chart");
const chartContainer = document.getElementById("chart-container");
const chartWrapper = document.getElementById("chart-wrapper");
if (existingCanvas) {
chartContainer.removeChild(existingCanvas);
}
// Create a new canvas element
const newCanvas = document.createElement("canvas");
newCanvas.id = "usage-chart";
newCanvas.classList.add("line"); // Add the class directly to the canvas element
chartContainer.appendChild(newCanvas);
$(chartWrapper).hide();
const ctx = newCanvas.getContext("2d");
currentChart = new Chart(ctx, {
type: "line",
data: {
labels: [],
datasets: [
{
label: "CPU",
data: [],
borderColor: function (context) {
const dataset = context.dataset;
const datasetIndex = context.datasetIndex;
const shouldUseRed = dataset.data.some((value) => value > 90);
if (shouldUseRed) {
return "#D9534F"; // Return red color if any value exceeds 90
}
return borderColors[datasetIndex % borderColors.length];
},
borderWidth: 1.5,
backgroundColor: function (context) {
const dataset = context.dataset;
const datasetIndex = context.datasetIndex;
const shouldUseRed = dataset.data.some((value) => value > 90);
if (shouldUseRed) {
return "#D9534F"; // Return red color if any value exceeds 90
}
return colorPalette[datasetIndex % borderColors.length];
},
fill: false,
tension: 0.1,
},
{
label: "RAM",
data: [],
borderColor: function (context) {
const dataset = context.dataset;
const datasetIndex = context.datasetIndex;
const shouldUseRed = dataset.data.some((value) => value > 90);
if (shouldUseRed) {
return "#D9534F"; // Return red color if any value exceeds 90
}
return borderColors[datasetIndex % borderColors.length];
},
borderWidth: 1.5,
backgroundColor: function (context) {
const dataset = context.dataset;
const datasetIndex = context.datasetIndex;
const shouldUseRed = dataset.data.some((value) => value > 90);
if (shouldUseRed) {
return "#D9534F"; // Return red color if any value exceeds 90
}
return colorPalette[datasetIndex % borderColors.length];
},
fill: false,
tension: 0.1,
},
{
label: "GPU",
data: [],
borderColor: function (context) {
const dataset = context.dataset;
const datasetIndex = context.datasetIndex;
const shouldUseRed = dataset.data.some((value) => value > 90);
if (shouldUseRed) {
return "#D9534F"; // Return red color if any value exceeds 90
}
return borderColors[datasetIndex % borderColors.length];
},
borderWidth: 1.5,
backgroundColor: function (context) {
const dataset = context.dataset;
const datasetIndex = context.datasetIndex;
const shouldUseRed = dataset.data.some((value) => value > 90);
if (shouldUseRed) {
return "#D9534F"; // Return red color if any value exceeds 90
}
return colorPalette[datasetIndex % borderColors.length];
},
fill: false,
tension: 0.1,
},
{
label: "VRAM",
data: [],
borderColor: function (context) {
const dataset = context.dataset;
const datasetIndex = context.datasetIndex;
const shouldUseRed = dataset.data.some((value) => value > 90);
if (shouldUseRed) {
return "#D9534F"; // Return red color if any value exceeds 90
}
return borderColors[datasetIndex % borderColors.length];
},
borderWidth: 1.5,
backgroundColor: function (context) {
const dataset = context.dataset;
const datasetIndex = context.datasetIndex;
const shouldUseRed = dataset.data.some((value) => value > 90);
if (shouldUseRed) {
return "#D9534F"; // Return red color if any value exceeds 90
}
return colorPalette[datasetIndex % borderColors.length];
},
fill: false,
tension: 0.1,
},
{
label: "HDD",
data: [],
borderColor: function (context) {
const dataset = context.dataset;
const datasetIndex = context.datasetIndex;
const shouldUseRed = dataset.data.some((value) => value > 90);
if (shouldUseRed) {
return "#D9534F"; // Return red color if any value exceeds 90
}
return borderColors[datasetIndex % borderColors.length];
},
borderWidth: 1.5,
backgroundColor: function (context) {
const dataset = context.dataset;
const datasetIndex = context.datasetIndex;
const shouldUseRed = dataset.data.some((value) => value > 90);
if (shouldUseRed) {
return "#D9534F"; // Return red color if any value exceeds 90
}
return colorPalette[datasetIndex % borderColors.length];
},
fill: false,
tension: 0.1,
},
{
label: "TEMP",
data: [],
borderColor: function (context) {
const dataset = context.dataset;
const datasetIndex = context.datasetIndex;
const shouldUseRed = dataset.data.some((value) => value > 90);
if (shouldUseRed) {
return "#D9534F"; // Return red color if any value exceeds 90
}
return borderColors[datasetIndex % borderColors.length];
},
borderWidth: 1.5,
backgroundColor: function (context) {
const dataset = context.dataset;
const datasetIndex = context.datasetIndex;
const shouldUseRed = dataset.data.some((value) => value > 90);
if (shouldUseRed) {
return "#D9534F"; // Return red color if any value exceeds 90
}
return colorPalette[datasetIndex % borderColors.length];
},
fill: false,
tension: 0.1,
},
],
},
options: {
animation: {
enabled: false,
tension: {
duration: 1000,
easing: "linear",
from: 1,
to: 0,
loop: true,
},
},
elements: {
point: {
radius: 0,
},
},
scales: {
x: {
ticks: {
display: false,
},
},
y: {
beginAtZero: true,
max: 100,
ticks: {
color: "#FFFFFF",
crossAlign: "far",
padding: 0,
font: {
weight: 600,
size: 7,
},
callback: function (value, index, ticks) {
return value + "%";
},
},
},
},
responsive: true,
plugins: {
legend: {
display: true,
labels: {
generateLabels: false,
},
},
title: {
display: false,
},
},
},
});
currentChart.options.animation = false;
generateCustomLegend();
document.getElementById("settingsMenu").classList.remove("show"); // Hide the menu
window.addEventListener("resize", () => {
currentChart.resize();
});
$(chartWrapper).fadeIn(300);
}
function generateCustomLegend() {
const legendContainer = document.getElementById("custom-legend");
legendContainer.innerHTML = "";
currentChart.data.datasets.forEach((dataset, index) => {
const legendItem = document.createElement("div");
legendItem.className = "custom-legend-item";
// Create text element
const legendText = document.createElement("span");
legendText.className = "custom-legend-text";
legendText.textContent = dataset.label;
const shouldUseRed = dataset.data.some((value) => value > 90);
legendText.style.color = shouldUseRed
? "#D9534F"
: `${borderColors[index]}`;
legendText.style.fontWeight = shouldUseRed ? "800" : `600`;
const size = localStorage.getItem("chart-size") ?? "small";
switch (size) {
case "small":
legendText.style.fontSize = "10px";
break;
case "medium":
legendText.style.fontSize = "16px";
break;
default:
legendText.style.fontSize = "18px";
break;
}
legendItem.appendChild(legendText);
legendContainer.appendChild(legendItem);
});
}
async function updateUsage() {
try {
const response = await fetch(apiUrl);
const data = await response.json();
const timestamp = new Date();
if (currentChart) {
if (currentChart.config.type === "bar") {
// Update data for bar chart
currentChart.data.datasets[0].data = [
data.cpu,
data.ram,
data.gpu,
data.vram,
data.hdd,
data.temp,
];
} else if (currentChart.config.type === "line") {
// Update data for line chart
currentChart.data.labels.push(timestamp);
currentChart.data.datasets[0].data.push(data.cpu);
currentChart.data.datasets[1].data.push(data.ram);
currentChart.data.datasets[2].data.push(data.gpu);
currentChart.data.datasets[3].data.push(data.vram);
currentChart.data.datasets[4].data.push(data.hdd);
currentChart.data.datasets[5].data.push(data.temp);
// Prune old data if the number of points exceeds the limit
if (currentChart.data.labels.length > MAX_DATA_POINTS) {
currentChart.data.labels.shift(); // Remove the oldest label
currentChart.data.datasets.forEach((dataset) => dataset.data.shift()); // Remove the oldest data points
}
generateCustomLegend();
}
// Update the chart with new data
currentChart.update();
}
} catch (error) {
console.error("Failed to fetch usage data.", error);
}
}
let intervalId; // Variable to store the interval ID
// Function to start the interval
function startInterval() {
intervalId = setInterval(updateUsage, 500);
}
// Function to stop the interval
function stopInterval() {
if (intervalId) {
clearInterval(intervalId);
intervalId = null; // Optional: Reset intervalId to indicate no active interval
}
}