1
0
Fork 0

gv - editable & createable nodes, edges [ci skip]

This commit is contained in:
hkernbach 2016-07-14 15:57:18 +02:00
parent f79ecfc162
commit b22c34753e
4 changed files with 325 additions and 43 deletions

View File

@ -291,7 +291,17 @@ authRouter.get('/graph/:name', function (req, res) {
// var traversal = require("@arangodb/graph/traversal");
var graph = gm._graph(name);
var vertexName = graph._vertexCollections()[0].name();
var vertices = graph._vertexCollections();
var vertexName = vertices[Math.floor(Math.random() * vertices.length)].name();
var vertexCollections = [];
_.each(graph._vertexCollections(), function (vertex) {
vertexCollections.push({
name: vertex.name(),
id: vertex._id
});
});
var startVertex;
var config;
@ -309,7 +319,6 @@ authRouter.get('/graph/:name', function (req, res) {
res.throw('bad request', e.message, {cause: e});
}
console.log(startVertex);
if (!startVertex) {
startVertex = db[vertexName].any();
}
@ -363,8 +372,7 @@ authRouter.get('/graph/:name', function (req, res) {
_.each(obj.vertices, function (node) {
if (config.nodeLabel) {
nodeLabel = node[config.nodeLabel];
}
if (!nodeLabel) {
} else {
nodeLabel = node._id;
}
@ -393,7 +401,11 @@ authRouter.get('/graph/:name', function (req, res) {
res.json({
nodes: nodesArr,
edges: edgesArr
edges: edgesArr,
settings: {
vertexCollections: vertexCollections,
startVertex: startVertex
}
});
})
.summary('Return vertices and edges of a graph.')

View File

@ -60,7 +60,7 @@ window.ArangoDocument = Backbone.Collection.extend({
}
});
},
createTypeDocument: function (collectionID, key, callback) {
createTypeDocument: function (collectionID, key, callback, returnNew) {
var newDocument;
if (key) {
@ -71,15 +71,25 @@ window.ArangoDocument = Backbone.Collection.extend({
newDocument = JSON.stringify({});
}
var url = arangoHelper.databaseUrl('/_api/document?collection=' + encodeURIComponent(collectionID));
if (returnNew) {
url = url + '?returnNew=true';
}
$.ajax({
cache: false,
type: 'POST',
url: arangoHelper.databaseUrl('/_api/document?collection=' + encodeURIComponent(collectionID)),
url: url,
data: newDocument,
contentType: 'application/json',
processData: false,
success: function (data) {
callback(false, data._id);
if (returnNew) {
callback(false, data);
} else {
callback(false, data._id);
}
},
error: function (data) {
callback(true, data._id);

View File

@ -676,6 +676,8 @@
}
this.graphViewer2 = new window.GraphViewer2({
name: name,
documentStore: this.arangoDocumentStore,
collection: new window.GraphCollection(),
userConfig: this.userConfig
});
this.graphViewer2.render();

View File

@ -1,6 +1,6 @@
/* jshint browser: true */
/* jshint unused: false */
/* global arangoHelper, _, slicePath, icon, wheelnav, document, sigma, Backbone, templateEngine, $, window*/
/* global arangoHelper, _, slicePath, icon, Joi, wheelnav, document, sigma, Backbone, templateEngine, $, window*/
(function () {
'use strict';
@ -16,18 +16,38 @@
template: templateEngine.createTemplate('graphViewer2.ejs'),
initialize: function (options) {
var self = this;
this.name = options.name;
this.userConfig = options.userConfig;
this.documentStore = options.documentStore;
this.initSigma();
this.collection.fetch({
cache: false,
success: function (data) {
self.model = self.collection.findWhere({_key: options.name}).toJSON();
}
});
},
events: {
'click #downloadPNG': 'downloadSVG'
'click #downloadPNG': 'downloadSVG',
'click #reloadGraph': 'reloadGraph'
},
cursorX: 0,
cursorY: 0,
model: null,
viewStates: {
captureMode: false
},
graphConfig: null,
graphSettings: null,
initSigma: function () {
// init sigma
try {
@ -103,12 +123,22 @@
self.renderGraph(data);
},
error: function (e) {
console.log(e);
try {
arangoHelper.arangoError('Graph', e.responseJSON.exception);
} catch (ignore) {}
$('#calculatingGraph').html('Failed to fetch graph information.');
var found = e.responseJSON.exception.search('1205');
if (found !== -1) {
var string = 'Starting point: <span style="font-weight: 400">' + self.graphConfig.nodeStart + '</span> is invalid';
$('#calculatingGraph').html(
'<div style="font-weight: 300; font-size: 10.5pt"><span style="font-weight: 400">Stopped. </span></br></br>' +
string +
'. Please <a style="color: #3498db" href="' + window.location.href +
'/settings">choose a different start node.</a></div>'
);
} else {
$('#calculatingGraph').html('Failed to fetch graph information.');
}
} catch (ignore) {}
}
});
}.bind(this);
@ -176,11 +206,204 @@
this.cursorY = e.y;
},
addNode: function () {
var self = this;
var collectionId = $('.modal-body #new-node-collection-attr').val();
var key = $('.modal-body #new-node-key-attr').last().val();
var callback = function (error, id) {
if (error) {
arangoHelper.arangoError('Error', 'Could not create node');
} else {
console.log(id);
self.currentGraph.graph.addNode({
id: id,
label: self.graphConfig.nodeLabel,
size: self.graphConfig.nodeSize || Math.random(),
color: self.graphConfig.nodeColor || '#2ecc71',
x: self.cursorX,
y: self.cursorY
});
window.modalView.hide();
// rerender graph
self.currentGraph.refresh();
}
};
if (key !== '' || key !== undefined) {
this.documentStore.createTypeDocument(collectionId, key, callback);
} else {
this.documentStore.createTypeDocument(collectionId, null, callback);
}
},
addNodeModal: function () {
if (this.graphSettings.vertexCollections !== 0) {
var buttons = []; var tableContent = []; var collections = [];
_.each(this.graphSettings.vertexCollections, function (val) {
collections.push({
label: val.name,
value: val.id
});
});
tableContent.push(
window.modalView.createTextEntry(
'new-node-key-attr',
'_key',
undefined,
'The nodes unique key(optional attribute, leave empty for autogenerated key',
'is optional: leave empty for autogenerated key',
false,
[
{
rule: Joi.string().allow('').optional(),
msg: ''
}
]
)
);
tableContent.push(
window.modalView.createSelectEntry(
'new-node-collection-attr',
'Collection',
undefined,
'Please select the destination for the new node.',
collections
)
);
buttons.push(
window.modalView.createSuccessButton('Create', this.addNode.bind(this))
);
window.modalView.show(
'modalTable.ejs',
'Create node',
buttons,
tableContent
);
} else {
arangoHelper.arangoError('Graph', 'No valid vertex collections found.');
}
},
addEdge: function () {
var self = this;
var from = self.contextState._from;
var to = self.contextState._to;
var collectionName;
if ($('.modal-body #new-edge-collection-attr').val() === '') {
collectionName = $('.modal-body #new-edge-collection-attr').text();
} else {
collectionName = $('.modal-body #new-edge-collection-attr').val();
}
var key = $('.modal-body #new-edge-key-attr').last().val();
var callback = function (error, data) {
if (!error) {
// success
self.currentGraph.graph.addEdge({
source: from,
target: to,
id: data._id,
color: self.graphConfig.edgeColor
});
// rerender graph
self.currentGraph.refresh();
} else {
console.log('could not create edge');
}
// then clear states
self.clearOldContextMenu(true);
window.modalView.hide();
};
if (key !== '' || key !== undefined) {
this.documentStore.createTypeEdge(collectionName, from, to, key, callback);
} else {
this.documentStore.createTypeEdge(collectionName, from, to, null, callback);
}
},
addEdgeModal: function (edgeDefinitions) {
if (edgeDefinitions !== 0) {
var buttons = []; var tableContent = [];
tableContent.push(
window.modalView.createTextEntry(
'new-edge-key-attr',
'_key',
undefined,
'The edges unique key(optional attribute, leave empty for autogenerated key',
'is optional: leave empty for autogenerated key',
false,
[
{
rule: Joi.string().allow('').optional(),
msg: ''
}
]
)
);
if (edgeDefinitions.length > 1) {
var collections = [];
_.each(edgeDefinitions, function (val) {
collections.push({
label: val,
value: val
});
});
tableContent.push(
window.modalView.createSelectEntry(
'new-edge-collection-attr',
'Edge collection',
undefined,
'Please select the destination for the new edge.',
collections
)
);
} else {
tableContent.push(
window.modalView.createReadOnlyEntry(
'new-edge-collection-attr',
'Edge collection',
edgeDefinitions[0],
'The edges collection to be used.'
)
);
}
buttons.push(
window.modalView.createSuccessButton('Create', this.addEdge.bind(this))
);
window.modalView.show(
'modalTable.ejs',
'Create edge',
buttons,
tableContent
);
} else {
arangoHelper.arangoError('Graph', 'No valid edge definitions found.');
}
},
// right click background context menu
createContextMenu: function (e) {
var self = this;
var x = self.cursorX - 50;
var y = self.cursorY - 50;
console.log(e);
this.clearOldContextMenu();
var generateMenu = function (e) {
@ -196,21 +419,28 @@
wheel.multiSelect = true;
wheel.clickModeRotate = false;
wheel.slicePathFunction = slicePath().DonutSlice;
wheel.createWheel([icon.plus, icon.trash]);
if (self.viewStates.captureMode) {
wheel.createWheel([icon.plus, icon.trash]);
} else {
wheel.createWheel([icon.plus, '']);
}
wheel.navItems[0].selected = false;
wheel.navItems[0].hovered = false;
// add menu events
// function 0: edit
// function 0: add node
wheel.navItems[0].navigateFunction = function (e) {
self.clearOldContextMenu();
self.addNodeModal();
};
// function 1: delete
wheel.navItems[1].navigateFunction = function (e) {
self.clearOldContextMenu();
};
if (self.viewStates.captureMode) {
// function 1: delete all selected nodes
wheel.navItems[1].navigateFunction = function (e) {
self.clearOldContextMenu();
};
}
// deselect active default entry
wheel.navItems[0].selected = false;
@ -226,16 +456,19 @@
generateMenu(e);
},
// right click node context menu
createNodeContextMenu: function (nodeId, e) {
var self = this;
var x; var y;
// var x = e.data.node['renderer1:x'];
// var y = e.data.node['renderer1:y'];
// better to use x,y from top, but sometimes values are not correct ...
console.log(e);
var x = e.data.captor.clientX - 52;
var y = e.data.captor.clientY - 52;
console.log(e.data);
_.each(e.data.node, function (val, key) {
if (key.substr(0, 8) === 'renderer' && key.charAt(key.length - 1) === 'x') {
x = val;
}
if (key.substr(0, 8) === 'renderer' && key.charAt(key.length - 1) === 'y') {
y = val;
}
});
this.clearOldContextMenu();
@ -294,8 +527,8 @@
wheel.navItems[0].hovered = false;
};
$('#nodeContextMenu').css('left', x);
$('#nodeContextMenu').css('top', y);
$('#nodeContextMenu').css('left', x + 115);
$('#nodeContextMenu').css('top', y + 72);
$('#nodeContextMenu').width(100);
$('#nodeContextMenu').height(100);
@ -348,13 +581,45 @@
arangoHelper.openDocEditor(id, 'doc', callback);
},
reloadGraph: function () {
Backbone.history.loadUrl(Backbone.history.fragment);
},
getEdgeDefinitionCollections: function (fromCollection, toCollection) {
var array = [];
_.each(this.model.edgeDefinitions, function (edgeDefinition) {
_.each(edgeDefinition.from, function (from) {
if (from === fromCollection) {
_.each(edgeDefinition.to, function (to) {
if (to === toCollection) {
array.push(edgeDefinition.collection);
}
});
}
});
});
return array;
},
renderGraph: function (graph) {
var self = this;
if (graph.edges.left === 0) {
this.graphSettings = graph.settings;
if (graph.edges.length === 0) {
var string = 'No edges found for starting point: <span style="font-weight: 400">' + self.graphSettings.startVertex._id + '</span>';
arangoHelper.arangoError('Graph', string);
$('#calculatingGraph').html(
'<div style="font-weight: 300; font-size: 10.5pt"><span style="font-weight: 400">Stopped. </span></br></br>' +
string +
'. Please <a style="color: #3498db" href="' + window.location.href +
'/settings">choose a different start node </a>or try to reload the graph. ' +
'<i id="reloadGraph" class="fa fa-refresh" style="cursor: pointer"></i></div>'
);
return;
}
this.Sigma = sigma;
// defaults
@ -466,19 +731,12 @@
if (self.contextState.createEdge === true) {
// create the edge
self.contextState._to = e.data.node.id;
var fromCollection = self.contextState._from.split('/')[0];
var toCollection = self.contextState._to.split('/')[0];
self.currentGraph.graph.addEdge({
source: self.contextState._from,
target: self.contextState._to,
id: Math.random(),
color: self.graphConfig.edgeColor
});
// rerender graph
self.currentGraph.refresh();
// then clear states
self.clearOldContextMenu(true);
// validate edgeDefinitions
var foundEdgeDefinitions = self.getEdgeDefinitionCollections(fromCollection, toCollection);
self.addEdgeModal(foundEdgeDefinitions, self.contextState._from, self.contextState._to);
}
});