Skip to content

Commit 96da729

Browse files
committed
Now adds text above links in global graph view, and added side ribbon button for choosing colors.
1 parent ac2af64 commit 96da729

File tree

3 files changed

+819
-28
lines changed

3 files changed

+819
-28
lines changed

main.ts

Lines changed: 234 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,142 @@
1-
import { Plugin, WorkspaceLeaf, Notice } from 'obsidian';
1+
import { Plugin, App, WorkspaceLeaf, Notice, Modal } from 'obsidian';
22
import { getAPI } from 'obsidian-dataview';
3+
import * as PIXI from 'pixi.js';
4+
5+
class ColorPickerModal extends Modal {
6+
keyColorMap: Map<string | null, number>;
7+
tableBody: HTMLElement;
8+
9+
constructor(app: App, keyColorMap: Map<string | null, number>) {
10+
super(app);
11+
this.keyColorMap = keyColorMap;
12+
}
13+
14+
onOpen() {
15+
const {contentEl} = this;
16+
contentEl.createEl('h2', {text: 'Key Colors'});
17+
18+
// Add CSS styles
19+
const styleEl = contentEl.createEl('style', {text: `
20+
.color-table {
21+
width: 100%;
22+
border-collapse: collapse;
23+
}
24+
.color-table th, .color-table td {
25+
border: 1px solid #ccc;
26+
padding: 8px;
27+
text-align: left;
28+
}
29+
.color-table th {
30+
background-color: #f2f2f2;
31+
}
32+
.color-table tr:hover {
33+
background-color: #ddd;
34+
}
35+
.color-preview {
36+
width: 50px;
37+
height: 20px;
38+
border: 1px solid #ccc;
39+
cursor: pointer;
40+
}
41+
.color-preview-box {
42+
display: inline-block;
43+
width: 20px;
44+
height: 20px;
45+
border: 1px solid #000;
46+
margin-right: 5px;
47+
vertical-align: middle;
48+
}
49+
`});
50+
51+
// Create table with styles
52+
const table = contentEl.createEl('table', {cls: 'color-table'});
53+
const thead = table.createEl('thead');
54+
const headerRow = thead.createEl('tr');
55+
headerRow.createEl('th', {text: 'Key'});
56+
headerRow.createEl('th', {text: 'Color'});
57+
58+
const tbody = table.createEl('tbody');
59+
this.tableBody = tbody;
60+
this.refreshTable();
61+
}
62+
63+
refreshTable() {
64+
this.tableBody.empty();
65+
66+
this.keyColorMap.forEach((color, key) => {
67+
console.log(`Key: ${key}, Color: ${color}`); // Debug log
68+
69+
const row = this.tableBody.createEl('tr');
70+
row.createEl('td', {text: key});
71+
72+
const colorCell = row.createEl('td');
73+
const colorString = (typeof color === 'number') ? color.toString(16).padStart(6, '0') : color;
74+
75+
// Ensure color is a hex string and set it as background color
76+
let colorHex = (typeof color === 'number') ? color.toString(16).padStart(6, '0') : color;
77+
78+
const colorPreviewBox = colorCell.createEl('div', {
79+
cls: 'color-preview-box',
80+
});
81+
82+
colorPreviewBox.style.backgroundColor = `#${colorHex}`;
83+
84+
// Log the computed style of colorPreviewBox
85+
console.log(colorPreviewBox.style.backgroundColor);
86+
87+
88+
const colorText = colorCell.createEl('span', {
89+
text: `#${colorString}`
90+
});
91+
92+
colorPreviewBox.addEventListener('click', () => {
93+
this.openColorPicker(key);
94+
});
95+
});
96+
}
97+
98+
99+
onClose() {
100+
const {contentEl} = this;
101+
contentEl.empty();
102+
}
103+
104+
openColorPicker(key: string | null) {
105+
const colorPickerModal = new Modal(this.app);
106+
colorPickerModal.titleEl.setText("Select Color");
107+
108+
const colorInput = colorPickerModal.contentEl.createEl('input', {
109+
type: 'text',
110+
value: "#ffffff"
111+
});
112+
113+
const submitButton = colorPickerModal.contentEl.createEl('button', {
114+
text: 'Apply Color'
115+
});
116+
117+
submitButton.addEventListener('click', () => {
118+
const newColor = colorInput.value;
119+
120+
if (newColor && key) {
121+
const colorInt = parseInt(newColor.replace('#', ''), 16);
122+
this.keyColorMap.set(key, colorInt);
123+
this.refreshTable();
124+
colorPickerModal.close();
125+
}
126+
});
127+
128+
colorPickerModal.open();
129+
}
130+
131+
132+
}
3133

4134
export default class UniqueMetadataKeysPlugin extends Plugin {
5135
api = getAPI();
6-
keyColorMap = new Map<string, number>();
136+
keyColorMap = new Map<string | null, number>();
137+
nodeTextMap = new Map(); // Store node-text pairs
138+
selectedKey: string | null;
139+
7140

8141
onload() {
9142
this.addCommand({
@@ -12,9 +145,18 @@ export default class UniqueMetadataKeysPlugin extends Plugin {
12145
callback: () => this.printUniqueMetadataKeys()
13146
});
14147
this.addCommand({
15-
id: 'print-graph-leaf',
16-
name: 'Print Graph Leaf',
17-
callback: () => this.findGraphLeaf()
148+
id: 'print-link-type',
149+
name: 'Print Link Type',
150+
callback: () => this.startUpdateLoop()
151+
});
152+
153+
this.printUniqueMetadataKeys();
154+
155+
// Assume these are your keys
156+
const keys = ['key1', 'key2', 'key3'];
157+
158+
this.addRibbonIcon('palette', 'Choose Colors', () => {
159+
new ColorPickerModal(this.app, this.keyColorMap).open();
18160
});
19161
}
20162

@@ -45,14 +187,12 @@ export default class UniqueMetadataKeysPlugin extends Plugin {
45187
this.keyColorMap.set(key, color);
46188
});
47189

48-
console.log('Unique Metadata Keys with Link Values:');
190+
this.keyColorMap.set(null, 0);
49191
this.keyColorMap.forEach((color, key) => console.log(`${key}: ${color}`));
50192
}
193+
51194

52-
getColorForKey(key: string | null): number | undefined {
53-
if (key === null) {
54-
return 0;
55-
}
195+
getColorForKey(key: string | null): number | undefined{
56196
return this.keyColorMap.get(key);
57197
}
58198

@@ -76,6 +216,20 @@ export default class UniqueMetadataKeysPlugin extends Plugin {
76216
}
77217

78218
findGraphLeaf(): WorkspaceLeaf | null{
219+
var t = [];
220+
this.app.workspace.iterateAllLeaves(function(n) {
221+
n.view && t.push(n.getDisplayText())
222+
})
223+
console.log(t);
224+
var t = [];
225+
this.app.workspace.iterateAllLeaves(function(n) {
226+
n.view && t.push(n)
227+
})
228+
console.log(t);
229+
console.log(this.app.workspace.getLeavesOfType())
230+
viewType
231+
232+
79233
let graphLeaves = this.app.workspace.getLeavesOfType('graph');
80234
if (graphLeaves.length != 1) {
81235
if (graphLeaves.length < 1) {
@@ -85,23 +239,77 @@ export default class UniqueMetadataKeysPlugin extends Plugin {
85239
}
86240
return null;
87241
}
88-
const links = graphLeaves[0].view.renderer.links;
89-
90-
for (let i = 0; i < 2; i++) {
91-
const sourceId = links[i].source.id;
92-
const targetId = links[i].target.id;
93-
console.log(sourceId);
94-
console.log(targetId);
95-
const linkKey = this.getMetadataKeyForLink(sourceId, targetId);
96-
const linkColor = this.getColorForKey(linkKey);
97-
console.log(linkColor);
98-
console.log(links[i].renderer);
99-
links[i].line._tintRGB = linkColor;
100-
links[i].renderer.colors.line.rgb = links[i].line._tintRGB;
101-
102-
}
103-
242+
console.log(graphLeaves[0].view.renderer);
104243

105244
return graphLeaves[0]
106245
}
246+
247+
createTextForLink(renderer, link) {
248+
const linkString = this.getMetadataKeyForLink(link.source.id, link.target.id);
249+
if (linkString === null) return;
250+
console.log(this.getColorForKey(linkString))
251+
const textStyle = new PIXI.TextStyle({
252+
fontFamily: 'Arial',
253+
fontSize: 36,
254+
fill: this.getColorForKey(linkString)
255+
});
256+
const text = new PIXI.Text(linkString, textStyle);
257+
text.alpha = 0.7;
258+
text.anchor.set(0.5, 0.5);
259+
this.nodeTextMap.set(link, text);
260+
this.updateTextPosition(renderer, link);
261+
renderer.px.stage.addChild(text);
262+
}
263+
264+
265+
updateTextPosition(renderer, link) {
266+
const text = this.nodeTextMap.get(link);
267+
if (text) {
268+
const midX = (link.source.x + link.target.x) / 2;
269+
const midY = (link.source.y + link.target.y) / 2;
270+
const { x, y } = this.getLinkToTextCoordinates(midX, midY, renderer.panX, renderer.panY, renderer.scale);
271+
text.x = x;
272+
text.y = y;
273+
text.scale.set(1/(3*renderer.nodeScale));
274+
}
275+
}
276+
277+
startUpdateLoop() {
278+
const graphLeaf = this.findGraphLeaf();
279+
if (graphLeaf === null) {
280+
console.log("Graph leaf not found.");
281+
return;
282+
}
283+
const renderer = graphLeaf.view.renderer;
284+
const links = renderer.links;
285+
links.forEach(link => this.createTextForLink(renderer, link));
286+
requestAnimationFrame(this.updatePositions.bind(this));
287+
}
288+
289+
updatePositions() {
290+
const graphLeaf = this.findGraphLeaf();
291+
if (graphLeaf === null) {
292+
console.log("Graph leaf not found.");
293+
return;
294+
}
295+
const renderer = graphLeaf.view.renderer;
296+
const links = renderer.links;
297+
links.forEach(link => {
298+
this.updateTextPosition(renderer, link);
299+
});
300+
requestAnimationFrame(this.updatePositions.bind(this));
301+
}
302+
303+
getLinkToTextCoordinates(nodeX, nodeY, panX, panY, scale) {
304+
// Apply scaling - assuming node coordinates are scaled
305+
let scaledX = nodeX * scale;
306+
let scaledY = nodeY * scale;
307+
308+
// Apply panning - assuming the entire scene is panned
309+
let pannedX = scaledX + panX;
310+
let pannedY = scaledY + panY;
311+
312+
return { x: pannedX, y: pannedY };
313+
}
314+
107315
}

0 commit comments

Comments
 (0)