import libraryLoader from "../services/library_loader.js"; import linkMapDialog from "../dialogs/link_map.js"; import server from "../services/server.js"; import treeCache from "../services/tree_cache.js"; import linkService from "../services/link.js"; let linkMapContainerIdCtr = 1; const TPL = `
`; const linkOverlays = [ [ "Arrow", { location: 1, id: "arrow", length: 10, width: 10, foldback: 0.7 } ] ]; class LinkMapWidget { /** * @param {TabContext} ctx * @param {jQuery} $widget */ constructor(ctx, $widget) { this.ctx = ctx; this.$widget = $widget; this.$widget.on('show.bs.collapse', () => this.renderBody()); this.$widget.on('show.bs.collapse', () => this.ctx.stateChanged()); this.$widget.on('hide.bs.collapse', () => this.ctx.stateChanged()); this.$title = this.$widget.find('.widget-title'); this.$title.text("Link map"); this.$headerActions = this.$widget.find('.widget-header-actions'); this.$bodyWrapper = this.$widget.find('.body-wrapper'); const $showFullButton = $("").append("show full").addClass('widget-header-action'); $showFullButton.click(() => { linkMapDialog.showDialog(); }); this.$headerActions.append($showFullButton); } async renderBody() { if (!this.isVisible()) { return; } const $body = this.$widget.find('.card-body'); $body.html(TPL); this.$linkMapContainer = $body.find('.link-map-container'); this.$linkMapContainer.attr("id", "link-map-container-" + linkMapContainerIdCtr++); await libraryLoader.requireLibrary(libraryLoader.LINK_MAP); jsPlumb.ready(() => { this.initJsPlumbInstance(); this.initPanZoom(); this.loadNotesAndRelations(); }); } async loadNotesAndRelations() { this.cleanup(); const linkTypes = [ "hyper", "image", "relation", "relation-map" ]; const maxNotes = 50; const noteId = this.ctx.note.noteId; const links = await server.post(`notes/${noteId}/link-map`, { linkTypes, maxNotes, maxDepth: 1 }); const noteIds = new Set(links.map(l => l.noteId).concat(links.map(l => l.targetNoteId))); if (noteIds.size === 0) { noteIds.add(noteId); } // preload all notes const notes = await treeCache.getNotes(Array.from(noteIds)); const graph = new Springy.Graph(); graph.addNodes(...noteIds); graph.addEdges(...links.map(l => [l.noteId, l.targetNoteId])); const layout = new Springy.Layout.ForceDirected( graph, 400.0, // Spring stiffness 400.0, // Node repulsion 0.5 // Damping ); const getNoteBox = noteId => { const noteBoxId = this.noteIdToId(noteId); const $existingNoteBox = $("#" + noteBoxId); if ($existingNoteBox.length > 0) { return $existingNoteBox; } const note = notes.find(n => n.noteId === noteId); const $noteBox = $("