mirror of
https://github.com/zadam/trilium.git
synced 2025-10-09 15:08:14 +08:00
refactor(notemap): use proper types
This commit is contained in:
parent
d2dda95654
commit
cf37549f19
3 changed files with 33 additions and 30 deletions
|
@ -3,9 +3,9 @@ import "./NoteMap.css";
|
||||||
import { getThemeStyle, MapType, NoteMapWidgetMode, rgb2hex } from "./utils";
|
import { getThemeStyle, MapType, NoteMapWidgetMode, rgb2hex } from "./utils";
|
||||||
import { RefObject } from "preact";
|
import { RefObject } from "preact";
|
||||||
import FNote from "../../entities/fnote";
|
import FNote from "../../entities/fnote";
|
||||||
import { useElementSize, useNoteContext, useNoteLabel } from "../react/hooks";
|
import { useElementSize, useNoteLabel } from "../react/hooks";
|
||||||
import ForceGraph, { LinkObject, NodeObject } from "force-graph";
|
import ForceGraph from "force-graph";
|
||||||
import { loadNotesAndRelations, Node, NotesAndRelationsData } from "./data";
|
import { loadNotesAndRelations, NoteMapLinkObject, NoteMapNodeObject, NotesAndRelationsData } from "./data";
|
||||||
import { CssData, setupRendering } from "./rendering";
|
import { CssData, setupRendering } from "./rendering";
|
||||||
import ActionButton from "../react/ActionButton";
|
import ActionButton from "../react/ActionButton";
|
||||||
import { t } from "../../services/i18n";
|
import { t } from "../../services/i18n";
|
||||||
|
@ -27,7 +27,7 @@ export default function NoteMap({ note, widgetMode, parentRef }: NoteMapProps) {
|
||||||
const [ mapRootIdLabel ] = useNoteLabel(note, "mapRootNoteId");
|
const [ mapRootIdLabel ] = useNoteLabel(note, "mapRootNoteId");
|
||||||
const mapType: MapType = mapTypeRaw === "tree" ? "tree" : "link";
|
const mapType: MapType = mapTypeRaw === "tree" ? "tree" : "link";
|
||||||
|
|
||||||
const graphRef = useRef<ForceGraph<NodeObject, LinkObject<NodeObject>>>();
|
const graphRef = useRef<ForceGraph<NoteMapNodeObject, NoteMapLinkObject>>();
|
||||||
const containerSize = useElementSize(parentRef);
|
const containerSize = useElementSize(parentRef);
|
||||||
const [ fixNodes, setFixNodes ] = useState(false);
|
const [ fixNodes, setFixNodes ] = useState(false);
|
||||||
const [ linkDistance, setLinkDistance ] = useState(40);
|
const [ linkDistance, setLinkDistance ] = useState(40);
|
||||||
|
@ -49,7 +49,7 @@ export default function NoteMap({ note, widgetMode, parentRef }: NoteMapProps) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const container = containerRef.current;
|
const container = containerRef.current;
|
||||||
if (!container || !mapRootId) return;
|
if (!container || !mapRootId) return;
|
||||||
const graph = new ForceGraph(container);
|
const graph = new ForceGraph<NoteMapNodeObject, NoteMapLinkObject>(container);
|
||||||
|
|
||||||
graphRef.current = graph;
|
graphRef.current = graph;
|
||||||
|
|
||||||
|
@ -76,11 +76,11 @@ export default function NoteMap({ note, widgetMode, parentRef }: NoteMapProps) {
|
||||||
graph
|
graph
|
||||||
.onNodeClick((node) => {
|
.onNodeClick((node) => {
|
||||||
if (!node.id) return;
|
if (!node.id) return;
|
||||||
appContext.tabManager.getActiveContext()?.setNote((node as Node).id);
|
appContext.tabManager.getActiveContext()?.setNote(node.id);
|
||||||
})
|
})
|
||||||
.onNodeRightClick((node, e) => {
|
.onNodeRightClick((node, e) => {
|
||||||
if (!node.id) return;
|
if (!node.id) return;
|
||||||
link_context_menu.openContextMenu((node as Node).id, e);
|
link_context_menu.openContextMenu(node.id, e);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set data
|
// Set data
|
||||||
|
|
|
@ -11,28 +11,26 @@ interface GroupedLink {
|
||||||
names: string[];
|
names: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Node extends NodeObject {
|
export interface NoteMapNodeObject extends NodeObject {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
type: string;
|
type: string;
|
||||||
color: string;
|
color: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Link extends LinkObject<NodeObject> {
|
export interface NoteMapLinkObject extends LinkObject<NoteMapNodeObject> {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
x: number;
|
x?: number;
|
||||||
y: number;
|
y?: number;
|
||||||
source: Node;
|
|
||||||
target: Node;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NotesAndRelationsData {
|
export interface NotesAndRelationsData {
|
||||||
nodes: Node[];
|
nodes: NoteMapNodeObject[];
|
||||||
links: {
|
links: {
|
||||||
id: string;
|
id: string;
|
||||||
source: string;
|
source: string | NoteMapNodeObject;
|
||||||
target: string;
|
target: string | NoteMapNodeObject;
|
||||||
name: string;
|
name: string;
|
||||||
}[];
|
}[];
|
||||||
noteIdToSizeMap: Record<string, number>;
|
noteIdToSizeMap: Record<string, number>;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type ForceGraph from "force-graph";
|
import type ForceGraph from "force-graph";
|
||||||
import { Link, Node, NotesAndRelationsData } from "./data";
|
import { NoteMapLinkObject, NoteMapNodeObject, NotesAndRelationsData } from "./data";
|
||||||
import { LinkObject, NodeObject } from "force-graph";
|
import { LinkObject, NodeObject } from "force-graph";
|
||||||
import { generateColorFromString, MapType, NoteMapWidgetMode } from "./utils";
|
import { generateColorFromString, MapType, NoteMapWidgetMode } from "./utils";
|
||||||
import { escapeHtml } from "../../services/utils";
|
import { escapeHtml } from "../../services/utils";
|
||||||
|
@ -22,14 +22,14 @@ interface RenderData {
|
||||||
mapType: MapType;
|
mapType: MapType;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setupRendering(graph: ForceGraph, { note, noteId, themeStyle, widgetMode, noteIdToSizeMap, notesAndRelations, cssData, mapType }: RenderData) {
|
export function setupRendering(graph: ForceGraph<NoteMapNodeObject, NoteMapLinkObject>, { note, noteId, themeStyle, widgetMode, noteIdToSizeMap, notesAndRelations, cssData, mapType }: RenderData) {
|
||||||
// variables for the hover effect. We have to save the neighbours of a hovered node in a set. Also we need to save the links as well as the hovered node itself
|
// variables for the hover effect. We have to save the neighbours of a hovered node in a set. Also we need to save the links as well as the hovered node itself
|
||||||
const neighbours = new Set();
|
const neighbours = new Set();
|
||||||
const highlightLinks = new Set();
|
const highlightLinks = new Set();
|
||||||
let hoverNode: NodeObject | null = null;
|
let hoverNode: NodeObject | null = null;
|
||||||
let zoomLevel: number;
|
let zoomLevel: number;
|
||||||
|
|
||||||
function getColorForNode(node: Node) {
|
function getColorForNode(node: NoteMapNodeObject) {
|
||||||
if (node.color) {
|
if (node.color) {
|
||||||
return node.color;
|
return node.color;
|
||||||
} else if (widgetMode === "ribbon" && node.id === noteId) {
|
} else if (widgetMode === "ribbon" && node.id === noteId) {
|
||||||
|
@ -39,7 +39,7 @@ export function setupRendering(graph: ForceGraph, { note, noteId, themeStyle, wi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function paintNode(node: Node, color: string, ctx: CanvasRenderingContext2D) {
|
function paintNode(node: NoteMapNodeObject, color: string, ctx: CanvasRenderingContext2D) {
|
||||||
const { x, y } = node;
|
const { x, y } = node;
|
||||||
if (!x || !y) {
|
if (!x || !y) {
|
||||||
return;
|
return;
|
||||||
|
@ -72,7 +72,7 @@ export function setupRendering(graph: ForceGraph, { note, noteId, themeStyle, wi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function paintLink(link: Link, ctx: CanvasRenderingContext2D) {
|
function paintLink(link: NoteMapLinkObject, ctx: CanvasRenderingContext2D) {
|
||||||
if (zoomLevel < 5) {
|
if (zoomLevel < 5) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -117,16 +117,17 @@ export function setupRendering(graph: ForceGraph, { note, noteId, themeStyle, wi
|
||||||
.d3VelocityDecay(0.08)
|
.d3VelocityDecay(0.08)
|
||||||
.maxZoom(7)
|
.maxZoom(7)
|
||||||
.warmupTicks(30)
|
.warmupTicks(30)
|
||||||
.nodeCanvasObject((_node, ctx) => {
|
.nodeCanvasObject((node, ctx) => {
|
||||||
const node: Node = _node as Node;
|
|
||||||
if (hoverNode == node) {
|
if (hoverNode == node) {
|
||||||
//paint only hovered node
|
//paint only hovered node
|
||||||
paintNode(node, "#661822", ctx);
|
paintNode(node, "#661822", ctx);
|
||||||
neighbours.clear(); //clearing neighbours or the effect would be maintained after hovering is over
|
neighbours.clear(); //clearing neighbours or the effect would be maintained after hovering is over
|
||||||
for (const _link of notesAndRelations.links) {
|
for (const link of notesAndRelations.links) {
|
||||||
const link = _link as unknown as Link;
|
const { source, target } = link;
|
||||||
|
if (typeof source !== "object" || typeof target !== "object") continue;
|
||||||
|
|
||||||
//check if node is part of a link in the canvas, if so add it´s neighbours and related links to the previous defined variables to paint the nodes
|
//check if node is part of a link in the canvas, if so add it´s neighbours and related links to the previous defined variables to paint the nodes
|
||||||
if (link.source.id == node.id || link.target.id == node.id) {
|
if (source.id == node.id || target.id == node.id) {
|
||||||
neighbours.add(link.source);
|
neighbours.add(link.source);
|
||||||
neighbours.add(link.target);
|
neighbours.add(link.target);
|
||||||
highlightLinks.add(link);
|
highlightLinks.add(link);
|
||||||
|
@ -145,7 +146,7 @@ export function setupRendering(graph: ForceGraph, { note, noteId, themeStyle, wi
|
||||||
hoverNode = node || null;
|
hoverNode = node || null;
|
||||||
highlightLinks.clear();
|
highlightLinks.clear();
|
||||||
})
|
})
|
||||||
.nodePointerAreaPaint((node, _, ctx) => paintNode(node as Node, getColorForNode(node as Node), ctx))
|
.nodePointerAreaPaint((node, _, ctx) => paintNode(node, getColorForNode(node), ctx))
|
||||||
.nodePointerAreaPaint((node, color, ctx) => {
|
.nodePointerAreaPaint((node, color, ctx) => {
|
||||||
if (!node.id) {
|
if (!node.id) {
|
||||||
return;
|
return;
|
||||||
|
@ -158,7 +159,7 @@ export function setupRendering(graph: ForceGraph, { note, noteId, themeStyle, wi
|
||||||
}
|
}
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
})
|
})
|
||||||
.nodeLabel((node) => escapeHtml((node as Node).name))
|
.nodeLabel((node) => escapeHtml(node.name))
|
||||||
.onZoom((zoom) => zoomLevel = zoom.k);
|
.onZoom((zoom) => zoomLevel = zoom.k);
|
||||||
|
|
||||||
// set link width to immitate a highlight effect. Checking the condition if any links are saved in the previous defined set highlightlinks
|
// set link width to immitate a highlight effect. Checking the condition if any links are saved in the previous defined set highlightlinks
|
||||||
|
@ -171,8 +172,12 @@ export function setupRendering(graph: ForceGraph, { note, noteId, themeStyle, wi
|
||||||
// Link-specific config
|
// Link-specific config
|
||||||
if (mapType) {
|
if (mapType) {
|
||||||
graph
|
graph
|
||||||
.linkLabel((l) => `${escapeHtml((l as Link).source.name)} - <strong>${escapeHtml((l as Link).name)}</strong> - ${escapeHtml((l as Link).target.name)}`)
|
.linkLabel((link) => {
|
||||||
.linkCanvasObject((link, ctx) => paintLink(link as Link, ctx))
|
const { source, target } = link;
|
||||||
|
if (typeof source !== "object" || typeof target !== "object") return escapeHtml(link.name);
|
||||||
|
return `${escapeHtml(source.name)} - <strong>${escapeHtml(link.name)}</strong> - ${escapeHtml(target.name)}`;
|
||||||
|
})
|
||||||
|
.linkCanvasObject((link, ctx) => paintLink(link, ctx))
|
||||||
.linkCanvasObjectMode(() => "after");
|
.linkCanvasObjectMode(() => "after");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue