Skip to content

Commit

Permalink
enable css customization of graph based on node distance (#57)
Browse files Browse the repository at this point in the history
  • Loading branch information
goliath-walker committed Mar 21, 2022
1 parent 9561bfc commit 5bc35e0
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 38 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "joplin-plugin-link-graph-ui",
"version": "1.2.3",
"version": "1.3.0",
"scripts": {
"dist": "webpack --joplin-plugin-config buildMain && webpack --joplin-plugin-config buildExtraScripts && webpack --joplin-plugin-config createArchive",
"dev": "webpack --mode development --joplin-plugin-config buildMain && webpack --joplin-plugin-config buildExtraScripts && webpack --joplin-plugin-config createArchive",
Expand Down
13 changes: 9 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@ var deepEqual = require("fast-deep-equal");
interface Edge {
source: string;
target: string;
sourceDistanceToCurrentNode?: number;
targetDistanceToCurrentNode?: number;
focused: boolean;
}

interface Node {
id: string;
title: string;
focused: boolean;
distanceToCurrentNote?: number;
distanceToCurrentNode?: number;
}

interface GraphData {
Expand All @@ -24,7 +26,8 @@ interface GraphData {
nodeFontSize: number;
nodeDistanceRatio: number;
showLinkDirection: boolean;
maxDegree: number;
// maxDegree > 0
graphIsSelectionBased: boolean;
}

let data: GraphData;
Expand Down Expand Up @@ -211,7 +214,7 @@ async function fetchData() {
nodeDistanceRatio:
(await joplin.settings.value("SETTING_NODE_DISTANCE")) / 100.0,
showLinkDirection,
maxDegree
graphIsSelectionBased: maxDegree > 0
};

notes.forEach(function (note, id) {
Expand All @@ -231,6 +234,8 @@ async function fetchData() {
data.edges.push({
source: id,
target: link,
sourceDistanceToCurrentNode: notes.get(id).distanceToCurrentNote,
targetDistanceToCurrentNode: notes.get(link).distanceToCurrentNote,
focused: id === selectedNote.id || link === selectedNote.id,
});

Expand All @@ -248,7 +253,7 @@ async function fetchData() {
id: id,
title: note.title,
focused: note.linkedToCurrentNote,
distanceToCurrentNote: note.distanceToCurrentNote
distanceToCurrentNode: note.distanceToCurrentNote
});
});

Expand Down
2 changes: 1 addition & 1 deletion src/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"manifest_version": 1,
"id": "io.treymo.LinkGraph",
"app_min_version": "1.7",
"version": "1.2.3",
"version": "1.3.0",
"name": "Link Graph UI",
"description": "Visualize the connections between Joplin notes.",
"author": "Trey Mo",
Expand Down
107 changes: 83 additions & 24 deletions src/ui/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,29 @@ function update() {
});
}

function addMarkerEndDef(defs, distance) {
defs
.append("marker")
.attr("id", `line-marker-end-${distance}`)
.attr("viewBox", "0 -5 10 10")
.attr("refX", 20)
.attr("refY", 0)
.attr("markerWidth", 15)
.attr("markerHeight", 15)
.attr("markerUnits", "userSpaceOnUse")
.attr("orient", "auto")
.style("fill", `var(--distance-${distance}-primary-color, var(--distance-remaining-primary-color))`)
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5");
}

function minimalDistanceOfLink(link) {
return Math.min(
link.sourceDistanceToCurrentNode,
link.targetDistanceToCurrentNode
);
}

document.getElementById("redrawButton").addEventListener("click", update);

update();
Expand All @@ -31,6 +54,12 @@ function buildGraph(data) {
width = window.innerWidth;
height = window.innerHeight;

if (data.graphIsSelectionBased) {
document
.querySelector("#note_graph")
.classList.add("mode-selection-based-graph");
}

d3.select("#note_graph > svg").remove();
svg = d3
.select("#note_graph")
Expand All @@ -47,13 +76,10 @@ function buildGraph(data) {
return d.id;
})

if (data.maxDegree > 0) {
if (data.graphIsSelectionBased) {
// we are in selection-based graph
forceLink.strength((link) => {
const minDistance = Math.min(
link.source.distanceToCurrentNote,
link.target.distanceToCurrentNote
);
const minDistance = minimalDistanceOfLink(link);
if (minDistance === 0) {
return 1;
} else if (minDistance === 1) {
Expand All @@ -75,20 +101,15 @@ function buildGraph(data) {
.force("center", d3.forceCenter(width / 2, height / 2));

if (data.showLinkDirection) {
svg
.append("defs")
.append("marker")
.attr("id", "arrow")
.attr("viewBox", "0 -5 10 10")
.attr("refX", 20)
.attr("refY", 0)
.attr("markerWidth", 15)
.attr("markerHeight", 15)
.attr("markerUnits", "userSpaceOnUse")
.attr("orient", "auto")
.attr("class", "line-marker-end")
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5");
const defs = svg.append("defs");
// For now add arrows for ten layers (excl. center).
// todo: make more dynamic
const COUNT_LAYERS = 10;
for (let i = 0; i < COUNT_LAYERS; i++) {
addMarkerEndDef(defs, i);
}
// marker, if whole graph is shown
addMarkerEndDef(defs, "default");
}

//add zoom capabilities
Expand Down Expand Up @@ -116,8 +137,26 @@ function updateGraph(data) {
.append("line")
.classed("adjacent-line", (d) => d.focused);

// provide distance classes for links
if (data.graphIsSelectionBased) {
link.attr("class", function (d) {
const linkIsInward =
d.sourceDistanceToCurrentNode > d.targetDistanceToCurrentNode;
return [
...this.classList,
`distance-${minimalDistanceOfLink(d)}`,
...(linkIsInward ? ["inward-link"] : []),
].join(" ");
});
}

if (data.showLinkDirection) {
link.attr("marker-end","url(#arrow)");
link.attr("marker-end", (d) => {
if (data.graphIsSelectionBased) {
const minDistance = minimalDistanceOfLink(d);
return `url(#line-marker-end-${minDistance})`;
} else return `url(#line-marker-end-default)`;
});
}

// Draw nodes.
Expand All @@ -129,8 +168,9 @@ function updateGraph(data) {
.enter()
.append("g");

node
.append("circle")
const circle = node.append("circle");

circle
.classed("current-note", (d) => d.id === data.currentNoteID)
.classed("adjacent-note", (d) => d.focused)
.on("click", function (_, i) {
Expand All @@ -140,8 +180,18 @@ function updateGraph(data) {
});
});

node
.append("text")
// provide distance classes for circles
if (data.graphIsSelectionBased) {
circle.attr("class", function (d) {
return [...this.classList, `distance-${d.distanceToCurrentNode}`].join(
" "
);
});
}

const nodeLabel = node.append("text");

nodeLabel
.attr("class", "node-label")
.attr("font-size", data.nodeFontSize + "px")
.text(function (d) {
Expand All @@ -150,6 +200,15 @@ function updateGraph(data) {
.attr("x", (d) => (d.id === data.currentNoteID ? 20 : 14))
.attr("y", 5);

// provide distance classes for node labels
if (data.graphIsSelectionBased) {
nodeLabel.attr("class", function (d) {
return [...this.classList, `distance-${d.distanceToCurrentNode}`].join(
" "
);
});
}

// update simulation nodes, links, and alpha
simulation.nodes(data.nodes).on("tick", ticked);

Expand Down
46 changes: 38 additions & 8 deletions src/webview.css
Original file line number Diff line number Diff line change
Expand Up @@ -29,35 +29,65 @@ button {
}

circle {
fill: var(--joplin-background-color3);
stroke: var(--joplin-color4);
fill: var(--distance-remaining-primary-color);
stroke: var(--distance-remaining-secondary-color);
r: 10;
}

.adjacent-note {
fill: var(--joplin-color4);
fill: var(--distance-1-primary-color);
r: 13;
}

.current-note {
fill: var(--joplin-color);
fill: var(--distance-0-primary-color);
stroke: var(--distance-0-secondary-color);
r: 18;
}

line {
stroke: var(--joplin-color4);
stroke: var(--distance-remaining-primary-color);
}

line.distance-0 {
stroke: var(--distance-0-primary-color);
stroke-width: 3px;
}

line.distance-1 {
stroke: var(--distance-1-primary-color);
}

.adjacent-line {
stroke: var(--joplin-color);
stroke: var(--distance-0-primary-color);
stroke-width: 3px;
}

.node-label {
fill: var(--joplin-color);
}

.line-marker-end {
fill: var(--joplin-search-marker-background-color);
#note_graph {
/* distance colors for selection-based graph */
--distance-0-primary-color: var(--joplin-color);
--distance-0-secondary-color: var(--joplin-color4);
--distance-1-primary-color: var(--joplin-color4);
--distance-1-secondary-color: var(--joplin-color);
--distance-remaining-primary-color: var(--joplin-background-color-hover3);
--distance-remaining-secondary-color: var(--joplin-color4);
}

/*
* Make nodes far away from selected nodes less apparent:
* Remove stroke for circles > distance-2 in selection-based graphs
*/
#note_graph.mode-selection-based-graph circle:not(.distance-0):not(.distance-1):not(.distance-2) {
stroke: unset;
}

/*
* Mark links which are directed inwards/towards selected note
*/
#note_graph.mode-selection-based-graph .inward-link {
stroke-dasharray: 3;
}

0 comments on commit 5bc35e0

Please sign in to comment.