From 2dc5cb6b3a1eb611137ecfcae63966f699925395 Mon Sep 17 00:00:00 2001 From: Zsolt Viczian Date: Thu, 5 May 2022 20:36:06 +0200 Subject: [PATCH] added link style and directional links --- src/Scene.ts | 10 +-- src/Settings.ts | 163 +++++++++++++++++++++++---------------------- src/Types.ts | 10 ++- src/graph/Link.ts | 26 ++++++-- src/graph/Links.ts | 25 +++++-- src/graph/Page.ts | 41 ++++++++---- src/graph/Pages.ts | 30 ++++----- src/main.ts | 23 ++++++- 8 files changed, 203 insertions(+), 125 deletions(-) diff --git a/src/Scene.ts b/src/Scene.ts index d73cea5..2fb2b8c 100644 --- a/src/Scene.ts +++ b/src/Scene.ts @@ -1,4 +1,4 @@ -import { App, FileView, MarkdownView, Notice, TextFileView, TFile, Vault, WorkspaceLeaf } from "obsidian"; +import { App, FileView, Notice, TextFileView, TFile, Vault, WorkspaceLeaf } from "obsidian"; import { ExcalidrawAutomate } from "obsidian-excalidraw-plugin/lib/ExcalidrawAutomate"; import { EMPTYBRAIN } from "./constants/emptyBrainFile"; import { Layout } from "./graph/Layout"; @@ -8,7 +8,7 @@ import ExcaliBrain from "./main"; import { ExcaliBrainSettings } from "./Settings"; import { SearchBox } from "./Suggesters/SearchBox"; import { Neighbour, RelationType, Role } from "./Types"; -import { log } from "./utils/utils"; + export class Scene { settings: ExcaliBrainSettings; @@ -24,7 +24,7 @@ export class Scene { public disregardLeafChange: boolean = false; public terminated: boolean; private nodesMap: Map = new Map(); - private links: Links = new Links(); + private links: Links; private layouts: Layout[] = []; private removeEH: Function; private removeTimer: Function; @@ -38,6 +38,7 @@ export class Scene { this.app = plugin.app; this.leaf = leaf ?? app.workspace.getLeaf(newLeaf); this.terminated = false; + this.links = new Links(plugin); } public async initialize() { @@ -231,7 +232,7 @@ export class Scene { //------------------------------------------------------- // Generate layout and nodes this.nodesMap = new Map(); - this.links = new Links(); + this.links = new Links(this.plugin); this.layouts = []; const manyChildren = children.length >10; const manySiblings = siblings.length > 10; @@ -349,6 +350,7 @@ export class Scene { role, neighbour.relationType, neighbour.typeDefinition, + neighbour.linkDirection, this.ea, this.settings ) diff --git a/src/Settings.ts b/src/Settings.ts index 6e600ac..025bf7c 100644 --- a/src/Settings.ts +++ b/src/Settings.ts @@ -12,7 +12,7 @@ import { ExcalidrawAutomate } from "obsidian-excalidraw-plugin/lib/ExcalidrawAut import { Page } from "./graph/Page"; import { t } from "./lang/helpers"; import ExcaliBrain from "./main"; -import { Hierarchy, NodeStyle, LinkStyle, RelationType, NodeStyleData, LinkStyleData } from "./Types"; +import { Hierarchy, NodeStyle, LinkStyle, RelationType, NodeStyleData, LinkStyleData, LinkDirection } from "./Types"; import { WarningPrompt } from "./utils/Prompts"; import { Node } from "./graph/Node"; import { svgToBase64 } from "./utils/utils"; @@ -38,7 +38,6 @@ export interface ExcaliBrainSettings { baseLinkStyle: LinkStyle; inferredLinkStyle: LinkStyle; hierarchyLinkStyles: {[key: string]: LinkStyle}; - hierarchyStyleList: string[]; } export const DEFAULT_SETTINGS: ExcaliBrainSettings = { @@ -108,7 +107,6 @@ export const DEFAULT_SETTINGS: ExcaliBrainSettings = { strokeStyle: "dashed", }, hierarchyLinkStyles: {}, - hierarchyStyleList: [] }; const HIDE_DISABLED_STYLE = "excalibrain-hide-disabled"; @@ -141,7 +139,7 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { ea: ExcalidrawAutomate; private dirty:boolean = false; private demoNode: Node; - private demoImg: HTMLImageElement; + private demoNodeImg: HTMLImageElement; private demoLinkImg: HTMLImageElement; private demoLinkStyle: LinkStyleData; private demoNodeStyle: NodeStyleData; @@ -151,7 +149,14 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { this.plugin = plugin; } - async updateDemoImg() { + get hierarchyStyleList(): string[] { + return ["base","inferred"] + .concat(Array.from(this.plugin.settings.hierarchy.parents)) + .concat(Array.from(this.plugin.settings.hierarchy.children)) + .concat(Array.from(this.plugin.settings.hierarchy.friends)); + }; + + async updateNodeDemoImg() { this.ea.reset(); this.ea.canvas.viewBackgroundColor = this.plugin.settings.backgroundColor; this.demoNode.style = { @@ -162,7 +167,7 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { const svg = await this.ea.createSVG(null,true,{withBackground:true, withTheme:false},null,"",40); svg.removeAttribute("width"); svg.removeAttribute("height"); - this.demoImg.setAttribute("src", svgToBase64(svg.outerHTML)); + this.demoNodeImg.setAttribute("src", svgToBase64(svg.outerHTML)); }; async updateLinkDemoImg() { @@ -186,6 +191,7 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { if(!this.dirty) { return; } + this.plugin.setHierarchyLinkStylesExtended(); this.plugin.settings.tagStyleList = Object.keys(this.plugin.settings.tagNodeStyles); this.plugin.saveSettings(); this.plugin.scene?.reRender(); @@ -463,7 +469,7 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { if(!value) { setDisabled(true); setting.prefix = undefined; - this.updateDemoImg(); + this.updateNodeDemoImg(); return; } setDisabled(false); @@ -477,7 +483,7 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { .setValue(setting.prefix??inheritedStyle.prefix) .onChange(value => { setting.prefix = value; - this.updateDemoImg(); + this.updateNodeDemoImg(); this.dirty = true; }) }) @@ -490,11 +496,11 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { ()=>setting.backgroundColor, val=>{ setting.backgroundColor=val; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, ()=>{ delete setting.backgroundColor; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, allowOverride, inheritedStyle.backgroundColor, @@ -508,11 +514,11 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { () => setting.fillStyle?.toString(), (val) => { setting.fillStyle = val as FillStyle; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, ()=> { delete setting.fillStyle; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, allowOverride, inheritedStyle.fillStyle.toString(), @@ -525,11 +531,11 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { ()=>setting.textColor, val=> { setting.textColor=val; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, ()=> { delete setting.textColor; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, allowOverride, inheritedStyle.textColor, @@ -542,11 +548,11 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { ()=>setting.borderColor, val=> { setting.borderColor=val; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, ()=> { delete setting.borderColor; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, allowOverride, inheritedStyle.borderColor, @@ -560,11 +566,11 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { () => setting.fontSize, (val) => { setting.fontSize = val; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, ()=> { delete setting.fontSize; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, allowOverride, inheritedStyle.fontSize, @@ -578,11 +584,11 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { () => setting.fontFamily?.toString(), (val) => { setting.fontFamily = parseInt(val); - this.updateDemoImg(); + this.updateNodeDemoImg(); }, ()=> { delete setting.fontFamily; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, allowOverride, inheritedStyle.fontFamily.toString(), @@ -596,11 +602,11 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { () => setting.maxLabelLength, (val) => { setting.maxLabelLength = val; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, ()=> { delete setting.maxLabelLength; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, allowOverride, inheritedStyle.maxLabelLength, @@ -614,11 +620,11 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { () => setting.roughness?.toString(), (val) => { setting.roughness = parseInt(val); - this.updateDemoImg(); + this.updateNodeDemoImg(); }, ()=> { delete setting.roughness; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, allowOverride, inheritedStyle.roughness.toString(), @@ -632,11 +638,11 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { () => setting.strokeShaprness, (val) => { setting.strokeShaprness = val as StrokeSharpness; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, ()=> { delete setting.strokeShaprness; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, allowOverride, inheritedStyle.strokeShaprness, @@ -650,11 +656,11 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { () => setting.strokeWidth, (val) => { setting.strokeWidth = val; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, ()=> { delete setting.strokeWidth; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, allowOverride, inheritedStyle.strokeWidth, @@ -668,11 +674,11 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { () => setting.strokeStyle, (val) => { setting.strokeStyle = val as StrokeStyle; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, ()=> { delete setting.strokeStyle; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, allowOverride, inheritedStyle.strokeStyle, @@ -686,11 +692,11 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { () => setting.padding, (val) => { setting.padding = val; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, ()=> { delete setting.padding; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, allowOverride, inheritedStyle.padding, @@ -704,11 +710,11 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { () => setting.gateRadius, (val) => { setting.gateRadius = val; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, ()=> { delete setting.gateRadius; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, allowOverride, inheritedStyle.gateRadius, @@ -722,11 +728,11 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { () => setting.gateOffset, (val) => { setting.gateOffset = val; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, ()=> { delete setting.gateOffset; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, allowOverride, inheritedStyle.gateOffset, @@ -739,11 +745,11 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { ()=>setting.gateStrokeColor, val=> { setting.gateStrokeColor=val; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, ()=> { delete setting.gateStrokeColor; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, allowOverride, inheritedStyle.gateStrokeColor, @@ -756,11 +762,11 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { ()=>setting.gateBackgroundColor, val=> { setting.gateBackgroundColor=val; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, ()=> { delete setting.gateBackgroundColor; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, allowOverride, inheritedStyle.gateBackgroundColor, @@ -774,11 +780,11 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { () => setting.gateFillStyle?.toString(), (val) => { setting.gateFillStyle = val as FillStyle; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, ()=> { delete setting.gateFillStyle; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, allowOverride, inheritedStyle.gateFillStyle.toString(), @@ -849,7 +855,7 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { t("LINKSTYLE_ARROWSTART"), null, {"":"None","arrow":"Arrow","bar":"Bar","dot":"Dot","triangle":"Triangle"}, - () => setting.startArrowHead, + () => setting.startArrowHead??"", (val) => { setting.startArrowHead = (val === "") ? null : val as Arrowhead; this.updateLinkDemoImg(); @@ -896,7 +902,8 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { null, this.plugin ) - page.addChild(page2,RelationType.DEFINED); + page.addChild(page2,RelationType.DEFINED,LinkDirection.FROM); + page2.addParent(page,RelationType.DEFINED,LinkDirection.TO); this.demoNode = new Node({ page, isInferred: false, @@ -1077,7 +1084,7 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { ()=>this.plugin.settings.backgroundColor, (val)=> { this.plugin.settings.backgroundColor=val; - this.updateDemoImg(); + this.updateNodeDemoImg(); }, ()=>{}, false, @@ -1099,7 +1106,7 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { nodeStyle.getInheritedStyle() ) this.demoNodeStyle = nodeStyle; - this.updateDemoImg(); + this.updateNodeDemoImg(); } const taglist = new Setting(containerEl) @@ -1153,19 +1160,19 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { taglist.descEl.style.maxWidth="400px"; const nodeStylesWrapper = containerEl.createDiv({cls:"setting-item"}); - const dropodownWrapper = nodeStylesWrapper.createDiv({cls:"setting-item-info"}); - nodeStylesDropdown = new DropdownComponent(dropodownWrapper); + const nodeStylesDropdownWrapper = nodeStylesWrapper.createDiv({cls:"setting-item-info"}); + nodeStylesDropdown = new DropdownComponent(nodeStylesDropdownWrapper); - const toggleLabel = nodeStylesWrapper.createDiv({ + const nodeStylestoggleLabel = nodeStylesWrapper.createDiv({ text: "Show inherited", cls: "setting-item-name" }); - toggleLabel.style.marginRight = "10px"; + nodeStylestoggleLabel.style.marginRight = "10px"; let linkStylesToggle: ToggleComponent; - const toggle = new ToggleComponent(nodeStylesWrapper) - toggle + const nodeStylesToggle = new ToggleComponent(nodeStylesWrapper) + nodeStylesToggle .setValue(true) .setTooltip("Show/Hide Inherited Properties") .onChange(value => { @@ -1181,7 +1188,7 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { nodeStylesDropdown.addOption(item[0],item[1].display) }) - this.demoImg = containerEl.createEl("img",{cls: "excalibrain-settings-demoimg"}); + this.demoNodeImg = containerEl.createEl("img",{cls: "excalibrain-settings-demoimg"}); nodeStyleDiv = containerEl.createDiv({ cls: "excalibrain-setting-nodestyle-section" @@ -1198,7 +1205,7 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { nodeStyle.getInheritedStyle() ) this.demoNodeStyle = nodeStyle; - this.updateDemoImg(); + this.updateNodeDemoImg(); //----------------------------- // Link Style settings @@ -1208,21 +1215,21 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { let linkStyleDiv: HTMLDivElement; const linkDropdownOnChange = (value:string) => { linkStyleDiv.empty(); - const linkStyle = this.plugin.linkStyles[value]; + const ls = this.plugin.linkStyles[value]; this.linkSettings( linkStyleDiv, - linkStyle.style, - linkStyle.allowOverride, - linkStyle.getInheritedStyle() + ls.style, + ls.allowOverride, + ls.getInheritedStyle() ) - this.demoLinkStyle = linkStyle; + this.demoLinkStyle = ls; this.updateLinkDemoImg(); } const linkStylesWrapper = containerEl.createDiv({cls:"setting-item"}); - const linkStylesDropodownWrapper = linkStylesWrapper.createDiv({cls:"setting-item-info"}); - linkStylesDropdown = new DropdownComponent(linkStylesDropodownWrapper); + const linkStylesDropdownWrapper = linkStylesWrapper.createDiv({cls:"setting-item-info"}); + linkStylesDropdown = new DropdownComponent(linkStylesDropdownWrapper); const linkStylesToggleLabel = linkStylesWrapper.createDiv({ text: "Show inherited", @@ -1242,7 +1249,7 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { } else { addStylesheet(HIDE_DISABLED_STYLE, HIDE_DISABLED_CLASS); } - linkStylesToggle.setValue(value); + nodeStylesToggle.setValue(value); }); Object.entries(this.plugin.linkStyles).forEach(item=>{ @@ -1254,42 +1261,38 @@ export class ExcaliBrainSettingTab extends PluginSettingTab { linkStyleDiv = containerEl.createDiv({ cls: "excalibrain-setting-nodestyle-section" }); - removeStylesheet(HIDE_DISABLED_STYLE); + linkStylesDropdown .setValue("base") .onChange(linkDropdownOnChange) - const linkStyle = this.plugin.linkStyles["base"]; + const ls = this.plugin.linkStyles["base"]; this.linkSettings( linkStyleDiv, - linkStyle.style, - linkStyle.allowOverride, - linkStyle.getInheritedStyle() + ls.style, + ls.allowOverride, + ls.getInheritedStyle() ) - this.demoLinkStyle = linkStyle; + this.demoLinkStyle = ls; this.updateLinkDemoImg(); onHierarchyChange = () => { - const hierarchy = this.plugin.settings.hierarchy; const hierarchyLinkStyles = this.plugin.settings.hierarchyLinkStyles const linkStyles = this.plugin.linkStyles; - this.plugin.settings.hierarchyStyleList = - Array.from(hierarchy.parents) - .concat(Array.from(hierarchy.children)) - .concat(Array.from(hierarchy.friends)); + Object.keys(linkStyles).forEach(key => { - if(!this.plugin.settings.hierarchyStyleList.contains(key)) { + if(!this.hierarchyStyleList.contains(key)) { delete linkStyles[key]; delete hierarchyLinkStyles[key]; } }); - this.plugin.settings.hierarchyStyleList.forEach(link => { - if(!Object.keys(hierarchyLinkStyles).contains(link)) { - hierarchyLinkStyles[link] = {}; - linkStyles[link] = { - style: hierarchyLinkStyles[link], + this.hierarchyStyleList.forEach(dataviewfield => { + if(!Object.keys(hierarchyLinkStyles).contains(dataviewfield)) { + hierarchyLinkStyles[dataviewfield] = {}; + linkStyles[dataviewfield] = { + style: hierarchyLinkStyles[dataviewfield], allowOverride: true, userStyle: true, - display: link, + display: dataviewfield, getInheritedStyle: () => this.plugin.settings.baseLinkStyle } } diff --git a/src/Types.ts b/src/Types.ts index 539bc5d..fd917b1 100644 --- a/src/Types.ts +++ b/src/Types.ts @@ -13,8 +13,15 @@ export enum Role { FRIEND } +export enum LinkDirection { + TO = 1, + FROM = 2, + BOTH = 3, +} + export type Relation = { target: Page; + direction: LinkDirection; isParent: boolean; parentType?: RelationType; parentTypeDefinition?: string; @@ -79,7 +86,7 @@ export type LinkStyleData = { allowOverride:boolean, userStyle: boolean, display: string, - getInheritedStyle: ()=>LinkStyle + getInheritedStyle: ()=>LinkStyle, } export type LinkStyles = { @@ -90,6 +97,7 @@ export type Neighbour = { page: Page; relationType: RelationType; typeDefinition: string; + linkDirection: LinkDirection; } export type LayoutSpecification = { diff --git a/src/graph/Link.ts b/src/graph/Link.ts index d669890..e34de9f 100644 --- a/src/graph/Link.ts +++ b/src/graph/Link.ts @@ -1,4 +1,6 @@ +import { link } from "fs"; import { ExcalidrawAutomate } from "obsidian-excalidraw-plugin/lib/ExcalidrawAutomate"; +import ExcaliBrain from "src/main"; import { ExcaliBrainSettings } from "src/Settings"; import { LinkStyle, RelationType, Role } from "src/Types"; import { Node } from "./Node"; @@ -10,19 +12,35 @@ export class Link { public nodeA: Node, public nodeB: Node, private nodeBRole: Role, - private relation: RelationType, - private hierarchyDefinition: string, + relation: RelationType, + hierarchyDefinition: string, private ea: ExcalidrawAutomate, - private settings: ExcaliBrainSettings + settings: ExcaliBrainSettings, + plugin: ExcaliBrain ) { + const hlist = hierarchyDefinition?.split(",").map(h=>h.trim()); + let linkstyle: LinkStyle = {}; + if(hlist) { + hlist.forEach(h=>{ + if(!plugin.hierarchyLinkStylesExtended[h]) { + return; + } + linkstyle = { + ...linkstyle, + ...plugin.hierarchyLinkStylesExtended[h] + } + }) + } this.style = { ...settings.baseLinkStyle, ...relation === RelationType.INFERRED ? settings.inferredLinkStyle - : {} + : {}, + ...linkstyle }; } + render() { const ea = this.ea; const style = this.style; diff --git a/src/graph/Links.ts b/src/graph/Links.ts index 8168df6..7f74e8b 100644 --- a/src/graph/Links.ts +++ b/src/graph/Links.ts @@ -1,6 +1,7 @@ import { ExcalidrawAutomate } from "obsidian-excalidraw-plugin/lib/ExcalidrawAutomate"; +import ExcaliBrain from "src/main"; import { ExcaliBrainSettings } from "src/Settings"; -import { RelationType, Role } from "src/Types"; +import { LinkDirection, RelationType, Role } from "src/Types"; import { Link } from "./Link"; import { Node } from "./Node"; @@ -9,7 +10,7 @@ const SEPARATOR = "|:?:|" export class Links { links: Map = new Map(); reverseLinks: Set = new Set(); - constructor() { + constructor(private plugin:ExcaliBrain) { } @@ -19,6 +20,7 @@ export class Links { nodeBRole: Role, relation: RelationType, hierarchyDefinition: string, + linkDirection: LinkDirection, ea: ExcalidrawAutomate, settings: ExcaliBrainSettings ) { @@ -28,13 +30,24 @@ export class Links { } const key2 = nodeB.page.path+SEPARATOR+nodeA.page.path; const link = new Link( - nodeA, - nodeB, - nodeBRole, + linkDirection===LinkDirection.FROM + ? nodeB + : nodeA, + linkDirection===LinkDirection.FROM + ? nodeA + : nodeB, + linkDirection===LinkDirection.FROM + ? nodeBRole === Role.FRIEND + ? Role.FRIEND + : nodeBRole === Role.CHILD + ? Role.PARENT + : Role.CHILD + : nodeBRole, relation, hierarchyDefinition, ea, - settings + settings, + this.plugin ) this.links.set(key1, link), this.reverseLinks.add(key2) diff --git a/src/graph/Page.ts b/src/graph/Page.ts index 22086a7..fae9826 100644 --- a/src/graph/Page.ts +++ b/src/graph/Page.ts @@ -1,16 +1,14 @@ import { TFile } from "obsidian"; import ExcaliBrain from "src/main"; import { ExcaliBrainSettings } from "src/Settings"; -import { Neighbour, Relation, RelationType } from "src/Types"; -import { pipeline } from "stream"; - - +import { LinkDirection, Neighbour, Relation, RelationType } from "src/Types"; const DEFAULT_RELATION:Relation = { target: null, isParent: false, isChild: false, - isFriend: false + isFriend: false, + direction: null } const getRelationVector = (r:Relation):{ @@ -37,6 +35,16 @@ const concat = (s1: string, s2: string): string => { : s2 } +const directionToSet = (currentDirection:LinkDirection, newDirection: LinkDirection):LinkDirection => { + if(!currentDirection) { + return newDirection; + } + if(currentDirection === LinkDirection.BOTH || currentDirection === newDirection) { + return currentDirection; + } + return LinkDirection.BOTH; +} + const relationTypeToSet = (currentType: RelationType, newType: RelationType):RelationType => { if(currentType === RelationType.DEFINED) { return RelationType.DEFINED @@ -91,7 +99,7 @@ export class Page { //----------------------------------------------- // add relationships //----------------------------------------------- - addParent(page: Page, relationType:RelationType, definition?: string) { + addParent(page: Page, relationType:RelationType, direction: LinkDirection, definition?: string) { if(page.path === this.plugin.settings.excalibrainFilepath) { return; }; @@ -100,6 +108,7 @@ export class Page { neighbour.isParent = true; neighbour.parentType = relationTypeToSet(neighbour.parentType,relationType); neighbour.parentTypeDefinition = concat(definition, neighbour.parentTypeDefinition); + neighbour.direction = directionToSet(neighbour.direction, direction); return; } this.neighbours.set(page.path, { @@ -108,10 +117,11 @@ export class Page { isParent: true, parentType: relationType, parentTypeDefinition: definition, + direction }); } - addChild(page: Page, relationType:RelationType, definition?: string) { + addChild(page: Page, relationType:RelationType, direction: LinkDirection, definition?: string) { if(page.path === this.plugin.settings.excalibrainFilepath) { return; }; @@ -120,6 +130,7 @@ export class Page { neighbour.isChild = true; neighbour.childType = relationTypeToSet(neighbour.childType,relationType); neighbour.childTypeDefinition = concat(definition,neighbour.childTypeDefinition); + neighbour.direction = directionToSet(neighbour.direction, direction); return; } this.neighbours.set(page.path, { @@ -128,10 +139,11 @@ export class Page { isChild: true, childType: relationType, childTypeDefinition: definition, + direction }); } - addFriend(page: Page, relationType:RelationType, definition?: string) { + addFriend(page: Page, relationType:RelationType, direction: LinkDirection, definition?: string) { if(page.path === this.plugin.settings.excalibrainFilepath) { return; }; @@ -139,7 +151,8 @@ export class Page { if(neighbour) { neighbour.isFriend = true; neighbour.friendType = relationTypeToSet(neighbour.friendType,relationType); - neighbour.friendTypeDefinition = concat(definition,neighbour.friendTypeDefinition);; + neighbour.friendTypeDefinition = concat(definition,neighbour.friendTypeDefinition); + neighbour.direction = directionToSet(neighbour.direction, direction); return; } this.neighbours.set(page.path, { @@ -148,6 +161,7 @@ export class Page { isFriend: true, friendType: relationType, friendTypeDefinition: definition, + direction }); } @@ -184,7 +198,8 @@ export class Page { return { page: x[1].target, relationType: x[1].childType, - typeDefinition: x[1].childTypeDefinition + typeDefinition: x[1].childTypeDefinition, + linkDirection: x[1].direction } });//.sort } @@ -217,7 +232,8 @@ export class Page { return { page: x[1].target, relationType: x[1].parentType, - typeDefinition: x[1].parentTypeDefinition + typeDefinition: x[1].parentTypeDefinition, + linkDirection: x[1].direction } });//.sort } @@ -255,7 +271,8 @@ export class Page { ? RelationType.DEFINED //case I : RelationType.INFERRED, - typeDefinition: x[1].friendTypeDefinition + typeDefinition: x[1].friendTypeDefinition, + linkDirection: x[1].direction } });//.sort } diff --git a/src/graph/Pages.ts b/src/graph/Pages.ts index b784616..b3d272d 100644 --- a/src/graph/Pages.ts +++ b/src/graph/Pages.ts @@ -1,6 +1,6 @@ import { App, TFile } from "obsidian"; import ExcaliBrain from "src/main"; -import { Relation, RelationType } from "src/Types"; +import { LinkDirection, Relation, RelationType } from "src/Types"; import { getDVFieldLinksForPage } from "src/utils/dataview"; import { log } from "src/utils/utils"; import { Page} from "./Page"; @@ -59,8 +59,8 @@ export class Pages { log(`Unexpected: ${page.file.path} is referenced from ${link} as backlink in metadataCache, but page for ${link} has not yet been registered in ExcaliBrain index.`); return; } - parent.addChild(page,RelationType.INFERRED); - page.addParent(parent,RelationType.INFERRED); + parent.addChild(page,RelationType.INFERRED,LinkDirection.TO); + page.addParent(parent,RelationType.INFERRED,LinkDirection.FROM); }) this.addUnresolvedLinks(page); @@ -74,11 +74,11 @@ export class Pages { if(page && page.path !== parentPath) { return; } + const parent = this.pages.get(parentPath); Object.keys(resolvedLinks[parentPath]).forEach(childPath=>{ const child = this.pages.get(childPath); - const parent = this.pages.get(parentPath); - child.addParent(parent,RelationType.INFERRED); - parent.addChild(child,RelationType.INFERRED); + child.addParent(parent,RelationType.INFERRED, LinkDirection.TO); + parent.addChild(child,RelationType.INFERRED, LinkDirection.FROM); }) }); } @@ -92,11 +92,11 @@ export class Pages { if(page && page.path !== parentPath) { return; } + const parent = this.pages.get(parentPath); Object.keys(unresolvedLinks[parentPath]).forEach(childPath=>{ const newPage = new Page(childPath,null,this.plugin); - const parent = this.pages.get(parentPath); - newPage.addParent(parent,RelationType.INFERRED); - parent.addChild(newPage,RelationType.INFERRED); + newPage.addParent(parent,RelationType.INFERRED, LinkDirection.TO); + parent.addChild(newPage,RelationType.INFERRED, LinkDirection.FROM); this.add(childPath,newPage); }) }); @@ -115,8 +115,8 @@ export class Pages { log(`Unexpected: ${page.file.path} references ${item.link} in DV, but it was not found in app.metadataCache. The page was skipped.`); return; } - page.addParent(referencedPage,RelationType.DEFINED,item.field); - referencedPage.addChild(page,RelationType.DEFINED,item.field); + page.addParent(referencedPage,RelationType.DEFINED,LinkDirection.FROM, item.field); + referencedPage.addChild(page,RelationType.DEFINED,LinkDirection.TO, item.field); }); const childFields = this.plugin.settings.hierarchy.children; getDVFieldLinksForPage(this.plugin,dvPage,childFields).forEach(item=>{ @@ -125,8 +125,8 @@ export class Pages { log(`Unexpected: ${page.file.path} references ${item.link} in DV, but it was not found in app.metadataCache. The page was skipped.`); return; } - page.addChild(referencedPage,RelationType.DEFINED,item.field); - referencedPage.addParent(page,RelationType.DEFINED,item.field); + page.addChild(referencedPage,RelationType.DEFINED,LinkDirection.FROM, item.field); + referencedPage.addParent(page,RelationType.DEFINED,LinkDirection.TO, item.field); }); const friendFields = this.plugin.settings.hierarchy.friends; getDVFieldLinksForPage(this.plugin,dvPage,friendFields).forEach(item=>{ @@ -135,8 +135,8 @@ export class Pages { log(`Unexpected: ${page.file.path} references ${item.link} in DV, but it was not found in app.metadataCache. The page was skipped.`); return; } - page.addFriend(referencedPage,RelationType.DEFINED,item.field); - referencedPage.addFriend(page,RelationType.DEFINED,item.field); + page.addFriend(referencedPage,RelationType.DEFINED,LinkDirection.FROM,item.field); + referencedPage.addFriend(page,RelationType.DEFINED,LinkDirection.TO, item.field); }); } } \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 8a8feba..845082e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -25,6 +25,7 @@ export default class ExcaliBrain extends Plugin { public settings:ExcaliBrainSettings; public nodeStyles: NodeStyles; public linkStyles: LinkStyles; + public hierarchyLinkStylesExtended: {[key: string]: LinkStyle}; //including datafields lowercase and "-" instead of " " public pages: Pages; public DVAPI: DvAPIInterface; public EA: ExcalidrawAutomate; @@ -183,11 +184,24 @@ export default class ExcaliBrain extends Plugin { } } + public setHierarchyLinkStylesExtended() { + this.hierarchyLinkStylesExtended = {}; + Object.entries(this.settings.hierarchyLinkStyles).forEach(item=>{ + const lowercase = item[0].toLowerCase().replaceAll(" ","-"); + this.hierarchyLinkStylesExtended[item[0]] = item[1]; + if(item[0]!==lowercase) { + this.hierarchyLinkStylesExtended[lowercase] = item[1]; + } + }) + } + async loadSettings() { this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); + + this.setHierarchyLinkStylesExtended(); this.linkStyles = {}; - this.linkStyles["base"] = { + this.linkStyles["base"] = { //! update also Settings.hierarchyStyleList() style: this.settings.baseLinkStyle, allowOverride: false, userStyle: false, @@ -195,7 +209,7 @@ export default class ExcaliBrain extends Plugin { getInheritedStyle: () => this.settings.baseLinkStyle, } - this.linkStyles["inferred"] = { + this.linkStyles["inferred"] = { //! update also Settings.hierarchyStyleList() style: this.settings.inferredLinkStyle, allowOverride: true, userStyle: false, @@ -204,12 +218,15 @@ export default class ExcaliBrain extends Plugin { } Object.entries(this.settings.hierarchyLinkStyles).forEach((item:[string,LinkStyle])=>{ + if(["base","inferred"].contains(item[0])) { + return; + } this.linkStyles[item[0]] = { style: item[1], allowOverride: true, userStyle: true, display: item[0], - getInheritedStyle: ()=> this.settings.baseNodeStyle + getInheritedStyle: ()=> this.settings.baseNodeStyle, } })