mirror of https://gitee.com/bigwinds/arangodb
gv - editable & createable nodes, edges [ci skip]
This commit is contained in:
parent
f79ecfc162
commit
b22c34753e
|
@ -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.')
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -676,6 +676,8 @@
|
|||
}
|
||||
this.graphViewer2 = new window.GraphViewer2({
|
||||
name: name,
|
||||
documentStore: this.arangoDocumentStore,
|
||||
collection: new window.GraphCollection(),
|
||||
userConfig: this.userConfig
|
||||
});
|
||||
this.graphViewer2.render();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue