Merge branch 'modularize'

This commit is contained in:
Kritagya Bhattarai (CalfMoon) 2026-03-31 11:44:44 +05:45
commit 99cb882ff3
7 changed files with 299 additions and 226 deletions

67
src/calculator.ts Normal file
View file

@ -0,0 +1,67 @@
import { App } from "obsidian";
import { NodeFactorSettings, ObsidianNode } from "types";
export default class Calculations {
private app: App;
private settings: NodeFactorSettings;
constructor(app: App, settings: NodeFactorSettings) {
this.app = app;
this.settings = settings;
}
calcNodeWeight(node: ObsidianNode): number {
const settings = this.settings;
let weight = 0;
const manualFileData = settings.manual.find(
(manualFileData) => manualFileData.id == node.id,
);
if (manualFileData != null) {
return manualFileData.weight;
}
weight += Object.keys(node.reverse).length * settings.bwdMultiplier;
if (settings.fwdTree) {
weight +=
this.fwdNodeTreeSize(node, new Set()) * settings.fwdMultiplier;
} else {
weight += Object.keys(node.forward).length * settings.fwdMultiplier;
}
if (settings.lettersPerWt != 0) {
weight += this.letterCount(node) / settings.lettersPerWt;
}
return Math.round(weight);
}
private letterCount(node: ObsidianNode): number {
const file = this.app.vault.getFileByPath(node.id);
if (file == null || file.extension != "md") return 0;
return file.stat.size;
}
private fwdNodeTreeSize(
node: ObsidianNode,
antiLoopSet: Set<string>,
): number {
let size = 0;
antiLoopSet.add(node.id);
Object.entries(node.forward).forEach(([key, value]) => {
// @ts-ignore
const childNode: ObsidianNode = value.target;
// Prevents looping if A -> B -> C -> D -> B
if (!antiLoopSet.has(key)) {
size++;
const childSize = this.fwdNodeTreeSize(childNode, antiLoopSet);
size += childSize;
}
});
return size;
}
}

View file

@ -1,7 +1,8 @@
import { Plugin } from "obsidian";
import { ObsidianNode, NodeFactorSettings, DEFAULT_SETTINGS } from "./types";
import NodeFactorSettingTab from "./settings";
import { ObsidianNode, NodeFactorSettings, DEFAULT_SETTINGS } from "types";
import NodeFactorSettingTab from "settings";
import Calculator from "calculator";
export default class NodeFactor extends Plugin {
settings: NodeFactorSettings;
@ -56,12 +57,14 @@ export default class NodeFactor extends Plugin {
// if graph view is initially opened when opening obsidian
clearTimeout(this.timeoutId);
this.timeoutId = setTimeout(() => {
const calculator = new Calculator(this.app, this.settings);
nodes.forEach((node, _i) => {
let weight = 0;
if (this.sizeCache.get(node.id) != undefined) {
weight = this.sizeCache.get(node.id) as number;
} else {
weight = this.calcNodeWeight(node);
weight = calculator.calcNodeWeight(node);
this.sizeCache.set(node.id, weight);
}
node.weight = weight;
@ -69,60 +72,6 @@ export default class NodeFactor extends Plugin {
}, 500);
}
private calcNodeWeight(node: ObsidianNode): number {
const settings = this.settings;
let weight = 0;
const manualFileData = settings.manual.find(
(manualFileData) => manualFileData.id == node.id,
);
if (manualFileData != null) {
return manualFileData.weight;
}
weight += Object.keys(node.reverse).length * settings.bwdMultiplier;
if (settings.fwdTree) {
weight +=
this.fwdNodeTreeSize(node, new Set()) * settings.fwdMultiplier;
} else {
weight += Object.keys(node.forward).length * settings.fwdMultiplier;
}
if (settings.lettersPerWt != 0) {
weight += this.letterCount(node) / settings.lettersPerWt;
}
return Math.round(weight);
}
private letterCount(node: ObsidianNode): number {
const file = this.app.vault.getFileByPath(node.id);
if (file == null || file.extension != "md") return 0;
return file.stat.size;
}
private fwdNodeTreeSize(
node: ObsidianNode,
antiLoopSet: Set<string>,
): number {
let size = 0;
antiLoopSet.add(node.id);
Object.entries(node.forward).forEach(([key, value]) => {
// @ts-ignore
const childNode: ObsidianNode = value.target;
// Prevents looping if A -> B -> C -> D -> B
if (!antiLoopSet.has(key)) {
size++;
const childSize = this.fwdNodeTreeSize(childNode, antiLoopSet);
size += childSize;
}
});
return size;
}
recalculateSize() {
this.sizeCache.clear();
this.updateGraph();

View file

@ -1,169 +0,0 @@
import {
App,
ButtonComponent,
Notice,
PluginSettingTab,
SearchComponent,
Setting,
SliderComponent,
} from "obsidian";
import NodeFactor from "./main";
import FileSuggest from "./file-suggest";
import { FileData } from "./types";
export default class NodeFactorSettingTab extends PluginSettingTab {
plugin: NodeFactor;
constructor(app: App, plugin: NodeFactor) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
const { containerEl } = this;
containerEl.empty();
new Setting(containerEl)
.setName("Programatically set size")
.setHeading();
new Setting(containerEl)
.setName("Forward link weight multiplier")
.setDesc("Multiplier for forward links weight (0 to disable).")
.addSlider((slider) => {
slider
.setLimits(0, 20, 1)
.setDynamicTooltip()
.setValue(this.plugin.settings.fwdMultiplier)
.onChange(async (value) => {
this.plugin.settings.fwdMultiplier = value;
await this.plugin.saveSettings();
this.plugin.recalculateSize();
});
});
new Setting(containerEl)
.setName("Travel forward tree")
.setDesc(
"Travel forward and add all other nodes to determine final node size.",
)
.addToggle((toggle) => {
toggle
.setValue(this.plugin.settings.fwdTree)
.onChange(async (value) => {
this.plugin.settings.fwdTree = value;
await this.plugin.saveSettings();
this.plugin.recalculateSize();
});
});
new Setting(containerEl)
.setName("Backward link weight multiplier")
.setDesc("Multiplier for backward links weight (0 to disable).")
.addSlider((slider) => {
slider
.setLimits(0, 20, 1)
.setDynamicTooltip()
.setValue(this.plugin.settings.bwdMultiplier)
.onChange(async (value) => {
this.plugin.settings.bwdMultiplier = value;
await this.plugin.saveSettings();
this.plugin.recalculateSize();
});
});
new Setting(containerEl)
.setName("Character per weight")
.setDesc(
"Add 1 weight to node size per no of given character (0 to disable).",
)
.addSlider((slider) => {
slider
.setLimits(0, 5000, 100)
.setDynamicTooltip()
.setValue(this.plugin.settings.lettersPerWt)
.onChange(async (value) => {
this.plugin.settings.lettersPerWt = value;
await this.plugin.saveSettings();
this.plugin.recalculateSize();
});
});
new Setting(containerEl).setName("Manually set size").setHeading();
let selectedWeight: SliderComponent;
let selectedFile: SearchComponent;
let submitButton: ButtonComponent;
new Setting(containerEl)
.setName("Add new weight")
.setDesc("Weight added here overrides everything else.")
.addSearch((search) => {
new FileSuggest(this.app, search.inputEl);
selectedFile = search;
search
.setPlaceholder("Enter file name")
.onChange(async (value) => {
submitButton.setDisabled(value.length === 0);
});
})
.addSlider((slider) => {
selectedWeight = slider;
slider.setLimits(0, 100, 5).setDynamicTooltip().setValue(0);
})
.addButton((button) => {
submitButton = button;
button
.setDisabled(true)
.setButtonText("Add")
.setTooltip("Click to add")
.onClick(async () => {
const enteredFileData: FileData = {
id: selectedFile.getValue(),
weight: selectedWeight.getValue(),
};
selectedWeight.setValue(0);
selectedFile.setValue("");
const fileExists = this.plugin.settings.manual.find(
(foundFile) => foundFile.id == enteredFileData.id,
);
if (fileExists) {
new Notice(
"That file's size has already been entered," +
" remove it first to change weight.",
);
return;
}
this.plugin.settings.manual.push(enteredFileData);
await this.plugin.saveSettings();
new Notice("Manual size added");
// Rerender display
this.display();
this.plugin.recalculateSize();
});
});
// Display all manually added weights
this.plugin.settings.manual.forEach((value: FileData) => {
new Setting(containerEl)
.setName(value.id)
.setDesc(`Weight: ${String(value.weight)}`)
.addButton((button) => {
button
.setIcon("trash")
.setTooltip("Remove manually added size")
.onClick(async () => {
this.plugin.settings.manual.remove(value);
await this.plugin.saveSettings();
this.display();
this.plugin.recalculateSize();
});
});
});
}
}

26
src/settings/index.ts Normal file
View file

@ -0,0 +1,26 @@
import { App, PluginSettingTab } from "obsidian";
import NodeFactor from "main";
import ManualSetting from "./manual";
import ProgrameticalSetting from "./programetical";
export default class NodeFactorSettingTab extends PluginSettingTab {
private plugin: NodeFactor;
constructor(app: App, plugin: NodeFactor) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
const { plugin, containerEl, app } = this;
containerEl.empty();
new ProgrameticalSetting(plugin, containerEl).display();
new ManualSetting(app, plugin, containerEl, () =>
this.display(),
).display();
}
}

115
src/settings/manual.ts Normal file
View file

@ -0,0 +1,115 @@
import {
App,
ButtonComponent,
Notice,
SearchComponent,
Setting,
SliderComponent,
} from "obsidian";
import NodeFactor from "main";
import { FileData } from "types";
import FileSuggest from "./file-suggest";
export default class ManualSetting {
private app: App;
private plugin: NodeFactor;
private containerEl: HTMLElement;
private refreshDisplay: () => void;
constructor(
app: App,
plugin: NodeFactor,
containerEl: HTMLElement,
refreshDisplay: () => void,
) {
this.app = app;
this.plugin = plugin;
this.containerEl = containerEl;
this.refreshDisplay = refreshDisplay;
}
display(): void {
new Setting(this.containerEl).setName("Manually set size").setHeading();
let selectedWeight: SliderComponent;
let selectedFile: SearchComponent;
let submitButton: ButtonComponent;
const addWt = new Setting(this.containerEl)
.setName("Add new weight")
.setDesc("Weight added here overrides everything else.");
addWt.addSearch((search) => {
new FileSuggest(this.app, search.inputEl);
selectedFile = search;
search.setPlaceholder("Enter file name");
search.onChange(async (value) => {
submitButton.setDisabled(value.length === 0);
});
});
addWt.addSlider((slider) => {
selectedWeight = slider;
slider.setLimits(0, 100, 5);
slider.setDynamicTooltip();
slider.setValue(0);
});
addWt.addButton((button) => {
submitButton = button;
button.setDisabled(true);
button.setButtonText("Add");
button.setTooltip("Click to add new manual size");
button.onClick(async () => {
const enteredFileData: FileData = {
id: selectedFile.getValue(),
weight: selectedWeight.getValue(),
};
selectedWeight.setValue(0);
selectedFile.setValue("");
const fileExists = this.plugin.settings.manual.find(
(foundFile) => foundFile.id == enteredFileData.id,
);
if (fileExists != undefined) {
new Notice(
"That file's size has already been entered," +
" remove it first to change weight.",
);
return;
}
this.plugin.settings.manual.push(enteredFileData);
await this.plugin.saveSettings();
new Notice("New size added manually");
this.refreshDisplay();
this.plugin.recalculateSize();
});
});
// Display all manually added weights & option to remove them
this.plugin.settings.manual.forEach((value: FileData) => {
const manualDisplay = new Setting(this.containerEl)
.setName(value.id)
.setDesc(`Weight: ${String(value.weight)}`);
manualDisplay.addButton((button) => {
button.setIcon("trash");
button.setTooltip("Remove manually added size");
button.onClick(async () => {
this.plugin.settings.manual.remove(value);
await this.plugin.saveSettings();
this.refreshDisplay();
this.plugin.recalculateSize();
});
});
});
}
}

View file

@ -0,0 +1,85 @@
import { Setting } from "obsidian";
import NodeFactor from "main";
export default class ProgrameticalSetting {
private plugin: NodeFactor;
private containerEl: HTMLElement;
constructor(plugin: NodeFactor, containerEl: HTMLElement) {
this.plugin = plugin;
this.containerEl = containerEl;
}
display(): void {
new Setting(this.containerEl)
.setName("Programatically set size")
.setHeading();
const fwdLinkWt = new Setting(this.containerEl)
.setName("Forward link weight multiplier")
.setDesc("Multiplier for forward links weight (0 to disable).");
fwdLinkWt.addSlider((slider) => {
slider.setLimits(0, 20, 1);
slider.setDynamicTooltip();
slider.setValue(this.plugin.settings.fwdMultiplier);
slider.onChange(async (value) => {
this.plugin.settings.fwdMultiplier = value;
await this.plugin.saveSettings();
this.plugin.recalculateSize();
});
});
const travelFwdTree = new Setting(this.containerEl)
.setName("Travel forward tree")
.setDesc(
"Travel forward and add all other nodes to determine final node size.",
);
travelFwdTree.addToggle((toggle) => {
toggle.setValue(this.plugin.settings.fwdTree);
toggle.onChange(async (value) => {
this.plugin.settings.fwdTree = value;
await this.plugin.saveSettings();
this.plugin.recalculateSize();
});
});
const bwdLinkWt = new Setting(this.containerEl)
.setName("Backward link weight multiplier")
.setDesc("Multiplier for backward links weight (0 to disable).");
bwdLinkWt.addSlider((slider) => {
slider.setLimits(0, 20, 1);
slider.setDynamicTooltip();
slider.setValue(this.plugin.settings.bwdMultiplier);
slider.onChange(async (value) => {
this.plugin.settings.bwdMultiplier = value;
await this.plugin.saveSettings();
this.plugin.recalculateSize();
});
});
const charWt = new Setting(this.containerEl)
.setName("Character per weight")
.setDesc(
"Add 1 weight to node size per no of given character (0 to disable).",
);
charWt.addSlider((slider) => {
slider.setLimits(0, 5000, 100);
slider.setDynamicTooltip();
slider.setValue(this.plugin.settings.lettersPerWt);
slider.onChange(async (value) => {
this.plugin.settings.lettersPerWt = value;
await this.plugin.saveSettings();
this.plugin.recalculateSize();
});
});
}
}