Initial references graphs commit

pull/3063/head
root 2018-03-19 08:44:25 +00:00
parent 2857ee4f32
commit a3a6a77611
22 changed files with 503 additions and 1 deletions

View File

@ -4315,6 +4315,25 @@ class EventsController extends AppController {
return new CakeResponse(array('body' => json_encode($json), 'status' => 200, 'type' => 'json'));
}
public function getReferences($id, $type = 'event') {
$validTools = array('event');
if (!in_array($type, $validTools)) throw new MethodNotAllowedException('Invalid type.');
App::uses('ReferencesGraphTool', 'Tools');
$grapher = new ReferencesGraphTool();
$data = $this->request->is('post') ? $this->request->data : array();
$grapher->construct($this->Event, $this->Auth->user(), $data);
$json = $grapher->get_all_data($id);
array_walk_recursive($json, function(&$item, $key){
if(!mb_detect_encoding($item, 'utf-8', true)){
$item = utf8_encode($item);
}
});
$this->response->type('json');
return new CakeResponse(array('body' => json_encode($json), 'status' => 200, 'type' => 'json'));
}
public function delegation_index() {
$this->loadModel('EventDelegation');
$delegatedEvents = $this->EventDelegation->find('list', array(

View File

@ -0,0 +1,27 @@
<?php
class ReferencesGraphTool {
public function construct($eventModel, $user, $json) {
$this->__eventModel = $eventModel;
$this->__user = $user;
$this->__json = $json;
$this->__lookupTables = array(
'analysisLevels' => $this->__eventModel->analysisLevels,
'distributionLevels' => $this->__eventModel->Attribute->distributionLevels
);
return true;
}
public function get_all_data($id) {
$event = $this->__eventModel->fetchEvent($this->__user, array('eventid' => $id, 'flatten' => 0, 'includeTagRelations' => 1));
if (empty($event)) return $this->__json;
//return $event;
if (!empty($event[0]['Object'])) {
$this->__json['Object'] = $event[0]['Object'];
}
if (!empty($event[0]['Attribute'])) {
$this->__json['Attribute'] = $event[0]['Attribute'];
}
return $this->__json;
}
}
?>

View File

@ -331,6 +331,9 @@
<button class="btn btn-inverse toggle qet galaxy-toggle-button" id="galaxies_toggle" data-toggle-type="galaxies">
<span class="icon-minus icon-white" title="<?php echo __('Toggle galaxies');?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle galaxies');?>" style="vertical-align:top;"></span><?php echo __('Galaxy');?>
</button>
<button class="btn btn-inverse toggle qet galaxy-toggle-button" id="references_toggle" data-toggle-type="references">
<span class="icon-minus icon-white" title="<?php echo __('Toggle references');?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle references');?>" style="vertical-align:top;"></span><?php echo __('References');?>
</button>
<button class="btn btn-inverse toggle qet galaxy-toggle-button" id="attributes_toggle" data-toggle-type="attributes">
<span class="icon-minus icon-white" title="<?php echo __('Toggle attributes');?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle attributes');?>" style="vertical-align:top;"></span><?php echo __('Attributes');?>
</button>
@ -347,6 +350,9 @@
<h4 class="blue"><?php echo __('Galaxies');?></h4>
<?php echo $this->element('galaxyQuickView', array('mayModify' => $mayModify, 'isAclTagger' => $isAclTagger)); ?>
</div>
<div id="references_div" class="info_container_references_network">
<div id="references_network" class="references_network" data-event-id="<?php echo h($event['Event']['id']); ?>" data-user-manipulation="<?php echo h($mayModify) ? 'true' : 'false'; ?>"></div>
</div>
<div id="attributes_div">
<?php echo $this->element('eventattribute'); ?>
</div>
@ -371,4 +377,8 @@ $(document).ready(function () {
});
});
</script>
<input type="hidden" value="/shortcuts/event_view.json" class="keyboardShortcutsConfig" />
<input type="hidden" value="/shortcuts/event_view.json" class="keyboardShortcutsConfig" />
<?php echo $this->Html->script('vis'); ?>
<?php echo $this->Html->css('vis'); ?>
<?php echo $this->Html->css('references-graph'); ?>
<?php echo $this->Html->script('references-graph'); ?>

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -0,0 +1,13 @@
.info_container_references_network {
margin-top: 10px;
border: 1px solid #0088cc;
border-radius: 7px;
box-shadow: 0px 0px 6px #B2B2B2;
padding: 2px;
width: 100%;
height: 800px;
}
.references_network {
height: inherit;
}

1
app/webroot/css/vis.css Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,385 @@
// Util
function getRandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
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';
}
}
function get_node_color(uuid) {
return nodes.get(uuid).icon.color;
}
// Global var
var scope_id = $('#references_network').data('event-id');
var container = document.getElementById('references_network');
var nodes = new vis.DataSet();
var edges = new vis.DataSet();
var map_id_to_uuid = new Map();
var map_fromto_to_rel_id = new Map();
var all_obj_relation = new Map();
var user_manipulation = $('#references_network').data('user-manipulation');
var data = {
nodes: nodes,
edges: edges
};
// Options
var network_options = {
interaction: {
hover: true
},
manipulation: {
enabled: user_manipulation,
initiallyActive: true,
addEdge: add_reference,
editEdge: false,
addNode: false,
deleteNode: false,
deleteEdge: remove_reference
},
physics: {
enabled: true,
barnesHut: {
gravitationalConstant: -10000,
centralGravity: 0.3,
springLength: 150,
springConstant: 0.24,
damping: 0.6,
}
},
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;
shadowColor: "rgba(0,0,0,0.1)"
}
}
},
groups: {
object: {
shape: 'icon',
icon: {
face: 'FontAwesome',
code: '\uf00a',
size: 50,
},
font: {
size: 18, // px
background: 'white'
}
},
obj_relation: {
size: 10,
color: {
border:'black'
},
},
attribute: {
shape: 'box',
color: {
background:'orange',
border:'black'
},
size: 15
},
},
locales: {
en: {
edit: 'Edit',
del: 'Delete selected',
back: 'Back',
addEdge: 'Add Reference',
edgeDescription: 'Click on an Object and drag the edge to another Object (or Attribute) to connect them.'
}
}
};
// Graph interaction
function collapse_node(parent_id) {
if (parent_id === undefined) { // node node selected
return
}
var connected_nodes = network.getConnectedNodes(parent_id);
var connected_edges = network.getConnectedEdges(parent_id);
// Remove nodes
for (var nodeID of connected_nodes) {
// Object's attribute are in UUID format (while other object or in simple integer)
if (nodeID.length > 10) {
nodes.remove(nodeID);
}
}
// Remove edges
for (var edgeID of connected_edges) {
// Object's attribute (edge) are in UUID format (while other object or in simple integer)
if (edgeID.length > 10) {
edges.remove(edgeID);
}
}
}
function expand_node(parent_id) {
if (parent_id === undefined) { // node node selected
return;
} else if (nodes.get(parent_id).group == "attribute") { // cannot expand attribute
return;
}
newNodes = [];
newRelations = [];
for(var attr of all_obj_relation.get(parent_id)) {
var parent_color = get_node_color(parent_id);
// Ensure unicity of nodes
if (nodes.get(attr.uuid) !== null) {
continue;
}
var node = {
id: attr.uuid,
label: attr.type + ': ' + attr.value,
group: 'obj_relation',
color: {
background: parent_color
},
font: {
color: getTextColour(parent_color)
}
};
newNodes.push(node);
var rel = {
from: parent_id,
to: attr.uuid,
arrows: '',
color: {
opacity: 0.5,
color: parent_color
},
length: 40
};
newRelations.push(rel);
}
nodes.add(newNodes);
edges.add(newRelations);
}
function remove_reference(edgeData, callback) {
edge_id = edgeData.edges[0];
var fromto = edge_id;
var relation_id = map_fromto_to_rel_id.get(fromto);
deleteObject('object_references', 'delete', relation_id, scope_id);
}
function add_reference(edgeData, callback) {
var uuid = map_id_to_uuid.get(edgeData.to);
genericPopup('/objectReferences/add/'+edgeData.from, '#popover_form', function() {
$('#targetSelect').val(uuid);
$('option[value='+uuid+']').click()
});
}
function reset_graphs() {
nodes.clear();
edges.clear();
}
function update_graph(data) {
reset_graphs();
newNodes = [];
for(var node of data.items) {
var group, label;
if ( node.node_type == 'object' ) {
group = 'object';
label = '('+node.val+') ' + node.type;
label = node.type;
} else {
group = 'attribute';
label = node.type + ': ' + node.val;
}
var node = {
id: node.id,
label: label,
group: group,
mass: 5,
icon: {
color: getRandomColor()
}
};
newNodes.push(node);
}
nodes.update(newNodes);
newRelations = [];
for(var rel of data.relations) {
var fromto = rel.from + '-' + rel.to;
var rel = {
id: fromto,
from: rel.from,
to: rel.to,
label: rel.type,
title: rel.comment,
color: {
opacity: 1.0
}
};
newRelations.push(rel);
}
edges.update(newRelations);
}
// Data
function extract_references(data) {
var items = [];
var relations = [];
if (data.Attribute !== undefined) {
for (var attr of data.Attribute) {
map_id_to_uuid.set(attr.id, attr.uuid);
items.push({
'id': attr.id,
'type': attr.type,
'val': attr.value,
'node_type': 'attribute'
});
}
}
if (data.Object !== undefined) {
for (var obj of data.Object) {
map_id_to_uuid.set(obj.id, obj.uuid);
all_obj_relation.set(obj.id, obj.Attribute);
items.push({
'id': obj.id,
'type': obj.name,
'val': obj.value,
'node_type': 'object'
});
for (var rel of obj.ObjectReference) {
var fromto = obj.id + '-' + rel.referenced_id;
map_fromto_to_rel_id.set(fromto, rel.id);
relations.push({
'from': obj.id,
'to': rel.referenced_id,
'type': rel.relationship_type,
'comment': rel.comment != "" ? rel.comment : "[Comment not set]"
});
}
}
}
return {
items: items,
relations: relations
}
}
function fetch_data_and_update() {
$.getJSON( "/events/getReferences/"+scope_id+"/event.json", function( data ) {
extracted = extract_references(data);
update_graph(extracted);
});
}
$( document ).ready(function() {
network = new vis.Network(container, data, network_options);
network.on("selectNode", function (params) {
network.moveTo({
position: {
x: params.pointer.canvas.x,
y: params.pointer.canvas.y
},
animation: true,
});
});
$(document).on("keydown", function(evt) {
switch(evt.keyCode) {
case 88: // x
var selected_id = network.getSelectedNodes()[0];
expand_node(selected_id);
break;
case 67: // c
var selected_id = network.getSelectedNodes()[0];
collapse_node(selected_id);
break;
case 86: // v
network.moveTo({
position: {
x: 0,
y: 0
},
animation: true,
});
break;
case 16: // <SHIFT>
if (!user_manipulation) { // user can't modify references
break;
}
network.addEdgeMode(); // toggle edit mode
break;
case 46: // <Delete>
if (!user_manipulation) { // user can't modify references
break;
}
var selected_id = network.getSelectedEdges()[0];
var edge = { edges: [selected_id] }; // trick to use the same function
remove_reference(edge);
break;
default:
break;
}
});
$(document).on("keyup", function(evt) {
switch(evt.keyCode) {
case 16: // <SHIFT>
if (!user_manipulation) { // user can't modify references
break;
}
network.disableEditMode(); // un-toggle edit mode
break;
default:
break;
}
});
fetch_data_and_update();
});

47
app/webroot/js/vis.js Normal file

File diff suppressed because one or more lines are too long