sleepy time update
This commit is contained in:
271
Mizzajl/home/UIGraph.js
Normal file
271
Mizzajl/home/UIGraph.js
Normal file
@@ -0,0 +1,271 @@
|
||||
/** @param {NS} ns */
|
||||
export async function main(ns) {
|
||||
const doc = eval("document");
|
||||
|
||||
// File to store money data
|
||||
const moneyRecordFile = "MoneyRecord.txt";
|
||||
const recordInterval = 10000; // Record every 10 seconds
|
||||
const graphDuration = 300000; // Last 5 minutes (in milliseconds)
|
||||
let isClosed = false; // Track if the window is closed
|
||||
|
||||
// Function to format numbers as K (thousand), M (million), B (billion), etc.
|
||||
function formatLargeNumber(number) {
|
||||
if (number >= 1e12) {
|
||||
return `$${(number / 1e12).toFixed(3)}t`;
|
||||
} else if (number >= 1e9) {
|
||||
return `$${(number / 1e9).toFixed(3)}b`;
|
||||
} else if (number >= 1e6) {
|
||||
return `$${(number / 1e6).toFixed(3)}m`;
|
||||
} else if (number >= 1e3) {
|
||||
return `$${(number / 1e3).toFixed(3)}k`;
|
||||
} else {
|
||||
return `$${number.toFixed(2)}`; // Less than 1000, show as a standard number
|
||||
}
|
||||
}
|
||||
|
||||
// Remove any existing container if it exists
|
||||
const existingContainer = doc.getElementById("money-graph-container");
|
||||
if (existingContainer) {
|
||||
existingContainer.remove(); // Remove the existing container
|
||||
ns.tprint("Previous graph closed.");
|
||||
}
|
||||
|
||||
// Create the container for the graph
|
||||
const container = doc.createElement("div");
|
||||
container.id = "money-graph-container";
|
||||
container.style = `
|
||||
position: absolute;
|
||||
top: 200px;
|
||||
left: 200px;
|
||||
width: 600px;
|
||||
height: 300px;
|
||||
background-color: rgba(0, 0, 0, 0.9); /* Black background with 90% opacity */
|
||||
color: #0c0; /* Green text */
|
||||
border: 2px solid #666;
|
||||
border-radius: 8px;
|
||||
padding: 10px;
|
||||
font-family: "Source Code Pro", monospace;
|
||||
z-index: 1000;
|
||||
cursor: move;
|
||||
box-shadow: 0px 0px 15px rgba(0, 255, 0, 0.5); /* Glow effect */
|
||||
`;
|
||||
|
||||
// Create a header bar with a close button
|
||||
const header = doc.createElement("div");
|
||||
header.style = `
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-weight: bold;
|
||||
color: #0c0; /* Green text */
|
||||
padding: 5px;
|
||||
background: rgba(17, 17, 17, 0.9); /* Dark background with 90% opacity */
|
||||
border-bottom: 1px solid #666;
|
||||
text-shadow: 0px 0px 10px #0f0;
|
||||
`;
|
||||
header.innerText = "Server Money Graph";
|
||||
|
||||
// Close button
|
||||
const closeButton = doc.createElement("button");
|
||||
closeButton.innerText = "X";
|
||||
closeButton.style = `
|
||||
background: none;
|
||||
border: 1px solid #666;
|
||||
color: #0c0; /* Green text */
|
||||
cursor: pointer;
|
||||
padding: 2px 8px;
|
||||
font-weight: bold;
|
||||
border-radius: 3px;
|
||||
margin-left: 10px;
|
||||
`;
|
||||
closeButton.addEventListener("click", () => {
|
||||
container.remove(); // Close the graph container
|
||||
ns.tprint("Graph window closed.");
|
||||
isClosed = true; // Mark the window as closed
|
||||
});
|
||||
|
||||
header.appendChild(closeButton);
|
||||
container.appendChild(header);
|
||||
|
||||
// Create the canvas for the graph
|
||||
const canvas = doc.createElement("canvas");
|
||||
canvas.id = "money-graph";
|
||||
canvas.width = 580; // Slightly smaller than the container for padding
|
||||
canvas.height = 200;
|
||||
canvas.style = `
|
||||
background-color: rgba(17, 17, 17, 0.9); /* Dark background with 90% opacity */
|
||||
border: 1px solid #666;
|
||||
border-radius: 4px;
|
||||
margin-top: 10px;
|
||||
`;
|
||||
container.appendChild(canvas);
|
||||
|
||||
// Create the money display (on the right side of the graph)
|
||||
const moneyDisplay = doc.createElement("div");
|
||||
moneyDisplay.style = `
|
||||
color: #ffd700; /* Yellow color for money display */
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 100px;
|
||||
`;
|
||||
moneyDisplay.innerText = "Money: Loading...";
|
||||
container.appendChild(moneyDisplay);
|
||||
|
||||
doc.body.appendChild(container);
|
||||
|
||||
const ctx = canvas.getContext("2d");
|
||||
|
||||
// Movable functionality for the entire container
|
||||
let isMoving = false;
|
||||
let offsetX = 0, offsetY = 0;
|
||||
|
||||
// Start moving the container on mousedown
|
||||
function startMove(e) {
|
||||
isMoving = true;
|
||||
offsetX = e.clientX - container.getBoundingClientRect().left;
|
||||
offsetY = e.clientY - container.getBoundingClientRect().top;
|
||||
container.style.cursor = "grabbing"; // Change cursor to grabbing while moving
|
||||
}
|
||||
|
||||
// Stop moving on mouseup
|
||||
function stopMove() {
|
||||
if (isMoving) {
|
||||
isMoving = false;
|
||||
container.style.cursor = "move"; // Change cursor back to move
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the movement of the window
|
||||
function moveWindow(e) {
|
||||
if (isMoving) {
|
||||
container.style.left = `${e.clientX - offsetX}px`;
|
||||
container.style.top = `${e.clientY - offsetY}px`;
|
||||
}
|
||||
}
|
||||
|
||||
// Attach event listeners for movement
|
||||
container.addEventListener("mousedown", startMove);
|
||||
doc.addEventListener("mousemove", moveWindow);
|
||||
doc.addEventListener("mouseup", stopMove);
|
||||
doc.addEventListener("mouseleave", stopMove); // Stop moving if mouse leaves the window
|
||||
|
||||
// Function to record money data to file with timestamps
|
||||
function recordMoneyData() {
|
||||
const currentMoney = ns.getServerMoneyAvailable("home");
|
||||
const timestamp = Date.now();
|
||||
const record = `${timestamp},${currentMoney}\n`;
|
||||
ns.write(moneyRecordFile, record, "a"); // Append without await
|
||||
moneyDisplay.innerText = `Money: ${formatLargeNumber(currentMoney)}`; // Update money display with formatted value
|
||||
}
|
||||
|
||||
// Function to draw grid lines
|
||||
function drawGridLines(maxMoney, minMoney) {
|
||||
const numSteps = 5; // Number of steps on the axes
|
||||
const stepY = (maxMoney - minMoney) / numSteps; // Step size for Y-axis
|
||||
const stepX = graphDuration / numSteps; // Step size for X-axis (time)
|
||||
|
||||
// Draw vertical grid lines (X-axis steps)
|
||||
for (let i = 1; i <= numSteps; i++) {
|
||||
const x = 40 + (i * (canvas.width - 60)) / numSteps;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x, 10);
|
||||
ctx.lineTo(x, 180);
|
||||
ctx.strokeStyle = 'rgba(0, 255, 0, 0.2)'; // Faint green grid line
|
||||
ctx.stroke();
|
||||
// Draw X-axis labels
|
||||
const timeLabel = `${Math.round((i * stepX) / 1000)}s`;
|
||||
ctx.fillStyle = '#0c0';
|
||||
ctx.font = '12px "Source Code Pro"';
|
||||
ctx.fillText(timeLabel, x - 10, 190);
|
||||
}
|
||||
|
||||
// Draw horizontal grid lines (Y-axis steps)
|
||||
for (let i = 1; i <= numSteps; i++) {
|
||||
const y = 180 - (i * 170) / numSteps;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(40, y);
|
||||
ctx.lineTo(550, y);
|
||||
ctx.strokeStyle = 'rgba(0, 255, 0, 0.2)'; // Faint green grid line
|
||||
ctx.stroke();
|
||||
// Draw Y-axis labels with formatted money
|
||||
const moneyLabel = formatLargeNumber(minMoney + i * stepY);
|
||||
ctx.fillStyle = '#0c0';
|
||||
ctx.font = '12px "Source Code Pro"';
|
||||
ctx.fillText(moneyLabel, 5, y + 5);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to draw the graph with dynamic scaling from file
|
||||
async function drawGraph() {
|
||||
const fileData = await ns.read(moneyRecordFile);
|
||||
if (!fileData) return;
|
||||
|
||||
const records = fileData.trim().split("\n").map(line => {
|
||||
const [timestamp, money] = line.split(",");
|
||||
return { timestamp: parseInt(timestamp), money: parseFloat(money) };
|
||||
});
|
||||
|
||||
const now = Date.now();
|
||||
const recentRecords = records.filter(record => now - record.timestamp <= graphDuration);
|
||||
|
||||
// Clear the canvas
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
if (recentRecords.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const maxMoney = Math.max(...recentRecords.map(record => record.money));
|
||||
const minMoney = Math.min(...recentRecords.map(record => record.money));
|
||||
|
||||
if (maxMoney === minMoney) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Draw gridlines
|
||||
drawGridLines(maxMoney, minMoney);
|
||||
|
||||
// Draw axes
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(40, 10); // Left margin
|
||||
ctx.lineTo(40, 180); // Bottom margin
|
||||
ctx.lineTo(550, 180); // Right margin
|
||||
ctx.strokeStyle = '#0c0'; // Green for axes
|
||||
ctx.stroke();
|
||||
|
||||
// Plot the data points with yellow line
|
||||
ctx.strokeStyle = '#ffd700'; // Yellow for the money line
|
||||
ctx.beginPath();
|
||||
const firstPoint = recentRecords[0];
|
||||
const startTime = firstPoint.timestamp;
|
||||
const initialY = 180 - ((firstPoint.money - minMoney) / (maxMoney - minMoney)) * 170; // Scale to fit graph height
|
||||
ctx.moveTo(40, initialY);
|
||||
|
||||
recentRecords.forEach((record) => {
|
||||
const timeDiff = record.timestamp - startTime;
|
||||
const x = 40 + (timeDiff / graphDuration) * (canvas.width - 60); // Scaled x-axis
|
||||
const y = 180 - ((record.money - minMoney) / (maxMoney - minMoney)) * 170; // Scaled y-axis
|
||||
ctx.lineTo(x, y);
|
||||
});
|
||||
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
// Main loop to record money data and update graph
|
||||
try {
|
||||
while (!isClosed) {
|
||||
recordMoneyData(); // Record data without await
|
||||
await drawGraph(); // Ensure graph is updated properly
|
||||
await ns.sleep(recordInterval); // Wait for 10 seconds
|
||||
}
|
||||
} catch (e) {
|
||||
ns.tprint(`Error: ${e.message}`);
|
||||
} finally {
|
||||
if (doc.body.contains(container)) {
|
||||
container.remove(); // Clean up the container when the script ends
|
||||
}
|
||||
ns.tprint("Script stopped.");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user