chore(react): reintroduce centering i note map

This commit is contained in:
Elian Doran
2025-10-04 13:55:22 +03:00
parent e6e9cd3f35
commit 656b234740
3 changed files with 95 additions and 98 deletions

View File

@@ -82,101 +82,6 @@ export default class NoteMapWidget extends NoteContextAwareWidget {
this.renderData(data); this.renderData(data);
} }
renderData(data: Data) {
if (this.widgetMode === "ribbon" && this.note?.type !== "search") {
setTimeout(() => {
this.setDimensions();
const subGraphNoteIds = this.getSubGraphConnectedToCurrentNote(data);
this.graph.zoomToFit(400, 50, (node) => subGraphNoteIds.has(node.id));
if (subGraphNoteIds.size < 30) {
this.graph.d3VelocityDecay(0.4);
}
}, 1000);
} else {
if (data.nodes.length > 1) {
setTimeout(() => {
this.setDimensions();
const noteIdsWithLinks = this.getNoteIdsWithLinks(data);
if (noteIdsWithLinks.size > 0) {
this.graph.zoomToFit(400, 30, (node) => noteIdsWithLinks.has(node.id ?? ""));
}
if (noteIdsWithLinks.size < 30) {
this.graph.d3VelocityDecay(0.4);
}
}, 1000);
}
}
}
getNoteIdsWithLinks(data: Data) {
const noteIds = new Set<string | number>();
for (const link of data.links) {
if (typeof link.source === "object" && link.source.id) {
noteIds.add(link.source.id);
}
if (typeof link.target === "object" && link.target.id) {
noteIds.add(link.target.id);
}
}
return noteIds;
}
getSubGraphConnectedToCurrentNote(data: Data) {
function getGroupedLinks(links: LinkObject<NodeObject>[], type: "source" | "target") {
const map: Record<string | number, LinkObject<NodeObject>[]> = {};
for (const link of links) {
if (typeof link[type] !== "object") {
continue;
}
const key = link[type].id;
if (key) {
map[key] = map[key] || [];
map[key].push(link);
}
}
return map;
}
const linksBySource = getGroupedLinks(data.links, "source");
const linksByTarget = getGroupedLinks(data.links, "target");
const subGraphNoteIds = new Set();
function traverseGraph(noteId?: string | number) {
if (!noteId || subGraphNoteIds.has(noteId)) {
return;
}
subGraphNoteIds.add(noteId);
for (const link of linksBySource[noteId] || []) {
if (typeof link.target === "object") {
traverseGraph(link.target?.id);
}
}
for (const link of linksByTarget[noteId] || []) {
if (typeof link.source === "object") {
traverseGraph(link.source?.id);
}
}
}
traverseGraph(this.noteId);
return subGraphNoteIds;
}
cleanup() { cleanup() {
this.$container.html(""); this.$container.html("");
} }

View File

@@ -48,9 +48,10 @@ export default function NoteMap({ note, widgetMode, parentRef }: NoteMapProps) {
// Configure rendering properties. // Configure rendering properties.
setupRendering(graph, { setupRendering(graph, {
cssData, note,
noteId: note.noteId, noteId: note.noteId,
noteIdToSizeMap: notesAndRelations.noteIdToSizeMap, noteIdToSizeMap: notesAndRelations.noteIdToSizeMap,
cssData,
notesAndRelations, notesAndRelations,
themeStyle: getThemeStyle(), themeStyle: getThemeStyle(),
widgetMode, widgetMode,

View File

@@ -1,8 +1,9 @@
import type ForceGraph from "force-graph"; import type ForceGraph from "force-graph";
import { Link, Node, NotesAndRelationsData } from "./data"; import { Link, Node, NotesAndRelationsData } from "./data";
import { 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";
import FNote from "../../entities/fnote";
export interface CssData { export interface CssData {
fontFamily: string; fontFamily: string;
@@ -11,6 +12,7 @@ export interface CssData {
} }
interface RenderData { interface RenderData {
note: FNote;
noteIdToSizeMap: Record<string, number>; noteIdToSizeMap: Record<string, number>;
cssData: CssData; cssData: CssData;
noteId: string; noteId: string;
@@ -20,7 +22,7 @@ interface RenderData {
mapType: MapType; mapType: MapType;
} }
export function setupRendering(graph: ForceGraph, { noteId, themeStyle, widgetMode, noteIdToSizeMap, notesAndRelations, cssData, mapType }: RenderData) { export function setupRendering(graph: ForceGraph, { 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();
@@ -173,5 +175,94 @@ export function setupRendering(graph: ForceGraph, { noteId, themeStyle, widgetMo
.linkCanvasObject((link, ctx) => paintLink(link as Link, ctx)) .linkCanvasObject((link, ctx) => paintLink(link as Link, ctx))
.linkCanvasObjectMode(() => "after"); .linkCanvasObjectMode(() => "after");
} }
// Zoom to notes
if (widgetMode === "ribbon" && note?.type !== "search") {
setTimeout(() => {
const subGraphNoteIds = getSubGraphConnectedToCurrentNote(noteId, notesAndRelations);
graph.zoomToFit(400, 50, (node) => subGraphNoteIds.has(node.id));
if (subGraphNoteIds.size < 30) {
graph.d3VelocityDecay(0.4);
}
}, 1000);
} else {
if (notesAndRelations.nodes.length > 1) {
setTimeout(() => {
const noteIdsWithLinks = getNoteIdsWithLinks(notesAndRelations);
if (noteIdsWithLinks.size > 0) {
graph.zoomToFit(400, 30, (node) => noteIdsWithLinks.has(node.id ?? ""));
} }
if (noteIdsWithLinks.size < 30) {
graph.d3VelocityDecay(0.4);
}
}, 1000);
}
}
}
function getNoteIdsWithLinks(data: NotesAndRelationsData) {
const noteIds = new Set<string | number>();
for (const link of data.links) {
if (typeof link.source === "object" && link.source.id) {
noteIds.add(link.source.id);
}
if (typeof link.target === "object" && link.target.id) {
noteIds.add(link.target.id);
}
}
return noteIds;
}
function getSubGraphConnectedToCurrentNote(noteId: string, data: NotesAndRelationsData) {
function getGroupedLinks(links: LinkObject<NodeObject>[], type: "source" | "target") {
const map: Record<string | number, LinkObject<NodeObject>[]> = {};
for (const link of links) {
if (typeof link[type] !== "object") {
continue;
}
const key = link[type].id;
if (key) {
map[key] = map[key] || [];
map[key].push(link);
}
}
return map;
}
const linksBySource = getGroupedLinks(data.links, "source");
const linksByTarget = getGroupedLinks(data.links, "target");
const subGraphNoteIds = new Set();
function traverseGraph(noteId?: string | number) {
if (!noteId || subGraphNoteIds.has(noteId)) {
return;
}
subGraphNoteIds.add(noteId);
for (const link of linksBySource[noteId] || []) {
if (typeof link.target === "object") {
traverseGraph(link.target?.id);
}
}
for (const link of linksByTarget[noteId] || []) {
if (typeof link.source === "object") {
traverseGraph(link.source?.id);
}
}
}
traverseGraph(noteId);
return subGraphNoteIds;
}