mirror of https://github.com/MISP/MISP
new: First round of updates to the correlation engine ready
- node deletion temporarily disabled until a bug is resolvedpull/2547/head
parent
b5b4652c61
commit
fa7d3fdb36
|
@ -3955,12 +3955,23 @@ class EventsController extends AppController {
|
||||||
$event = $this->Event->fetchEvent($this->Auth->user(), array('eventid' => $id));
|
$event = $this->Event->fetchEvent($this->Auth->user(), array('eventid' => $id));
|
||||||
if (empty($event)) throw new MethodNotAllowedException('Invalid Event.');
|
if (empty($event)) throw new MethodNotAllowedException('Invalid Event.');
|
||||||
$this->set('event', $event[0]);
|
$this->set('event', $event[0]);
|
||||||
|
$this->set('scope', 'event');
|
||||||
$this->set('id', $id);
|
$this->set('id', $id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
public function deleteNode($id) {
|
||||||
|
if (!$this->request->is('post')) throw new MethodNotAllowedException('Only POST requests are allowed.');
|
||||||
|
App::uses('CorrelationGraphTool', 'Tools');
|
||||||
|
$grapher = new CorrelationGraphTool();
|
||||||
|
$grapher->construct($this->Event, $this->Taxonomy, $this->GalaxyCluster, $this->Auth->user(), $this->request->data);
|
||||||
|
$json = $grapher->deleteNode($id);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
public function updateGraph($id, $type = 'event') {
|
public function updateGraph($id, $type = 'event') {
|
||||||
$validTools = array('event', 'galaxy', 'tag');
|
$validTools = array('event', 'galaxy', 'tag');
|
||||||
if (!in_array($type, $validTools)) throw new NotAllowedException('Invalid type.');
|
if (!in_array($type, $validTools)) throw new MethodNotAllowedException('Invalid type.');
|
||||||
$this->loadModel('Taxonomy');
|
$this->loadModel('Taxonomy');
|
||||||
$this->loadModel('GalaxyCluster');
|
$this->loadModel('GalaxyCluster');
|
||||||
App::uses('CorrelationGraphTool', 'Tools');
|
App::uses('CorrelationGraphTool', 'Tools');
|
||||||
|
|
|
@ -140,4 +140,18 @@ class GalaxiesController extends AppController {
|
||||||
$this->redirect($this->referer());
|
$this->redirect($this->referer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function viewGraph($id) {
|
||||||
|
$cluster = $this->Galaxy->GalaxyCluster->find('first', array(
|
||||||
|
'conditions' => array('GalaxyCluster.id' => $id),
|
||||||
|
'contain' => array('Galaxy'),
|
||||||
|
'recursive' => -1
|
||||||
|
));
|
||||||
|
if (empty($cluster)) throw new MethodNotAllowedException('Invalid Galaxy.');
|
||||||
|
$this->set('cluster', $cluster);
|
||||||
|
$this->set('scope', 'galaxy');
|
||||||
|
$this->set('id', $id);
|
||||||
|
$this->set('galaxy_id' , $cluster['Galaxy']['id']);
|
||||||
|
$this->render('/Events/view_graph');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,6 +113,8 @@ class GalaxyClustersController extends AppController {
|
||||||
$cluster['GalaxyCluster']['tag_id'] = $tag['Tag']['id'];
|
$cluster['GalaxyCluster']['tag_id'] = $tag['Tag']['id'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$this->set('id', $id);
|
||||||
|
$this->set('galaxy_id' , $cluster['Galaxy']['id']);
|
||||||
$this->set('cluster', $cluster);
|
$this->set('cluster', $cluster);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -749,4 +749,20 @@ class TagsController extends AppController {
|
||||||
return $this->RestResponse->saveFailResponse('Tags', 'removeTagFromObject', false, 'Failed to remove tag from object.', $this->response->type());
|
return $this->RestResponse->saveFailResponse('Tags', 'removeTagFromObject', false, 'Failed to remove tag from object.', $this->response->type());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function viewGraph($id) {
|
||||||
|
$tag = $this->Tag->find('first', array(
|
||||||
|
'conditions' => array('Tag.id' => $id),
|
||||||
|
'recursive' => -1
|
||||||
|
));
|
||||||
|
if (empty($tag)) throw new MethodNotAllowedException('Invalid Tag.');
|
||||||
|
$this->loadModel('Taxonomy');
|
||||||
|
$taxonomy = $this->Taxonomy->getTaxonomyForTag($tag['Tag']['name']);
|
||||||
|
if (!empty($taxonomy)) {
|
||||||
|
$this->set('taxonomy', $taxonomy);
|
||||||
|
}
|
||||||
|
$this->set('scope', 'tag');
|
||||||
|
$this->set('id', $id);
|
||||||
|
$this->render('/Events/view_graph');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,6 @@
|
||||||
|
|
||||||
public function buildGraphJson($id, $type = 'event', $action = 'create') {
|
public function buildGraphJson($id, $type = 'event', $action = 'create') {
|
||||||
if ($action == 'delete') {
|
if ($action == 'delete') {
|
||||||
|
|
||||||
return $this->__json;
|
return $this->__json;
|
||||||
}
|
}
|
||||||
switch ($type) {
|
switch ($type) {
|
||||||
|
@ -76,10 +75,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
private function __deleteObject($id) {
|
private function __deleteObject($id) {
|
||||||
unset($this->__json['nodes'][$id]);
|
$this->cleanLinks();
|
||||||
foreach ($this->__json['links'] as $k => $link) {
|
return $this->__json;
|
||||||
debug($link);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function __handleObjects($objects, $anchor_id, $full = false) {
|
private function __handleObjects($objects, $anchor_id, $full = false) {
|
||||||
|
@ -121,6 +118,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function __addTag($id) {
|
||||||
|
$tag = $this->__eventModel->EventTag->Tag->find('first', array(
|
||||||
|
'conditions' => array('Tag.id' => $id),
|
||||||
|
'recursive' => -1
|
||||||
|
));
|
||||||
|
return $this->__createNode('tag', $tag['Tag']);
|
||||||
|
}
|
||||||
|
|
||||||
private function __handleTags($tags, $anchor_id) {
|
private function __handleTags($tags, $anchor_id) {
|
||||||
foreach ($tags as $tag) {
|
foreach ($tags as $tag) {
|
||||||
if (strpos($tag['name'], 'misp-galaxy:') === 0) {
|
if (strpos($tag['name'], 'misp-galaxy:') === 0) {
|
||||||
|
@ -143,7 +148,9 @@
|
||||||
|
|
||||||
private function __expandTag($id) {
|
private function __expandTag($id) {
|
||||||
$current_tag_id = $this->graphJsonContains('tag', array('id' => $id));
|
$current_tag_id = $this->graphJsonContains('tag', array('id' => $id));
|
||||||
if (empty($current_tag_id)) return false;
|
if (empty($current_tag_id)) {
|
||||||
|
$current_tag_id = $this->__addTag($id);
|
||||||
|
}
|
||||||
$this->cleanLinks();
|
$this->cleanLinks();
|
||||||
$events = $this->__eventModel->EventTag->Tag->fetchSimpleEventsForTag($id, $this->__user);
|
$events = $this->__eventModel->EventTag->Tag->fetchSimpleEventsForTag($id, $this->__user);
|
||||||
foreach ($events as $event) {
|
foreach ($events as $event) {
|
||||||
|
@ -161,13 +168,17 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
private function __expandGalaxy($id) {
|
private function __expandGalaxy($id) {
|
||||||
|
if (!empty($this->__json['nodes'])) {
|
||||||
foreach ($this->__json['nodes'] as $k => $node) {
|
foreach ($this->__json['nodes'] as $k => $node) {
|
||||||
if ($node['type'] == 'galaxy' && $node['id'] == $id) {
|
if ($node['type'] == 'galaxy' && $node['id'] == $id) {
|
||||||
$current_galaxy_id = $k;
|
$current_galaxy_id = $k;
|
||||||
$tag_name = $node['tag_name'];
|
$tag_name = $node['tag_name'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (empty($current_galaxy_id)) return false;
|
}
|
||||||
|
if (empty($current_galaxy_id)) {
|
||||||
|
$current_galaxy_id = $this->__addGalaxy($id);
|
||||||
|
}
|
||||||
$this->cleanLinks();
|
$this->cleanLinks();
|
||||||
$events = $this->__eventModel->EventTag->Tag->fetchSimpleEventsForTag($this->__json['nodes'][$current_galaxy_id]['tag_name'], $this->__user, true);
|
$events = $this->__eventModel->EventTag->Tag->fetchSimpleEventsForTag($this->__json['nodes'][$current_galaxy_id]['tag_name'], $this->__user, true);
|
||||||
foreach ($events as $event) {
|
foreach ($events as $event) {
|
||||||
|
@ -177,6 +188,15 @@
|
||||||
$this->_json['nodes'][$current_galaxy_id]['expanded'] = 1;
|
$this->_json['nodes'][$current_galaxy_id]['expanded'] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function __addGalaxy($id) {
|
||||||
|
$temp = $this->__galaxyClusterModel->getCluster($id);
|
||||||
|
// move stuff around to resemble the galaxies attached to events
|
||||||
|
$galaxy = $temp['GalaxyCluster']['Galaxy'];
|
||||||
|
unset($temp['GalaxyCluster']['Galaxy']);
|
||||||
|
$galaxy['GalaxyCluster'][0] = $temp['GalaxyCluster'];
|
||||||
|
return $this->__createNode('galaxy', $galaxy);
|
||||||
|
}
|
||||||
|
|
||||||
private function __addLink($from_id, $to_id, $linkDistance = 150) {
|
private function __addLink($from_id, $to_id, $linkDistance = 150) {
|
||||||
$link = $this->graphJsonContainsLink($from_id, $to_id);
|
$link = $this->graphJsonContainsLink($from_id, $to_id);
|
||||||
if ($link === false) $this->__json['links'][] = array('source' => $from_id, 'target' => $to_id, 'linkDistance' => $linkDistance);
|
if ($link === false) $this->__json['links'][] = array('source' => $from_id, 'target' => $to_id, 'linkDistance' => $linkDistance);
|
||||||
|
@ -304,8 +324,8 @@
|
||||||
foreach ($this->__json['nodes'] as $k => $node) {
|
foreach ($this->__json['nodes'] as $k => $node) {
|
||||||
if ($link['source'] == $node) $temp['source'] = $k;
|
if ($link['source'] == $node) $temp['source'] = $k;
|
||||||
if ($link['target'] == $node) $temp['target'] = $k;
|
if ($link['target'] == $node) $temp['target'] = $k;
|
||||||
$temp['linkDistance'] = $link['linkDistance'];
|
|
||||||
}
|
}
|
||||||
|
$temp['linkDistance'] = $link['linkDistance'];
|
||||||
$links[] = $temp;
|
$links[] = $temp;
|
||||||
}
|
}
|
||||||
$this->__json['links'] = $links;
|
$this->__json['links'] = $links;
|
||||||
|
@ -333,7 +353,7 @@
|
||||||
if ($type == 'event' && $node['type'] == 'event' && $node['id'] == $element['id']) {
|
if ($type == 'event' && $node['type'] == 'event' && $node['id'] == $element['id']) {
|
||||||
return $k;
|
return $k;
|
||||||
}
|
}
|
||||||
if ($type == 'attribute' && $node['type'] == 'attribute' && $node['id'] == $element['id']) {
|
if ($type == 'attribute' && $node['type'] == 'attribute' && $node['name'] == $element['value']) {
|
||||||
return $k;
|
return $k;
|
||||||
}
|
}
|
||||||
if ($type == 'tag' && $node['type'] == 'tag' && $node['id'] == $element['id']) {
|
if ($type == 'tag' && $node['type'] == 'tag' && $node['id'] == $element['id']) {
|
||||||
|
|
|
@ -49,7 +49,6 @@ class Galaxy extends AppModel{
|
||||||
}
|
}
|
||||||
foreach ($galaxies as $k => $galaxy) {
|
foreach ($galaxies as $k => $galaxy) {
|
||||||
if (isset($existingGalaxies[$galaxy['uuid']])) {
|
if (isset($existingGalaxies[$galaxy['uuid']])) {
|
||||||
//debug($galaxy);
|
|
||||||
if (
|
if (
|
||||||
$existingGalaxies[$galaxy['uuid']]['version'] < $galaxy['version'] ||
|
$existingGalaxies[$galaxy['uuid']]['version'] < $galaxy['version'] ||
|
||||||
(!empty($galaxy['icon']) && ($existingGalaxies[$galaxy['uuid']]['icon'] != $galaxy['icon']))
|
(!empty($galaxy['icon']) && ($existingGalaxies[$galaxy['uuid']]['icon'] != $galaxy['icon']))
|
||||||
|
@ -62,7 +61,6 @@ class Galaxy extends AppModel{
|
||||||
$this->save($galaxy);
|
$this->save($galaxy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//throw new Exception();
|
|
||||||
return $this->find('list', array('recursive' => -1, 'fields' => array('type', 'id')));
|
return $this->find('list', array('recursive' => -1, 'fields' => array('type', 'id')));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
<li class="divider"></li>
|
<li class="divider"></li>
|
||||||
<?php endif;?>
|
<?php endif;?>
|
||||||
<li id='liviewEvent'><a href="<?php echo $baseurl;?>/events/view/<?php echo h($event['Event']['id']);?>">View Event</a></li>
|
<li id='liviewEvent'><a href="<?php echo $baseurl;?>/events/view/<?php echo h($event['Event']['id']);?>">View Event</a></li>
|
||||||
<li id='liviewEventGraph'><a href="<?php echo $baseurl;?>/events/viewGraph/<?php echo h($event['Event']['id']);?>">View Correlation Graph</a></li>
|
<li id='liviewGraph'><a href="<?php echo $baseurl;?>/events/viewGraph/<?php echo h($event['Event']['id']);?>">View Correlation Graph</a></li>
|
||||||
<li id='lieventLog'><a href="<?php echo $baseurl;?>/logs/event_index/<?php echo h($event['Event']['id']);?>">View Event History</a></li>
|
<li id='lieventLog'><a href="<?php echo $baseurl;?>/logs/event_index/<?php echo h($event['Event']['id']);?>">View Event History</a></li>
|
||||||
<li class="divider"></li>
|
<li class="divider"></li>
|
||||||
<?php if ($isSiteAdmin || (isset($mayModify) && $mayModify)): ?>
|
<?php if ($isSiteAdmin || (isset($mayModify) && $mayModify)): ?>
|
||||||
|
@ -273,13 +273,25 @@
|
||||||
case 'tags': ?>
|
case 'tags': ?>
|
||||||
<li id='liindexfav'><?php echo $this->Html->link('List Favourite Tags', array('action' => 'index', true));?></li>
|
<li id='liindexfav'><?php echo $this->Html->link('List Favourite Tags', array('action' => 'index', true));?></li>
|
||||||
<li id='liindex'><?php echo $this->Html->link('List Tags', array('action' => 'index'));?></li>
|
<li id='liindex'><?php echo $this->Html->link('List Tags', array('action' => 'index'));?></li>
|
||||||
<?php if ($isAclTagEditor): ?>
|
<?php
|
||||||
|
if ($isAclTagEditor):
|
||||||
|
?>
|
||||||
<li id='liadd'><?php echo $this->Html->link('Add Tag', array('action' => 'add'));?></li>
|
<li id='liadd'><?php echo $this->Html->link('Add Tag', array('action' => 'add'));?></li>
|
||||||
<?php
|
<?php
|
||||||
endif;
|
endif;
|
||||||
if ($menuItem === 'edit'):
|
if ($menuItem === 'edit'):
|
||||||
?>
|
?>
|
||||||
<li class="active"><?php echo $this->Html->link('Edit Tag', array('action' => 'edit'));?></li>
|
<li class="active"><?php echo $this->Html->link('Edit Tag', array('action' => 'edit'));?></li>
|
||||||
|
<?php
|
||||||
|
endif;
|
||||||
|
if ($menuItem === 'viewGraph'):
|
||||||
|
if (!empty($taxonomy)):
|
||||||
|
?>
|
||||||
|
<li><a href="<?php echo $baseurl; ?>/taxonomies/view/<?php echo h($taxonomy['Taxonomy']['id']); ?>">View Taxonomy</a></li>
|
||||||
|
<?php
|
||||||
|
endif;
|
||||||
|
?>
|
||||||
|
<li id='liviewGraph'><a href="<?php echo $baseurl;?>/tags/viewGraph/<?php echo h($id); ?>">View Correlation Graph</a></li>
|
||||||
<?php
|
<?php
|
||||||
endif;
|
endif;
|
||||||
break;
|
break;
|
||||||
|
@ -350,14 +362,16 @@
|
||||||
<li><?php echo $this->Form->postLink('Update Galaxies', array('controller' => 'galaxies', 'action' => 'update'), null, __('Are you sure you want to reimport all galaxies from the submodule?')); ?></li>
|
<li><?php echo $this->Form->postLink('Update Galaxies', array('controller' => 'galaxies', 'action' => 'update'), null, __('Are you sure you want to reimport all galaxies from the submodule?')); ?></li>
|
||||||
<?php
|
<?php
|
||||||
endif;
|
endif;
|
||||||
|
if ($menuItem === 'viewGraph' || $menuItem === 'view_cluster'): ?>
|
||||||
|
<li><a href="<?php echo $baseurl;?>/galaxies/view/<?php echo h($galaxy_id); ?>">View Galaxy</a></li>
|
||||||
|
<li id='liview_cluster'><a href="<?php echo $baseurl;?>/galaxy_clusters/view/<?php echo h($id); ?>">View Cluster</a></li>
|
||||||
|
<li id='liviewGraph'><a href="<?php echo $baseurl;?>/galaxies/viewGraph/<?php echo h($id); ?>">View Correlation Graph</a></li>
|
||||||
|
<?php
|
||||||
|
endif;
|
||||||
|
|
||||||
if ($menuItem === 'view'):
|
if ($menuItem === 'view'):
|
||||||
?>
|
?>
|
||||||
<li class="active"><a href="#">View Galaxy</a></li>
|
<li class="active"><a href="#">View Galaxy</a></li>
|
||||||
<?php
|
|
||||||
endif;
|
|
||||||
if ($menuItem === 'view_cluster'):
|
|
||||||
?>
|
|
||||||
<li class="active"><a href="#">View Cluster</a></li>
|
|
||||||
<?php
|
<?php
|
||||||
endif;
|
endif;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,91 +1,13 @@
|
||||||
<?php
|
<?php
|
||||||
|
if ($scope == 'event') {
|
||||||
$mayModify = (($isAclModify && $event['Event']['user_id'] == $me['id'] && $event['Orgc']['id'] == $me['org_id']) || ($isAclModifyOrg && $event['Orgc']['id'] == $me['org_id']));
|
$mayModify = (($isAclModify && $event['Event']['user_id'] == $me['id'] && $event['Orgc']['id'] == $me['org_id']) || ($isAclModifyOrg && $event['Orgc']['id'] == $me['org_id']));
|
||||||
$mayPublish = ($isAclPublish && $event['Orgc']['id'] == $me['org_id']);
|
$mayPublish = ($isAclPublish && $event['Orgc']['id'] == $me['org_id']);
|
||||||
|
}
|
||||||
echo $this->Html->css('font-awesome');
|
echo $this->Html->css('font-awesome');
|
||||||
echo $this->Html->script('d3'); ?>
|
echo $this->Html->css('correlation-graph');
|
||||||
<style>
|
echo $this->Html->script('d3');
|
||||||
|
echo $this->Html->script('correlation-graph');
|
||||||
.node circle {
|
?>
|
||||||
cursor: pointer;
|
|
||||||
stroke: #3182bd;
|
|
||||||
stroke-width: 1.5px;
|
|
||||||
}
|
|
||||||
.node text {
|
|
||||||
font: 10px sans-serif;
|
|
||||||
pointer-events: none;
|
|
||||||
text-anchor: middle;
|
|
||||||
}
|
|
||||||
line.link {
|
|
||||||
fill: none;
|
|
||||||
stroke: #9ecae1;
|
|
||||||
stroke-width: 1.5px;
|
|
||||||
}
|
|
||||||
#main {
|
|
||||||
display: inline-block;
|
|
||||||
background-color: grey;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.menu {
|
|
||||||
border: 1px solid black;
|
|
||||||
background-color: grey;
|
|
||||||
display: none;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.menu,
|
|
||||||
.menu li {
|
|
||||||
padding: 0px;
|
|
||||||
margin: 0px;
|
|
||||||
width: 250px;
|
|
||||||
}
|
|
||||||
.menu li {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
.menu > li:hover {
|
|
||||||
background-color: lightblue;
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
.menu li {
|
|
||||||
display: block;
|
|
||||||
word-wrap: break-word;
|
|
||||||
}
|
|
||||||
.menu li:hover ul {
|
|
||||||
display:inline-block;
|
|
||||||
position: relative;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
.menu > li > span > a {
|
|
||||||
color:white;
|
|
||||||
font-weight:bold;
|
|
||||||
}
|
|
||||||
.menu > li > span:first-child {
|
|
||||||
font-weight:bold;
|
|
||||||
}
|
|
||||||
.graphMenuTitle {
|
|
||||||
background-color:#0088cc;
|
|
||||||
font-weight:bold;
|
|
||||||
color:white;
|
|
||||||
}
|
|
||||||
.graphMenuActions {
|
|
||||||
background-color:#0088cc;
|
|
||||||
color:white;
|
|
||||||
}
|
|
||||||
.graphMenuAction {
|
|
||||||
cursor: hand;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu-container {
|
|
||||||
position:absolute;
|
|
||||||
width:300px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.font-white {
|
|
||||||
color:white;
|
|
||||||
}
|
|
||||||
.corrected-icon {
|
|
||||||
top:-5px;
|
|
||||||
margin-left:100px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<div class="view">
|
<div class="view">
|
||||||
<div id="chart" style="width:100%;height:100%"></div>
|
<div id="chart" style="width:100%;height:100%"></div>
|
||||||
<div id="hover-menu-container" class="menu-container">
|
<div id="hover-menu-container" class="menu-container">
|
||||||
|
@ -103,466 +25,26 @@ echo $this->Html->script('d3'); ?>
|
||||||
<li id="context-delete">Delete</li>
|
<li id="context-delete">Delete</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="graph_init" class="hidden" data-id="<?php echo h($id);?>" data-scope="<?php echo h($scope);?>">
|
||||||
|
</div>
|
||||||
<?php
|
<?php
|
||||||
echo $this->element('side_menu', array('menuList' => 'event', 'menuItem' => 'viewEventGraph', 'mayModify' => $mayModify, 'mayPublish' => $mayPublish));
|
$scope_list = array(
|
||||||
?>
|
'event' => 'event',
|
||||||
<script>
|
'galaxy' => 'galaxies',
|
||||||
var currentMousePos = { x: -1, y: -1 };
|
'tag' => 'tags'
|
||||||
$(document).mousemove(function(event) {
|
|
||||||
currentMousePos.x = event.pageX;
|
|
||||||
currentMousePos.y = event.pageY;
|
|
||||||
});
|
|
||||||
|
|
||||||
var margin = {top: -5, right: -5, bottom: -5, left: -5},
|
|
||||||
width = $(window).width() - margin.left - margin.right,
|
|
||||||
height = $(window).height() - 160 - margin.top - margin.bottom;
|
|
||||||
var menu_x_buffer_ = width - 150;
|
|
||||||
var menu_y_buffer = height - 100;
|
|
||||||
$('.menu-container').css('left', '200px');
|
|
||||||
$('#hover-menu-container').css('top', '50px');
|
|
||||||
$('#hover-menu-container').css('z-index', 1);
|
|
||||||
$('#selected-menu-container').css('top', '400px');
|
|
||||||
$('#selected-menu-container').css('z-index', 2);
|
|
||||||
|
|
||||||
var root;
|
|
||||||
|
|
||||||
var highlighted;
|
|
||||||
var hovered;
|
|
||||||
|
|
||||||
var icon_sizes = {
|
|
||||||
"event": 24,
|
|
||||||
"object": 12,
|
|
||||||
"attribute": 12,
|
|
||||||
"galaxy": 32,
|
|
||||||
"tag": 24
|
|
||||||
}
|
|
||||||
|
|
||||||
var selection_radius_sizes = {
|
|
||||||
"event": 18,
|
|
||||||
"object": 12,
|
|
||||||
"attribute": 12,
|
|
||||||
"galaxy": 18,
|
|
||||||
"tag": 18
|
|
||||||
}
|
|
||||||
|
|
||||||
var force = d3.layout.force()
|
|
||||||
.linkDistance(function (d) {
|
|
||||||
return d.linkDistance;
|
|
||||||
})
|
|
||||||
.linkStrength(0.9)
|
|
||||||
.friction(0.5)
|
|
||||||
.theta(0.9)
|
|
||||||
.charge(-500)
|
|
||||||
.gravity(0.21)
|
|
||||||
.size([width, height])
|
|
||||||
.on("tick", tick);
|
|
||||||
|
|
||||||
var vis = d3.select("#chart");
|
|
||||||
|
|
||||||
var svg = vis.append("svg:svg")
|
|
||||||
.attr("width", width)
|
|
||||||
.attr("height", height)
|
|
||||||
.attr("pointer-events", "all");
|
|
||||||
|
|
||||||
var rect = svg.append("svg:rect")
|
|
||||||
.attr('width', width)
|
|
||||||
.attr('height', height)
|
|
||||||
.attr('fill', 'white')
|
|
||||||
.call(d3.behavior.zoom().on("zoom", zoomhandler));
|
|
||||||
|
|
||||||
var plotting_area = svg.append("g")
|
|
||||||
.attr("class", "plotting-area");
|
|
||||||
|
|
||||||
var drag1 = d3.behavior.drag()
|
|
||||||
.on("dragstart", dragstart)
|
|
||||||
.on("drag", dragmove)
|
|
||||||
.on("dragend", dragend);
|
|
||||||
|
|
||||||
var link = plotting_area.selectAll(".link");
|
|
||||||
var node = plotting_area.selectAll(".node");
|
|
||||||
|
|
||||||
d3.json("/events/updateGraph/<?php echo $id; ?>.json", function(error, json) {
|
|
||||||
root = json;
|
|
||||||
update();
|
|
||||||
});
|
|
||||||
|
|
||||||
var graphElementScale = 1;
|
|
||||||
var graphElementTranslate = [0, 0];
|
|
||||||
|
|
||||||
function zoomhandler() {
|
|
||||||
plotting_area.attr("transform",
|
|
||||||
"translate(" + d3.event.translate + ")"
|
|
||||||
+ " scale(" + d3.event.scale + ")");
|
|
||||||
graphElementScale = d3.event.scale;
|
|
||||||
graphElementTranslate = d3.event.translate;
|
|
||||||
}
|
|
||||||
|
|
||||||
function update() {
|
|
||||||
var nodes = root['nodes'], links = root['links'];
|
|
||||||
|
|
||||||
|
|
||||||
// Restart the force layout.
|
|
||||||
force.nodes(nodes).links(links).start();
|
|
||||||
|
|
||||||
// Update links.
|
|
||||||
link = link.data(links);
|
|
||||||
link.exit().remove();
|
|
||||||
link.enter().insert("line", ".node").attr("class", "link");
|
|
||||||
// Update nodes.
|
|
||||||
node = node.data(nodes);
|
|
||||||
node.exit().remove();
|
|
||||||
|
|
||||||
var nodeEnter = node.enter().append("g").attr("class", "node").call(drag1);
|
|
||||||
|
|
||||||
nodeEnter.attr('id', function(d) { return 'id-' + d.unique_id; })
|
|
||||||
|
|
||||||
nodeEnter.insert("circle", ".circle")
|
|
||||||
.classed("highlighted_circle", true)
|
|
||||||
.attr("cx", function(d) { return d.x_axis; })
|
|
||||||
.attr("cy", function(d) { return d.y_axis; })
|
|
||||||
.attr("r", function(d) { return selection_radius_sizes[d.type] })
|
|
||||||
.attr("stroke", "red")
|
|
||||||
.attr("stroke-opacity", "0")
|
|
||||||
.attr("fill-opacity", "0")
|
|
||||||
.attr("fill", "red");
|
|
||||||
|
|
||||||
nodeEnter.filter(function(d) {return d.image !== undefined})
|
|
||||||
.append("svg:image")
|
|
||||||
.attr("class", "circle")
|
|
||||||
.attr("xlink:href", function(d) {
|
|
||||||
return d.image
|
|
||||||
})
|
|
||||||
.attr("x", function(d) {
|
|
||||||
return (0 - (icon_sizes[d.type]/2)) + "px";
|
|
||||||
})
|
|
||||||
.attr("y", function(d) {
|
|
||||||
return (0 - (icon_sizes[d.type]/2)) + "px";
|
|
||||||
})
|
|
||||||
.attr("width", function(d) {
|
|
||||||
return ((icon_sizes[d.type])) + "px";
|
|
||||||
})
|
|
||||||
.attr("height", function(d) {
|
|
||||||
return ((icon_sizes[d.type])) + "px";
|
|
||||||
});
|
|
||||||
|
|
||||||
nodeEnter.filter(function(d) {return d.imgClass !== undefined})
|
|
||||||
.append("g")
|
|
||||||
.append('svg:foreignObject')
|
|
||||||
.attr("width", 12)
|
|
||||||
.attr("height", 12)
|
|
||||||
.attr("x", function(d) {
|
|
||||||
if (d.type == 'galaxy' || d.type == 'tag') {
|
|
||||||
return '-10px';
|
|
||||||
} else {
|
|
||||||
return '-6px';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.attr("y", function(d) {
|
|
||||||
if (d.type == 'galaxy' || d.type == 'tag') {
|
|
||||||
return '-12px';
|
|
||||||
} else {
|
|
||||||
return '-8px';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.append("xhtml:body")
|
|
||||||
.html(function (d) {
|
|
||||||
var result = 'fa-' + d.imgClass;
|
|
||||||
if (d.type == 'galaxy' || d.type == 'tag') result = 'fa-2x ' + result;
|
|
||||||
return '<i class="fa ' + result + '"></i>';
|
|
||||||
});
|
|
||||||
|
|
||||||
nodeEnter.append("text")
|
|
||||||
.attr("dy", function(d) {
|
|
||||||
if (d.type == "event" || d.type == "galaxy") {
|
|
||||||
return "10px";
|
|
||||||
} else {
|
|
||||||
return "0px";
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.attr("fill", function(d) {
|
|
||||||
if (d.type == "event") {
|
|
||||||
if (d.expanded == 1) {
|
|
||||||
return "#0000ff";
|
|
||||||
} else {
|
|
||||||
return "#ff0000";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.text(function(d) {
|
|
||||||
return d.type + ': ' + d.name;
|
|
||||||
});
|
|
||||||
|
|
||||||
node.selectAll("text")
|
|
||||||
.attr("y", 20);
|
|
||||||
|
|
||||||
node.on('mouseover', function(d) {
|
|
||||||
link.style('stroke', function(l) {
|
|
||||||
if (d === l.source || d === l.target)
|
|
||||||
return "#ff0000";
|
|
||||||
else
|
|
||||||
return "#9ecae1";
|
|
||||||
});
|
|
||||||
link.style('stroke-width', function(l) {
|
|
||||||
if (d === l.source || d === l.target)
|
|
||||||
return 2;
|
|
||||||
else
|
|
||||||
return 1;
|
|
||||||
});
|
|
||||||
showPane(d, 'hover');
|
|
||||||
});
|
|
||||||
|
|
||||||
node.on('mouseout', function() {
|
|
||||||
link.style('stroke-width', 1);
|
|
||||||
link.style('stroke', "#9ecae1");
|
|
||||||
});
|
|
||||||
|
|
||||||
node.on("click", function(d) {
|
|
||||||
showPane(d, 'selected');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function highlightNode(d) {
|
|
||||||
d3.selectAll('.highlighted_circle')
|
|
||||||
.style("stroke-opacity", 0);
|
|
||||||
d3.select('#id-' + d.unique_id)
|
|
||||||
.select('.highlighted_circle')
|
|
||||||
.style("stroke", "red")
|
|
||||||
.style("stroke-opacity", 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
function contextMenu(d, newContext) {
|
|
||||||
d3.event.preventDefault();
|
|
||||||
if (d.type == 'event') showPane(d, 'context');
|
|
||||||
}
|
|
||||||
|
|
||||||
function bindExpand(d, type) {
|
|
||||||
if (!d.expanded) {
|
|
||||||
var expandName = 'Expand (ctrl+x)';
|
|
||||||
if (type == 'selected') {
|
|
||||||
expandName = 'Expand (x)';
|
|
||||||
}
|
|
||||||
$("#" + type + "-menu").append('<li id="expand_' + type + '_' + d.id +'" class="graphMenuAction"><span>' + expandName + '</span></li>');
|
|
||||||
d3.select('#expand_' + type + '_' + d.id)
|
|
||||||
.on('click', function() {
|
|
||||||
expand(d);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function bindDelete(d, type) {
|
|
||||||
var deleteName = 'Delete (ctrl+d)';
|
|
||||||
if (type == 'selected') {
|
|
||||||
deleteName = 'Delete (d)';
|
|
||||||
}
|
|
||||||
$("#" + type + "-menu").append('<li id="remove_' + type + '_' + d.id +'" class="graphMenuAction"><span>' + deleteName + '</span></li>');
|
|
||||||
d3.select('#remove_' + type + '_' + d.id)
|
|
||||||
.on('click', function() {
|
|
||||||
remove(d);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function createInfoPane(d, data, type) {
|
|
||||||
var i = 0;
|
|
||||||
var view_urls = {
|
|
||||||
'event': '/events/view/' + parseInt(d.id),
|
|
||||||
'tag': '/tags/view/' + parseInt(d.id),
|
|
||||||
'galaxy': '/galaxy_clusters/view/' + parseInt(d.id)
|
|
||||||
};
|
|
||||||
data["fields"].forEach(function(e) {
|
|
||||||
var title = e;
|
|
||||||
if (i == 0) title = d.type;
|
|
||||||
title = title.split("_").join(" ");
|
|
||||||
title = title.charAt(0).toUpperCase() + title.slice(1);
|
|
||||||
var span1 = $('<span />').text(title + ': ');
|
|
||||||
var span2 = $('<span />').text(d[e]);
|
|
||||||
var li = $('<li />');
|
|
||||||
li.append(span1);
|
|
||||||
li.append(span2);
|
|
||||||
if (i == 0) li.addClass('graphMenuTitle');
|
|
||||||
i++;
|
|
||||||
$("#" + type + "-menu").append(li);
|
|
||||||
});
|
|
||||||
$("#" + type + "-menu").append('<li class="graphMenuActions">Actions</li>');
|
|
||||||
if ($.inArray("navigate", data["actions"]) !== -1) {
|
|
||||||
console.log($.inArray("navigate", data["actions"]));
|
|
||||||
$("#" + type + "-menu").append('<li><span><a href="' + view_urls[d.type] + '">Go to ' + d.type + '</a></span></li>');
|
|
||||||
}
|
|
||||||
if ($.inArray("expand", data["actions"]) !== -1) {
|
|
||||||
bindExpand(d, type);
|
|
||||||
}
|
|
||||||
if ($.inArray("delete", data["actions"]) !== -1) {
|
|
||||||
bindDelete(d, type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function showPane(d, type) {
|
|
||||||
if (type == 'hover') {
|
|
||||||
hovered = d;
|
|
||||||
} else {
|
|
||||||
highlighted = d;
|
|
||||||
highlightNode(d);
|
|
||||||
}
|
|
||||||
$('#' + type + '-header').show();
|
|
||||||
d3.select("#" + type + "-menu").style('display', 'inline-block');
|
|
||||||
$("#" + type + "-menu").empty();
|
|
||||||
if (d.type== 'attribute') {
|
|
||||||
var data = {
|
|
||||||
"fields": ["id", "name", "category", "type", "comment"],
|
|
||||||
"actions": ["delete"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (d.type== 'event') {
|
|
||||||
var tempid = parseInt(d.id);
|
|
||||||
var data = {
|
|
||||||
"fields": ["id", "info", "date", "analysis", "org"],
|
|
||||||
"actions": ["expand", "delete", "navigate"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (d.type == 'tag') {
|
|
||||||
var data = {
|
|
||||||
"fields": ["id", "name"],
|
|
||||||
"actions": ["expand", "delete"]
|
|
||||||
}
|
|
||||||
if (d.taxonomy !== undefined) {
|
|
||||||
data["fields"].push("taxonomy");
|
|
||||||
data["fields"].push("taxonomy_description");
|
|
||||||
if (d.description !== "") {
|
|
||||||
data["fields"].push("Description");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (d.type == 'galaxy') {
|
|
||||||
var data = {
|
|
||||||
"fields": ["id", "name", "galaxy", "synonyms", "authors", "description", "source"],
|
|
||||||
"actions": ["expand", "delete", "navigate"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (d.type == 'object') {
|
|
||||||
var data = {
|
|
||||||
"fields": ["id", "name", "metacategory", "description", "comment"],
|
|
||||||
"actions": ["delete"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
createInfoPane(d, data, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
function expand(d) {
|
|
||||||
if (d.type == 'event' || d.type == 'galaxy' || d.type == 'tag') {
|
|
||||||
d3.xhr("/events/updateGraph/" + d.id + "/" + d.type + ".json")
|
|
||||||
.header("Content-Type", "application/json")
|
|
||||||
.post(
|
|
||||||
JSON.stringify(root),
|
|
||||||
function(err, rawData){
|
|
||||||
root = JSON.parse(rawData.response);
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
$params = array(
|
||||||
|
'menuList' => $scope_list[$scope],
|
||||||
|
'menuItem' => 'viewGraph'
|
||||||
|
);
|
||||||
|
if ($scope == 'event') {
|
||||||
|
$params['mayModify'] = $mayModify;
|
||||||
|
$params['mayPublish'] = $mayPublish;
|
||||||
|
}
|
||||||
|
if ($scope == 'tag') {
|
||||||
|
if (!empty($taxoomy)) {
|
||||||
|
$params['taxonomy'] = $taxonomy['Taxonomy']['id'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
echo $this->element('side_menu', $params);
|
||||||
function tick() {
|
?>
|
||||||
link.attr("x1", function(d) { return d.source.x; })
|
|
||||||
.attr("y1", function(d) { return d.source.y; })
|
|
||||||
.attr("x2", function(d) { return d.target.x; })
|
|
||||||
.attr("y2", function(d) { return d.target.y; });
|
|
||||||
|
|
||||||
node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns a list of all nodes under the root.
|
|
||||||
function flatten(root) {
|
|
||||||
var nodes = [], i = 0;
|
|
||||||
|
|
||||||
function recurse(node) {
|
|
||||||
if (node.children) node.children.forEach(recurse);
|
|
||||||
if (!node.id) node.id = ++i;
|
|
||||||
nodes.push(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
recurse(root);
|
|
||||||
return nodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function dragstart(d, i) {
|
|
||||||
force.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
function dragmove(d, i) {
|
|
||||||
d.px += d3.event.dx;
|
|
||||||
d.py += d3.event.dy;
|
|
||||||
d.x += d3.event.dx;
|
|
||||||
d.y += d3.event.dy;
|
|
||||||
tick();
|
|
||||||
}
|
|
||||||
|
|
||||||
function dragend(d, i) {
|
|
||||||
d.fixed = true;
|
|
||||||
tick();
|
|
||||||
force.resume();
|
|
||||||
}
|
|
||||||
|
|
||||||
function searchArray(arr, val) {
|
|
||||||
for (var i=0; i < arr.length; i++)
|
|
||||||
if (arr[i] === val)
|
|
||||||
return i;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$(document).on('keydown', function(e) {
|
|
||||||
if (e.which == 69) {
|
|
||||||
if (highlighted == undefined) {
|
|
||||||
showPane(root['nodes'][0], 'selected');
|
|
||||||
} else {
|
|
||||||
var current = searchArray(root['nodes'], highlighted);
|
|
||||||
if (current == root['nodes'].length-1) {
|
|
||||||
showPane(root['nodes'][0], 'selected');
|
|
||||||
} else {
|
|
||||||
showPane(root['nodes'][current+1], 'selected');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (e.which == 81) {
|
|
||||||
if (highlighted == undefined) {
|
|
||||||
showPane(root['nodes'][root['nodes'].length-1], 'selected');
|
|
||||||
} else {
|
|
||||||
var current = searchArray(root['nodes'], highlighted);
|
|
||||||
if (current == 0) {
|
|
||||||
showPane(root['nodes'][root['nodes'].length-1], 'selected');
|
|
||||||
} else {
|
|
||||||
showPane(root['nodes'][current-1], 'selected');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$(document).on('keydown', function(e) {
|
|
||||||
if (e.which == 68) {
|
|
||||||
e.preventDefault();
|
|
||||||
if (e.ctrlKey) {
|
|
||||||
if (hovered != undefined) {
|
|
||||||
remove(hovered);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (highlighted != undefined) {
|
|
||||||
remove(highlighted);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$(document).on('keydown', function(e) {
|
|
||||||
if (e.which == 88) {
|
|
||||||
e.preventDefault();
|
|
||||||
if (e.ctrlKey) {
|
|
||||||
if (hovered != undefined) {
|
|
||||||
expand(hovered);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (highlighted != undefined) {
|
|
||||||
expand(highlighted);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
|
@ -4,7 +4,10 @@
|
||||||
<div class="galaxy view">
|
<div class="galaxy view">
|
||||||
<div class="row-fluid">
|
<div class="row-fluid">
|
||||||
<div class="span8">
|
<div class="span8">
|
||||||
<h2><?php echo h($galaxy['Galaxy']['name']); ?> galaxy</h2>
|
<h2>
|
||||||
|
<span class="fa fa-<?php echo h($galaxy['Galaxy']['icon']); ?>"></span>
|
||||||
|
<?php echo h($galaxy['Galaxy']['name']); ?> galaxy
|
||||||
|
</h2>
|
||||||
<dl>
|
<dl>
|
||||||
<dt>Galaxy ID</dt>
|
<dt>Galaxy ID</dt>
|
||||||
<dd><?php echo h($galaxy['Galaxy']['id']); ?></dd>
|
<dd><?php echo h($galaxy['Galaxy']['id']); ?></dd>
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
</td>
|
</td>
|
||||||
<td><?php echo h($item['GalaxyCluster']['description']); ?> </td>
|
<td><?php echo h($item['GalaxyCluster']['description']); ?> </td>
|
||||||
<td class="short action-links">
|
<td class="short action-links">
|
||||||
|
<?php echo $this->Html->link('', array('controller' => 'galaxies', 'action' => 'viewGraph', $item['GalaxyCluster']['id']), array('class' => 'fa fa-line-chart', 'title' => 'View graph'));?>
|
||||||
<?php echo $this->Html->link('', array('action' => 'view', $item['GalaxyCluster']['id']), array('class' => 'icon-list-alt', 'title' => 'View'));?>
|
<?php echo $this->Html->link('', array('action' => 'view', $item['GalaxyCluster']['id']), array('class' => 'icon-list-alt', 'title' => 'View'));?>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -104,6 +104,7 @@ foreach ($list as $k => $item): ?>
|
||||||
</td>
|
</td>
|
||||||
<?php if ($isSiteAdmin): ?>
|
<?php if ($isSiteAdmin): ?>
|
||||||
<td class="short action-links">
|
<td class="short action-links">
|
||||||
|
<?php echo $this->Html->link('', array('controller' => 'tags', 'action' => 'viewGraph', $item['Tag']['id']), array('class' => 'fa fa-line-chart', 'title' => 'View graph'));?>
|
||||||
<?php echo $this->Html->link('', array('action' => 'edit', $item['Tag']['id']), array('class' => 'icon-edit', 'title' => 'Edit'));?>
|
<?php echo $this->Html->link('', array('action' => 'edit', $item['Tag']['id']), array('class' => 'icon-edit', 'title' => 'Edit'));?>
|
||||||
<?php echo $this->Form->postLink('', array('action' => 'delete', $item['Tag']['id']), array('class' => 'icon-trash', 'title' => 'Delete'), __('Are you sure you want to delete "%s"?', $item['Tag']['name']));?>
|
<?php echo $this->Form->postLink('', array('action' => 'delete', $item['Tag']['id']), array('class' => 'icon-trash', 'title' => 'Delete'), __('Are you sure you want to delete "%s"?', $item['Tag']['name']));?>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -122,6 +122,7 @@
|
||||||
<a href="<?php echo $url;?>" class="<?php echo $isAclTagger ? 'tagFirstHalf' : 'tag' ?>" style="background-color:<?php echo h($item['existing_tag']['Tag']['colour']);?>;color:<?php echo $this->TextColour->getTextColour($item['existing_tag']['Tag']['colour']);?>"><?php echo h($item['existing_tag']['Tag']['name']); ?></a>
|
<a href="<?php echo $url;?>" class="<?php echo $isAclTagger ? 'tagFirstHalf' : 'tag' ?>" style="background-color:<?php echo h($item['existing_tag']['Tag']['colour']);?>;color:<?php echo $this->TextColour->getTextColour($item['existing_tag']['Tag']['colour']);?>"><?php echo h($item['existing_tag']['Tag']['name']); ?></a>
|
||||||
<?php
|
<?php
|
||||||
endif;
|
endif;
|
||||||
|
echo ' ' . $this->Html->link('', array('controller' => 'tags', 'action' => 'viewGraph', $item['existing_tag']['Tag']['id']), array('class' => 'fa fa-line-chart black', 'title' => 'View graph'));
|
||||||
endif;
|
endif;
|
||||||
?>
|
?>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
.node circle {
|
||||||
|
cursor: pointer;
|
||||||
|
stroke: #3182bd;
|
||||||
|
stroke-width: 1.5px;
|
||||||
|
}
|
||||||
|
.node text {
|
||||||
|
font: 10px sans-serif;
|
||||||
|
pointer-events: none;
|
||||||
|
text-anchor: middle;
|
||||||
|
}
|
||||||
|
line.link {
|
||||||
|
fill: none;
|
||||||
|
stroke: #9ecae1;
|
||||||
|
stroke-width: 1.5px;
|
||||||
|
}
|
||||||
|
#main {
|
||||||
|
display: inline-block;
|
||||||
|
background-color: grey;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.menu {
|
||||||
|
border: 1px solid black;
|
||||||
|
background-color: grey;
|
||||||
|
display: none;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.menu,
|
||||||
|
.menu li {
|
||||||
|
padding: 0px;
|
||||||
|
margin: 0px;
|
||||||
|
width: 250px;
|
||||||
|
}
|
||||||
|
.menu li {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.menu > li:hover {
|
||||||
|
background-color: lightblue;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
.menu li {
|
||||||
|
display: block;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
.menu li:hover ul {
|
||||||
|
display:inline-block;
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
.menu > li > span > a {
|
||||||
|
color:white;
|
||||||
|
font-weight:bold;
|
||||||
|
}
|
||||||
|
.menu > li > span:first-child {
|
||||||
|
font-weight:bold;
|
||||||
|
}
|
||||||
|
.graphMenuTitle {
|
||||||
|
background-color:#0088cc;
|
||||||
|
font-weight:bold;
|
||||||
|
color:white;
|
||||||
|
}
|
||||||
|
.graphMenuActions {
|
||||||
|
background-color:#0088cc;
|
||||||
|
color:white;
|
||||||
|
}
|
||||||
|
.graphMenuAction {
|
||||||
|
cursor: hand;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-container {
|
||||||
|
position:absolute;
|
||||||
|
width:300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.font-white {
|
||||||
|
color:white;
|
||||||
|
}
|
||||||
|
.corrected-icon {
|
||||||
|
top:-5px;
|
||||||
|
margin-left:100px;
|
||||||
|
}
|
|
@ -1912,6 +1912,10 @@ table tr:hover .down-expand-button {
|
||||||
border:50px solid black;
|
border:50px solid black;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.action-links > .fa {
|
||||||
|
color:black;
|
||||||
|
}
|
||||||
|
|
||||||
@-webkit-keyframes rotation {
|
@-webkit-keyframes rotation {
|
||||||
from {-webkit-transform: rotate(0deg);}
|
from {-webkit-transform: rotate(0deg);}
|
||||||
to {-webkit-transform: rotate(359deg);}
|
to {-webkit-transform: rotate(359deg);}
|
||||||
|
|
|
@ -0,0 +1,507 @@
|
||||||
|
$(document).ready( function() {
|
||||||
|
|
||||||
|
var currentMousePos = { x: -1, y: -1 };
|
||||||
|
$(document).mousemove(function(event) {
|
||||||
|
currentMousePos.x = event.pageX;
|
||||||
|
currentMousePos.y = event.pageY;
|
||||||
|
});
|
||||||
|
|
||||||
|
var margin = {top: -5, right: -5, bottom: -5, left: -5},
|
||||||
|
width = $(window).width() - margin.left - margin.right,
|
||||||
|
height = $(window).height() - 160 - margin.top - margin.bottom;
|
||||||
|
var menu_x_buffer_ = width - 150;
|
||||||
|
var menu_y_buffer = height - 100;
|
||||||
|
$('.menu-container').css('left', '200px');
|
||||||
|
$('#hover-menu-container').css('top', '50px');
|
||||||
|
$('#hover-menu-container').css('z-index', 1);
|
||||||
|
$('#selected-menu-container').css('top', '400px');
|
||||||
|
$('#selected-menu-container').css('z-index', 2);
|
||||||
|
|
||||||
|
var root;
|
||||||
|
|
||||||
|
var highlighted;
|
||||||
|
var hovered;
|
||||||
|
|
||||||
|
var icon_sizes = {
|
||||||
|
"event": 24,
|
||||||
|
"object": 12,
|
||||||
|
"attribute": 12,
|
||||||
|
"galaxy": 32,
|
||||||
|
"tag": 24
|
||||||
|
}
|
||||||
|
|
||||||
|
var selection_radius_sizes = {
|
||||||
|
"event": 18,
|
||||||
|
"object": 12,
|
||||||
|
"attribute": 12,
|
||||||
|
"galaxy": 18,
|
||||||
|
"tag": 18
|
||||||
|
}
|
||||||
|
|
||||||
|
var force = d3.layout.force()
|
||||||
|
.linkDistance(function (d) {
|
||||||
|
return d.linkDistance;
|
||||||
|
})
|
||||||
|
.linkStrength(0.9)
|
||||||
|
.friction(0.5)
|
||||||
|
.theta(0.9)
|
||||||
|
.charge(-500)
|
||||||
|
.gravity(0.21)
|
||||||
|
.size([width, height])
|
||||||
|
.on("tick", tick);
|
||||||
|
|
||||||
|
var vis = d3.select("#chart");
|
||||||
|
|
||||||
|
var svg = vis.append("svg:svg")
|
||||||
|
.attr("width", width)
|
||||||
|
.attr("height", height)
|
||||||
|
.attr("pointer-events", "all");
|
||||||
|
|
||||||
|
var rect = svg.append("svg:rect")
|
||||||
|
.attr('width', width)
|
||||||
|
.attr('height', height)
|
||||||
|
.attr('fill', 'white')
|
||||||
|
.call(d3.behavior.zoom().on("zoom", zoomhandler));
|
||||||
|
|
||||||
|
var plotting_area = svg.append("g")
|
||||||
|
.attr("class", "plotting-area");
|
||||||
|
|
||||||
|
var drag1 = d3.behavior.drag()
|
||||||
|
.on("dragstart", dragstart)
|
||||||
|
.on("drag", dragmove)
|
||||||
|
.on("dragend", dragend);
|
||||||
|
|
||||||
|
var link = plotting_area.selectAll(".link");
|
||||||
|
var node = plotting_area.selectAll(".node");
|
||||||
|
|
||||||
|
var scope_id = $('#graph_init').data('id');
|
||||||
|
var scope = $('#graph_init').data('scope');
|
||||||
|
|
||||||
|
d3.json("/events/updateGraph/" + scope_id + "/" + scope + ".json", function(error, json) {
|
||||||
|
root = json;
|
||||||
|
update();
|
||||||
|
});
|
||||||
|
|
||||||
|
var graphElementScale = 1;
|
||||||
|
var graphElementTranslate = [0, 0];
|
||||||
|
|
||||||
|
function zoomhandler() {
|
||||||
|
plotting_area.attr("transform",
|
||||||
|
"translate(" + d3.event.translate + ")"
|
||||||
|
+ " scale(" + d3.event.scale + ")");
|
||||||
|
graphElementScale = d3.event.scale;
|
||||||
|
graphElementTranslate = d3.event.translate;
|
||||||
|
}
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
var nodes = root['nodes'], links = root['links'];
|
||||||
|
|
||||||
|
|
||||||
|
// Restart the force layout.
|
||||||
|
force.nodes(nodes).links(links).start();
|
||||||
|
|
||||||
|
// Update links.
|
||||||
|
link = link.data(links);
|
||||||
|
link.exit().remove();
|
||||||
|
link.enter().insert("line", ".node").attr("class", "link");
|
||||||
|
// Update nodes.
|
||||||
|
node = node.data(nodes);
|
||||||
|
node.exit().remove();
|
||||||
|
|
||||||
|
var nodeEnter = node.enter().append("g").attr("class", "node").call(drag1);
|
||||||
|
|
||||||
|
nodeEnter.attr('id', function(d) { return 'id-' + d.unique_id; })
|
||||||
|
|
||||||
|
nodeEnter.insert("circle", ".circle")
|
||||||
|
.classed("highlighted_circle", true)
|
||||||
|
.attr("cx", function(d) { return d.x_axis; })
|
||||||
|
.attr("cy", function(d) { return d.y_axis; })
|
||||||
|
.attr("r", function(d) { return selection_radius_sizes[d.type] })
|
||||||
|
.attr("stroke", "red")
|
||||||
|
.attr("stroke-opacity", "0")
|
||||||
|
.attr("fill-opacity", "0")
|
||||||
|
.attr("fill", "red");
|
||||||
|
|
||||||
|
nodeEnter.filter(function(d) {return d.image !== undefined})
|
||||||
|
.append("svg:image")
|
||||||
|
.attr("class", "circle")
|
||||||
|
.attr("xlink:href", function(d) {
|
||||||
|
return d.image
|
||||||
|
})
|
||||||
|
.attr("x", function(d) {
|
||||||
|
return (0 - (icon_sizes[d.type]/2)) + "px";
|
||||||
|
})
|
||||||
|
.attr("y", function(d) {
|
||||||
|
return (0 - (icon_sizes[d.type]/2)) + "px";
|
||||||
|
})
|
||||||
|
.attr("width", function(d) {
|
||||||
|
return ((icon_sizes[d.type])) + "px";
|
||||||
|
})
|
||||||
|
.attr("height", function(d) {
|
||||||
|
return ((icon_sizes[d.type])) + "px";
|
||||||
|
});
|
||||||
|
|
||||||
|
nodeEnter.filter(function(d) {return d.imgClass !== undefined})
|
||||||
|
.append("g")
|
||||||
|
.append('svg:foreignObject')
|
||||||
|
.attr("width", 12)
|
||||||
|
.attr("height", 12)
|
||||||
|
.attr("x", function(d) {
|
||||||
|
if (d.type == 'galaxy' || d.type == 'tag') {
|
||||||
|
return '-10px';
|
||||||
|
} else {
|
||||||
|
return '-6px';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.attr("y", function(d) {
|
||||||
|
if (d.type == 'galaxy' || d.type == 'tag') {
|
||||||
|
return '-12px';
|
||||||
|
} else {
|
||||||
|
return '-8px';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.append("xhtml:body")
|
||||||
|
.html(function (d) {
|
||||||
|
var result = 'fa-' + d.imgClass;
|
||||||
|
if (d.type == 'galaxy' || d.type == 'tag') result = 'fa-2x ' + result;
|
||||||
|
return '<i class="fa ' + result + '"></i>';
|
||||||
|
});
|
||||||
|
|
||||||
|
nodeEnter.append("text")
|
||||||
|
.attr("dy", function(d) {
|
||||||
|
if (d.type == "event" || d.type == "galaxy") {
|
||||||
|
return "10px";
|
||||||
|
} else {
|
||||||
|
return "0px";
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.attr("fill", function(d) {
|
||||||
|
if (d.type == "event") {
|
||||||
|
if (d.expanded == 1) {
|
||||||
|
return "#0000ff";
|
||||||
|
} else {
|
||||||
|
return "#ff0000";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.text(function(d) {
|
||||||
|
return d.type + ': ' + d.name;
|
||||||
|
});
|
||||||
|
|
||||||
|
node.selectAll("text")
|
||||||
|
.attr("y", 20);
|
||||||
|
|
||||||
|
node.on('mouseover', function(d) {
|
||||||
|
link.style('stroke', function(l) {
|
||||||
|
if (d === l.source || d === l.target)
|
||||||
|
return "#ff0000";
|
||||||
|
else
|
||||||
|
return "#9ecae1";
|
||||||
|
});
|
||||||
|
link.style('stroke-width', function(l) {
|
||||||
|
if (d === l.source || d === l.target)
|
||||||
|
return 2;
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
});
|
||||||
|
showPane(d, 'hover');
|
||||||
|
});
|
||||||
|
|
||||||
|
node.on('mouseout', function() {
|
||||||
|
link.style('stroke-width', 1);
|
||||||
|
link.style('stroke', "#9ecae1");
|
||||||
|
});
|
||||||
|
|
||||||
|
node.on("click", function(d) {
|
||||||
|
showPane(d, 'selected');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function highlightNode(d) {
|
||||||
|
d3.selectAll('.highlighted_circle')
|
||||||
|
.style("stroke-opacity", 0);
|
||||||
|
d3.select('#id-' + d.unique_id)
|
||||||
|
.select('.highlighted_circle')
|
||||||
|
.style("stroke", "red")
|
||||||
|
.style("stroke-opacity", 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function contextMenu(d, newContext) {
|
||||||
|
d3.event.preventDefault();
|
||||||
|
if (d.type == 'event') showPane(d, 'context');
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindExpand(d, type) {
|
||||||
|
if (!d.expanded) {
|
||||||
|
var expandName = 'Expand (ctrl+x)';
|
||||||
|
if (type == 'selected') {
|
||||||
|
expandName = 'Expand (x)';
|
||||||
|
}
|
||||||
|
$("#" + type + "-menu").append('<li id="expand_' + type + '_' + d.id +'" class="graphMenuAction"><span>' + expandName + '</span></li>');
|
||||||
|
d3.select('#expand_' + type + '_' + d.id)
|
||||||
|
.on('click', function() {
|
||||||
|
expand(d);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function remove_node(d) {
|
||||||
|
var index = root.nodes.indexOf(d);
|
||||||
|
if (index > -1) {
|
||||||
|
root.nodes.splice(index, 1);
|
||||||
|
}
|
||||||
|
var temp = [];
|
||||||
|
root['links'].forEach(function(n) {
|
||||||
|
if (n.source != d && n.target != d) {
|
||||||
|
temp.push(n);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
root['links'] = temp;
|
||||||
|
|
||||||
|
var i = 0;
|
||||||
|
var links = [];
|
||||||
|
root.links.forEach(function(l) {
|
||||||
|
var j = 0;
|
||||||
|
var temp = {};
|
||||||
|
root.nodes.forEach(function(n) {
|
||||||
|
if (l.source == n) {
|
||||||
|
temp.source = j;
|
||||||
|
}
|
||||||
|
if (l.target == n) {
|
||||||
|
temp.target = j;
|
||||||
|
}
|
||||||
|
var j = j+1;
|
||||||
|
});
|
||||||
|
temp.linkDistance = l.linkDistance;
|
||||||
|
links.push(temp);
|
||||||
|
var i = i+1;
|
||||||
|
});
|
||||||
|
root = {
|
||||||
|
'nodes': root['nodes'],
|
||||||
|
'links': root['links']
|
||||||
|
};
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
function bindDelete(d, type) {
|
||||||
|
var deleteName = 'Delete (ctrl+d)';
|
||||||
|
if (type == 'selected') {
|
||||||
|
deleteName = 'Delete (d)';
|
||||||
|
}
|
||||||
|
$("#" + type + "-menu").append('<li id="remove_' + type + '_' + d.id +'" class="graphMenuAction"><span>' + deleteName + '</span></li>');
|
||||||
|
d3.select('#remove_' + type + '_' + d.id)
|
||||||
|
.on('click', function() {
|
||||||
|
remove_node(d);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function createInfoPane(d, data, type) {
|
||||||
|
var i = 0;
|
||||||
|
var view_urls = {
|
||||||
|
'event': '/events/view/' + parseInt(d.id),
|
||||||
|
'tag': '/tags/view/' + parseInt(d.id),
|
||||||
|
'galaxy': '/galaxy_clusters/view/' + parseInt(d.id)
|
||||||
|
};
|
||||||
|
data["fields"].forEach(function(e) {
|
||||||
|
var title = e;
|
||||||
|
if (i == 0) title = d.type;
|
||||||
|
title = title.split("_").join(" ");
|
||||||
|
title = title.charAt(0).toUpperCase() + title.slice(1);
|
||||||
|
var span1 = $('<span />').text(title + ': ');
|
||||||
|
var span2 = $('<span />').text(d[e]);
|
||||||
|
var li = $('<li />');
|
||||||
|
li.append(span1);
|
||||||
|
li.append(span2);
|
||||||
|
if (i == 0) li.addClass('graphMenuTitle');
|
||||||
|
i++;
|
||||||
|
$("#" + type + "-menu").append(li);
|
||||||
|
});
|
||||||
|
$("#" + type + "-menu").append('<li class="graphMenuActions">Actions</li>');
|
||||||
|
if ($.inArray("navigate", data["actions"]) !== -1) {
|
||||||
|
$("#" + type + "-menu").append('<li><span><a href="' + view_urls[d.type] + '">Go to ' + d.type + '</a></span></li>');
|
||||||
|
}
|
||||||
|
if ($.inArray("expand", data["actions"]) !== -1) {
|
||||||
|
bindExpand(d, type);
|
||||||
|
}
|
||||||
|
if ($.inArray("delete", data["actions"]) !== -1) {
|
||||||
|
bindDelete(d, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPane(d, type) {
|
||||||
|
if (type == 'hover') {
|
||||||
|
hovered = d;
|
||||||
|
} else {
|
||||||
|
highlighted = d;
|
||||||
|
highlightNode(d);
|
||||||
|
}
|
||||||
|
$('#' + type + '-header').show();
|
||||||
|
d3.select("#" + type + "-menu").style('display', 'inline-block');
|
||||||
|
$("#" + type + "-menu").empty();
|
||||||
|
if (d.type== 'attribute') {
|
||||||
|
var data = {
|
||||||
|
"fields": ["id", "name", "category", "type", "comment"],
|
||||||
|
"actions": ["delete"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (d.type== 'event') {
|
||||||
|
var tempid = parseInt(d.id);
|
||||||
|
var data = {
|
||||||
|
"fields": ["id", "info", "date", "analysis", "org"],
|
||||||
|
"actions": ["expand", "delete", "navigate"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (d.type == 'tag') {
|
||||||
|
var data = {
|
||||||
|
"fields": ["id", "name"],
|
||||||
|
"actions": ["expand", "delete"]
|
||||||
|
}
|
||||||
|
if (d.taxonomy !== undefined) {
|
||||||
|
data["fields"].push("taxonomy");
|
||||||
|
data["fields"].push("taxonomy_description");
|
||||||
|
if (d.description !== "") {
|
||||||
|
data["fields"].push("Description");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (d.type == 'galaxy') {
|
||||||
|
var data = {
|
||||||
|
"fields": ["id", "name", "galaxy", "synonyms", "authors", "description", "source"],
|
||||||
|
"actions": ["expand", "delete", "navigate"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (d.type == 'object') {
|
||||||
|
var data = {
|
||||||
|
"fields": ["id", "name", "metacategory", "description", "comment"],
|
||||||
|
"actions": ["delete"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
createInfoPane(d, data, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
function expand(d) {
|
||||||
|
if (d.type == 'event' || d.type == 'galaxy' || d.type == 'tag') {
|
||||||
|
d3.xhr("/events/updateGraph/" + d.id + "/" + d.type + ".json")
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.post(
|
||||||
|
JSON.stringify(root),
|
||||||
|
function(err, rawData){
|
||||||
|
root = JSON.parse(rawData.response);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function tick() {
|
||||||
|
link.attr("x1", function(d) { return d.source.x; })
|
||||||
|
.attr("y1", function(d) { return d.source.y; })
|
||||||
|
.attr("x2", function(d) { return d.target.x; })
|
||||||
|
.attr("y2", function(d) { return d.target.y; });
|
||||||
|
|
||||||
|
node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a list of all nodes under the root.
|
||||||
|
function flatten(root) {
|
||||||
|
var nodes = [], i = 0;
|
||||||
|
|
||||||
|
function recurse(node) {
|
||||||
|
if (node.children) node.children.forEach(recurse);
|
||||||
|
if (!node.id) node.id = ++i;
|
||||||
|
nodes.push(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
recurse(root);
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function dragstart(d, i) {
|
||||||
|
force.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
function dragmove(d, i) {
|
||||||
|
d.px += d3.event.dx;
|
||||||
|
d.py += d3.event.dy;
|
||||||
|
d.x += d3.event.dx;
|
||||||
|
d.y += d3.event.dy;
|
||||||
|
tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
function dragend(d, i) {
|
||||||
|
d.fixed = true;
|
||||||
|
tick();
|
||||||
|
force.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
function searchArray(arr, val) {
|
||||||
|
for (var i=0; i < arr.length; i++)
|
||||||
|
if (arr[i] === val)
|
||||||
|
return i;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).on('keydown', function(e) {
|
||||||
|
if (e.which == 69) {
|
||||||
|
if (highlighted == undefined) {
|
||||||
|
showPane(root['nodes'][0], 'selected');
|
||||||
|
} else {
|
||||||
|
var current = searchArray(root['nodes'], highlighted);
|
||||||
|
if (current == root['nodes'].length-1) {
|
||||||
|
showPane(root['nodes'][0], 'selected');
|
||||||
|
} else {
|
||||||
|
showPane(root['nodes'][current+1], 'selected');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (e.which == 81) {
|
||||||
|
if (highlighted == undefined) {
|
||||||
|
showPane(root['nodes'][root['nodes'].length-1], 'selected');
|
||||||
|
} else {
|
||||||
|
var current = searchArray(root['nodes'], highlighted);
|
||||||
|
if (current == 0) {
|
||||||
|
showPane(root['nodes'][root['nodes'].length-1], 'selected');
|
||||||
|
} else {
|
||||||
|
showPane(root['nodes'][current-1], 'selected');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
$(document).on('keydown', function(e) {
|
||||||
|
if (e.which == 68) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (e.ctrlKey) {
|
||||||
|
if (hovered != undefined) {
|
||||||
|
remove_node(hovered);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (highlighted != undefined) {
|
||||||
|
remove_node(highlighted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
|
$(document).on('keydown', function(e) {
|
||||||
|
if (e.which == 88) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (e.ctrlKey) {
|
||||||
|
if (hovered != undefined) {
|
||||||
|
expand(hovered);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (highlighted != undefined) {
|
||||||
|
expand(highlighted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue