I find it useful to 'cross off' items I've completed, visually. This tampermonkey script enables this, allowing the user to double-click nodes to 'disable' them visually. Sankey lines connecting two disabled nodes also get the disabled styling.
Obviously this would need to be tuned to your actual code, but I find it incredibly useful.
// ==UserScript==
// @name KirkMcDonald Calc - Disable Nodes
// @namespace https://github.com/KirkMcDonald
// @version 0.1.0
// @description Double-click a node in the sankey to visually disable it. A link is disabled only when both of its endpoints are disabled.
// @match https://kirkmcdonald.github.io/*
// @run-at document-idle
// @grant none
// ==/UserScript==
(function () {
"use strict";
const STORAGE_KEY = "kmcd_disabled_nodes_v1";
const disabled = new Set(
JSON.parse(localStorage.getItem(STORAGE_KEY) || "[]")
);
function save() {
localStorage.setItem(STORAGE_KEY, JSON.stringify([...disabled]));
}
const style = document.createElement("style");
style.textContent = `
svg#graph g.node.kmcdDisabled { opacity: 0.15; }
svg#graph g.link.kmcdDisabled { opacity: 0.08; }
`;
document.head.appendChild(style);
function datumOf(el) {
if (typeof d3 === "undefined") return null;
try { return d3.select(el).datum(); } catch (_) { return null; }
}
function recipeNameFromNode(node) {
return node && node.recipe ? node.recipe.name : null;
}
function applyDisabled() {
const svg = document.querySelector("svg#graph");
if (!svg) return;
svg.querySelectorAll("g.nodes > g.node").forEach((g) => {
const node = datumOf(g);
const name = recipeNameFromNode(node);
g.classList.toggle("kmcdDisabled", !!name && disabled.has(name));
});
svg.querySelectorAll("g.links > g.link").forEach((g) => {
const link = datumOf(g);
if (!link || !link.source || !link.target) {
g.classList.remove("kmcdDisabled");
return;
}
const a = recipeNameFromNode(link.source);
const b = recipeNameFromNode(link.target);
const both = a && b && disabled.has(a) && disabled.has(b);
g.classList.toggle("kmcdDisabled", !!both);
});
}
function attachHandlers() {
const svg = document.querySelector("svg#graph");
if (!svg) return;
svg.querySelectorAll("g.overlay > rect").forEach((rect) => {
if (rect.__kmcdHooked) return;
rect.__kmcdHooked = true;
rect.addEventListener("dblclick", (event) => {
event.preventDefault();
const d = datumOf(rect);
const name = recipeNameFromNode(d && d.node);
if (!name) return;
if (disabled.has(name)) disabled.delete(name);
else disabled.add(name);
save();
applyDisabled();
});
});
}
let pending = false;
function refresh() {
if (pending) return;
pending = true;
requestAnimationFrame(() => {
pending = false;
attachHandlers();
applyDisabled();
});
}
function waitForGraph() {
const svg = document.querySelector("svg#graph");
if (!svg) {
setTimeout(waitForGraph, 200);
return;
}
new MutationObserver(refresh).observe(svg, {
childList: true,
subtree: true,
});
refresh();
}
waitForGraph();
})();
I find it useful to 'cross off' items I've completed, visually. This tampermonkey script enables this, allowing the user to double-click nodes to 'disable' them visually. Sankey lines connecting two disabled nodes also get the disabled styling.
Obviously this would need to be tuned to your actual code, but I find it incredibly useful.