Skip to content

Commit 521278d

Browse files
committed
Moved types to different file - working on making paired links (mutual links) much faster and better.
1 parent f6a1f8b commit 521278d

File tree

4 files changed

+305
-57
lines changed

4 files changed

+305
-57
lines changed

linkManager.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
2+
import { CustomLink, LinkStatus } from 'types';
3+
4+
5+
// Create a mapping from numeric values to string values
6+
const LinkStatusStringMap: Record<LinkStatus, 'first' | 'second' | 'none'> = {
7+
[LinkStatus.First]: 'first',
8+
[LinkStatus.Second]: 'second',
9+
[LinkStatus.None]: 'none',
10+
};
11+
12+
export class LinkManager {
13+
linksMap: Map<string, CustomLink>;
14+
linkStatus: Map<string, LinkStatus>;
15+
16+
constructor() {
17+
this.linksMap = new Map<string, CustomLink>();
18+
this.linkStatus = new Map<string, LinkStatus>();
19+
}
20+
21+
generateKey(sourceId: string, targetId: string): string {
22+
return `${sourceId}-${targetId}`;
23+
}
24+
25+
addLink(link: CustomLink): void {
26+
const key = this.generateKey(link.source.id, link.target.id);
27+
const reverseKey = this.generateKey(link.target.id, link.source.id);
28+
29+
// Add the new link
30+
this.linksMap.set(key, link);
31+
32+
// Manage the pair statuses
33+
if (this.linksMap.has(reverseKey)) {
34+
// If the reverse link is already present, set the statuses accordingly
35+
this.linkStatus.set(key, LinkStatus.Second);
36+
this.linkStatus.set(reverseKey, LinkStatus.First);
37+
} else {
38+
// If it's a standalone link (no pair yet), do not assign a pair status
39+
// This will be managed when the reverse link is added (if it happens)
40+
}
41+
}
42+
43+
removeLink(link: CustomLink): void {
44+
const key = this.generateKey(link.source.id, link.target.id);
45+
const reverseKey = this.generateKey(link.target.id, link.source.id);
46+
47+
this.linksMap.delete(key);
48+
if (this.linkStatus.has(key)) {
49+
this.linkStatus.delete(key);
50+
}
51+
if (this.linkStatus.get(reverseKey) === LinkStatus.Second) {
52+
this.linkStatus.delete(reverseKey);
53+
}
54+
}
55+
56+
updateLinks(currentLinks: CustomLink[]): void {
57+
const currentKeys = new Set(currentLinks.map(link => this.generateKey(link.source.id, link.target.id)));
58+
for (const key of this.linksMap.keys()) {
59+
if (!currentKeys.has(key)) {
60+
const link = this.linksMap.get(key);
61+
if (link) {
62+
this.removeLink(link);
63+
}
64+
}
65+
}
66+
}
67+
68+
getLinkStatus(key: string): 'first' | 'second' | 'none' {
69+
return LinkStatusStringMap[this.linkStatus.get(key) || LinkStatus.None];
70+
}
71+
}

main.ts

Lines changed: 79 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { Plugin, WorkspaceLeaf, Notice} from 'obsidian';
22
import { getAPI, Page } from 'obsidian-dataview';
3+
import { CustomRenderer, CustomLink, DataviewLinkType} from 'types';
4+
import { LinkManager } from 'linkManager';
35
import * as PIXI from 'pixi.js';
46
import extractLinks from 'markdown-link-extractor';
57

@@ -29,12 +31,73 @@ export default class GraphLinkTypesPlugin extends Plugin {
2931
id: 'print-link-type',
3032
name: 'Print Link Type',
3133
callback: () => {
32-
this.checkAndUpdateRenderer();
33-
this.startUpdateLoop(1);
34+
this.toyLinks();
3435
}
3536
});
3637
}
3738

39+
toyLinks() {
40+
// Example frames: Each frame is an array of links
41+
const frames: CustomLink[][] = [
42+
// Frame 1: Simple links, some will form pairs later
43+
[
44+
{ source: { id: "A", x: 0, y: 0 }, target: { id: "B", x: 0, y: 0 } },
45+
{ source: { id: "C", x: 0, y: 0 }, target: { id: "D", x: 0, y: 0 } },
46+
],
47+
48+
// Frame 2: Adding reverse links to form pairs and keeping existing links
49+
[
50+
{ source: { id: "A", x: 0, y: 0 }, target: { id: "B", x: 0, y: 0 } }, // Existing link
51+
{ source: { id: "B", x: 0, y: 0 }, target: { id: "A", x: 0, y: 0 } }, // Forms a pair with Frame 1's A-B
52+
{ source: { id: "C", x: 0, y: 0 }, target: { id: "D", x: 0, y: 0 } }, // Existing link
53+
{ source: { id: "E", x: 0, y: 0 }, target: { id: "F", x: 0, y: 0 } }, // New link
54+
],
55+
56+
// Frame 3: Keeping a pair, removing a single link, adding a new link
57+
[
58+
{ source: { id: "A", x: 0, y: 0 }, target: { id: "B", x: 0, y: 0 } }, // Existing link
59+
{ source: { id: "B", x: 0, y: 0 }, target: { id: "A", x: 0, y: 0 } }, // Existing pair
60+
{ source: { id: "G", x: 0, y: 0 }, target: { id: "H", x: 0, y: 0 } }, // New link
61+
],
62+
63+
// Frame 4:
64+
[
65+
{ source: { id: "B", x: 0, y: 0 }, target: { id: "A", x: 0, y: 0 } },
66+
{ source: { id: "G", x: 0, y: 0 }, target: { id: "H", x: 0, y: 0 } }, // New link
67+
],
68+
];
69+
70+
const linkManager = new LinkManager();
71+
72+
frames.forEach((frame, frameIndex) => {
73+
console.log(`Frame ${frameIndex + 1}:`);
74+
75+
// Update link manager with the current frame's links
76+
linkManager.updateLinks(frame);
77+
78+
// Process links
79+
frame.forEach(link => {
80+
const key = linkManager.generateKey(link.source.id, link.target.id);
81+
if (!linkManager.linksMap.has(key)) {
82+
linkManager.addLink(link);
83+
}
84+
const status = linkManager.getLinkStatus(key);
85+
86+
// Print link status
87+
if (status === 'first') {
88+
console.log('first: ' + key);
89+
} else if (status === 'second') {
90+
console.log('second: ' + key);
91+
} else {
92+
console.log(key); // Not part of a pair
93+
}
94+
});
95+
});
96+
97+
}
98+
99+
100+
38101
// Find the first valid graph renderer in the workspace
39102
findRenderer(): CustomRenderer | null {
40103
let graphLeaves = this.app.workspace.getLeavesOfType('graph');
@@ -243,17 +306,17 @@ export default class GraphLinkTypesPlugin extends Plugin {
243306
}
244307

245308
// Method to determine the type of a value, now a class method
246-
private determineLinkType(value: any): LinkType {
309+
private determineDataviewLinkType(value: any): DataviewLinkType {
247310
if (typeof value === 'object' && value !== null && 'path' in value) {
248-
return LinkType.DataviewLink;
311+
return DataviewLinkType.WikiLink;
249312
} else if (typeof value === 'string' && value.includes('](')) {
250-
return LinkType.MarkdownLink;
313+
return DataviewLinkType.MarkdownLink;
251314
} else if (typeof value === 'string') {
252-
return LinkType.String;
315+
return DataviewLinkType.String;
253316
} else if (Array.isArray(value)) {
254-
return LinkType.Array;
317+
return DataviewLinkType.Array;
255318
} else {
256-
return LinkType.Other;
319+
return DataviewLinkType.Other;
257320
}
258321
}
259322

@@ -263,27 +326,25 @@ export default class GraphLinkTypesPlugin extends Plugin {
263326
if (!sourcePage) return null;
264327

265328
for (const [key, value] of Object.entries(sourcePage)) {
266-
const valueType = this.determineLinkType(value);
329+
const valueType = this.determineDataviewLinkType(value);
267330

268331
switch (valueType) {
269-
case LinkType.DataviewLink:
332+
case DataviewLinkType.WikiLink:
270333
if (value.path === targetId) {
271334
return key;
272335
}
273336
break;
274-
case LinkType.MarkdownLink:
337+
case DataviewLinkType.MarkdownLink:
275338
if (this.extractPathFromMarkdownLink(value) === targetId) {
276-
console.log(targetId);
277339
return key;
278340
}
279341
break;
280-
case LinkType.Array:
342+
case DataviewLinkType.Array:
281343
for (const item of value) {
282-
if (this.determineLinkType(item) === LinkType.DataviewLink && item.path === targetId) {
344+
if (this.determineDataviewLinkType(item) === DataviewLinkType.WikiLink && item.path === targetId) {
283345
return key;
284346
}
285-
if (this.determineLinkType(item) === LinkType.MarkdownLink && this.extractPathFromMarkdownLink(item) === targetId) {
286-
console.log(targetId);
347+
if (this.determineDataviewLinkType(item) === DataviewLinkType.MarkdownLink && this.extractPathFromMarkdownLink(item) === targetId) {
287348
return key;
288349
}
289350
}
@@ -295,9 +356,8 @@ export default class GraphLinkTypesPlugin extends Plugin {
295356
}
296357

297358
// Utility function to extract the file path from a Markdown link
298-
private extractPathFromMarkdownLink(markdownLink: string): string {
359+
private extractPathFromMarkdownLink(markdownLink: string | unknown): string {
299360
const links = extractLinks(markdownLink).links;
300-
console.log(links[0]);
301361
// The package returns an array of links. Assuming you want the first link.
302362
return links.length > 0 ? links[0] : '';
303363
}
@@ -313,7 +373,7 @@ export default class GraphLinkTypesPlugin extends Plugin {
313373
}
314374

315375
// Utility function to check if a value is a link
316-
isDataviewLink(value: any): boolean {
376+
isWikiLink(value: any): boolean {
317377
return typeof value === 'object' && value.hasOwnProperty('path');
318378
}
319379

@@ -358,41 +418,3 @@ export default class GraphLinkTypesPlugin extends Plugin {
358418

359419
}
360420

361-
362-
interface CustomRenderer {
363-
px: {
364-
stage: {
365-
addChild: (child: any) => void;
366-
removeChild: (child: any) => void;
367-
children: any[];
368-
};
369-
};
370-
links: any[];
371-
nodeScale: number;
372-
panX: number;
373-
panY: number;
374-
scale: number;
375-
}
376-
377-
interface CustomLink {
378-
source: {
379-
id: string;
380-
x: number;
381-
y: number;
382-
};
383-
target: {
384-
id: string;
385-
x: number;
386-
y: number;
387-
};
388-
}
389-
390-
// Define the enum outside the class
391-
enum LinkType {
392-
DataviewLink,
393-
MarkdownLink,
394-
String,
395-
Array,
396-
Other
397-
}
398-

scratchpad.ts

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
2+
import { CustomLink } from './types';
3+
4+
class LinkManager {
5+
private linksMap: Map<string, CustomLink>;
6+
private linkStatus: Map<string, 'first' | 'second'>;
7+
8+
constructor() {
9+
this.linksMap = new Map<string, CustomLink>();
10+
this.linkStatus = new Map<string, 'first' | 'second'>();
11+
}
12+
13+
private generateKey(sourceId: string, targetId: string): string {
14+
return `${sourceId}-${targetId}`;
15+
}
16+
17+
addLink(link: Link): void {
18+
const key = this.generateKey(link.source.id, link.target.id);
19+
const reverseKey = this.generateKey(link.target.id, link.source.id);
20+
21+
// Add the new link
22+
this.linksMap.set(key, link);
23+
24+
// Manage the pair statuses
25+
if (this.linksMap.has(reverseKey)) {
26+
// If the reverse link is already present, set the statuses accordingly
27+
this.linkStatus.set(key, 'second');
28+
this.linkStatus.set(reverseKey, 'first');
29+
} else {
30+
// If it's a standalone link (no pair yet), do not assign a pair status
31+
// This will be managed when the reverse link is added (if it happens)
32+
}
33+
}
34+
35+
removeLink(link: Link): void {
36+
const key = this.generateKey(link.source.id, link.target.id);
37+
const reverseKey = this.generateKey(link.target.id, link.source.id);
38+
39+
this.linksMap.delete(key);
40+
if (this.linkStatus.has(key)) {
41+
this.linkStatus.delete(key);
42+
}
43+
if (this.linkStatus.get(reverseKey) === 'second') {
44+
this.linkStatus.delete(reverseKey);
45+
}
46+
}
47+
48+
updateLinks(currentLinks: Link[]): void {
49+
const currentKeys = new Set(currentLinks.map(link => this.generateKey(link.source.id, link.target.id)));
50+
for (const key of this.linksMap.keys()) {
51+
if (!currentKeys.has(key)) {
52+
const link = this.linksMap.get(key);
53+
if (link) {
54+
this.removeLink(link);
55+
}
56+
}
57+
}
58+
}
59+
60+
getLinkStatus(key: string): 'first' | 'second' | 'none' {
61+
return this.linkStatus.get(key) || 'none';
62+
}
63+
}
64+
65+
// Example frames: Each frame is an array of links
66+
const frames: Link[][] = [
67+
// Frame 1: Simple links, some will form pairs later
68+
[{ source: { id: "A" }, target: { id: "B" } },
69+
{ source: { id: "C" }, target: { id: "D" } }],
70+
71+
// Frame 2: Adding reverse links to form pairs and keeping existing links
72+
[{ source: { id: "A" }, target: { id: "B" } }, // Existing link
73+
{ source: { id: "B" }, target: { id: "A" } }, // Forms a pair with Frame 1's A-B
74+
{ source: { id: "C" }, target: { id: "D" } }, // Existing link
75+
{ source: { id: "E" }, target: { id: "F" } }], // New link
76+
77+
// Frame 3: Keeping a pair, removing a single link, adding a new link
78+
[{ source: { id: "A" }, target: { id: "B" } }, // Existing link
79+
{ source: { id: "B" }, target: { id: "A" } }, // Existing pair
80+
{ source: { id: "G" }, target: { id: "H" } }], // New link
81+
82+
// Frame 4:
83+
[{ source: { id: "B" }, target: { id: "A" } },
84+
{ source: { id: "G" }, target: { id: "H" } }], // New link
85+
];
86+
87+
const linkManager = new LinkManager();
88+
89+
frames.forEach((frame, frameIndex) => {
90+
console.log(`Frame ${frameIndex + 1}:`);
91+
92+
// Update link manager with the current frame's links
93+
linkManager.updateLinks(frame);
94+
95+
// Process links
96+
frame.forEach(link => {
97+
const key = linkManager.generateKey(link.source.id, link.target.id);
98+
if (!linkManager.linksMap.has(key)) {
99+
linkManager.addLink(link);
100+
}
101+
const status = linkManager.getLinkStatus(key);
102+
103+
// Print link status
104+
if (status === 'first') {
105+
console.log('\n' + key);
106+
} else if (status === 'second') {
107+
console.log(key + '\n');
108+
} else {
109+
console.log(key); // Not part of a pair
110+
}
111+
});
112+
});

0 commit comments

Comments
 (0)