From 4b96ada78163ec4efc943cbcf2a1900a6de0b5c8 Mon Sep 17 00:00:00 2001 From: zadam Date: Tue, 4 Jun 2019 22:57:10 +0200 Subject: [PATCH] link map WIP --- src/public/javascripts/dialogs/link_map.js | 56 ++++++++++++++++++---- src/public/stylesheets/desktop.css | 6 +++ src/routes/api/link_map.js | 4 +- 3 files changed, 54 insertions(+), 12 deletions(-) diff --git a/src/public/javascripts/dialogs/link_map.js b/src/public/javascripts/dialogs/link_map.js index 24dc25013..59b44e61e 100644 --- a/src/public/javascripts/dialogs/link_map.js +++ b/src/public/javascripts/dialogs/link_map.js @@ -1,6 +1,7 @@ import server from '../services/server.js'; import noteDetailService from "../services/note_detail.js"; import libraryLoader from "../services/library_loader.js"; +import treeCache from "../services/tree_cache.js"; const $linkMapContainer = $("#link-map-container"); @@ -84,9 +85,12 @@ async function loadNotesAndRelations() { const noteIds = new Set(links.map(l => l.noteId).concat(links.map(l => l.targetNoteId))); + // 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])); + graph.addEdges(...links.map(l => [l.noteId, l.targetNoteId])); const layout = new Springy.Layout.ForceDirected( graph, @@ -95,10 +99,38 @@ async function loadNotesAndRelations() { 0.5 // Damping ); + const renderer = new Springy.Renderer( + layout, + () => {}, + () => {}, + () => {}, + () => { + layout.eachNode((node, point) => { + console.log(node, point.p); - for (const link of links) { + const note = notes.find(n => n.noteId === node.id); - } + const $noteBox = $("
") + .addClass("note-box") + .prop("id", noteIdToId(node.id)) + .append($("").addClass("title").append(note.title)) + .css("left", (300 + point.p.x * 100) + "px") + .css("top", (300 + point.p.y * 100) + "px"); + + jsPlumbInstance.getContainer().appendChild($noteBox[0]); + }); + + for (const link of links) { + const connection = jsPlumbInstance.connect({ + source: noteIdToId(link.noteId), + target: noteIdToId(link.targetNoteId), + type: link.type + }); + } + } + ); + + renderer.start(); } function initJsPlumbInstance() { @@ -113,23 +145,27 @@ function initJsPlumbInstance() { return; } - this.jsPlumbInstance = jsPlumb.getInstance({ + jsPlumbInstance = jsPlumb.getInstance({ Endpoint: ["Dot", {radius: 2}], Connector: "StateMachine", ConnectionOverlays: uniDirectionalOverlays, HoverPaintStyle: { stroke: "#777", strokeWidth: 1 }, - Container: this.$relationMapContainer.attr("id") + Container: $linkMapContainer.attr("id") }); - this.jsPlumbInstance.registerConnectionType("uniDirectional", { anchor:"Continuous", connector:"StateMachine", overlays: uniDirectionalOverlays }); + jsPlumbInstance.registerConnectionType("uniDirectional", { anchor:"Continuous", connector:"StateMachine", overlays: uniDirectionalOverlays }); - this.jsPlumbInstance.registerConnectionType("biDirectional", { anchor:"Continuous", connector:"StateMachine", overlays: biDirectionalOverlays }); + jsPlumbInstance.registerConnectionType("biDirectional", { anchor:"Continuous", connector:"StateMachine", overlays: biDirectionalOverlays }); - this.jsPlumbInstance.registerConnectionType("inverse", { anchor:"Continuous", connector:"StateMachine", overlays: inverseRelationsOverlays }); + jsPlumbInstance.registerConnectionType("inverse", { anchor:"Continuous", connector:"StateMachine", overlays: inverseRelationsOverlays }); - this.jsPlumbInstance.registerConnectionType("link", { anchor:"Continuous", connector:"StateMachine", overlays: linkOverlays }); + jsPlumbInstance.registerConnectionType("link", { anchor:"Continuous", connector:"StateMachine", overlays: linkOverlays }); - this.jsPlumbInstance.bind("connection", (info, originalEvent) => this.connectionCreatedHandler(info, originalEvent)); + jsPlumbInstance.bind("connection", (info, originalEvent) => connectionCreatedHandler(info, originalEvent)); +} + +function noteIdToId(noteId) { + return "link-map-note-" + noteId; } export default { diff --git a/src/public/stylesheets/desktop.css b/src/public/stylesheets/desktop.css index 30beb328d..e6b1ee608 100644 --- a/src/public/stylesheets/desktop.css +++ b/src/public/stylesheets/desktop.css @@ -335,4 +335,10 @@ li.dropdown-submenu:hover > ul.dropdown-menu { .note-tab-row.note-tab-row-is-sorting .note-tab:not(.note-tab-is-dragging), .note-tab-row:not(.note-tab-row-is-sorting) .note-tab.note-tab-was-just-dragged { transition: transform 120ms ease-in-out; +} + +#link-map-container { + position: relative; + height: 700px; + outline: none; /* remove dotted outline on click */ } \ No newline at end of file diff --git a/src/routes/api/link_map.js b/src/routes/api/link_map.js index 66568c2da..e34bae139 100644 --- a/src/routes/api/link_map.js +++ b/src/routes/api/link_map.js @@ -14,7 +14,7 @@ async function getLinks(noteIds) { WHERE (noteId IN (???) OR value IN (???)) AND type = 'relation' AND isDeleted = 0 - `, noteIds); + `, Array.from(noteIds)); } async function getLinkMap(req) { @@ -27,7 +27,7 @@ async function getLinkMap(req) { const newLinks = await getLinks(noteIds); const newNoteIds = new Set(newLinks.map(l => l.noteId).concat(newLinks.map(l => l.targetNoteId))); - if (newNoteIds.length === noteIds.length) { + if (newNoteIds.size === noteIds.size) { // no new note discovered, no need to search any further break; }