css/html CrimeMonitor
This commit is contained in:
@@ -3,7 +3,7 @@ import { GetCrimeStat } from "./Library";
|
|||||||
/** @param {NS} ns */
|
/** @param {NS} ns */
|
||||||
export async function main(ns) {
|
export async function main(ns) {
|
||||||
ns.tail();
|
ns.tail();
|
||||||
ns.resizeTail(1876, 412);
|
ns.resizeTail(2005, 412);
|
||||||
ns.disableLog("sleep");
|
ns.disableLog("sleep");
|
||||||
|
|
||||||
let aCrimes = [
|
let aCrimes = [
|
||||||
@@ -26,9 +26,9 @@ export async function main(ns) {
|
|||||||
ns.clearLog();
|
ns.clearLog();
|
||||||
|
|
||||||
// Header with ASCII box
|
// Header with ASCII box
|
||||||
ns.printRaw("╔══════════════════╦════════════╦═════════╦════════════════════╦════════════════════╦════════════════════╦════════════════════╦════════════════════╦════════════════════╦════════════╦════════════╗");
|
ns.printRaw("╔══════════════════╦════════════╦═════════╦════════════════════╦════════════════════╦════════════════════╦════════════════════╦════════════════════╦════════════════════╦════════════╦════════════╦════════════╗");
|
||||||
ns.printRaw("║ Crime ║ Chance ║ $/%/s ║ Hack w/xp ║ Str w/xp ║ Def w/xp ║ Dex w/xp ║ Agi w/xp ║ Cha w/xp ║ Money/s ║ Karma/s ║");
|
ns.printRaw("║ Crime ║ Chance ║ $/%/s ║ Hack w/xp ║ Str w/xp ║ Def w/xp ║ Dex w/xp ║ Agi w/xp ║ Cha w/xp ║ IntXP /s ║ Money/s ║ Karma/s ║");
|
||||||
ns.printRaw("╠══════════════════╬════════════╬═════════╬════════════════════╬════════════════════╬════════════════════╬════════════════════╬════════════════════╬════════════════════╬════════════╬════════════╣");
|
ns.printRaw("╠══════════════════╬════════════╬═════════╬════════════════════╬════════════════════╬════════════════════╬════════════════════╬════════════════════╬════════════════════╬════════════╬════════════╬════════════╣");
|
||||||
|
|
||||||
// Loop through each crime and display stats
|
// Loop through each crime and display stats
|
||||||
for (let i = 0; i < aCrimes.length; i++) {
|
for (let i = 0; i < aCrimes.length; i++) {
|
||||||
@@ -42,6 +42,7 @@ export async function main(ns) {
|
|||||||
let dexterityExpPerSecond = await GetCrimeStat(ns, crime, "dexterity_exp") / (await GetCrimeStat(ns, crime, "time") / 1000);
|
let dexterityExpPerSecond = await GetCrimeStat(ns, crime, "dexterity_exp") / (await GetCrimeStat(ns, crime, "time") / 1000);
|
||||||
let agilityExpPerSecond = await GetCrimeStat(ns, crime, "agility_exp") / (await GetCrimeStat(ns, crime, "time") / 1000);
|
let agilityExpPerSecond = await GetCrimeStat(ns, crime, "agility_exp") / (await GetCrimeStat(ns, crime, "time") / 1000);
|
||||||
let charismaExpPerSecond = await GetCrimeStat(ns, crime, "charisma_exp") / (await GetCrimeStat(ns, crime, "time") / 1000);
|
let charismaExpPerSecond = await GetCrimeStat(ns, crime, "charisma_exp") / (await GetCrimeStat(ns, crime, "time") / 1000);
|
||||||
|
let IntelligenceExpPerSecond = await GetCrimeStat(ns, crime, "intelligence_exp") / (await GetCrimeStat(ns, crime, "time") / 1000);
|
||||||
|
|
||||||
// Success weights for each attribute
|
// Success weights for each attribute
|
||||||
let hackingSuccessWeight = await GetCrimeStat(ns, crime, "hacking_success_weight");
|
let hackingSuccessWeight = await GetCrimeStat(ns, crime, "hacking_success_weight");
|
||||||
@@ -70,15 +71,16 @@ export async function main(ns) {
|
|||||||
let dexterityDisplay = `${dexteritySuccessWeight.toFixed(2)} / ${dexterityExpPerSecond.toFixed(4)}`.padEnd(19, " ");
|
let dexterityDisplay = `${dexteritySuccessWeight.toFixed(2)} / ${dexterityExpPerSecond.toFixed(4)}`.padEnd(19, " ");
|
||||||
let agilityDisplay = `${agilitySuccessWeight.toFixed(2)} / ${agilityExpPerSecond.toFixed(4)}`.padEnd(19, " ");
|
let agilityDisplay = `${agilitySuccessWeight.toFixed(2)} / ${agilityExpPerSecond.toFixed(4)}`.padEnd(19, " ");
|
||||||
let charismaDisplay = `${charismaSuccessWeight.toFixed(2)} / ${charismaExpPerSecond.toFixed(4)}`.padEnd(19, " ");
|
let charismaDisplay = `${charismaSuccessWeight.toFixed(2)} / ${charismaExpPerSecond.toFixed(4)}`.padEnd(19, " ");
|
||||||
|
let IntelligenceDisplay = `${IntelligenceExpPerSecond.toFixed(4)}`.padEnd(11, " ");
|
||||||
|
|
||||||
let moneyDisplay = moneyPerSecond.toFixed(2).padEnd(11, " ");
|
let moneyDisplay = moneyPerSecond.toFixed(2).padEnd(11, " ");
|
||||||
let karmaDisplay = karmaPerSecond.toFixed(4).padEnd(11, " ");
|
let karmaDisplay = karmaPerSecond.toFixed(4).padEnd(11, " ");
|
||||||
|
|
||||||
ns.printRaw(`║ ${crimeDisplay}║ ${chanceDisplay}║ ${nMoneyPerChancePerSecondDisplay}║ ${hackingDisplay}║ ${strengthDisplay}║ ${defenseDisplay}║ ${dexterityDisplay}║ ${agilityDisplay}║ ${charismaDisplay}║ ${moneyDisplay}║ ${karmaDisplay}║`);
|
ns.printRaw(`║ ${crimeDisplay}║ ${chanceDisplay}║ ${nMoneyPerChancePerSecondDisplay}║ ${hackingDisplay}║ ${strengthDisplay}║ ${defenseDisplay}║ ${dexterityDisplay}║ ${agilityDisplay}║ ${charismaDisplay}║ ${IntelligenceDisplay}║ ${moneyDisplay}║ ${karmaDisplay}║`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Footer with ASCII box
|
// Footer with ASCII box
|
||||||
ns.printRaw("╚══════════════════╩════════════╩═════════╩════════════════════╩════════════════════╩════════════════════╩════════════════════╩════════════════════╩════════════════════╩════════════╩════════════╝");
|
ns.printRaw("╚══════════════════╩════════════╩═════════╩════════════════════╩════════════════════╩════════════════════╩════════════════════╩════════════════════╩════════════════════╩════════════╩════════════╩════════════╝");
|
||||||
|
|
||||||
// Wait for 1 second before updating the display again
|
// Wait for 1 second before updating the display again
|
||||||
await ns.sleep(1000);
|
await ns.sleep(1000);
|
||||||
|
|||||||
238
Mizzajl/home/test.js
Normal file
238
Mizzajl/home/test.js
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
/** @param {NS} ns */
|
||||||
|
export async function main(ns) {
|
||||||
|
ns.disableLog('sleep'); // Disable log spamming
|
||||||
|
|
||||||
|
let counter = 0;
|
||||||
|
let incrementValue = 1;
|
||||||
|
let isRunning = true;
|
||||||
|
let isMinimized = false; // Tracks whether the window is minimized or not
|
||||||
|
|
||||||
|
// Define colors from the provided theme
|
||||||
|
const theme = {
|
||||||
|
primary: "#0c0",
|
||||||
|
primarylight: "#0f0",
|
||||||
|
primarydark: "#090",
|
||||||
|
error: "#c00",
|
||||||
|
backgroundprimary: "#000", // Black background
|
||||||
|
button: "#333", // Button background
|
||||||
|
buttonHoverLight: "#555", // Lighter button hover effect
|
||||||
|
buttonHoverDark: "#111", // Darker button hover effect
|
||||||
|
rippleColor: "rgba(255, 255, 255, 0.5)", // Color of the ripple effect
|
||||||
|
border: "#666" // Border color
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a div for the display (the main window)
|
||||||
|
const doc = eval("document");
|
||||||
|
let container = doc.createElement("div");
|
||||||
|
container.style = `
|
||||||
|
position: fixed;
|
||||||
|
top: 100px;
|
||||||
|
left: 100px;
|
||||||
|
background: ${theme.backgroundprimary}; /* Solid black background */
|
||||||
|
color: ${theme.primary}; /* Primary color for text */
|
||||||
|
padding: 5px;
|
||||||
|
z-index: 1000;
|
||||||
|
font-family: monospace;
|
||||||
|
border: 2px solid ${theme.border}; /* Border around the whole window */
|
||||||
|
width: 220px;
|
||||||
|
border-radius: 5px;
|
||||||
|
`;
|
||||||
|
doc.body.appendChild(container);
|
||||||
|
|
||||||
|
// Create title bar with ^ and X buttons (minimize and close)
|
||||||
|
let titleBar = doc.createElement("div");
|
||||||
|
titleBar.style = `
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
font-weight: bold;
|
||||||
|
color: ${theme.primarylight}; /* Light primary color for header */
|
||||||
|
cursor: default;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
border-bottom: 1px solid ${theme.border}; /* Border between title and content */
|
||||||
|
`;
|
||||||
|
container.appendChild(titleBar);
|
||||||
|
|
||||||
|
let title = doc.createElement("span");
|
||||||
|
title.innerText = "Overview Counter";
|
||||||
|
titleBar.appendChild(title);
|
||||||
|
|
||||||
|
let controls = doc.createElement("div");
|
||||||
|
|
||||||
|
// Create minimize button (^ for minimize/restore)
|
||||||
|
let minimizeButton = doc.createElement("button");
|
||||||
|
minimizeButton.innerText = "^";
|
||||||
|
minimizeButton.style = `
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: ${theme.primarylight}; /* Light primary color for minimize button */
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 0 5px;
|
||||||
|
`;
|
||||||
|
controls.appendChild(minimizeButton);
|
||||||
|
|
||||||
|
// Create close button (X to close)
|
||||||
|
let closeButton = doc.createElement("button");
|
||||||
|
closeButton.innerText = "X";
|
||||||
|
closeButton.style = `
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: ${theme.error}; /* Error color for close button */
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 0 5px;
|
||||||
|
`;
|
||||||
|
controls.appendChild(closeButton);
|
||||||
|
|
||||||
|
titleBar.appendChild(controls);
|
||||||
|
|
||||||
|
// Create the content area (display for counter and buttons)
|
||||||
|
let content = doc.createElement("div");
|
||||||
|
content.style = "margin-top: 10px;";
|
||||||
|
container.appendChild(content);
|
||||||
|
|
||||||
|
let counterDisplay = doc.createElement("p");
|
||||||
|
counterDisplay.style = `
|
||||||
|
margin: 5px 0;
|
||||||
|
color: ${theme.primarylight}; /* Primary light color for counter text */
|
||||||
|
`;
|
||||||
|
content.appendChild(counterDisplay);
|
||||||
|
|
||||||
|
// Function to apply button styles with hover and ripple effects
|
||||||
|
function createStyledButton(text) {
|
||||||
|
let button = doc.createElement("button");
|
||||||
|
button.innerText = text;
|
||||||
|
button.style = `
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden; /* Allow ripple effect to be confined inside the button */
|
||||||
|
background: ${theme.button}; /* Button background color */
|
||||||
|
color: ${theme.primary}; /* Primary color for button text */
|
||||||
|
border: 1px solid ${theme.border};
|
||||||
|
cursor: pointer;
|
||||||
|
margin-right: 5px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
padding: 5px;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 3px;
|
||||||
|
transition: background-color 0.3s ease; /* Smooth transition for hover effect */
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Apply hover effect (lighter if button is dark, darker if light)
|
||||||
|
button.addEventListener("mouseenter", () => {
|
||||||
|
button.style.backgroundColor = theme.button === "#333" ? theme.buttonHoverLight : theme.buttonHoverDark;
|
||||||
|
});
|
||||||
|
|
||||||
|
button.addEventListener("mouseleave", () => {
|
||||||
|
button.style.backgroundColor = theme.button;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add ripple effect on click
|
||||||
|
button.addEventListener("click", (e) => {
|
||||||
|
let ripple = doc.createElement("span");
|
||||||
|
let size = Math.max(button.offsetWidth, button.offsetHeight);
|
||||||
|
let x = e.clientX - button.getBoundingClientRect().left - size / 2;
|
||||||
|
let y = e.clientY - button.getBoundingClientRect().top - size / 2;
|
||||||
|
|
||||||
|
ripple.style = `
|
||||||
|
position: absolute;
|
||||||
|
width: ${size}px;
|
||||||
|
height: ${size}px;
|
||||||
|
background: ${theme.rippleColor};
|
||||||
|
border-radius: 50%;
|
||||||
|
opacity: 0;
|
||||||
|
animation: ripple-animation 0.6s ease-out;
|
||||||
|
left: ${x}px;
|
||||||
|
top: ${y}px;
|
||||||
|
`;
|
||||||
|
button.appendChild(ripple);
|
||||||
|
|
||||||
|
// Remove ripple element after animation
|
||||||
|
ripple.addEventListener("animationend", () => {
|
||||||
|
ripple.remove();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add keyframes for ripple animation
|
||||||
|
const styleSheet = doc.styleSheets[0];
|
||||||
|
styleSheet.insertRule(`
|
||||||
|
@keyframes ripple-animation {
|
||||||
|
from {
|
||||||
|
transform: scale(0);
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: scale(4);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`, styleSheet.cssRules.length);
|
||||||
|
|
||||||
|
// Create buttons with hover effects, animations, and ripple effect
|
||||||
|
let incrementButton = createStyledButton("Increase Increment");
|
||||||
|
let decrementButton = createStyledButton("Decrease Increment");
|
||||||
|
let pauseButton = createStyledButton("Pause/Resume");
|
||||||
|
let quitButton = createStyledButton("Quit");
|
||||||
|
|
||||||
|
content.appendChild(incrementButton);
|
||||||
|
content.appendChild(decrementButton);
|
||||||
|
content.appendChild(pauseButton);
|
||||||
|
content.appendChild(quitButton);
|
||||||
|
|
||||||
|
// Add event listeners for the buttons
|
||||||
|
incrementButton.addEventListener("click", () => incrementValue += 1);
|
||||||
|
decrementButton.addEventListener("click", () => incrementValue = Math.max(0, incrementValue - 1));
|
||||||
|
pauseButton.addEventListener("click", () => incrementValue = incrementValue === 0 ? 1 : 0);
|
||||||
|
quitButton.addEventListener("click", () => {
|
||||||
|
isRunning = false;
|
||||||
|
container.remove(); // Remove the container on quit
|
||||||
|
});
|
||||||
|
|
||||||
|
// Minimize/Restore window
|
||||||
|
minimizeButton.addEventListener("click", () => {
|
||||||
|
isMinimized = !isMinimized;
|
||||||
|
content.style.display = isMinimized ? "none" : "block";
|
||||||
|
});
|
||||||
|
|
||||||
|
// Close window
|
||||||
|
closeButton.addEventListener("click", () => {
|
||||||
|
isRunning = false;
|
||||||
|
container.remove(); // Remove the window
|
||||||
|
});
|
||||||
|
|
||||||
|
// Make the window draggable
|
||||||
|
let isDragging = false;
|
||||||
|
let offsetX, offsetY;
|
||||||
|
|
||||||
|
container.addEventListener("mousedown", (e) => {
|
||||||
|
isDragging = true;
|
||||||
|
offsetX = e.clientX - container.getBoundingClientRect().left;
|
||||||
|
offsetY = e.clientY - container.getBoundingClientRect().top;
|
||||||
|
});
|
||||||
|
|
||||||
|
doc.addEventListener("mousemove", (e) => {
|
||||||
|
if (isDragging) {
|
||||||
|
container.style.left = `${e.clientX - offsetX}px`;
|
||||||
|
container.style.top = `${e.clientY - offsetY}px`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
doc.addEventListener("mouseup", () => {
|
||||||
|
isDragging = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Main loop to update the counter display
|
||||||
|
while (isRunning) {
|
||||||
|
counter += incrementValue;
|
||||||
|
counterDisplay.innerText = `Counter: ${counter}\nIncrement Value: ${incrementValue}`;
|
||||||
|
|
||||||
|
await ns.sleep(1000); // Sleep 1 second between updates
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the container when the script stops
|
||||||
|
container.remove();
|
||||||
|
ns.tprint("Script terminated.");
|
||||||
|
}
|
||||||
286
Mizzajl/home/test2.js
Normal file
286
Mizzajl/home/test2.js
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
/** @param {NS} ns */
|
||||||
|
export async function main(ns) {
|
||||||
|
ns.disableLog('sleep'); // Disable log spamming
|
||||||
|
|
||||||
|
const doc = eval("document");
|
||||||
|
const body = doc.body;
|
||||||
|
let isMinimized = false; // Track the minimize state
|
||||||
|
|
||||||
|
// Read crime stats from the CrimeStats.txt file
|
||||||
|
let crimeStatsData = await ns.read("CrimeStats.txt");
|
||||||
|
let crimes = JSON.parse(crimeStatsData); // Parse the JSON data from the file
|
||||||
|
|
||||||
|
// Add dynamic crime chance and calculate stats per second
|
||||||
|
for (let crime of crimes) {
|
||||||
|
crime.chance = ns.singularity.getCrimeChance(crime.name) * 100; // Get success chance as a number
|
||||||
|
let timeInSeconds = crime.time / 1000; // Convert ms to seconds for calculations
|
||||||
|
|
||||||
|
// Calculate stats per second
|
||||||
|
crime.hacking_exp_per_sec = crime.hacking_exp / timeInSeconds;
|
||||||
|
crime.strength_exp_per_sec = crime.strength_exp / timeInSeconds;
|
||||||
|
crime.defense_exp_per_sec = crime.defense_exp / timeInSeconds;
|
||||||
|
crime.dexterity_exp_per_sec = crime.dexterity_exp / timeInSeconds;
|
||||||
|
crime.agility_exp_per_sec = crime.agility_exp / timeInSeconds;
|
||||||
|
crime.charisma_exp_per_sec = crime.charisma_exp / timeInSeconds;
|
||||||
|
crime.intelligence_exp_per_sec = crime.intelligence_exp / timeInSeconds || 0; // Handle potential missing data
|
||||||
|
crime.money_per_sec = crime.money / timeInSeconds;
|
||||||
|
crime.karma_per_sec = crime.karma / timeInSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the CSS window container
|
||||||
|
let container = doc.createElement("div");
|
||||||
|
container.style = `
|
||||||
|
position: fixed;
|
||||||
|
top: 100px;
|
||||||
|
left: 100px;
|
||||||
|
background: black; /* Black background */
|
||||||
|
color: #0c0; /* Green text */
|
||||||
|
z-index: 1000;
|
||||||
|
font-family: "Source Code Pro", monospace; /* Apply the terminal font */
|
||||||
|
font-size: 16px;
|
||||||
|
border: 2px solid #666;
|
||||||
|
border-radius: 5px;
|
||||||
|
width: 1400px; /* Increased width */
|
||||||
|
height: 400px; /* Increased height */
|
||||||
|
overflow-y: auto;
|
||||||
|
`;
|
||||||
|
body.appendChild(container);
|
||||||
|
|
||||||
|
// Create the title bar with minimize and close buttons
|
||||||
|
let titleBar = doc.createElement("div");
|
||||||
|
titleBar.style = `
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
background: black; /* Black background for title bar */
|
||||||
|
color: #0c0; /* Green text */
|
||||||
|
border-bottom: 1px solid #666;
|
||||||
|
font-weight: bold;
|
||||||
|
`;
|
||||||
|
container.appendChild(titleBar);
|
||||||
|
|
||||||
|
// Title text
|
||||||
|
let title = doc.createElement("span");
|
||||||
|
title.innerText = "Crime Stats Monitor";
|
||||||
|
titleBar.appendChild(title);
|
||||||
|
|
||||||
|
// Create a container for the buttons and align them to the right
|
||||||
|
let buttonContainer = doc.createElement("div");
|
||||||
|
buttonContainer.style = `
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
`;
|
||||||
|
titleBar.appendChild(buttonContainer);
|
||||||
|
|
||||||
|
// Minimize button (▲ for minimize, ▼ for restore)
|
||||||
|
let minimizeButton = doc.createElement("button");
|
||||||
|
minimizeButton.innerText = "▲"; // Start as minimize button
|
||||||
|
minimizeButton.style = `
|
||||||
|
background: none;
|
||||||
|
border: 1px solid #666;
|
||||||
|
color: #0c0; /* Green text */
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 5px;
|
||||||
|
width: 30px; /* Set same width for buttons */
|
||||||
|
`;
|
||||||
|
buttonContainer.appendChild(minimizeButton);
|
||||||
|
|
||||||
|
minimizeButton.addEventListener("click", () => {
|
||||||
|
if (isMinimized) {
|
||||||
|
minimizeButton.innerText = "▲"; // Minimize arrow
|
||||||
|
container.style.height = "400px"; // Restore height
|
||||||
|
} else {
|
||||||
|
minimizeButton.innerText = "▼"; // Restore arrow
|
||||||
|
container.style.height = "25px"; // Minimize height
|
||||||
|
}
|
||||||
|
isMinimized = !isMinimized;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Close button (X)
|
||||||
|
let closeButton = doc.createElement("button");
|
||||||
|
closeButton.innerText = "X";
|
||||||
|
closeButton.style = `
|
||||||
|
background: none;
|
||||||
|
border: 1px solid #666;
|
||||||
|
color: #0c0; /* Green text */
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 5px;
|
||||||
|
width: 30px; /* Set same width for buttons */
|
||||||
|
`;
|
||||||
|
buttonContainer.appendChild(closeButton);
|
||||||
|
|
||||||
|
closeButton.addEventListener("click", () => {
|
||||||
|
container.remove(); // Close the window
|
||||||
|
});
|
||||||
|
|
||||||
|
// Table for displaying the crime stats
|
||||||
|
let table = doc.createElement("table");
|
||||||
|
table.style = `
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
color: #0c0; /* Green text */
|
||||||
|
`;
|
||||||
|
container.appendChild(table);
|
||||||
|
|
||||||
|
// Track the current sort direction for each column (null, 'asc', or 'desc')
|
||||||
|
let sortOrder = new Array(13).fill(null); // One for each column
|
||||||
|
|
||||||
|
// Add table headers with clickable sorting functionality and arrows
|
||||||
|
let headers = [
|
||||||
|
"Crime", "Time (s)", "Chance", "Hack Exp/s", "Str Exp/s", "Def Exp/s",
|
||||||
|
"Dex Exp/s", "Agi Exp/s", "Cha Exp/s", "Money/s", "Karma/s", "$/%/s", "IntXP/s"
|
||||||
|
];
|
||||||
|
|
||||||
|
let headerRow = doc.createElement("tr");
|
||||||
|
|
||||||
|
headers.forEach((header, index) => {
|
||||||
|
let th = doc.createElement("th");
|
||||||
|
th.innerHTML = `${header} <span></span>`; // Span for the arrow
|
||||||
|
th.style = `
|
||||||
|
padding: 5px;
|
||||||
|
background: #333;
|
||||||
|
border: 1px solid #666;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap; /* Prevent wrapping */
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Add sorting functionality for each column
|
||||||
|
th.addEventListener("click", () => {
|
||||||
|
clearAllArrows(); // Remove all arrows
|
||||||
|
sortCrimesByColumn(index); // Sort by this column
|
||||||
|
toggleSortOrder(index); // Toggle sort order for this column
|
||||||
|
});
|
||||||
|
headerRow.appendChild(th);
|
||||||
|
});
|
||||||
|
|
||||||
|
table.appendChild(headerRow);
|
||||||
|
|
||||||
|
// Function to toggle the sort order for a column
|
||||||
|
function toggleSortOrder(columnIndex) {
|
||||||
|
// Toggle between 'asc' and 'desc'
|
||||||
|
if (sortOrder[columnIndex] === 'asc') {
|
||||||
|
sortOrder[columnIndex] = 'desc';
|
||||||
|
} else {
|
||||||
|
sortOrder[columnIndex] = 'asc';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the arrows for this column
|
||||||
|
updateArrow(columnIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to update the arrow for a specific column
|
||||||
|
function updateArrow(columnIndex) {
|
||||||
|
let th = headerRow.querySelectorAll("th")[columnIndex];
|
||||||
|
let arrowSpan = th.querySelector("span");
|
||||||
|
|
||||||
|
if (sortOrder[columnIndex] === 'asc') {
|
||||||
|
arrowSpan.innerHTML = " ▲"; // Up arrow for ascending
|
||||||
|
} else if (sortOrder[columnIndex] === 'desc') {
|
||||||
|
arrowSpan.innerHTML = " ▼"; // Down arrow for descending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to clear all arrows
|
||||||
|
function clearAllArrows() {
|
||||||
|
headerRow.querySelectorAll("th span").forEach(arrow => {
|
||||||
|
arrow.innerHTML = ""; // Remove all arrows
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to format numbers with 4 decimal places
|
||||||
|
function formatNumber(num) {
|
||||||
|
return parseFloat(num.toFixed(4)); // Convert to number with 4 decimal places
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to display crimes in the table
|
||||||
|
function displayCrimes(crimesList) {
|
||||||
|
// Clear any existing rows (except the header)
|
||||||
|
while (table.rows.length > 1) {
|
||||||
|
table.deleteRow(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
crimesList.forEach(crime => {
|
||||||
|
let row = doc.createElement("tr");
|
||||||
|
|
||||||
|
let columns = [
|
||||||
|
{ text: crime.name, value: crime.name }, // Treat as string
|
||||||
|
{ text: formatNumber(crime.time / 1000), value: crime.time / 1000 }, // Time in seconds
|
||||||
|
{ text: formatNumber(crime.chance), value: crime.chance }, // Success chance
|
||||||
|
{ text: formatNumber(crime.hacking_exp_per_sec), value: crime.hacking_exp_per_sec },
|
||||||
|
{ text: formatNumber(crime.strength_exp_per_sec), value: crime.strength_exp_per_sec },
|
||||||
|
{ text: formatNumber(crime.defense_exp_per_sec), value: crime.defense_exp_per_sec },
|
||||||
|
{ text: formatNumber(crime.dexterity_exp_per_sec), value: crime.dexterity_exp_per_sec },
|
||||||
|
{ text: formatNumber(crime.agility_exp_per_sec), value: crime.agility_exp_per_sec },
|
||||||
|
{ text: formatNumber(crime.charisma_exp_per_sec), value: crime.charisma_exp_per_sec },
|
||||||
|
{ text: formatNumber(crime.money_per_sec), value: crime.money_per_sec },
|
||||||
|
{ text: formatNumber(crime.karma_per_sec), value: crime.karma_per_sec },
|
||||||
|
{ text: formatNumber(crime.money * crime.chance / 100), value: crime.money * crime.chance / 100 }, // Money per chance per second
|
||||||
|
{ text: formatNumber(crime.intelligence_exp_per_sec), value: crime.intelligence_exp_per_sec } // Intelligence XP per second
|
||||||
|
];
|
||||||
|
|
||||||
|
columns.forEach((col, index) => {
|
||||||
|
let td = doc.createElement("td");
|
||||||
|
td.innerText = col.text; // Display formatted text
|
||||||
|
td.dataset.value = col.value; // Store the numeric value for sorting
|
||||||
|
|
||||||
|
td.style = `
|
||||||
|
padding: 5px;
|
||||||
|
border-bottom: 1px solid #666;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap; /* Prevent text wrapping */
|
||||||
|
`;
|
||||||
|
row.appendChild(td);
|
||||||
|
});
|
||||||
|
|
||||||
|
table.appendChild(row);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sorting function (high to low for numeric values)
|
||||||
|
function sortCrimesByColumn(columnIndex) {
|
||||||
|
let rows = Array.from(table.querySelectorAll('tr:nth-child(n+2)')); // Get all rows except header
|
||||||
|
let order = sortOrder[columnIndex]; // Ascending or descending
|
||||||
|
|
||||||
|
rows.sort((rowA, rowB) => {
|
||||||
|
let valA = rowA.cells[columnIndex].dataset.value;
|
||||||
|
let valB = rowB.cells[columnIndex].dataset.value;
|
||||||
|
|
||||||
|
// Check if values are numeric and sort accordingly
|
||||||
|
if (!isNaN(valA) && !isNaN(valB)) {
|
||||||
|
return order === 'asc' ? parseFloat(valA) - parseFloat(valB) : parseFloat(valB) - parseFloat(valA);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not numeric, sort alphabetically
|
||||||
|
return order === 'asc' ? String(valA).localeCompare(String(valB)) : String(valB).localeCompare(String(valA));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Append rows in sorted order
|
||||||
|
rows.forEach(row => table.appendChild(row));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display the crimes initially
|
||||||
|
displayCrimes(crimes);
|
||||||
|
|
||||||
|
// Make the window draggable
|
||||||
|
let isDragging = false;
|
||||||
|
let offsetX, offsetY;
|
||||||
|
|
||||||
|
titleBar.addEventListener("mousedown", (e) => {
|
||||||
|
isDragging = true;
|
||||||
|
offsetX = e.clientX - container.getBoundingClientRect().left;
|
||||||
|
offsetY = e.clientY - container.getBoundingClientRect().top;
|
||||||
|
});
|
||||||
|
|
||||||
|
doc.addEventListener("mousemove", (e) => {
|
||||||
|
if (isDragging) {
|
||||||
|
container.style.left = `${e.clientX - offsetX}px`;
|
||||||
|
container.style.top = `${e.clientY - offsetY}px`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
doc.addEventListener("mouseup", () => {
|
||||||
|
isDragging = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
330
Mizzajl/home/test3.js
Normal file
330
Mizzajl/home/test3.js
Normal file
@@ -0,0 +1,330 @@
|
|||||||
|
/** @param {NS} ns */
|
||||||
|
export async function main(ns) {
|
||||||
|
ns.disableLog('sleep'); // Disable log spamming
|
||||||
|
|
||||||
|
const doc = eval("document");
|
||||||
|
const body = doc.body;
|
||||||
|
let isMinimized = false; // Track the minimize state
|
||||||
|
|
||||||
|
// Read crime stats from the CrimeStats.txt file
|
||||||
|
let crimeStatsData = await ns.read("CrimeStats.txt");
|
||||||
|
let crimes = JSON.parse(crimeStatsData); // Parse the JSON data from the file
|
||||||
|
|
||||||
|
// Add dynamic crime chance and calculate stats per second
|
||||||
|
for (let crime of crimes) {
|
||||||
|
crime.chance = ns.singularity.getCrimeChance(crime.name) * 100; // Get success chance as a number
|
||||||
|
let timeInSeconds = crime.time / 1000; // Convert ms to seconds for calculations
|
||||||
|
|
||||||
|
// Calculate stats per second
|
||||||
|
crime.hacking_exp_per_sec = crime.hacking_exp / timeInSeconds;
|
||||||
|
crime.strength_exp_per_sec = crime.strength_exp / timeInSeconds;
|
||||||
|
crime.defense_exp_per_sec = crime.defense_exp / timeInSeconds;
|
||||||
|
crime.dexterity_exp_per_sec = crime.dexterity_exp / timeInSeconds;
|
||||||
|
crime.agility_exp_per_sec = crime.agility_exp / timeInSeconds;
|
||||||
|
crime.charisma_exp_per_sec = crime.charisma_exp / timeInSeconds;
|
||||||
|
crime.intelligence_exp_per_sec = crime.intelligence_exp / timeInSeconds || 0; // Handle potential missing data
|
||||||
|
crime.money_per_sec = crime.money / timeInSeconds;
|
||||||
|
crime.karma_per_sec = crime.karma / timeInSeconds;
|
||||||
|
crime.money_per_chance = crime.money * (crime.chance / 100) / timeInSeconds; // Money per chance per second
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to map value to a color between green and red
|
||||||
|
function getGradientColor(value, min, max, isReversed = false) {
|
||||||
|
if (min === max) return "rgb(0,255,0)"; // Return green if all values are the same
|
||||||
|
let normalized = (value - min) / (max - min);
|
||||||
|
if (isReversed) normalized = 1 - normalized; // Reverse the color gradient for columns where lower values are better
|
||||||
|
let r = Math.round(255 * (1 - normalized)); // Red for lower values
|
||||||
|
let g = Math.round(255 * normalized); // Green for higher values
|
||||||
|
return `rgb(${r},${g},0)`; // Return color from green to red
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the CSS window container
|
||||||
|
let container = doc.createElement("div");
|
||||||
|
container.style = `
|
||||||
|
position: fixed;
|
||||||
|
top: 100px;
|
||||||
|
left: 100px;
|
||||||
|
background: black; /* Black background */
|
||||||
|
color: #0c0; /* Green text */
|
||||||
|
z-index: 1000;
|
||||||
|
font-family: "Source Code Pro", monospace; /* Apply the terminal font */
|
||||||
|
font-size: 16px;
|
||||||
|
border: 2px solid #666;
|
||||||
|
border-radius: 5px;
|
||||||
|
width: 1400px; /* Increased width */
|
||||||
|
height: 400px; /* Increased height */
|
||||||
|
overflow-y: auto;
|
||||||
|
`;
|
||||||
|
body.appendChild(container);
|
||||||
|
|
||||||
|
// Create the title bar with minimize and close buttons
|
||||||
|
let titleBar = doc.createElement("div");
|
||||||
|
titleBar.style = `
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
background: black; /* Black background for title bar */
|
||||||
|
color: #0c0; /* Green text */
|
||||||
|
border-bottom: 1px solid #666;
|
||||||
|
font-weight: bold;
|
||||||
|
`;
|
||||||
|
container.appendChild(titleBar);
|
||||||
|
|
||||||
|
// Title text
|
||||||
|
let title = doc.createElement("span");
|
||||||
|
title.innerText = "Crime Stats Monitor";
|
||||||
|
titleBar.appendChild(title);
|
||||||
|
|
||||||
|
// Create a container for the buttons and align them to the right
|
||||||
|
let buttonContainer = doc.createElement("div");
|
||||||
|
buttonContainer.style = `
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
`;
|
||||||
|
titleBar.appendChild(buttonContainer);
|
||||||
|
|
||||||
|
// Minimize button (▲ for minimize, ▼ for restore)
|
||||||
|
let minimizeButton = doc.createElement("button");
|
||||||
|
minimizeButton.innerText = "▲"; // Start as minimize button
|
||||||
|
minimizeButton.style = `
|
||||||
|
background: none;
|
||||||
|
border: 1px solid #666;
|
||||||
|
color: #0c0; /* Green text */
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 5px;
|
||||||
|
width: 30px; /* Set same width for buttons */
|
||||||
|
`;
|
||||||
|
buttonContainer.appendChild(minimizeButton);
|
||||||
|
|
||||||
|
minimizeButton.addEventListener("click", () => {
|
||||||
|
if (isMinimized) {
|
||||||
|
minimizeButton.innerText = "▲"; // Minimize arrow
|
||||||
|
container.style.height = "400px"; // Restore height
|
||||||
|
} else {
|
||||||
|
minimizeButton.innerText = "▼"; // Restore arrow
|
||||||
|
container.style.height = "25px"; // Minimize height
|
||||||
|
}
|
||||||
|
isMinimized = !isMinimized;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Close button (X)
|
||||||
|
let closeButton = doc.createElement("button");
|
||||||
|
closeButton.innerText = "X";
|
||||||
|
closeButton.style = `
|
||||||
|
background: none;
|
||||||
|
border: 1px solid #666;
|
||||||
|
color: #0c0; /* Green text */
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 5px;
|
||||||
|
width: 30px; /* Set same width for buttons */
|
||||||
|
`;
|
||||||
|
buttonContainer.appendChild(closeButton);
|
||||||
|
|
||||||
|
closeButton.addEventListener("click", () => {
|
||||||
|
container.remove(); // Close the window
|
||||||
|
});
|
||||||
|
|
||||||
|
// Table for displaying the crime stats
|
||||||
|
let table = doc.createElement("table");
|
||||||
|
table.style = `
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
color: #0c0; /* Green text */
|
||||||
|
`;
|
||||||
|
container.appendChild(table);
|
||||||
|
|
||||||
|
// Track the current sort direction for each column (null, 'asc', or 'desc')
|
||||||
|
let sortOrder = new Array(13).fill(null); // One for each column
|
||||||
|
|
||||||
|
// Add table headers with clickable sorting functionality and arrows
|
||||||
|
let headers = [
|
||||||
|
"Crime", "Time (s)", "Chance", "Hack Exp/s", "Str Exp/s", "Def Exp/s",
|
||||||
|
"Dex Exp/s", "Agi Exp/s", "Cha Exp/s", "Money/s", "Karma/s", "$/%/s", "IntXP/s"
|
||||||
|
];
|
||||||
|
|
||||||
|
let headerRow = doc.createElement("tr");
|
||||||
|
|
||||||
|
headers.forEach((header, index) => {
|
||||||
|
let th = doc.createElement("th");
|
||||||
|
th.innerHTML = `${header} <span></span>`; // Span for the arrow
|
||||||
|
th.style = `
|
||||||
|
padding: 5px;
|
||||||
|
background: #333;
|
||||||
|
border: 1px solid #666;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap; /* Prevent wrapping */
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Add sorting functionality for each column
|
||||||
|
th.addEventListener("click", () => {
|
||||||
|
clearAllArrows(); // Remove all arrows
|
||||||
|
sortCrimesByColumn(index); // Sort by this column
|
||||||
|
toggleSortOrder(index); // Toggle sort order for this column
|
||||||
|
});
|
||||||
|
headerRow.appendChild(th);
|
||||||
|
});
|
||||||
|
|
||||||
|
table.appendChild(headerRow);
|
||||||
|
|
||||||
|
// Function to toggle the sort order for a column
|
||||||
|
function toggleSortOrder(columnIndex) {
|
||||||
|
// Toggle between 'asc' and 'desc'
|
||||||
|
if (sortOrder[columnIndex] === 'asc') {
|
||||||
|
sortOrder[columnIndex] = 'desc';
|
||||||
|
} else {
|
||||||
|
sortOrder[columnIndex] = 'asc';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the arrows for this column
|
||||||
|
updateArrow(columnIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to update the arrow for a specific column
|
||||||
|
function updateArrow(columnIndex) {
|
||||||
|
let th = headerRow.querySelectorAll("th")[columnIndex];
|
||||||
|
let arrowSpan = th.querySelector("span");
|
||||||
|
|
||||||
|
if (sortOrder[columnIndex] === 'asc') {
|
||||||
|
arrowSpan.innerHTML = " ▲"; // Up arrow for ascending
|
||||||
|
} else if (sortOrder[columnIndex] === 'desc') {
|
||||||
|
arrowSpan.innerHTML = " ▼"; // Down arrow for descending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to clear all arrows
|
||||||
|
function clearAllArrows() {
|
||||||
|
headerRow.querySelectorAll("th span").forEach(arrow => {
|
||||||
|
arrow.innerHTML = ""; // Remove all arrows
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to format numbers with 4 decimal places
|
||||||
|
function formatNumber(num) {
|
||||||
|
return parseFloat(num.toFixed(4)); // Convert to number with 4 decimal places
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to display crimes in the table
|
||||||
|
function displayCrimes(crimesList) {
|
||||||
|
// Clear any existing rows (except the header)
|
||||||
|
while (table.rows.length > 1) {
|
||||||
|
table.deleteRow(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find min and max for each column (for color gradient)
|
||||||
|
const columnsWithValues = [
|
||||||
|
{ key: "time", reverseGradient: true },
|
||||||
|
{ key: "chance", reverseGradient: false },
|
||||||
|
{ key: "hacking_exp_per_sec", reverseGradient: false },
|
||||||
|
{ key: "strength_exp_per_sec", reverseGradient: false },
|
||||||
|
{ key: "defense_exp_per_sec", reverseGradient: false },
|
||||||
|
{ key: "dexterity_exp_per_sec", reverseGradient: false },
|
||||||
|
{ key: "agility_exp_per_sec", reverseGradient: false },
|
||||||
|
{ key: "charisma_exp_per_sec", reverseGradient: false },
|
||||||
|
{ key: "money_per_sec", reverseGradient: false },
|
||||||
|
{ key: "karma_per_sec", reverseGradient: false },
|
||||||
|
{ key: "money_per_chance", reverseGradient: false },
|
||||||
|
{ key: "intelligence_exp_per_sec", reverseGradient: false }
|
||||||
|
];
|
||||||
|
|
||||||
|
let minMax = {};
|
||||||
|
|
||||||
|
// Get min and max values for each column, excluding non-data elements
|
||||||
|
columnsWithValues.forEach(column => {
|
||||||
|
let values = crimesList.map(crime => crime[column.key]).filter(v => !isNaN(v)); // Ensure we're working with numbers
|
||||||
|
minMax[column.key] = {
|
||||||
|
min: Math.min(...values),
|
||||||
|
max: Math.max(...values)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
crimesList.forEach(crime => {
|
||||||
|
let row = doc.createElement("tr");
|
||||||
|
|
||||||
|
let columns = [
|
||||||
|
{ text: crime.name, value: crime.name, isName: true }, // Crime name (always green)
|
||||||
|
{ text: formatNumber(crime.time / 1000), value: crime.time / 1000, key: "time" }, // Time in seconds
|
||||||
|
{ text: formatNumber(crime.chance), value: crime.chance, key: "chance" }, // Success chance
|
||||||
|
{ text: formatNumber(crime.hacking_exp_per_sec), value: crime.hacking_exp_per_sec, key: "hacking_exp_per_sec" },
|
||||||
|
{ text: formatNumber(crime.strength_exp_per_sec), value: crime.strength_exp_per_sec, key: "strength_exp_per_sec" },
|
||||||
|
{ text: formatNumber(crime.defense_exp_per_sec), value: crime.defense_exp_per_sec, key: "defense_exp_per_sec" },
|
||||||
|
{ text: formatNumber(crime.dexterity_exp_per_sec), value: crime.dexterity_exp_per_sec, key: "dexterity_exp_per_sec" },
|
||||||
|
{ text: formatNumber(crime.agility_exp_per_sec), value: crime.agility_exp_per_sec, key: "agility_exp_per_sec" },
|
||||||
|
{ text: formatNumber(crime.charisma_exp_per_sec), value: crime.charisma_exp_per_sec, key: "charisma_exp_per_sec" },
|
||||||
|
{ text: formatNumber(crime.money_per_sec), value: crime.money_per_sec, key: "money_per_sec" },
|
||||||
|
{ text: formatNumber(crime.karma_per_sec), value: crime.karma_per_sec, key: "karma_per_sec" },
|
||||||
|
{ text: formatNumber(crime.money_per_chance), value: crime.money_per_chance, key: "money_per_chance" }, // Money per chance per second
|
||||||
|
{ text: formatNumber(crime.intelligence_exp_per_sec), value: crime.intelligence_exp_per_sec, key: "intelligence_exp_per_sec" } // Intelligence XP per second
|
||||||
|
];
|
||||||
|
|
||||||
|
columns.forEach((col, index) => {
|
||||||
|
let td = doc.createElement("td");
|
||||||
|
td.innerText = col.text; // Display formatted text
|
||||||
|
td.dataset.value = col.value; // Store the numeric value for sorting
|
||||||
|
|
||||||
|
// Apply the color gradient to each cell based on the column
|
||||||
|
let gradientColor = col.isName
|
||||||
|
? "#0c0" // Always green for names
|
||||||
|
: getGradientColor(col.value, minMax[col.key].min, minMax[col.key].max, columnsWithValues[index]?.reverseGradient);
|
||||||
|
|
||||||
|
td.style.color = gradientColor; // Apply color
|
||||||
|
|
||||||
|
td.style.padding = "5px";
|
||||||
|
td.style.borderBottom = "1px solid #666";
|
||||||
|
td.style.textAlign = "center";
|
||||||
|
td.style.whiteSpace = "nowrap"; // Prevent text wrapping
|
||||||
|
|
||||||
|
row.appendChild(td);
|
||||||
|
});
|
||||||
|
|
||||||
|
table.appendChild(row);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sorting function (high to low for numeric values)
|
||||||
|
function sortCrimesByColumn(columnIndex) {
|
||||||
|
let rows = Array.from(table.querySelectorAll('tr:nth-child(n+2)')); // Get all rows except header
|
||||||
|
let order = sortOrder[columnIndex]; // Ascending or descending
|
||||||
|
|
||||||
|
rows.sort((rowA, rowB) => {
|
||||||
|
let valA = rowA.cells[columnIndex].dataset.value;
|
||||||
|
let valB = rowB.cells[columnIndex].dataset.value;
|
||||||
|
|
||||||
|
// Check if values are numeric and sort accordingly
|
||||||
|
if (!isNaN(valA) && !isNaN(valB)) {
|
||||||
|
return order === 'asc' ? parseFloat(valA) - parseFloat(valB) : parseFloat(valB) - parseFloat(valA);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not numeric, sort alphabetically
|
||||||
|
return order === 'asc' ? String(valA).localeCompare(String(valB)) : String(valB).localeCompare(String(valA));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Append rows in sorted order
|
||||||
|
rows.forEach(row => table.appendChild(row));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display the crimes initially
|
||||||
|
displayCrimes(crimes);
|
||||||
|
|
||||||
|
// Make the window draggable
|
||||||
|
let isDragging = false;
|
||||||
|
let offsetX, offsetY;
|
||||||
|
|
||||||
|
titleBar.addEventListener("mousedown", (e) => {
|
||||||
|
isDragging = true;
|
||||||
|
offsetX = e.clientX - container.getBoundingClientRect().left;
|
||||||
|
offsetY = e.clientY - container.getBoundingClientRect().top;
|
||||||
|
});
|
||||||
|
|
||||||
|
doc.addEventListener("mousemove", (e) => {
|
||||||
|
if (isDragging) {
|
||||||
|
container.style.left = `${e.clientX - offsetX}px`;
|
||||||
|
container.style.top = `${e.clientY - offsetY}px`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
doc.addEventListener("mouseup", () => {
|
||||||
|
isDragging = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user