relation map WIP

This commit is contained in:
azivner 2018-10-25 12:06:36 +02:00
parent b17f442d1f
commit 4a5a63d7b4
5 changed files with 88 additions and 17 deletions

4
.idea/encodings.xml generated Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with NO BOM" />
</project>

View File

@ -30,24 +30,45 @@ async function show() {
} }
} }
jsPlumb.ready(function () { jsPlumb.ready(async function () {
const uniDirectionalConnection = [
[ "Arrow", {
location: 1,
id: "arrow",
length: 14,
foldback: 0.8
} ],
[ "Label", { label: "", id: "label", cssClass: "aLabel" }]
];
const biDirectionalConnection = [
[ "Arrow", {
location: 1,
id: "arrow",
length: 14,
foldback: 0.8
} ],
[ "Label", { label: "", id: "label", cssClass: "aLabel" }],
[ "Arrow", {
location: 0,
id: "arrow2",
length: 14,
direction: -1,
foldback: 0.8
} ]
];
instance = jsPlumb.getInstance({ instance = jsPlumb.getInstance({
Endpoint: ["Dot", {radius: 2}], Endpoint: ["Dot", {radius: 2}],
Connector: "StateMachine", Connector: "StateMachine",
HoverPaintStyle: {stroke: "#1e8151", strokeWidth: 2 }, HoverPaintStyle: {stroke: "#1e8151", strokeWidth: 2 },
ConnectionOverlays: [
[ "Arrow", {
location: 1,
id: "arrow",
length: 14,
foldback: 0.8
} ],
[ "Label", { label: "", id: "label", cssClass: "aLabel" }]
],
Container: "relation-map-canvas" Container: "relation-map-canvas"
}); });
instance.registerConnectionType("basic", { anchor:"Continuous", connector:"StateMachine" });
instance.registerConnectionType("uniDirectional", { anchor:"Continuous", connector:"StateMachine", overlays: uniDirectionalConnection });
instance.registerConnectionType("biDirectional", { anchor:"Continuous", connector:"StateMachine", overlays: biDirectionalConnection });
// instance.bind("connection", function (info) { // instance.bind("connection", function (info) {
// const connection = info.connection; // const connection = info.connection;
@ -153,6 +174,9 @@ async function show() {
$relationMapCanvas.contextmenuRelation("open", e, { connection: c }); $relationMapCanvas.contextmenuRelation("open", e, { connection: c });
}); });
const noteIds = mapData.notes.map(note => note.noteId);
const data = await server.post("notes/relation-map", { noteIds });
instance.batch(function () { instance.batch(function () {
const maxY = mapData.notes.filter(note => !!note.y).map(note => note.y).reduce((a, b) => Math.max(a, b), 0); const maxY = mapData.notes.filter(note => !!note.y).map(note => note.y).reduce((a, b) => Math.max(a, b), 0);
let curX = 100; let curX = 100;
@ -179,12 +203,18 @@ async function show() {
} }
for (const relation of mapData.relations) { for (const relation of mapData.relations) {
const connection = instance.connect({ id: relation.id, source: relation.source, target: relation.target, type: "basic" }); if (relation.name === 'isChildOf') {
continue;
}
const connection = instance.connect({ id: relation.id, source: relation.source, target: relation.target, type: "uniDirectional" });
relation.connectionId = connection.id; relation.connectionId = connection.id;
connection.getOverlay("label").setLabel(relation.name); connection.getOverlay("label").setLabel(relation.name);
connection.canvas.setAttribute("data-connection-id", connection.id); connection.canvas.setAttribute("data-connection-id", connection.id);
//instance.recalculateOffsets(connection);
} }
initDone = true; initDone = true;
@ -200,8 +230,6 @@ async function show() {
} }
function saveData() { function saveData() {
const currentNote = noteDetailService.getCurrentNote();
noteDetailService.saveNote(); noteDetailService.saveNote();
} }
@ -296,9 +324,13 @@ $addChildNotesButton.click(async () => {
let curY = maxY + 200; let curY = maxY + 200;
for (const child of children) { for (const child of children) {
if (mapData.notes.some(note => note.id === child.noteId)) {
// note already exists
continue;
}
const note = { const note = {
id: child.noteId, id: child.noteId,
title: child.title,
width: "auto", width: "auto",
height: "auto" height: "auto"
}; };

View File

@ -1,7 +1,11 @@
#relation-map-canvas { #note-detail-relation-map {
height: 500px; height: 500px;
} }
#relation-map-canvas {
position: absolute; /* needs to be absolute otherwise connections will be misplaced */
}
.note-box { .note-box {
padding: 16px; padding: 16px;
position: absolute !important; position: absolute !important;

View File

@ -92,6 +92,35 @@ async function setNoteTypeMime(req) {
await note.save(); await note.save();
} }
async function getRelationMap(req) {
const noteIds = req.body.noteIds;
const resp = {
noteTitles: {},
relations: []
};
if (noteIds.length === 0) {
return resp;
}
const questionMarks = noteIds.map(noteId => '?').join(',');
(await repository.getEntities(`SELECT * FROM notes WHERE noteId IN (${questionMarks})`, noteIds))
.forEach(note => resp.noteTitles[note.noteId] = note.title);
// FIXME: this actually doesn't take into account inherited relations! But maybe it is better this way?
resp.relations = (await repository.getEntities(`SELECT * FROM attributes WHERE type = 'relation' AND noteId IN (${questionMarks})`, noteIds))
.map(relation => { return {
sourceNoteId: relation.noteId,
targetNoteId: relation.value,
name: relation.name
}; })
// both sourceNoteId and targetNoteId has to be in the included notes, but source was already checked in the SQL query
.filter(relation => noteIds.includes(relation.targetNoteId));
return resp;
}
module.exports = { module.exports = {
getNote, getNote,
updateNote, updateNote,
@ -99,5 +128,6 @@ module.exports = {
sortNotes, sortNotes,
protectSubtree, protectSubtree,
setNoteTypeMime, setNoteTypeMime,
getChildren getChildren,
getRelationMap
}; };

View File

@ -121,6 +121,7 @@ function register(app) {
apiRoute(PUT, '/api/notes/:noteId/protect/:isProtected', notesApiRoute.protectSubtree); apiRoute(PUT, '/api/notes/:noteId/protect/:isProtected', notesApiRoute.protectSubtree);
apiRoute(PUT, /\/api\/notes\/(.*)\/type\/(.*)\/mime\/(.*)/, notesApiRoute.setNoteTypeMime); apiRoute(PUT, /\/api\/notes\/(.*)\/type\/(.*)\/mime\/(.*)/, notesApiRoute.setNoteTypeMime);
apiRoute(GET, '/api/notes/:noteId/revisions', noteRevisionsApiRoute.getNoteRevisions); apiRoute(GET, '/api/notes/:noteId/revisions', noteRevisionsApiRoute.getNoteRevisions);
apiRoute(POST, '/api/notes/relation-map', notesApiRoute.getRelationMap);
apiRoute(PUT, '/api/notes/:noteId/clone-to/:parentNoteId', cloningApiRoute.cloneNoteToParent); apiRoute(PUT, '/api/notes/:noteId/clone-to/:parentNoteId', cloningApiRoute.cloneNoteToParent);
apiRoute(PUT, '/api/notes/:noteId/clone-after/:afterBranchId', cloningApiRoute.cloneNoteAfter); apiRoute(PUT, '/api/notes/:noteId/clone-after/:afterBranchId', cloningApiRoute.cloneNoteAfter);