2018-03-21 17:24:52 +01:00
|
|
|
/*=============
|
|
|
|
* GLOBAL VARS
|
|
|
|
* ============*/
|
|
|
|
var eventGraph;
|
|
|
|
var dataHandler;
|
|
|
|
var mispInteraction;
|
2018-03-19 09:44:25 +01:00
|
|
|
var nodes = new vis.DataSet();
|
|
|
|
var edges = new vis.DataSet();
|
2018-03-21 17:24:52 +01:00
|
|
|
|
2018-04-09 13:39:45 +02:00
|
|
|
var typeaheadDataSearch;
|
2018-03-21 17:24:52 +01:00
|
|
|
var scope_id = $('#eventgraph_network').data('event-id');
|
|
|
|
var container = document.getElementById('eventgraph_network');
|
|
|
|
var user_manipulation = $('#eventgraph_network').data('user-manipulation');
|
2018-04-09 11:12:26 +02:00
|
|
|
var root_id_attr = "rootNode:attribute";
|
|
|
|
var root_id_object = "rootNode:object";
|
|
|
|
var root_id_tag = "rootNode:tag";
|
|
|
|
var root_id_keyType = "rootNode:keyType";
|
2018-03-27 10:52:50 +02:00
|
|
|
var mapping_root_id_to_type = {};
|
|
|
|
mapping_root_id_to_type[root_id_attr] = 'attribute';
|
|
|
|
mapping_root_id_to_type[root_id_object] = 'object';
|
2018-04-06 16:44:40 +02:00
|
|
|
mapping_root_id_to_type[root_id_tag] = 'tag';
|
2018-04-09 11:12:26 +02:00
|
|
|
mapping_root_id_to_type[root_id_keyType] = 'keyType';
|
2018-03-26 12:18:56 +02:00
|
|
|
var root_node_x_pos = 800;
|
|
|
|
var cluster_expand_threshold = 100;
|
2018-03-19 09:44:25 +01:00
|
|
|
|
2018-03-21 17:24:52 +01:00
|
|
|
/*=========
|
|
|
|
* CLASSES
|
|
|
|
* ========*/
|
|
|
|
// network class (handle the event graph manipulation and events)
|
|
|
|
class EventGraph {
|
|
|
|
constructor(network_options, nodes, edges) {
|
2018-03-21 17:55:14 +01:00
|
|
|
// FIXME: Do the mapping between meta-catory and fa-icons.
|
|
|
|
// Should be replaced later on.
|
2018-03-21 17:24:52 +01:00
|
|
|
this.mapping_meta_fa = new Map();
|
|
|
|
this.mapping_meta_fa.set('file', {"meta-category": "file","fa_text": "file","fa-hex": "f15b"});
|
|
|
|
this.mapping_meta_fa.set('financial', {"meta-category": "financial","fa_text": "money-bil-alt","fa-hex": "f3d1"});
|
2018-03-26 12:18:56 +02:00
|
|
|
this.mapping_meta_fa.set('network', {"meta-category": "network","fa_text": "server","fa-hex": "f233"});
|
2018-04-06 09:37:41 +02:00
|
|
|
this.mapping_meta_fa.set('misc', {"meta-category": "misc","fa_text": "cube","fa-hex": "f1b2"}); // Also considered as default
|
2018-03-21 17:24:52 +01:00
|
|
|
// FIXME
|
2018-03-28 15:41:57 +02:00
|
|
|
this.network_options = network_options;
|
2018-04-06 16:44:40 +02:00
|
|
|
this.scope_name;
|
2018-04-09 13:39:45 +02:00
|
|
|
this.scope_keyType;
|
2018-04-05 12:31:26 +02:00
|
|
|
this.globalCounter = 0;
|
2018-03-26 12:18:56 +02:00
|
|
|
this.first_draw = true;
|
2018-04-16 11:29:36 +02:00
|
|
|
this.can_be_fitted_again = true;
|
2018-04-05 12:31:26 +02:00
|
|
|
this.root_node_shown = false;
|
|
|
|
this.is_filtered = false;
|
2018-04-04 11:38:36 +02:00
|
|
|
this.menu_scope = this.init_scope_menu();
|
2018-03-29 18:05:19 +02:00
|
|
|
this.menu_physic = this.init_physic_menu();
|
|
|
|
this.menu_display = this.init_display_menu();
|
2018-04-04 11:38:36 +02:00
|
|
|
this.menu_filter = this.init_filter_menu();
|
2018-04-09 15:12:27 +02:00
|
|
|
this.menu_canvas = this.init_canvas_menu();
|
2018-04-05 12:31:26 +02:00
|
|
|
this.new_edges_for_unreferenced_nodes = [];
|
2018-03-26 16:18:36 +02:00
|
|
|
this.layout = 'default';
|
2018-03-30 11:21:02 +02:00
|
|
|
this.solver = 'barnesHut';
|
2018-03-27 10:52:50 +02:00
|
|
|
this.backup_connection_edges = {};
|
2018-03-21 17:24:52 +01:00
|
|
|
this.nodes = nodes;
|
|
|
|
this.edges = edges;
|
|
|
|
var data = { // empty
|
|
|
|
nodes: this.nodes,
|
|
|
|
edges: this.edges
|
|
|
|
};
|
2018-03-29 18:05:19 +02:00
|
|
|
this.object_templates = {};
|
|
|
|
|
2018-03-26 12:18:56 +02:00
|
|
|
this.cluster_index = 0; // use to get uniq cluster ID
|
|
|
|
this.clusters = [];
|
2018-03-19 09:44:25 +01:00
|
|
|
|
2018-03-26 16:18:36 +02:00
|
|
|
this.network = new vis.Network(container, data, this.network_options);
|
2018-03-26 12:18:56 +02:00
|
|
|
this.add_unreferenced_root_node();
|
|
|
|
|
2018-04-10 17:43:37 +02:00
|
|
|
this.bind_listener();
|
|
|
|
}
|
|
|
|
|
|
|
|
bind_listener() {
|
2018-03-21 17:24:52 +01:00
|
|
|
var that = this;
|
|
|
|
this.network.on("selectNode", function (params) {
|
|
|
|
that.network.moveTo({
|
|
|
|
position: {
|
|
|
|
x: params.pointer.canvas.x,
|
|
|
|
y: params.pointer.canvas.y
|
|
|
|
},
|
|
|
|
animation: true,
|
|
|
|
});
|
|
|
|
});
|
2018-03-22 16:53:53 +01:00
|
|
|
|
2018-04-10 17:43:37 +02:00
|
|
|
this.network.on("dragStart", function (params) {
|
|
|
|
eventGraph.physics_state(false);
|
|
|
|
});
|
|
|
|
this.network.on("dragEnd", function (params) {
|
2018-04-16 13:29:39 +02:00
|
|
|
eventGraph.physics_state($('#checkbox_physics_enable').prop("checked"));
|
2018-04-10 17:43:37 +02:00
|
|
|
});
|
2018-03-21 17:24:52 +01:00
|
|
|
}
|
2018-03-19 09:44:25 +01:00
|
|
|
|
2018-03-21 17:24:52 +01:00
|
|
|
// Util
|
|
|
|
get_node_color(uuid) {
|
|
|
|
return this.nodes.get(uuid).icon.color;
|
|
|
|
}
|
2018-04-06 09:37:41 +02:00
|
|
|
get_FA_icon(metaCateg) {
|
|
|
|
var dict = this.mapping_meta_fa.get(metaCateg);
|
|
|
|
dict = dict === undefined ? this.mapping_meta_fa.get('misc') : dict; // if unknown meta-categ, take default
|
|
|
|
return String.fromCharCode(parseInt(dict['fa-hex'], 16))
|
|
|
|
}
|
2018-04-05 12:31:26 +02:00
|
|
|
getUniqId() {
|
|
|
|
this.globalCounter++;
|
|
|
|
return this.globalCounter-1;
|
|
|
|
}
|
2018-04-06 16:44:40 +02:00
|
|
|
update_scope(value) {
|
2018-04-09 13:39:45 +02:00
|
|
|
if (value === undefined) {
|
|
|
|
value = $("#select_graph_scope").val();
|
|
|
|
} else {
|
|
|
|
$("#select_graph_scope").val(value);
|
|
|
|
}
|
2018-04-09 14:07:53 +02:00
|
|
|
|
2018-04-16 11:17:19 +02:00
|
|
|
if (value == "Rotation key") {
|
2018-04-09 14:07:53 +02:00
|
|
|
$("#network-scope-badge").text(value + ": " + eventGraph.scope_keyType);
|
|
|
|
} else {
|
|
|
|
$("#network-scope-badge").text(value);
|
|
|
|
}
|
2018-04-06 16:44:40 +02:00
|
|
|
this.scope_name = value;
|
|
|
|
dataHandler.scope_name = value;
|
2018-04-06 10:34:47 +02:00
|
|
|
}
|
2018-04-16 11:17:19 +02:00
|
|
|
|
2018-04-04 11:38:36 +02:00
|
|
|
init_scope_menu() {
|
|
|
|
var menu_scope = new ContextualMenu({
|
|
|
|
trigger_container: document.getElementById("network-scope"),
|
|
|
|
bootstrap_popover: true,
|
|
|
|
});
|
|
|
|
menu_scope.add_select({
|
|
|
|
id: "select_graph_scope",
|
|
|
|
label: "Scope",
|
|
|
|
tooltip: "The scope represented by the network",
|
|
|
|
event: function(value) {
|
2018-04-16 11:17:19 +02:00
|
|
|
if (value == "Rotation key" && $('#input_graph_scope_jsonkey').val() == "") { // no key selected for Rotation key scope
|
2018-04-09 13:39:45 +02:00
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
eventGraph.update_scope(value);
|
|
|
|
dataHandler.fetch_data_and_update();
|
|
|
|
}
|
2018-04-04 11:38:36 +02:00
|
|
|
},
|
2018-04-16 14:02:43 +02:00
|
|
|
options: ["Reference", "Tag", "Rotation key"],
|
2018-04-04 11:38:36 +02:00
|
|
|
default: "Reference"
|
|
|
|
});
|
2018-04-16 11:17:19 +02:00
|
|
|
menu_scope.add_select({
|
2018-04-09 13:39:45 +02:00
|
|
|
id: "input_graph_scope_jsonkey",
|
2018-04-16 11:17:19 +02:00
|
|
|
label: "Rotation key",
|
|
|
|
tooltip: "The key around which the network will be constructed",
|
|
|
|
event: function(value) {
|
|
|
|
if (value == "Rotation key" && $('#input_graph_scope_jsonkey').val() == "") { // no key selected for Rotation key scope
|
|
|
|
return;
|
|
|
|
} else {
|
2018-04-09 13:39:45 +02:00
|
|
|
eventGraph.scope_keyType = value;
|
2018-04-16 11:17:19 +02:00
|
|
|
eventGraph.update_scope("Rotation key");
|
2018-04-09 13:39:45 +02:00
|
|
|
dataHandler.fetch_data_and_update();
|
2018-04-16 11:17:19 +02:00
|
|
|
}
|
2018-04-09 14:07:53 +02:00
|
|
|
},
|
2018-04-16 11:17:19 +02:00
|
|
|
options: dataHandler.available_rotation_key ? dataHandler.available_rotation_key : [],
|
|
|
|
default: ""
|
2018-04-09 13:39:45 +02:00
|
|
|
});
|
2018-04-04 11:38:36 +02:00
|
|
|
return menu_scope;
|
|
|
|
}
|
|
|
|
|
2018-03-29 18:05:19 +02:00
|
|
|
init_physic_menu() {
|
2018-04-03 12:03:59 +02:00
|
|
|
var menu_physic = new ContextualMenu({
|
2018-04-04 11:38:36 +02:00
|
|
|
trigger_container: document.getElementById("network-physic"),
|
2018-04-03 12:03:59 +02:00
|
|
|
bootstrap_popover: true
|
|
|
|
});
|
2018-03-30 11:21:02 +02:00
|
|
|
menu_physic.add_select({
|
|
|
|
id: "select_physic_solver",
|
|
|
|
label: "Solver",
|
|
|
|
tooltip: "Physics solver to use",
|
|
|
|
event: function(value) {
|
|
|
|
eventGraph.physics_change_solver(value);
|
|
|
|
},
|
|
|
|
options: ["barnesHut", "repulsion"],
|
|
|
|
default: "barnesHut"
|
|
|
|
});
|
2018-03-29 18:05:19 +02:00
|
|
|
menu_physic.add_slider({
|
2018-03-28 15:41:57 +02:00
|
|
|
id: 'slider_physic_node_repulsion',
|
|
|
|
label: "Node repulsion",
|
|
|
|
min: 0,
|
|
|
|
max: 1000,
|
|
|
|
value: this.network_options.physics.barnesHut.springLength,
|
|
|
|
step: 10,
|
|
|
|
event: function(value) {
|
|
|
|
eventGraph.physics_change_repulsion(parseInt(value));
|
2018-03-29 18:05:19 +02:00
|
|
|
},
|
|
|
|
tooltip: "Correspond to spring length for barnesHut and node spacing for hierachical"
|
2018-03-28 15:41:57 +02:00
|
|
|
});
|
2018-03-29 18:05:19 +02:00
|
|
|
menu_physic.add_checkbox({
|
2018-03-28 15:41:57 +02:00
|
|
|
label: "Enable physics",
|
2018-04-16 13:29:39 +02:00
|
|
|
id: "checkbox_physics_enable",
|
2018-03-28 15:41:57 +02:00
|
|
|
event: function(checked) {
|
|
|
|
eventGraph.physics_state(checked);
|
|
|
|
},
|
|
|
|
checked: true
|
|
|
|
});
|
2018-03-29 18:05:19 +02:00
|
|
|
return menu_physic;
|
|
|
|
}
|
2018-04-06 16:44:40 +02:00
|
|
|
|
2018-03-29 18:05:19 +02:00
|
|
|
init_display_menu() {
|
2018-04-03 12:03:59 +02:00
|
|
|
var menu_display = new ContextualMenu({
|
|
|
|
trigger_container: document.getElementById("network-display"),
|
|
|
|
bootstrap_popover: true
|
|
|
|
});
|
2018-04-04 11:38:36 +02:00
|
|
|
menu_display.add_select({
|
|
|
|
id: "select_display_layout",
|
|
|
|
label: "Layout",
|
|
|
|
event: function(value) {
|
|
|
|
switch(value) {
|
|
|
|
case "default":
|
2018-04-06 16:44:40 +02:00
|
|
|
eventGraph.change_layout_type("default");
|
2018-04-04 11:38:36 +02:00
|
|
|
break;
|
|
|
|
case "hierarchical.directed":
|
2018-04-06 16:44:40 +02:00
|
|
|
eventGraph.change_layout_type("directed");
|
2018-04-04 11:38:36 +02:00
|
|
|
break;
|
|
|
|
case "hierarchical.hubsize":
|
2018-04-06 16:44:40 +02:00
|
|
|
eventGraph.change_layout_type("hubsize");
|
2018-04-04 11:38:36 +02:00
|
|
|
break;
|
2018-04-06 16:44:40 +02:00
|
|
|
default:
|
|
|
|
eventGraph.change_layout_type("default");
|
2018-04-04 11:38:36 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
options: [
|
2018-04-16 11:17:19 +02:00
|
|
|
{text: "Default layout", value: "default"},
|
|
|
|
{text: "Hierachical directed", value: "hierarchical.directed"},
|
2018-04-04 11:38:36 +02:00
|
|
|
{text: "Hierachical hubsize", value: "hierarchical.hubsize"}
|
|
|
|
],
|
|
|
|
default: "default"
|
|
|
|
});
|
2018-03-29 18:05:19 +02:00
|
|
|
menu_display.add_select({
|
2018-03-30 10:14:23 +02:00
|
|
|
id: "select_display_object_field",
|
2018-04-04 11:38:36 +02:00
|
|
|
label: "Object-relation in label",
|
2018-03-30 10:14:23 +02:00
|
|
|
event: function(value) {
|
2018-04-05 12:31:26 +02:00
|
|
|
dataHandler.selected_type_to_display = value;
|
2018-03-30 10:14:23 +02:00
|
|
|
dataHandler.fetch_data_and_update();
|
2018-03-29 18:05:19 +02:00
|
|
|
},
|
2018-04-04 15:12:16 +02:00
|
|
|
options: [],
|
2018-03-30 10:14:23 +02:00
|
|
|
title: "If no item is selected, display the first requiredOneOf of the object"
|
2018-03-29 18:05:19 +02:00
|
|
|
});
|
2018-03-30 10:48:27 +02:00
|
|
|
menu_display.add_button({
|
|
|
|
label: "Expand all nodes",
|
|
|
|
type: "danger",
|
|
|
|
event: function() {
|
|
|
|
var objectIds = eventGraph.nodes.getIds({
|
|
|
|
filter: function(item) { return item.group == 'object'; }
|
|
|
|
})
|
|
|
|
for(var nodeId of objectIds) {
|
|
|
|
eventGraph.expand_node(nodeId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
menu_display.add_button({
|
|
|
|
label: "Collapse all nodes",
|
|
|
|
type: "danger",
|
|
|
|
event: function() {
|
|
|
|
var objectIds = eventGraph.nodes.getIds({
|
|
|
|
filter: function(item) { return item.group == 'object'; }
|
|
|
|
});
|
|
|
|
for(var nodeId of objectIds) {
|
|
|
|
eventGraph.collapse_node(nodeId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2018-03-30 12:13:09 +02:00
|
|
|
menu_display.add_slider({
|
|
|
|
id: 'slider_display_max_char_num',
|
|
|
|
label: "Charater to show",
|
|
|
|
title: "Maximum number of charater to display in the label",
|
|
|
|
min: 8,
|
|
|
|
max: 1024,
|
|
|
|
value: max_displayed_char,
|
|
|
|
step: 8,
|
|
|
|
applyButton: true,
|
|
|
|
event: function(value) {
|
|
|
|
$("#slider_display_max_char_num").parent().find("span").text(value);
|
|
|
|
},
|
|
|
|
eventApply: function(value) {
|
|
|
|
dataHandler.fetch_data_and_update();
|
|
|
|
}
|
|
|
|
});
|
2018-03-29 18:05:19 +02:00
|
|
|
return menu_display;
|
2018-03-28 15:41:57 +02:00
|
|
|
}
|
2018-04-06 16:44:40 +02:00
|
|
|
|
2018-04-04 11:38:36 +02:00
|
|
|
init_filter_menu() {
|
|
|
|
var menu_filter = new ContextualMenu({
|
|
|
|
trigger_container: document.getElementById("network-filter"),
|
|
|
|
bootstrap_popover: true
|
|
|
|
});
|
|
|
|
menu_filter.add_action_table({
|
|
|
|
id: "table_attr_presence",
|
|
|
|
container: menu_filter.menu,
|
|
|
|
title: "Filter on Attribute presence",
|
|
|
|
header: ["Relation", "Attribute"],
|
|
|
|
control_items: [
|
|
|
|
{
|
|
|
|
DOMType: "select",
|
|
|
|
item_options: {
|
|
|
|
options: ["Contains", "Do not contain"]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
DOMType: "select",
|
|
|
|
item_options: {
|
|
|
|
id: "table_control_select_attr_presence",
|
2018-04-04 15:12:16 +02:00
|
|
|
options: []
|
2018-04-04 11:38:36 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
],
|
2018-04-05 16:21:40 +02:00
|
|
|
data: [],
|
2018-04-04 11:38:36 +02:00
|
|
|
});
|
|
|
|
menu_filter.create_divider(3);
|
|
|
|
menu_filter.add_action_table({
|
|
|
|
id: "table_attr_value",
|
|
|
|
container: menu_filter.menu,
|
|
|
|
title: "Filter on Attribute value",
|
|
|
|
header: ["Attribute", "Comparison", "Value"],
|
|
|
|
control_items: [
|
|
|
|
{
|
|
|
|
DOMType: "select",
|
|
|
|
item_options: {
|
|
|
|
id: "table_control_select_attr_value",
|
2018-04-04 15:12:16 +02:00
|
|
|
options: []
|
2018-04-04 11:38:36 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
DOMType: "select",
|
|
|
|
item_options: {
|
|
|
|
options: ["<", "<=", "==", ">=", ">"]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
DOMType: "input",
|
|
|
|
item_options: {}
|
|
|
|
}
|
|
|
|
],
|
2018-04-05 16:21:40 +02:00
|
|
|
data: [],
|
|
|
|
onAddition: function(data) {
|
|
|
|
eventGraph.menu_filter.items["table_attr_presence"].add_row(["Contains", data[0]]);
|
|
|
|
}
|
2018-04-04 11:38:36 +02:00
|
|
|
});
|
2018-04-05 12:31:26 +02:00
|
|
|
menu_filter.items["table_attr_value"].table.style.minWidth = "550px";
|
2018-04-04 11:38:36 +02:00
|
|
|
menu_filter.add_button({
|
|
|
|
label: "Filter",
|
|
|
|
type: "primary",
|
|
|
|
event: function() {
|
2018-04-05 12:31:26 +02:00
|
|
|
dataHandler.fetch_data_and_update();
|
2018-04-04 11:38:36 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
return menu_filter;
|
|
|
|
}
|
2018-04-05 12:31:26 +02:00
|
|
|
|
2018-04-09 15:12:27 +02:00
|
|
|
init_canvas_menu() {
|
|
|
|
var menu_canvas = new ContextualMenu({
|
|
|
|
trigger_container: document.getElementById("eventgraph_network"),
|
|
|
|
right_click: true
|
|
|
|
});
|
|
|
|
menu_canvas.add_button({
|
|
|
|
label: "View/Edit",
|
|
|
|
type: "primary",
|
|
|
|
event: function() {
|
2018-04-16 11:17:19 +02:00
|
|
|
var selected_id = eventGraph.network.getSelectedNodes()[0];
|
2018-04-09 15:12:27 +02:00
|
|
|
if (selected_id === undefined) { // A node is selected
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var data = { id: selected_id };
|
|
|
|
mispInteraction.edit_item(data);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
menu_canvas.add_button({
|
2018-04-09 15:13:45 +02:00
|
|
|
label: "Hide",
|
2018-04-09 15:12:27 +02:00
|
|
|
type: "info",
|
|
|
|
event: function() {
|
2018-04-16 11:17:19 +02:00
|
|
|
var selected_id = eventGraph.network.getSelectedNodes()[0];
|
2018-04-09 15:12:27 +02:00
|
|
|
if (selected_id === undefined) { // A node is selected
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
eventGraph.nodes.remove(selected_id);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
menu_canvas.add_button({
|
|
|
|
label: "Expand",
|
|
|
|
type: "primary",
|
|
|
|
event: function() {
|
2018-04-16 11:17:19 +02:00
|
|
|
var selected_id = eventGraph.network.getSelectedNodes()[0];
|
2018-04-09 15:12:27 +02:00
|
|
|
if (selected_id === undefined) { // A node is selected
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
eventGraph.expand_node(selected_id);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
menu_canvas.add_button({
|
|
|
|
label: "Collapse",
|
|
|
|
type: "primary",
|
|
|
|
event: function() {
|
2018-04-16 11:17:19 +02:00
|
|
|
var selected_id = eventGraph.network.getSelectedNodes()[0];
|
2018-04-09 15:12:27 +02:00
|
|
|
if (selected_id === undefined) { // A node is selected
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
eventGraph.collapse_node(selected_id);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-04-05 12:31:26 +02:00
|
|
|
get_filtering_rules() {
|
|
|
|
var rules_presence = eventGraph.menu_filter.items["table_attr_presence"].get_data();
|
|
|
|
var rules_value = eventGraph.menu_filter.items["table_attr_value"].get_data();
|
|
|
|
var rules = { presence: rules_presence, value: rules_value };
|
|
|
|
return rules;
|
|
|
|
}
|
2018-03-21 17:24:52 +01:00
|
|
|
// Graph interaction
|
2018-04-16 11:17:19 +02:00
|
|
|
|
|
|
|
// Clusterize the specified node with its connected childs
|
2018-03-27 10:52:50 +02:00
|
|
|
clusterize(rootID) {
|
2018-03-26 12:18:56 +02:00
|
|
|
var that = eventGraph;
|
2018-03-27 10:52:50 +02:00
|
|
|
var type = mapping_root_id_to_type[rootID];
|
2018-03-26 12:18:56 +02:00
|
|
|
var clusterOptionsByData = {
|
|
|
|
processProperties: global_processProperties,
|
|
|
|
clusterNodeProperties: {borderWidth: 3, shape: 'database', font: {size: 30}},
|
|
|
|
joinCondition: function(nodeOptions) {
|
2018-03-27 10:52:50 +02:00
|
|
|
return nodeOptions.unreferenced == type || nodeOptions.id == rootID;
|
2018-03-26 12:18:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
};
|
2018-03-27 10:52:50 +02:00
|
|
|
that.network.cluster(clusterOptionsByData);
|
|
|
|
}
|
|
|
|
|
|
|
|
init_clusterize() {
|
|
|
|
for(var key of Object.keys(mapping_root_id_to_type)) {
|
|
|
|
this.clusterize(key);
|
|
|
|
}
|
2018-03-26 12:18:56 +02:00
|
|
|
}
|
|
|
|
|
2018-04-06 16:44:40 +02:00
|
|
|
reset_graphs(hard) {
|
2018-03-21 17:24:52 +01:00
|
|
|
this.nodes.clear();
|
|
|
|
this.edges.clear();
|
2018-04-06 16:44:40 +02:00
|
|
|
if (hard) {
|
|
|
|
this.backup_connection_edges = {};
|
|
|
|
}
|
2018-03-21 17:24:52 +01:00
|
|
|
}
|
2018-04-16 11:17:19 +02:00
|
|
|
|
2018-03-21 17:24:52 +01:00
|
|
|
update_graph(data) {
|
2018-04-06 16:44:40 +02:00
|
|
|
setTimeout(function() { eventGraph.network_loading(true, loadingText_creating); });
|
2018-04-16 11:17:19 +02:00
|
|
|
|
2018-03-21 17:24:52 +01:00
|
|
|
// New nodes will be automatically added
|
|
|
|
// removed references will be deleted
|
|
|
|
var node_conf;
|
|
|
|
var newNodes = [];
|
|
|
|
var newNodeIDs = [];
|
|
|
|
for(var node of data.items) {
|
|
|
|
var group, label;
|
|
|
|
if ( node.node_type == 'object' ) {
|
2018-04-04 15:12:16 +02:00
|
|
|
var group = 'object';
|
|
|
|
var label = dataHandler.generate_label(node);
|
2018-03-30 11:50:22 +02:00
|
|
|
var striped_value = this.strip_text_value(label);
|
2018-04-16 11:17:19 +02:00
|
|
|
node_conf = {
|
2018-03-21 17:24:52 +01:00
|
|
|
id: node.id,
|
2018-04-04 15:12:16 +02:00
|
|
|
uuid: node.uuid,
|
|
|
|
Attribute: node.Attribute,
|
2018-03-21 17:24:52 +01:00
|
|
|
label: striped_value,
|
|
|
|
title: label,
|
|
|
|
group: group,
|
|
|
|
mass: 5,
|
|
|
|
icon: {
|
|
|
|
color: getRandomColor(),
|
|
|
|
face: 'FontAwesome',
|
2018-04-06 09:37:41 +02:00
|
|
|
code: this.get_FA_icon(node['meta-category']),
|
2018-03-21 17:24:52 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
dataHandler.mapping_value_to_nodeID.set(striped_value, node.id);
|
2018-04-06 16:44:40 +02:00
|
|
|
} else if (node.node_type == 'tag') {
|
|
|
|
var tag_color = node.tagContent.colour;
|
|
|
|
group = 'tag';
|
|
|
|
label = node.label;
|
2018-04-16 11:17:19 +02:00
|
|
|
node_conf = {
|
2018-04-06 16:44:40 +02:00
|
|
|
id: node.id,
|
|
|
|
uuid: node.uuid,
|
|
|
|
label: label,
|
|
|
|
title: label,
|
|
|
|
group: group,
|
|
|
|
mass: 20,
|
2018-04-16 11:17:19 +02:00
|
|
|
color: {
|
2018-04-06 16:44:40 +02:00
|
|
|
background: tag_color,
|
|
|
|
border: tag_color
|
|
|
|
},
|
|
|
|
font: {
|
|
|
|
color: getTextColour(tag_color),
|
|
|
|
bold: true,
|
|
|
|
size: 28
|
|
|
|
},
|
|
|
|
shapeProperties: {
|
|
|
|
borderRadius: 6
|
|
|
|
}
|
|
|
|
};
|
|
|
|
dataHandler.mapping_value_to_nodeID.set(striped_value, node.id);
|
2018-04-09 11:12:26 +02:00
|
|
|
} else if (node.node_type == 'keyType') {
|
|
|
|
group = 'keyType';
|
2018-04-09 13:39:45 +02:00
|
|
|
label = this.scope_keyType + ": " + node.label;
|
2018-04-09 11:12:26 +02:00
|
|
|
var striped_value = this.strip_text_value(label);
|
|
|
|
node_conf = {
|
|
|
|
id: node.id,
|
|
|
|
label: striped_value,
|
|
|
|
title: label,
|
|
|
|
group: group
|
|
|
|
};
|
|
|
|
dataHandler.mapping_value_to_nodeID.set(striped_value, node.id);
|
2018-03-21 17:24:52 +01:00
|
|
|
} else {
|
|
|
|
group = 'attribute';
|
2018-04-04 15:12:16 +02:00
|
|
|
label = node.type + ': ' + node.label;
|
2018-03-30 11:50:22 +02:00
|
|
|
var striped_value = this.strip_text_value(label);
|
2018-04-16 11:17:19 +02:00
|
|
|
node_conf = {
|
2018-03-21 17:24:52 +01:00
|
|
|
id: node.id,
|
2018-04-04 15:12:16 +02:00
|
|
|
uuid: node.uuid,
|
2018-03-21 17:24:52 +01:00
|
|
|
label: striped_value,
|
|
|
|
title: label,
|
|
|
|
group: group,
|
|
|
|
mass: 5,
|
|
|
|
};
|
|
|
|
dataHandler.mapping_value_to_nodeID.set(striped_value, node.id);
|
2018-03-19 09:44:25 +01:00
|
|
|
}
|
2018-04-16 11:17:19 +02:00
|
|
|
|
2018-03-21 17:24:52 +01:00
|
|
|
newNodes.push(node_conf);
|
|
|
|
newNodeIDs.push(node.id);
|
2018-03-19 09:44:25 +01:00
|
|
|
}
|
2018-03-21 17:24:52 +01:00
|
|
|
// check if nodes got deleted
|
|
|
|
var old_node_ids = this.nodes.getIds();
|
|
|
|
for (var old_id of old_node_ids) {
|
2018-03-26 12:18:56 +02:00
|
|
|
// Ignore root node
|
2018-04-09 11:12:26 +02:00
|
|
|
if (old_id == "rootNode:attribute" || old_id == "rootNode:object" || old_id == "rootNode:tag" || old_id == "rootNode:keyType") {
|
2018-03-26 12:18:56 +02:00
|
|
|
continue;
|
|
|
|
}
|
2018-03-21 17:24:52 +01:00
|
|
|
// This old node got removed
|
|
|
|
if (newNodeIDs.indexOf(old_id) == -1) {
|
|
|
|
this.nodes.remove(old_id);
|
2018-03-19 11:40:27 +01:00
|
|
|
}
|
2018-03-19 09:44:25 +01:00
|
|
|
}
|
2018-04-16 11:17:19 +02:00
|
|
|
|
2018-03-21 17:24:52 +01:00
|
|
|
this.nodes.update(newNodes);
|
2018-04-16 11:17:19 +02:00
|
|
|
|
2018-03-21 17:24:52 +01:00
|
|
|
// New relations will be automatically added
|
|
|
|
// removed references will be deleted
|
|
|
|
var newRelations = [];
|
|
|
|
var newRelationIDs = [];
|
|
|
|
for(var rel of data.relations) {
|
|
|
|
var rel = {
|
2018-03-22 16:53:53 +01:00
|
|
|
id: rel.id,
|
2018-03-21 17:24:52 +01:00
|
|
|
from: rel.from,
|
|
|
|
to: rel.to,
|
|
|
|
label: rel.type,
|
|
|
|
title: rel.comment,
|
|
|
|
color: {
|
2018-03-26 12:18:56 +02:00
|
|
|
opacity: 1.0,
|
2018-03-21 17:24:52 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
newRelations.push(rel);
|
2018-03-22 16:53:53 +01:00
|
|
|
newRelationIDs.push(rel.id);
|
2018-03-21 13:20:58 +01:00
|
|
|
}
|
2018-03-21 17:24:52 +01:00
|
|
|
// check if nodes got deleted
|
|
|
|
var old_rel_ids = this.edges.getIds();
|
|
|
|
for (var old_id of old_rel_ids) {
|
|
|
|
// This old node got removed
|
|
|
|
if (newRelationIDs.indexOf(old_id) == -1) {
|
|
|
|
this.edges.remove(old_id);
|
|
|
|
}
|
|
|
|
}
|
2018-04-16 11:17:19 +02:00
|
|
|
|
2018-03-21 17:24:52 +01:00
|
|
|
this.edges.update(newRelations);
|
2018-04-16 11:17:19 +02:00
|
|
|
|
2018-04-06 16:44:40 +02:00
|
|
|
this.remove_root_nodes();
|
|
|
|
if (this.scope_name == 'Reference') {
|
2018-04-05 12:31:26 +02:00
|
|
|
this.add_unreferenced_root_node();
|
|
|
|
// links unreferenced attributes and object to root nodes
|
|
|
|
if (this.first_draw) {
|
|
|
|
this.link_not_referenced_nodes();
|
|
|
|
this.first_draw = !this.first_draw
|
|
|
|
}
|
2018-04-06 16:44:40 +02:00
|
|
|
} else if (this.scope_name == 'Tag') {
|
|
|
|
this.add_tag_root_node();
|
|
|
|
// links untagged attributes and object to root nodes
|
|
|
|
if (this.first_draw) {
|
|
|
|
this.link_not_referenced_nodes();
|
|
|
|
this.first_draw = !this.first_draw
|
|
|
|
}
|
|
|
|
} else if (this.scope_name == 'Distribution') {
|
|
|
|
} else if (this.scope_name == 'Correlation') {
|
|
|
|
} else {
|
2018-04-09 11:12:26 +02:00
|
|
|
this.add_keyType_root_node();
|
|
|
|
if (this.first_draw) {
|
|
|
|
this.link_not_referenced_nodes();
|
|
|
|
this.first_draw = !this.first_draw
|
|
|
|
}
|
2018-03-26 12:18:56 +02:00
|
|
|
}
|
|
|
|
|
2018-03-22 10:46:29 +01:00
|
|
|
this.network_loading(false, "");
|
2018-03-21 13:20:58 +01:00
|
|
|
}
|
2018-03-30 11:50:22 +02:00
|
|
|
|
|
|
|
strip_text_value(text) {
|
2018-03-30 12:13:09 +02:00
|
|
|
var max_num = $("#slider_display_max_char_num").val();
|
2018-03-30 11:50:22 +02:00
|
|
|
return text.substring(0, max_num) + (text.length < max_num ? "" : "[...]")
|
|
|
|
}
|
2018-04-16 11:17:19 +02:00
|
|
|
|
2018-03-21 17:24:52 +01:00
|
|
|
reset_view() {
|
|
|
|
this.network.fit({animation: true });
|
2018-03-19 09:44:25 +01:00
|
|
|
}
|
2018-04-16 11:17:19 +02:00
|
|
|
|
2018-04-16 11:29:36 +02:00
|
|
|
reset_view_on_stabilized() { // Avoid fitting more than once, (cause a bug if it occurs)
|
2018-03-26 12:18:56 +02:00
|
|
|
var that = eventGraph;
|
2018-04-16 11:29:36 +02:00
|
|
|
if (that.can_be_fitted_again) {
|
|
|
|
that.can_be_fitted_again = false;
|
|
|
|
this.network.once("stabilized", function(params) {
|
|
|
|
that.network.fit({ animation: true });
|
|
|
|
that.can_be_fitted_again = true;
|
|
|
|
});
|
|
|
|
}
|
2018-03-19 09:44:25 +01:00
|
|
|
}
|
|
|
|
|
2018-03-26 13:22:40 +02:00
|
|
|
focus_on_stabilized(nodeID) {
|
|
|
|
this.network.once("stabilized", function(params) {
|
|
|
|
eventGraph.network.focus(nodeID, {animation: true, scale: 1});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-03-27 15:51:25 +02:00
|
|
|
physics_state(state) {
|
|
|
|
var that = eventGraph;
|
2018-03-27 15:57:27 +02:00
|
|
|
that.network_options.physics.enabled = state;
|
2018-03-30 11:21:02 +02:00
|
|
|
if(that.layout == "default") {
|
|
|
|
$("#select_physic_solver").prop('disabled', !state);
|
|
|
|
}
|
|
|
|
$("#slider_physic_node_repulsion").prop('disabled', !state);
|
2018-03-27 15:51:25 +02:00
|
|
|
that.network.setOptions({physics: { enabled: state} })
|
|
|
|
}
|
|
|
|
|
2018-03-28 15:41:57 +02:00
|
|
|
physics_change_repulsion(value) {
|
|
|
|
var that = eventGraph;
|
|
|
|
if(that.layout == 'default') { // repulsion on default is related to spring length
|
2018-03-30 11:21:02 +02:00
|
|
|
if(that.solver == "barnesHut") {
|
|
|
|
that.network.setOptions({physics: { barnesHut: {springLength: value} } })
|
|
|
|
} else {
|
|
|
|
that.network.setOptions({physics: { repulsion: {nodeDistance: value} } })
|
|
|
|
}
|
2018-03-28 15:41:57 +02:00
|
|
|
} else {
|
|
|
|
that.network.setOptions({physics: { hierarchicalRepulsion: {nodeDistance: value} } })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-30 11:21:02 +02:00
|
|
|
physics_change_solver(solver) {
|
|
|
|
var that = eventGraph;
|
|
|
|
if(that.layout == 'default') { // only hierachical repulsion for other layout
|
|
|
|
that.network.setOptions({physics: { solver: solver } })
|
|
|
|
// update physics slider value
|
|
|
|
if(solver == "barnesHut") {
|
|
|
|
$("#slider_physic_node_repulsion").val(that.network_options.physics.barnesHut.springLength);
|
|
|
|
$("#slider_physic_node_repulsion").parent().find("span").text(that.network_options.physics.barnesHut.springLength);
|
|
|
|
} else {
|
|
|
|
$("#slider_physic_node_repulsion").val(that.network_options.physics.repulsion.nodeDistance);
|
|
|
|
$("#slider_physic_node_repulsion").parent().find("span").text(that.network_options.physics.repulsion.nodeDistance);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
that.solver = solver;
|
|
|
|
}
|
|
|
|
|
2018-03-22 10:46:29 +01:00
|
|
|
// state true: loading
|
|
|
|
// state false: finished
|
|
|
|
network_loading(state, message) {
|
|
|
|
if(state) {
|
2018-03-21 17:24:52 +01:00
|
|
|
$('.loading-network-div').show();
|
2018-03-22 10:46:29 +01:00
|
|
|
$('.loadingText-network').text(message);
|
|
|
|
} else {
|
2018-03-21 17:24:52 +01:00
|
|
|
setTimeout(function() {
|
|
|
|
$('.loading-network-div').hide();
|
2018-03-22 10:46:29 +01:00
|
|
|
}, 500)
|
2018-03-19 09:44:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-21 17:24:52 +01:00
|
|
|
collapse_node(parent_id) {
|
2018-03-26 12:18:56 +02:00
|
|
|
if(parent_id === undefined) { return; }
|
2018-04-16 11:17:19 +02:00
|
|
|
|
2018-04-09 11:12:26 +02:00
|
|
|
if (!(parent_id == root_id_attr || parent_id == root_id_object || parent_id == root_id_tag || parent_id == root_id_keyType)) { // Is not a root node
|
2018-03-26 12:18:56 +02:00
|
|
|
var node_group = this.nodes.get(parent_id).group;
|
|
|
|
if (parent_id === undefined || node_group != 'object') { // No node selected or collapse not permitted
|
|
|
|
return
|
|
|
|
}
|
2018-04-09 11:12:26 +02:00
|
|
|
var connected_nodes_ids = this.network.getConnectedNodes(parent_id);
|
|
|
|
var connected_nodes = this.nodes.get(connected_nodes_ids);
|
|
|
|
for (var node of connected_nodes) {
|
|
|
|
if (node.group == "obj_relation") {
|
|
|
|
// remove edge
|
|
|
|
var connected_edges = this.network.getConnectedEdges(node.id);
|
|
|
|
for (var edgeID of connected_edges) {
|
|
|
|
this.edges.remove(edgeID);
|
|
|
|
}
|
|
|
|
this.nodes.remove(node.id);
|
2018-03-26 12:18:56 +02:00
|
|
|
}
|
2018-03-21 17:24:52 +01:00
|
|
|
}
|
2018-03-26 12:18:56 +02:00
|
|
|
} else { // Is a root node
|
|
|
|
this.clusterize(parent_id);
|
2018-03-21 17:24:52 +01:00
|
|
|
}
|
2018-03-19 09:44:25 +01:00
|
|
|
}
|
2018-04-16 11:17:19 +02:00
|
|
|
|
2018-03-21 17:24:52 +01:00
|
|
|
expand_node(parent_id) {
|
2018-03-26 12:18:56 +02:00
|
|
|
if (!this.network.isCluster(parent_id)) {
|
|
|
|
|
2018-04-04 15:12:16 +02:00
|
|
|
var parent_node = this.nodes.get(parent_id);
|
2018-03-26 12:18:56 +02:00
|
|
|
if (parent_id === undefined // Node node selected
|
2018-04-04 15:12:16 +02:00
|
|
|
|| parent_node.group != "object") { // Cannot expand attribute
|
2018-03-26 12:18:56 +02:00
|
|
|
return;
|
|
|
|
}
|
2018-04-04 15:12:16 +02:00
|
|
|
|
|
|
|
var objAttributes = parent_node.Attribute;
|
2018-03-26 12:18:56 +02:00
|
|
|
var newNodes = [];
|
|
|
|
var newRelations = [];
|
2018-04-16 11:17:19 +02:00
|
|
|
|
2018-03-26 12:18:56 +02:00
|
|
|
var parent_pos = this.network.getPositions([parent_id])[parent_id];
|
2018-04-04 15:12:16 +02:00
|
|
|
for(var attr of objAttributes) {
|
2018-03-26 12:18:56 +02:00
|
|
|
var parent_color = eventGraph.get_node_color(parent_id);
|
2018-04-16 11:17:19 +02:00
|
|
|
|
2018-03-26 12:18:56 +02:00
|
|
|
// Ensure unicity of nodes
|
|
|
|
if (this.nodes.get(attr.uuid) !== null) {
|
|
|
|
continue;
|
|
|
|
}
|
2018-04-16 11:17:19 +02:00
|
|
|
|
2018-03-30 11:50:22 +02:00
|
|
|
var striped_value = this.strip_text_value(attr.value);
|
2018-04-16 11:17:19 +02:00
|
|
|
var node = {
|
2018-03-26 12:18:56 +02:00
|
|
|
id: attr.uuid,
|
|
|
|
x: parent_pos.x,
|
|
|
|
y: parent_pos.y,
|
2018-04-05 12:31:26 +02:00
|
|
|
label: attr.object_relation + ': ' + striped_value,
|
|
|
|
title: attr.object_relation + ': ' + attr.value,
|
2018-03-26 12:18:56 +02:00
|
|
|
group: 'obj_relation',
|
2018-04-16 11:17:19 +02:00
|
|
|
color: {
|
2018-03-26 12:18:56 +02:00
|
|
|
background: parent_color
|
|
|
|
},
|
|
|
|
font: {
|
|
|
|
color: getTextColour(parent_color)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
newNodes.push(node);
|
2018-03-30 10:23:50 +02:00
|
|
|
dataHandler.mapping_obj_relation_value_to_nodeID.set(striped_value, node.id);
|
2018-04-16 11:17:19 +02:00
|
|
|
|
2018-03-26 12:18:56 +02:00
|
|
|
var rel = {
|
|
|
|
from: parent_id,
|
|
|
|
to: attr.uuid,
|
|
|
|
arrows: '',
|
|
|
|
color: {
|
|
|
|
opacity: 0.5,
|
|
|
|
color: parent_color
|
|
|
|
},
|
|
|
|
length: 40
|
|
|
|
};
|
|
|
|
newRelations.push(rel);
|
2018-03-21 17:24:52 +01:00
|
|
|
}
|
2018-04-16 11:17:19 +02:00
|
|
|
|
2018-03-26 12:18:56 +02:00
|
|
|
this.nodes.add(newNodes);
|
|
|
|
this.edges.add(newRelations);
|
|
|
|
|
|
|
|
} else { // is a cluster
|
|
|
|
if(this.network.getNodesInCluster(parent_id).length > cluster_expand_threshold) {
|
|
|
|
if(!confirm("The cluster contains lots of nodes. Are you sure you want to expand it?")) {
|
|
|
|
return;
|
2018-03-21 17:24:52 +01:00
|
|
|
}
|
2018-03-26 12:18:56 +02:00
|
|
|
}
|
|
|
|
// expand cluster
|
|
|
|
this.network.openCluster(parent_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
link_not_referenced_nodes() {
|
2018-04-05 12:31:26 +02:00
|
|
|
// unlink previously linked
|
|
|
|
this.edges.remove(this.new_edges_for_unreferenced_nodes)
|
|
|
|
this.new_edges_for_unreferenced_nodes = [];
|
|
|
|
|
|
|
|
// link not referenced nodes
|
2018-03-26 12:18:56 +02:00
|
|
|
var newEdges = [];
|
|
|
|
var that = this;
|
|
|
|
this.nodes.forEach(function(nodeData) {
|
|
|
|
var cur_id = nodeData.id;
|
|
|
|
var cur_group = nodeData.group;
|
|
|
|
|
|
|
|
// Do not link already connected nodes
|
|
|
|
if (that.network.getConnectedEdges(cur_id).length > 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var new_edge = {
|
|
|
|
to: cur_id,
|
2018-04-05 12:31:26 +02:00
|
|
|
id: "temp_edge_unreferenced_" + that.getUniqId(),
|
2018-03-21 17:24:52 +01:00
|
|
|
arrows: '',
|
|
|
|
color: {
|
2018-03-26 12:18:56 +02:00
|
|
|
opacity: 0.7,
|
|
|
|
color: '#d9d9d9'
|
2018-03-21 17:24:52 +01:00
|
|
|
},
|
2018-03-26 12:18:56 +02:00
|
|
|
length: 150
|
|
|
|
}
|
2018-04-06 16:44:40 +02:00
|
|
|
|
|
|
|
if (that.scope_name == 'Reference') {
|
|
|
|
if (cur_group == 'attribute' || cur_group == 'object') {
|
|
|
|
new_edge.from = cur_group == 'attribute' ? root_id_attr : root_id_object;
|
|
|
|
that.nodes.update({id: nodeData.id, unreferenced: cur_group});
|
|
|
|
}
|
|
|
|
} else if (that.scope_name == 'Tag') {
|
|
|
|
if (cur_group == 'attribute' || cur_group == 'object') {
|
|
|
|
new_edge.from = root_id_tag;
|
|
|
|
that.nodes.update({id: nodeData.id, unreferenced: 'tag'});
|
|
|
|
}
|
2018-04-09 13:39:45 +02:00
|
|
|
} else if (that.scope_name == 'Correlation') {
|
|
|
|
} else { // specified key
|
2018-04-09 11:12:26 +02:00
|
|
|
if (cur_group == 'attribute' || cur_group == 'object') {
|
|
|
|
new_edge.from = root_id_keyType;
|
|
|
|
that.nodes.update({id: nodeData.id, unreferenced: that.scope_name});
|
|
|
|
}
|
2018-03-26 12:18:56 +02:00
|
|
|
}
|
2018-04-16 11:17:19 +02:00
|
|
|
|
2018-03-26 12:18:56 +02:00
|
|
|
newEdges.push(new_edge);
|
2018-04-05 12:31:26 +02:00
|
|
|
that.new_edges_for_unreferenced_nodes.push(new_edge.id);
|
2018-03-26 12:18:56 +02:00
|
|
|
});
|
|
|
|
this.edges.add(newEdges);
|
|
|
|
this.init_clusterize();
|
|
|
|
}
|
|
|
|
|
2018-04-06 16:44:40 +02:00
|
|
|
remove_root_nodes() {
|
|
|
|
this.remove_unreferenced_root_node();
|
|
|
|
this.remove_tag_root_node();
|
2018-04-09 11:12:26 +02:00
|
|
|
this.remove_keyType_root_node();
|
2018-04-06 16:44:40 +02:00
|
|
|
}
|
|
|
|
|
2018-03-26 12:18:56 +02:00
|
|
|
add_unreferenced_root_node() {
|
2018-04-05 12:31:26 +02:00
|
|
|
if (this.root_node_shown) {
|
|
|
|
return;
|
|
|
|
}
|
2018-03-26 12:18:56 +02:00
|
|
|
var root_node_attr = {
|
|
|
|
id: root_id_attr,
|
|
|
|
x: -root_node_x_pos,
|
|
|
|
y: 0,
|
|
|
|
label: 'Unreferenced Attributes',
|
|
|
|
title: 'All Attributes not being referenced',
|
|
|
|
group: 'rootNodeAttribute'
|
|
|
|
};
|
|
|
|
var root_node_obj = {
|
|
|
|
id: root_id_object,
|
|
|
|
x: root_node_x_pos,
|
|
|
|
y: 0,
|
|
|
|
label: 'Unreferenced Objects',
|
|
|
|
title: 'All Objects not being referenced',
|
|
|
|
group: 'rootNodeObject'
|
|
|
|
};
|
|
|
|
this.nodes.add([root_node_attr, root_node_obj]);
|
2018-04-05 12:31:26 +02:00
|
|
|
this.root_node_shown = true;
|
|
|
|
}
|
|
|
|
remove_unreferenced_root_node() {
|
|
|
|
this.nodes.remove([root_id_attr, root_id_object]);
|
|
|
|
this.root_node_shown = false;
|
2018-03-21 13:56:20 +01:00
|
|
|
}
|
2018-03-19 09:44:25 +01:00
|
|
|
|
2018-04-06 16:44:40 +02:00
|
|
|
add_tag_root_node() {
|
|
|
|
if (this.root_node_shown) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var root_node_tag = {
|
|
|
|
id: root_id_tag,
|
|
|
|
x: -root_node_x_pos,
|
|
|
|
y: 0,
|
|
|
|
label: 'Untagged Attribute',
|
|
|
|
title: 'All Attributes not being tagged',
|
|
|
|
group: 'rootNodeTag'
|
|
|
|
};
|
|
|
|
this.nodes.add([root_node_tag]);
|
|
|
|
this.root_node_shown = true;
|
|
|
|
}
|
|
|
|
remove_tag_root_node() {
|
|
|
|
this.nodes.remove([root_id_tag]);
|
|
|
|
this.root_node_shown = false;
|
|
|
|
}
|
|
|
|
|
2018-04-09 11:12:26 +02:00
|
|
|
add_keyType_root_node() {
|
|
|
|
if (this.root_node_shown) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var root_node_keyType = {
|
|
|
|
id: root_id_keyType,
|
|
|
|
x: -root_node_x_pos,
|
|
|
|
y: 0,
|
2018-04-09 14:07:53 +02:00
|
|
|
label: this.scope_keyType + ': No value',
|
2018-04-09 11:12:26 +02:00
|
|
|
title: 'All Attributes not having a value for the specified field',
|
|
|
|
group: 'rootNodeKeyType'
|
|
|
|
};
|
|
|
|
this.nodes.add([root_node_keyType]);
|
|
|
|
this.root_node_shown = true;
|
|
|
|
|
|
|
|
}
|
|
|
|
remove_keyType_root_node() {
|
|
|
|
this.nodes.remove([root_id_keyType]);
|
|
|
|
this.root_node_shown = false;
|
|
|
|
}
|
|
|
|
|
2018-03-27 10:52:50 +02:00
|
|
|
switch_unreferenced_nodes_connection() {
|
|
|
|
var that = eventGraph;
|
|
|
|
var to_update = [];
|
2018-04-09 11:12:26 +02:00
|
|
|
var root_ids;
|
|
|
|
switch(that.scope_name) {
|
|
|
|
case "Reference":
|
|
|
|
root_ids = [root_id_attr, root_id_object];
|
|
|
|
break;
|
|
|
|
case "Tag":
|
|
|
|
root_ids = [root_id_tag];
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
root_ids = [root_id_keyType];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-04-06 16:44:40 +02:00
|
|
|
for(var root_id of root_ids) {
|
2018-03-27 10:52:50 +02:00
|
|
|
if(that.layout == 'default') {
|
|
|
|
var all_edgesID = that.backup_connection_edges[root_id]
|
2018-04-06 16:44:40 +02:00
|
|
|
if (all_edgesID === undefined) { // edgesID was not saved (happen if we switch scope then layout)
|
|
|
|
// redraw everything
|
|
|
|
eventGraph.destroy_and_redraw();
|
|
|
|
return;
|
|
|
|
}
|
2018-03-27 10:52:50 +02:00
|
|
|
} else {
|
|
|
|
that.network.storePositions();
|
|
|
|
var prev_node = root_id;
|
|
|
|
var all_edgesID = that.network.getConnectedEdges(root_id)
|
|
|
|
that.backup_connection_edges[root_id] = all_edgesID;
|
|
|
|
}
|
|
|
|
var all_edges = that.edges.get(all_edgesID);
|
|
|
|
|
|
|
|
for(var i=0; i<all_edges.length; i++ ) {
|
|
|
|
var edge = all_edges[i];
|
|
|
|
if(that.layout == 'default') {
|
|
|
|
// restore all edges connected to root node
|
|
|
|
edge.from = root_id;
|
|
|
|
} else {
|
|
|
|
// change edges so that they are linked one node after the other
|
|
|
|
edge.from = prev_node;
|
|
|
|
prev_node = edge.to;
|
|
|
|
}
|
|
|
|
to_update.push(edge);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
that.edges.update(to_update);
|
|
|
|
}
|
|
|
|
|
2018-03-26 16:18:36 +02:00
|
|
|
change_layout_type(layout) {
|
|
|
|
var that = eventGraph;
|
|
|
|
if (that.layout == layout) { // Hasn't changed
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (layout == 'default') {
|
2018-03-30 11:32:43 +02:00
|
|
|
that.network_options = $.extend(true, {}, default_layout_option);;
|
2018-03-28 15:41:57 +02:00
|
|
|
// update physics slider value
|
|
|
|
$("#slider_physic_node_repulsion").val(that.network_options.physics.barnesHut.springLength);
|
|
|
|
$("#slider_physic_node_repulsion").parent().find("span").text(that.network_options.physics.barnesHut.springLength);
|
2018-03-30 11:21:02 +02:00
|
|
|
$("#select_physic_solver").prop('disabled', false);
|
2018-03-26 16:18:36 +02:00
|
|
|
} else {
|
|
|
|
that.network_options.layout.hierarchical.enabled = true;
|
|
|
|
that.network_options.layout.hierarchical.sortMethod = layout;
|
2018-03-28 15:41:57 +02:00
|
|
|
// update physics slider value
|
|
|
|
$("#slider_physic_node_repulsion").val(that.network_options.physics.hierarchicalRepulsion.nodeDistance);
|
|
|
|
$("#slider_physic_node_repulsion").parent().find("span").text(that.network_options.physics.hierarchicalRepulsion.nodeDistance);
|
2018-03-30 11:21:02 +02:00
|
|
|
$("#select_physic_solver").prop('disabled', true);
|
2018-03-26 16:18:36 +02:00
|
|
|
}
|
2018-03-28 15:41:57 +02:00
|
|
|
that.layout = layout;
|
2018-03-26 16:18:36 +02:00
|
|
|
that.network_loading(true, loadingText_redrawing);
|
2018-03-27 10:52:50 +02:00
|
|
|
that.switch_unreferenced_nodes_connection();
|
|
|
|
that.destroy_and_redraw();
|
2018-03-26 16:18:36 +02:00
|
|
|
that.network_loading(false, "");
|
|
|
|
}
|
|
|
|
|
|
|
|
destroy_and_redraw() {
|
|
|
|
var that = eventGraph;
|
2018-04-16 11:17:19 +02:00
|
|
|
that.network.destroy();
|
|
|
|
that.network = null;
|
2018-03-26 16:18:36 +02:00
|
|
|
var data = {nodes: that.nodes, edges: that.edges};
|
|
|
|
that.network = new vis.Network(container, data, that.network_options);
|
|
|
|
that.init_clusterize();
|
2018-04-10 17:43:37 +02:00
|
|
|
that.bind_listener();
|
2018-03-26 16:18:36 +02:00
|
|
|
}
|
|
|
|
|
2018-03-21 13:56:20 +01:00
|
|
|
}
|
|
|
|
|
2018-03-21 17:24:52 +01:00
|
|
|
// data class (handle data)
|
|
|
|
class DataHandler {
|
2018-03-29 18:05:19 +02:00
|
|
|
constructor() {
|
2018-03-21 17:24:52 +01:00
|
|
|
this.mapping_value_to_nodeID = new Map();
|
2018-03-30 10:23:50 +02:00
|
|
|
this.mapping_obj_relation_value_to_nodeID = new Map();
|
2018-03-29 18:05:19 +02:00
|
|
|
this.mapping_uuid_to_template = new Map();
|
2018-04-05 12:31:26 +02:00
|
|
|
this.selected_type_to_display = "";
|
2018-04-16 14:02:43 +02:00
|
|
|
this.extended_event = $('#eventgraph_network').data('extended') == 1 ? true : false;
|
2018-04-06 16:44:40 +02:00
|
|
|
this.scope_name;
|
|
|
|
}
|
|
|
|
|
|
|
|
get_scope_url() {
|
|
|
|
switch(this.scope_name) {
|
|
|
|
case "Reference":
|
|
|
|
return "getEventGraphReferences";
|
|
|
|
case "Tag":
|
|
|
|
return "getEventGraphTags";
|
|
|
|
case "Correlation":
|
|
|
|
return "getEventGraphReferences";
|
|
|
|
default:
|
2018-04-09 11:12:26 +02:00
|
|
|
return "getEventGraphGeneric";
|
2018-04-06 16:44:40 +02:00
|
|
|
}
|
2018-03-21 17:24:52 +01:00
|
|
|
}
|
2018-03-19 15:07:51 +01:00
|
|
|
|
2018-03-29 18:05:19 +02:00
|
|
|
generate_label(obj) {
|
2018-04-04 15:12:16 +02:00
|
|
|
var label = obj.type;
|
2018-03-30 10:14:23 +02:00
|
|
|
for (var attr of obj.Attribute) { // for each field
|
2018-04-05 12:31:26 +02:00
|
|
|
if (attr.object_relation == this.selected_type_to_display) {
|
2018-03-30 10:14:23 +02:00
|
|
|
label += ": " + attr.value;
|
|
|
|
return label;
|
|
|
|
}
|
|
|
|
}
|
2018-04-05 12:31:26 +02:00
|
|
|
if(this.selected_type_to_display !== "") { // User explicitly choose the type to display
|
2018-03-30 11:50:22 +02:00
|
|
|
return label;
|
|
|
|
}
|
2018-03-30 10:14:23 +02:00
|
|
|
// no matching, taking the first requiredOff
|
2018-03-29 18:05:19 +02:00
|
|
|
var template_uuid = obj.template_uuid;
|
|
|
|
var template_req = this.mapping_uuid_to_template.get(template_uuid);
|
2018-03-30 11:50:22 +02:00
|
|
|
if (template_req === undefined) { // template not known
|
|
|
|
return label;
|
|
|
|
}
|
2018-03-29 18:05:19 +02:00
|
|
|
// search if this field exists in the object
|
|
|
|
for (var attr of obj.Attribute) { // for each field
|
2018-03-30 10:14:23 +02:00
|
|
|
var attr_type = attr.type;
|
2018-03-29 18:05:19 +02:00
|
|
|
if (template_req.indexOf(attr_type) != -1) {
|
|
|
|
label += ": " + attr.value;
|
2018-03-30 10:14:23 +02:00
|
|
|
return label;
|
2018-03-29 18:05:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return label;
|
|
|
|
}
|
2018-03-30 10:14:23 +02:00
|
|
|
|
2018-04-04 15:12:16 +02:00
|
|
|
update_available_object_references(available_object_references) {
|
|
|
|
eventGraph.menu_display.add_options("select_display_object_field", available_object_references);
|
|
|
|
eventGraph.menu_filter.items["table_attr_presence"].add_options("table_control_select_attr_presence", available_object_references);
|
|
|
|
eventGraph.menu_filter.items["table_attr_value"].add_options("table_control_select_attr_value", available_object_references);
|
2018-03-30 10:14:23 +02:00
|
|
|
}
|
2018-04-16 11:17:19 +02:00
|
|
|
|
2018-03-22 16:53:53 +01:00
|
|
|
fetch_data_and_update(stabilize) {
|
2018-03-22 10:46:29 +01:00
|
|
|
eventGraph.network_loading(true, loadingText_fetching);
|
2018-03-29 18:05:19 +02:00
|
|
|
$.when(this.fetch_objects_template()).done(function() {
|
2018-04-05 12:31:26 +02:00
|
|
|
var filtering_rules = eventGraph.get_filtering_rules();
|
2018-04-09 13:39:45 +02:00
|
|
|
var keyType = eventGraph.scope_keyType;
|
2018-04-09 11:12:26 +02:00
|
|
|
var payload = {};
|
|
|
|
payload.filtering = filtering_rules;
|
|
|
|
payload.keyType = keyType;
|
2018-04-16 14:02:43 +02:00
|
|
|
var extended_text = dataHandler.extended_event ? "extended:1" : "";
|
2018-04-05 12:31:26 +02:00
|
|
|
$.ajax({
|
2018-04-16 14:02:43 +02:00
|
|
|
url: "/events/"+dataHandler.get_scope_url()+"/"+scope_id+"/"+extended_text+"/event.json",
|
2018-04-05 12:31:26 +02:00
|
|
|
dataType: 'json',
|
|
|
|
type: 'post',
|
|
|
|
contentType: 'application/json',
|
2018-04-09 11:12:26 +02:00
|
|
|
data: JSON.stringify( payload ),
|
2018-04-05 12:31:26 +02:00
|
|
|
processData: false,
|
|
|
|
success: function( data, textStatus, jQxhr ){
|
2018-04-06 16:44:40 +02:00
|
|
|
eventGraph.reset_graphs(true);
|
2018-04-05 12:31:26 +02:00
|
|
|
eventGraph.is_filtered = (filtering_rules.presence.length > 0 || filtering_rules.value.length > 0);
|
|
|
|
eventGraph.first_draw = true;
|
2018-04-16 11:17:19 +02:00
|
|
|
// update object state
|
2018-04-05 12:31:26 +02:00
|
|
|
var available_object_references = Object.keys(data.existing_object_relation);
|
|
|
|
dataHandler.update_available_object_references(available_object_references);
|
2018-04-16 11:17:19 +02:00
|
|
|
dataHandler.available_rotation_key = data.available_rotation_key;
|
|
|
|
eventGraph.menu_scope.add_options("input_graph_scope_jsonkey", dataHandler.available_rotation_key);
|
2018-04-05 12:31:26 +02:00
|
|
|
eventGraph.update_graph(data);
|
|
|
|
if ( stabilize === undefined || stabilize) {
|
|
|
|
eventGraph.reset_view_on_stabilized();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
error: function( jqXhr, textStatus, errorThrown ){
|
|
|
|
console.log( errorThrown );
|
2018-03-29 18:05:19 +02:00
|
|
|
}
|
|
|
|
});
|
2018-03-22 16:53:53 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
fetch_reference_data(rel_uuid, callback) {
|
|
|
|
$.getJSON( "/events/getReferenceData/"+rel_uuid+"/reference.json", function( data ) {
|
|
|
|
callback(data);
|
2018-03-21 17:24:52 +01:00
|
|
|
});
|
|
|
|
}
|
2018-03-20 17:29:26 +01:00
|
|
|
|
2018-03-29 18:05:19 +02:00
|
|
|
fetch_objects_template() {
|
|
|
|
return $.getJSON( "/events/getObjectTemplate/templates.json", function( data ) {
|
|
|
|
for (var i in data) {
|
|
|
|
var template = data[i].ObjectTemplate;
|
|
|
|
dataHandler.mapping_uuid_to_template.set(template.uuid, template.requirements.requiredOneOf);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-04-09 13:39:45 +02:00
|
|
|
get_typeaheadData_search() {
|
2018-03-21 17:24:52 +01:00
|
|
|
var to_ret = []
|
|
|
|
for( var entry of this.mapping_value_to_nodeID) {
|
|
|
|
var value = entry[0];
|
|
|
|
to_ret.push(value);
|
|
|
|
}
|
2018-03-30 10:23:50 +02:00
|
|
|
// object relation
|
|
|
|
for( var entry of this.mapping_obj_relation_value_to_nodeID) {
|
|
|
|
var value = entry[0];
|
|
|
|
to_ret.push(value);
|
|
|
|
}
|
2018-03-21 17:24:52 +01:00
|
|
|
return to_ret;
|
2018-03-19 16:19:09 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-19 09:44:25 +01:00
|
|
|
|
2018-03-22 09:46:54 +01:00
|
|
|
// MISP interaction class (handle interaction with misp)
|
2018-03-21 17:24:52 +01:00
|
|
|
class MispInteraction {
|
|
|
|
constructor(nodes, edges) {
|
|
|
|
this.nodes = nodes;
|
|
|
|
this.edges = edges;
|
2018-03-22 16:53:53 +01:00
|
|
|
// Dirty way to know what modif was successful as the callback gives no information
|
|
|
|
// May be changed in the futur
|
|
|
|
this.callback_to_be_called = null;
|
|
|
|
}
|
2018-04-16 11:17:19 +02:00
|
|
|
|
2018-03-22 16:53:53 +01:00
|
|
|
register_callback(callback) {
|
|
|
|
this.callback_to_be_called = callback;
|
|
|
|
}
|
|
|
|
|
|
|
|
apply_callback() {
|
|
|
|
var that = mispInteraction;
|
|
|
|
if (that.callback_to_be_called !== null) {
|
|
|
|
that.callback_to_be_called(that.callback_data);
|
|
|
|
}
|
|
|
|
that.callback_to_be_called = null;
|
|
|
|
that.callback_data = null;
|
2018-03-21 17:24:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
remove_reference(edgeData, callback) {
|
2018-03-22 16:53:53 +01:00
|
|
|
var that = mispInteraction;
|
2018-03-22 09:46:54 +01:00
|
|
|
var edge_id = edgeData.edges[0];
|
2018-03-22 16:53:53 +01:00
|
|
|
var relation_id = edge_id;
|
2018-03-21 17:24:52 +01:00
|
|
|
deleteObject('object_references', 'delete', relation_id, scope_id);
|
2018-03-27 11:07:16 +02:00
|
|
|
if (callback !== undefined) {
|
|
|
|
callback();
|
|
|
|
}
|
2018-03-21 17:24:52 +01:00
|
|
|
}
|
2018-04-16 11:17:19 +02:00
|
|
|
|
2018-03-21 17:24:52 +01:00
|
|
|
add_reference(edgeData, callback) {
|
|
|
|
var that = mispInteraction;
|
2018-04-04 15:12:16 +02:00
|
|
|
//var uuid = dataHandler.mapping_attr_id_to_uuid.get(edgeData.to);
|
|
|
|
var uuid = that.nodes.get(edgeData.to).uuid;
|
2018-03-21 17:24:52 +01:00
|
|
|
if (!that.can_create_reference(edgeData.from) || !that.can_be_referenced(edgeData.to)) {
|
|
|
|
return;
|
2018-03-19 09:44:25 +01:00
|
|
|
}
|
2018-03-21 17:24:52 +01:00
|
|
|
genericPopup('/objectReferences/add/'+edgeData.from, '#popover_form', function() {
|
|
|
|
$('#targetSelect').val(uuid);
|
|
|
|
$('option[value='+uuid+']').click()
|
|
|
|
});
|
2018-03-20 14:43:05 +01:00
|
|
|
}
|
2018-03-22 16:53:53 +01:00
|
|
|
|
|
|
|
edit_reference(edgeData, callback) {
|
2018-03-22 17:19:57 +01:00
|
|
|
if (callback !== undefined) {
|
|
|
|
callback();
|
|
|
|
}
|
2018-03-22 16:53:53 +01:00
|
|
|
var that = mispInteraction;
|
|
|
|
var rel_id = edgeData.id;
|
2018-04-04 15:12:16 +02:00
|
|
|
var rel_uuid = edgeData.uuid;
|
2018-04-16 11:17:19 +02:00
|
|
|
|
2018-03-22 16:53:53 +01:00
|
|
|
that.register_callback(function() {
|
|
|
|
var relation_id = edgeData.id;
|
|
|
|
submitDeletion(scope_id, 'delete', 'object_references', relation_id);
|
|
|
|
});
|
|
|
|
|
|
|
|
dataHandler.fetch_reference_data(rel_uuid, function(data) {
|
|
|
|
data = data[0].ObjectReference;
|
|
|
|
var uuid = data.referenced_uuid;
|
|
|
|
genericPopup('/objectReferences/add/'+data.object_id, '#popover_form', function() {
|
|
|
|
$('#targetSelect').val(uuid);
|
|
|
|
$('#ObjectReferenceComment').val(data.comment);
|
|
|
|
$('#ObjectReferenceRelationshipTypeSelect').val(data.relationship_type);
|
|
|
|
$('option[value='+uuid+']').click();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
2018-04-16 11:17:19 +02:00
|
|
|
|
2018-03-21 17:24:52 +01:00
|
|
|
can_create_reference(id) {
|
|
|
|
return this.nodes.get(id).group == "object";
|
|
|
|
}
|
|
|
|
|
|
|
|
can_be_referenced(id) {
|
|
|
|
var res;
|
|
|
|
if (this.nodes.get(id).group == "object") {
|
|
|
|
res = true;
|
|
|
|
} else if (this.nodes.get(id).group == "attribute") {
|
|
|
|
res = true;
|
|
|
|
} else {
|
|
|
|
res = false;
|
2018-03-20 14:43:05 +01:00
|
|
|
}
|
2018-03-21 17:24:52 +01:00
|
|
|
return res;
|
2018-03-19 09:44:25 +01:00
|
|
|
}
|
2018-03-20 14:43:05 +01:00
|
|
|
|
2018-03-21 17:24:52 +01:00
|
|
|
add_item(nodeData, callback) {
|
2018-03-22 16:53:53 +01:00
|
|
|
var that = mispInteraction;
|
2018-03-21 17:24:52 +01:00
|
|
|
choicePopup("Add an element", [
|
|
|
|
{
|
|
|
|
text: "Add an Object",
|
|
|
|
onclick: "getPopup('"+scope_id+"', 'objectTemplates', 'objectChoice');"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
text: "Add an Attribute",
|
|
|
|
onclick: "simplePopup('/attributes/add/"+scope_id+"');"
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
}
|
2018-04-16 11:17:19 +02:00
|
|
|
|
2018-03-21 17:24:52 +01:00
|
|
|
delete_item(nodeData, callback) {
|
|
|
|
var selected_nodes = nodeData.nodes;
|
|
|
|
for (var nodeID of selected_nodes) {
|
|
|
|
var node = this.nodes.get(nodeID)
|
|
|
|
if (node.group == "attribute") {
|
|
|
|
deleteObject('attributes', 'delete', nodeID, scope_id);
|
|
|
|
} else if (node.group == "object") {
|
|
|
|
deleteObject('objects', 'delete', nodeID, scope_id);
|
2018-03-19 09:44:25 +01:00
|
|
|
}
|
2018-03-20 14:43:05 +01:00
|
|
|
}
|
2018-03-21 17:24:52 +01:00
|
|
|
}
|
2018-04-16 11:17:19 +02:00
|
|
|
|
2018-03-21 17:24:52 +01:00
|
|
|
edit_item(nodeData, callback) {
|
2018-03-22 16:53:53 +01:00
|
|
|
var that = mispInteraction;
|
2018-03-21 17:24:52 +01:00
|
|
|
var id = nodeData.id
|
2018-03-22 16:53:53 +01:00
|
|
|
var group = nodes.get(id).group;
|
|
|
|
if (group == 'attribute') {
|
|
|
|
simplePopup('/attributes/edit/'+id);
|
|
|
|
} else if (group == 'object') {
|
|
|
|
window.location = '/objects/edit/'+id;
|
|
|
|
}
|
2018-03-19 09:44:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-19 10:57:26 +01:00
|
|
|
|
2018-03-21 17:24:52 +01:00
|
|
|
/*=========
|
|
|
|
* UTILS
|
|
|
|
* ========*/
|
|
|
|
function getRandomColor() {
|
|
|
|
var letters = '0123456789ABCDEF';
|
|
|
|
var color = '#';
|
|
|
|
for (var i = 0; i < 6; i++) {
|
|
|
|
color += letters[Math.floor(Math.random() * 16)];
|
|
|
|
}
|
|
|
|
return color;
|
2018-03-20 14:43:05 +01:00
|
|
|
}
|
|
|
|
|
2018-04-09 16:04:40 +02:00
|
|
|
function generate_background_shortcuts(shortcut_text) {
|
|
|
|
var table = document.createElement('table');
|
|
|
|
for (var shortcut of shortcut_text.split("\n")) {
|
|
|
|
var index = shortcut.indexOf(" ");
|
|
|
|
var text1 = shortcut.substring(0, index);
|
|
|
|
var text2 = shortcut.substring(index, shortcut.length);
|
|
|
|
var tr = document.createElement('tr');
|
|
|
|
var td = document.createElement('td');
|
|
|
|
td.innerHTML = text1;
|
|
|
|
tr.appendChild(td);
|
|
|
|
var td = document.createElement('td');
|
|
|
|
td.innerHTML = text2;
|
|
|
|
tr.appendChild(td);
|
|
|
|
table.appendChild(tr);
|
|
|
|
}
|
|
|
|
document.getElementById("eventgraph_shortcuts_background").appendChild(table);
|
|
|
|
}
|
|
|
|
|
2018-03-21 17:24:52 +01:00
|
|
|
function getTextColour(hex) {
|
|
|
|
hex = hex.slice(1);
|
|
|
|
var r = parseInt(hex.substring(0,2), 16);
|
|
|
|
var g = parseInt(hex.substring(2,4), 16);
|
|
|
|
var b = parseInt(hex.substring(4,6), 16);
|
|
|
|
var avg = ((2 * r) + b + (3 * g))/6;
|
|
|
|
if (avg < 128) {
|
|
|
|
return 'white';
|
|
|
|
} else {
|
|
|
|
return 'black';
|
2018-03-19 09:44:25 +01:00
|
|
|
}
|
2018-03-21 17:24:52 +01:00
|
|
|
}
|
2018-03-19 09:44:25 +01:00
|
|
|
|
|
|
|
|
2018-03-21 17:24:52 +01:00
|
|
|
function genericPopupCallback(result) {
|
2018-04-16 11:17:19 +02:00
|
|
|
// sucess and eventgraph is enabled
|
2018-03-22 16:53:53 +01:00
|
|
|
if (result == "success" && dataHandler !== undefined) {
|
|
|
|
mispInteraction.apply_callback();
|
|
|
|
dataHandler.fetch_data_and_update(false);
|
2018-03-19 09:44:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-20 14:43:05 +01:00
|
|
|
|
2018-03-21 17:24:52 +01:00
|
|
|
// Called when the user click on the 'Event graph' toggle
|
2018-03-20 14:43:05 +01:00
|
|
|
function enable_interactive_graph() {
|
|
|
|
// unregister onclick
|
2018-03-21 17:24:52 +01:00
|
|
|
$('#eventgraph_toggle').removeAttr('onclick');
|
2018-03-20 14:43:05 +01:00
|
|
|
|
|
|
|
// Defer the loading of the network to let some time for the DIV to appear
|
|
|
|
setTimeout(function() {
|
|
|
|
$('.shortcut-help').popover({
|
|
|
|
container: 'body',
|
|
|
|
title: 'Shortcuts',
|
|
|
|
content: shortcut_text,
|
|
|
|
placement: 'left',
|
|
|
|
trigger: 'hover',
|
|
|
|
html: true,
|
2018-03-19 09:44:25 +01:00
|
|
|
});
|
2018-04-09 16:04:40 +02:00
|
|
|
generate_background_shortcuts(shortcut_text);
|
2018-03-21 13:20:58 +01:00
|
|
|
$('.fullscreen-btn').click(function() {
|
2018-03-21 17:24:52 +01:00
|
|
|
var network_div = $('#eventgraph_div');
|
2018-03-21 13:20:58 +01:00
|
|
|
var fullscreen_enabled = !network_div.data('fullscreen');
|
|
|
|
network_div.data('fullscreen', fullscreen_enabled);
|
|
|
|
var height_val = fullscreen_enabled == true ? "calc(100vh - 42px - 42px - 10px)" : "500px";
|
|
|
|
|
|
|
|
network_div.css("height", height_val);
|
|
|
|
network_div[0].scrollIntoView({
|
|
|
|
behavior: "smooth",
|
|
|
|
|
|
|
|
});
|
|
|
|
});
|
2018-03-28 15:41:57 +02:00
|
|
|
|
2018-03-21 13:20:58 +01:00
|
|
|
$('#network-typeahead').typeahead(typeaheadOption);
|
2018-03-19 09:44:25 +01:00
|
|
|
|
2018-03-29 18:05:19 +02:00
|
|
|
dataHandler = new DataHandler();
|
2018-03-21 17:24:52 +01:00
|
|
|
eventGraph = new EventGraph(network_options, nodes, edges);
|
2018-03-20 14:43:05 +01:00
|
|
|
|
|
|
|
$(document).on("keydown", function(evt) {
|
2018-03-22 17:12:50 +01:00
|
|
|
if($('#network-typeahead').is(":focus")) {
|
2018-03-30 10:23:50 +02:00
|
|
|
if (evt.keyCode == 27) { // <ESC>
|
|
|
|
$('#network-typeahead').blur();
|
|
|
|
}
|
2018-03-22 17:12:50 +01:00
|
|
|
return;
|
|
|
|
}
|
2018-03-20 14:43:05 +01:00
|
|
|
switch(evt.keyCode) {
|
|
|
|
case 88: // x
|
2018-04-16 11:17:19 +02:00
|
|
|
var selected_id = eventGraph.network.getSelectedNodes()[0];
|
2018-03-21 17:24:52 +01:00
|
|
|
eventGraph.expand_node(selected_id);
|
2018-03-19 09:44:25 +01:00
|
|
|
break;
|
|
|
|
|
2018-03-20 14:43:05 +01:00
|
|
|
case 67: // c
|
2018-04-16 11:17:19 +02:00
|
|
|
var selected_id = eventGraph.network.getSelectedNodes()[0];
|
2018-03-21 17:24:52 +01:00
|
|
|
eventGraph.collapse_node(selected_id);
|
2018-03-20 14:43:05 +01:00
|
|
|
break;
|
|
|
|
case 86: // v
|
2018-03-21 17:24:52 +01:00
|
|
|
eventGraph.reset_view();
|
2018-03-19 09:44:25 +01:00
|
|
|
break;
|
2018-03-20 17:29:26 +01:00
|
|
|
|
|
|
|
case 69: // e
|
|
|
|
if (evt.shiftKey) {
|
2018-04-16 11:17:19 +02:00
|
|
|
var selected_id = eventGraph.network.getSelectedNodes()[0];
|
2018-03-22 16:53:53 +01:00
|
|
|
if (selected_id !== undefined) { // A node is selected
|
|
|
|
var data = { id: selected_id };
|
|
|
|
mispInteraction.edit_item(data);
|
|
|
|
break;
|
|
|
|
}
|
2018-04-16 11:17:19 +02:00
|
|
|
selected_id = eventGraph.network.getSelectedEdges()[0];
|
2018-03-22 16:53:53 +01:00
|
|
|
if (selected_id !== undefined) { // A edge is selected
|
|
|
|
var data = { id: selected_id };
|
|
|
|
mispInteraction.edit_reference(data);
|
|
|
|
break;
|
|
|
|
}
|
2018-03-20 17:29:26 +01:00
|
|
|
}
|
|
|
|
break;
|
2018-03-21 13:20:58 +01:00
|
|
|
|
|
|
|
case 70: // f
|
|
|
|
if (evt.shiftKey) {
|
|
|
|
// set focus to search input
|
2018-03-21 17:24:52 +01:00
|
|
|
eventGraph.network.disableEditMode(); // un-toggle edit mode
|
2018-03-21 13:20:58 +01:00
|
|
|
$('#network-typeahead').focus();
|
|
|
|
$('#network-typeahead').text('');
|
|
|
|
evt.preventDefault(); // avoid writting a 'F' in the input field
|
|
|
|
}
|
|
|
|
break;
|
2018-03-19 09:44:25 +01:00
|
|
|
|
2018-03-20 14:43:05 +01:00
|
|
|
case 16: // <SHIFT>
|
|
|
|
if (!user_manipulation) { // user can't modify references
|
|
|
|
break;
|
|
|
|
}
|
2018-03-21 17:24:52 +01:00
|
|
|
eventGraph.network.addEdgeMode(); // toggle edit mode
|
2018-03-19 09:44:25 +01:00
|
|
|
break;
|
|
|
|
|
2018-03-20 14:43:05 +01:00
|
|
|
case 46: // <Delete>
|
|
|
|
if (!user_manipulation) { // user can't modify references
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// References
|
2018-04-16 11:17:19 +02:00
|
|
|
var selected_ids = eventGraph.network.getSelectedEdges();
|
2018-03-20 14:43:05 +01:00
|
|
|
for (var selected_id of selected_ids) {
|
|
|
|
var edge = { edges: [selected_id] }; // trick to use the same function
|
2018-03-21 17:24:52 +01:00
|
|
|
mispInteraction.remove_reference(edge);
|
2018-03-20 14:43:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Objects or Attributes
|
2018-03-21 17:24:52 +01:00
|
|
|
selected_ids = eventGraph.network.getSelectedNodes();
|
2018-03-20 14:43:05 +01:00
|
|
|
data = { nodes: selected_ids };
|
2018-03-21 17:24:52 +01:00
|
|
|
mispInteraction.delete_item(data);
|
2018-03-20 14:43:05 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
$(document).on("keyup", function(evt) {
|
|
|
|
switch(evt.keyCode) {
|
|
|
|
case 16: // <SHIFT>
|
|
|
|
if (!user_manipulation) { // user can't modify references
|
|
|
|
break;
|
|
|
|
}
|
2018-03-21 17:24:52 +01:00
|
|
|
eventGraph.network.disableEditMode(); // un-toggle edit mode
|
2018-03-20 14:43:05 +01:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2018-04-06 16:44:40 +02:00
|
|
|
eventGraph.update_scope();
|
2018-03-22 17:05:49 +01:00
|
|
|
dataHandler.fetch_data_and_update();
|
2018-03-20 14:43:05 +01:00
|
|
|
}, 1);
|
|
|
|
}
|
2018-03-21 17:24:52 +01:00
|
|
|
|
|
|
|
/*=========
|
|
|
|
* OPTIONS
|
|
|
|
* ========*/
|
|
|
|
mispInteraction = new MispInteraction(nodes, edges);
|
|
|
|
|
|
|
|
var network_options = {
|
|
|
|
interaction: {
|
|
|
|
hover: true
|
|
|
|
},
|
2018-03-26 12:18:56 +02:00
|
|
|
layout: {
|
2018-03-26 16:18:36 +02:00
|
|
|
improvedLayout: false,
|
|
|
|
hierarchical: {
|
2018-04-16 11:17:19 +02:00
|
|
|
enabled: false,
|
|
|
|
levelSeparation: 150,
|
|
|
|
nodeSpacing: 5,
|
|
|
|
treeSpacing: 200,
|
|
|
|
blockShifting: true,
|
|
|
|
edgeMinimization: true,
|
|
|
|
parentCentralization: true,
|
|
|
|
direction: 'UD', // UD, DU, LR, RL
|
|
|
|
sortMethod: 'directed' // hubsize, directed
|
2018-03-26 16:18:36 +02:00
|
|
|
}
|
|
|
|
|
2018-03-26 12:18:56 +02:00
|
|
|
},
|
2018-03-21 17:24:52 +01:00
|
|
|
manipulation: {
|
|
|
|
enabled: user_manipulation,
|
|
|
|
initiallyActive: false,
|
|
|
|
addEdge: mispInteraction.add_reference,
|
2018-03-22 16:53:53 +01:00
|
|
|
editEdge: { editWithoutDrag: mispInteraction.edit_reference },
|
2018-03-21 17:24:52 +01:00
|
|
|
addNode: mispInteraction.add_item,
|
|
|
|
editNode: mispInteraction.edit_item,
|
|
|
|
deleteNode: mispInteraction.delete_item,
|
|
|
|
deleteEdge: mispInteraction.remove_reference
|
|
|
|
},
|
|
|
|
physics: {
|
|
|
|
enabled: true,
|
|
|
|
barnesHut: {
|
|
|
|
gravitationalConstant: -10000,
|
|
|
|
centralGravity: 5,
|
|
|
|
springLength: 150,
|
|
|
|
springConstant: 0.24,
|
|
|
|
damping: 1.0,
|
|
|
|
|
|
|
|
},
|
2018-03-30 11:21:02 +02:00
|
|
|
repulsion: {
|
|
|
|
centralGravity: 5,
|
|
|
|
springLength: 150,
|
|
|
|
springConstant: 0.04,
|
|
|
|
nodeDistance: 240,
|
2018-04-05 12:31:26 +02:00
|
|
|
damping: 0.3
|
2018-03-30 11:21:02 +02:00
|
|
|
},
|
2018-03-26 16:18:36 +02:00
|
|
|
hierarchicalRepulsion: {
|
|
|
|
centralGravity: 0,
|
|
|
|
springLength: 150,
|
|
|
|
springConstant: 0.24,
|
2018-03-28 15:41:57 +02:00
|
|
|
nodeDistance: 120,
|
2018-03-26 16:18:36 +02:00
|
|
|
damping: 1
|
|
|
|
},
|
2018-03-26 12:18:56 +02:00
|
|
|
minVelocity: 3.0,
|
2018-03-21 17:24:52 +01:00
|
|
|
},
|
|
|
|
edges: {
|
|
|
|
width: 3,
|
|
|
|
arrows: 'to'
|
|
|
|
},
|
|
|
|
nodes: {
|
|
|
|
chosen: {
|
|
|
|
node: function(values, id, selected, hovering) {
|
|
|
|
values.shadow = true;
|
|
|
|
values.shadowSize = 5;
|
|
|
|
values.shadowX = 2;
|
|
|
|
values.shadowY = 2;
|
|
|
|
values.shadowColor = "rgba(0,0,0,0.1)";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
groups: {
|
|
|
|
object: {
|
|
|
|
shape: 'icon',
|
|
|
|
icon: {
|
|
|
|
face: 'FontAwesome',
|
|
|
|
size: 50
|
|
|
|
},
|
|
|
|
font: {
|
|
|
|
size: 18, // px
|
|
|
|
background: 'rgba(255, 255, 255, 0.7)'
|
|
|
|
},
|
|
|
|
},
|
|
|
|
obj_relation: {
|
2018-04-06 16:44:40 +02:00
|
|
|
mass: 3,
|
2018-03-21 17:24:52 +01:00
|
|
|
size: 10,
|
2018-04-16 11:17:19 +02:00
|
|
|
color: {
|
2018-03-21 17:24:52 +01:00
|
|
|
border:'black'
|
|
|
|
}
|
|
|
|
},
|
|
|
|
attribute: {
|
|
|
|
shape: 'box',
|
2018-04-16 11:17:19 +02:00
|
|
|
color: {
|
|
|
|
background:'orange',
|
2018-03-21 17:24:52 +01:00
|
|
|
border:'black'
|
|
|
|
},
|
|
|
|
size: 15
|
|
|
|
},
|
2018-04-06 16:44:40 +02:00
|
|
|
tag: {
|
|
|
|
shape: 'box',
|
|
|
|
size: 15,
|
|
|
|
shadow: {
|
|
|
|
enabled: true,
|
|
|
|
size: 3,
|
|
|
|
x: 3, y: 3
|
2018-04-09 11:12:26 +02:00
|
|
|
},
|
|
|
|
mass: 20
|
|
|
|
},
|
|
|
|
keyType: {
|
|
|
|
shape: 'box',
|
|
|
|
color: {
|
|
|
|
border: '#303030',
|
|
|
|
background: '#808080',
|
|
|
|
},
|
|
|
|
font: {
|
|
|
|
size: 18, //px
|
|
|
|
color: 'white'
|
|
|
|
},
|
2018-04-09 13:39:45 +02:00
|
|
|
mass: 25
|
2018-04-09 11:12:26 +02:00
|
|
|
|
2018-04-06 16:44:40 +02:00
|
|
|
},
|
2018-03-26 12:18:56 +02:00
|
|
|
rootNodeObject: {
|
|
|
|
shape: 'icon',
|
|
|
|
icon: {
|
|
|
|
face: 'FontAwesome',
|
|
|
|
code: '\uf00a',
|
|
|
|
},
|
|
|
|
font: {
|
|
|
|
size: 18, // px
|
|
|
|
background: 'rgba(255, 255, 255, 0.7)'
|
|
|
|
},
|
2018-04-06 16:44:40 +02:00
|
|
|
mass: 5
|
2018-03-26 12:18:56 +02:00
|
|
|
},
|
|
|
|
rootNodeAttribute: {
|
|
|
|
shape: 'icon',
|
|
|
|
icon: {
|
|
|
|
face: 'FontAwesome',
|
|
|
|
code: '\uf1c0',
|
|
|
|
},
|
|
|
|
font: {
|
|
|
|
size: 18, // px
|
|
|
|
background: 'rgba(255, 255, 255, 0.7)'
|
|
|
|
},
|
2018-04-06 16:44:40 +02:00
|
|
|
mass: 5
|
|
|
|
},
|
2018-04-09 11:12:26 +02:00
|
|
|
rootNodeKeyType: {
|
|
|
|
shape: 'icon',
|
|
|
|
icon: {
|
|
|
|
face: 'FontAwesome',
|
|
|
|
code: '\uf111',
|
|
|
|
},
|
|
|
|
font: {
|
|
|
|
size: 22, // px
|
|
|
|
background: 'rgba(255, 255, 255, 0.7)'
|
|
|
|
},
|
|
|
|
mass: 5
|
|
|
|
},
|
2018-04-06 16:44:40 +02:00
|
|
|
rootNodeTag: {
|
|
|
|
shape: 'icon',
|
|
|
|
icon: {
|
|
|
|
face: 'FontAwesome',
|
|
|
|
code: '\uf02b',
|
|
|
|
},
|
|
|
|
font: {
|
|
|
|
size: 22, // px
|
|
|
|
background: 'rgba(255, 255, 255, 0.7)'
|
|
|
|
},
|
|
|
|
mass: 5
|
2018-03-26 12:18:56 +02:00
|
|
|
},
|
|
|
|
clustered_object: {
|
|
|
|
shape: 'icon',
|
|
|
|
icon: {
|
|
|
|
face: 'FontAwesome',
|
|
|
|
code: '\uf009',
|
|
|
|
},
|
|
|
|
font: {
|
|
|
|
size: 18, // px
|
|
|
|
background: 'rgba(255, 255, 255, 0.7)'
|
|
|
|
},
|
2018-04-06 16:44:40 +02:00
|
|
|
mass: 5
|
2018-03-26 12:18:56 +02:00
|
|
|
}
|
2018-03-21 17:24:52 +01:00
|
|
|
},
|
|
|
|
locales: {
|
|
|
|
en: {
|
|
|
|
edit: 'Edit',
|
|
|
|
del: 'Delete selected',
|
|
|
|
back: 'Back',
|
|
|
|
addNode: 'Add Object or Attribute',
|
|
|
|
editNode: 'Edit selected item',
|
|
|
|
addDescription: 'Click in an empty space to place a new node.',
|
|
|
|
addEdge: 'Add Reference',
|
2018-03-22 16:53:53 +01:00
|
|
|
editEdge: 'Edit Reference',
|
2018-03-21 17:24:52 +01:00
|
|
|
edgeDescription: 'Click on an Object and drag the edge to another Object (or Attribute) to connect them.'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2018-03-30 11:32:43 +02:00
|
|
|
var default_layout_option = $.extend(true, {}, network_options);
|
2018-03-21 17:24:52 +01:00
|
|
|
|
|
|
|
var typeaheadOption = {
|
|
|
|
source: function (query, process) {
|
2018-04-09 13:39:45 +02:00
|
|
|
if (typeaheadDataSearch === undefined) { // caching
|
|
|
|
typeaheadDataSearch = dataHandler.get_typeaheadData_search();
|
2018-03-21 17:24:52 +01:00
|
|
|
}
|
2018-04-09 13:39:45 +02:00
|
|
|
process(typeaheadDataSearch);
|
2018-03-21 17:24:52 +01:00
|
|
|
},
|
|
|
|
updater: function(value) {
|
|
|
|
var nodeID = dataHandler.mapping_value_to_nodeID.get(value);
|
2018-03-30 10:23:50 +02:00
|
|
|
// in case we searched for an object relation
|
|
|
|
nodeID = nodeID === undefined ? dataHandler.mapping_obj_relation_value_to_nodeID.get(value) : nodeID;
|
2018-03-26 13:22:40 +02:00
|
|
|
// check if node in cluster
|
|
|
|
nested_length = eventGraph.network.findNode(nodeID).length;
|
|
|
|
if (nested_length > 1) { // Node is in cluster
|
|
|
|
// As vis.js cannot supply a way to uncluster a single node, we remove it and add it again
|
|
|
|
searched_node = eventGraph.nodes.get(nodeID);
|
|
|
|
// Remove old node and edges
|
|
|
|
eventGraph.nodes.remove(nodeID);
|
|
|
|
eventGraph.nodes.add(searched_node);
|
2018-03-26 13:31:03 +02:00
|
|
|
/* don't need to re-add the edge as it is the same */
|
|
|
|
eventGraph.focus_on_stabilized(nodeID);
|
|
|
|
} else {
|
|
|
|
// set focus to the network
|
|
|
|
eventGraph.network.focus(nodeID, {animation: true, scale: 1});
|
2018-03-26 13:22:40 +02:00
|
|
|
}
|
2018-03-21 17:24:52 +01:00
|
|
|
// select node and focus on it
|
|
|
|
eventGraph.network.selectNodes([nodeID]);
|
|
|
|
$("#network-typeahead").blur();
|
|
|
|
},
|
|
|
|
autoSelect: true
|
|
|
|
}
|
|
|
|
var max_displayed_char = 32;
|
|
|
|
var progressbar_length = 3; // divided by 100
|
|
|
|
var loadingText_fetching = 'Fetching data';
|
|
|
|
var loadingText_creating = 'Constructing network';
|
2018-03-26 16:18:36 +02:00
|
|
|
var loadingText_redrawing = 'Redrawing network';
|
2018-03-21 17:24:52 +01:00
|
|
|
|
2018-04-09 16:04:40 +02:00
|
|
|
var shortcut_text = "<b>V</b> Center camera"
|
|
|
|
+ "\n<b>X</b> Expaned node"
|
|
|
|
+ "\n<b>C</b> Collapse node"
|
|
|
|
+ "\n<b>SHIFT+E</b> Edit node"
|
|
|
|
+ "\n<b>SHIFT+F</b> Search for value"
|
|
|
|
+ "\n<b>SHIFT</b> Hold to add a reference"
|
|
|
|
+ "\n<b>DEL</b> Delete selected item"
|
|
|
|
+ "\n<b>RIGHT-CLICK</b> Open contextual menu";
|
2018-03-26 12:18:56 +02:00
|
|
|
|
|
|
|
function global_processProperties(clusterOptions, childNodes) {
|
|
|
|
var concerned_root_node;
|
|
|
|
var that = eventGraph;
|
|
|
|
that.cluster_index = that.cluster_index + 1;
|
|
|
|
var childrenCount = 0;
|
|
|
|
for (var i = 0; i < childNodes.length; i++) {
|
|
|
|
var childNodeID = childNodes[i].id
|
2018-04-06 16:44:40 +02:00
|
|
|
if ( childNodeID.includes("rootNode:")) {
|
2018-03-26 12:18:56 +02:00
|
|
|
concerned_root_node = childNodeID;
|
|
|
|
}
|
|
|
|
childrenCount += childNodes[i].childrenCount || 1;
|
|
|
|
}
|
2018-03-26 12:23:43 +02:00
|
|
|
childrenCount--; // -1 because 2 nodes merged into 1
|
2018-03-26 12:18:56 +02:00
|
|
|
clusterOptions.childrenCount = childrenCount;
|
|
|
|
clusterOptions.font = {size: Math.sqrt(childrenCount)*0.5+30}
|
|
|
|
clusterOptions.id = 'cluster:' + that.cluster_index;
|
|
|
|
if (concerned_root_node !== undefined) {
|
|
|
|
clusterOptions.icon = { size: Math.sqrt(childrenCount)*5+100 };
|
|
|
|
if (concerned_root_node == "rootNode:object") {
|
|
|
|
clusterOptions.label = "Unreferenced Objects (" + childrenCount + ")";
|
|
|
|
clusterOptions.x = root_node_x_pos;
|
|
|
|
clusterOptions.group = 'rootNodeObject';
|
|
|
|
} else if (concerned_root_node == "rootNode:attribute") {
|
|
|
|
clusterOptions.label = "Unreferenced Attributes (" + childrenCount + ")";
|
|
|
|
clusterOptions.x = -root_node_x_pos;
|
|
|
|
clusterOptions.group = 'rootNodeAttribute';
|
2018-04-06 16:44:40 +02:00
|
|
|
} else if (concerned_root_node == "rootNode:tag") {
|
|
|
|
clusterOptions.label = "Untagged elements (" + childrenCount + ")";
|
|
|
|
clusterOptions.x = -root_node_x_pos;
|
|
|
|
clusterOptions.group = 'rootNodeTag';
|
2018-04-09 11:12:26 +02:00
|
|
|
} else if (concerned_root_node == "rootNode:keyType") {
|
|
|
|
clusterOptions.label = "Empty value elements (" + childrenCount + ")";
|
|
|
|
clusterOptions.x = -root_node_x_pos;
|
|
|
|
clusterOptions.group = 'rootNodeKeyType';
|
2018-03-26 12:18:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
clusterOptions.y = 0
|
|
|
|
that.clusters.push({id:'cluster:' + that.cluster_index, scale: that.cur_scale, group: clusterOptions.group});
|
|
|
|
return clusterOptions;
|
|
|
|
}
|