diff --git a/core/displayablegraph.class.inc.php b/core/displayablegraph.class.inc.php
index c2bda18ec..b87bfd25f 100644
--- a/core/displayablegraph.class.inc.php
+++ b/core/displayablegraph.class.inc.php
@@ -31,7 +31,7 @@ class DisplayableNode extends GraphNode
{
public $x;
public $y;
-
+
/**
* Create a new node inside a graph
* @param SimpleGraph $oGraph
@@ -51,27 +51,27 @@ class DisplayableNode extends GraphNode
{
return $this->GetProperty('icon_url', '');
}
-
+
public function GetLabel()
{
return $this->GetProperty('label', $this->sId);
}
-
+
public function GetWidth()
{
return max(32, 5*strlen($this->GetProperty('label'))); // approximation of the text's bounding box
}
-
+
public function GetHeight()
{
return 32;
}
-
+
public function Distance2(DisplayableNode $oNode)
{
$dx = $this->x - $oNode->x;
$dy = $this->y - $oNode->y;
-
+
$d2 = $dx*$dx + $dy*$dy - $this->GetHeight()*$this->GetHeight();
if ($d2 < 40)
{
@@ -79,12 +79,12 @@ class DisplayableNode extends GraphNode
}
return $d2;
}
-
+
public function Distance(DisplayableNode $oNode)
{
return sqrt($this->Distance2($oNode));
}
-
+
public function GetForRaphael($aContextDefs)
{
$aNode = array();
@@ -100,7 +100,7 @@ class DisplayableNode extends GraphNode
$aNode['label'] = $this->GetLabel();
$aNode['id'] = $this->GetId();
$fOpacity = ($this->GetProperty('is_reached') ? 1 : 0.4);
- $aNode['icon_attr'] = array('opacity' => $fOpacity);
+ $aNode['icon_attr'] = array('opacity' => $fOpacity);
$aNode['text_attr'] = array('opacity' => $fOpacity);
$aNode['tooltip'] = $this->GetTooltip($aContextDefs);
$aNode['context_icons'] = array();
@@ -114,7 +114,7 @@ class DisplayableNode extends GraphNode
}
return $aNode;
}
-
+
public function RenderAsPDF(iTopPDF $oPdf, DisplayableGraph $oGraph, $fScale, $aContextDefs)
{
$Alpha = 1.0;
@@ -170,7 +170,7 @@ class DisplayableNode extends GraphNode
$oPdf->SetTextColor(0, 0, 0);
$oPdf->Text($this->x*$fScale - $width/2, ($this->y + 18)*$fScale, $this->GetProperty('label'));
}
-
+
/**
* Create a "whitened" version of the icon (retaining the transparency) to be used a background for masking the underlying lines
* @param string $sIconFile The path to the file containing the icon
@@ -179,35 +179,35 @@ class DisplayableNode extends GraphNode
protected function CreateWhiteIcon(DisplayableGraph $oGraph, $sIconFile)
{
$aInfo = getimagesize($sIconFile);
-
+
$im = null;
switch($aInfo['mime'])
{
case 'image/png':
- if (function_exists('imagecreatefrompng'))
- {
- $im = imagecreatefrompng($sIconFile);
- }
- break;
-
+ if (function_exists('imagecreatefrompng'))
+ {
+ $im = imagecreatefrompng($sIconFile);
+ }
+ break;
+
case 'image/gif':
- if (function_exists('imagecreatefromgif'))
- {
- $im = imagecreatefromgif($sIconFile);
- }
- break;
-
+ if (function_exists('imagecreatefromgif'))
+ {
+ $im = imagecreatefromgif($sIconFile);
+ }
+ break;
+
case 'image/jpeg':
case 'image/jpg':
- if (function_exists('imagecreatefromjpeg'))
- {
- $im = imagecreatefromjpeg($sIconFile);
- }
- break;
-
+ if (function_exists('imagecreatefromjpeg'))
+ {
+ $im = imagecreatefromjpeg($sIconFile);
+ }
+ break;
+
default:
- return null;
-
+ return null;
+
}
if($im && imagefilter($im, IMG_FILTER_COLORIZE, 255, 255, 255))
{
@@ -222,17 +222,17 @@ class DisplayableNode extends GraphNode
return null;
}
}
-
+
public function GetObjectCount()
{
return 1;
}
-
+
public function GetObjectClass()
{
return is_object($this->GetProperty('object', null)) ? get_class($this->GetProperty('object', null)) : null;
}
-
+
protected function AddToStats($oNode, &$aNodesPerClass)
{
$sClass = $oNode->GetObjectClass();
@@ -256,9 +256,9 @@ class DisplayableNode extends GraphNode
{
$aNodesPerClass[$sClass][$sKey]['nodes'][$oNode->GetId()] = $oNode;
$aNodesPerClass[$sClass][$sKey]['count'] += $oNode->GetObjectCount();
- }
+ }
}
-
+
/**
* Retrieves the list of neighbour nodes, in the given direction: 'up' or 'down'
* @param bool $bDirectionDown
@@ -279,11 +279,11 @@ class DisplayableNode extends GraphNode
foreach($this->GetIncomingEdges() as $oEdge)
{
$aNextNodes[] = $oEdge->GetSourceNode();
- }
+ }
}
return $aNextNodes;
}
-
+
/**
* Replaces the next neighbour node (in the given direction: 'up' or 'down') by the supplied group node
* preserving the connectivity of the graph
@@ -351,7 +351,7 @@ class DisplayableNode extends GraphNode
}
}
}
-
+
if ($oGraph->GetNode($oNextNode->GetId()))
{
$oGraph->_RemoveNode($oNextNode);
@@ -367,9 +367,9 @@ class DisplayableNode extends GraphNode
{
$oNewNode->AddObject($oNextNode->GetProperty('object'));
}
- }
+ }
}
-
+
/**
* Group together (as a special kind of nodes) all the similar neighbours of the current node
* @param DisplayableGraph $oGraph
@@ -381,7 +381,7 @@ class DisplayableNode extends GraphNode
{
if ($this->GetProperty('grouped') === true) return;
$this->SetProperty('grouped', true);
-
+
$aNodesPerClass = array();
foreach($this->GetNextNodes($bDirectionDown) as $oNode)
{
@@ -412,7 +412,7 @@ class DisplayableNode extends GraphNode
$oNewNode->SetProperty('is_reached', ($sStatus == 'reached'));
$oNewNode->SetProperty('count', $aGroupProps['count']);
}
-
+
try
{
if ($bDirectionDown)
@@ -427,8 +427,8 @@ class DisplayableNode extends GraphNode
catch(Exception $e)
{
// Ignore this redundant egde
- }
-
+ }
+
foreach($aGroupProps['nodes'] as $oNextNode)
{
$this->ReplaceNextNodeBy($oGraph, $oNextNode, $oNewNode, $bDirectionDown);
@@ -445,7 +445,7 @@ class DisplayableNode extends GraphNode
}
}
}
-
+
public function GetTooltip($aContextDefs)
{
$sHtml = '';
@@ -474,9 +474,9 @@ class DisplayableNode extends GraphNode
$sHtml .= '
| '.$oAttDef->GetLabel().': | '.$oCurrObj->GetAsHtml($sAttCode).' |
';
}
$sHtml .= '';
- return $sHtml;
+ return $sHtml;
}
-
+
/**
* Get the description of the node in "dot" language
* Used to generate the positions in the graph, but we'd better use fake label
@@ -508,7 +508,7 @@ class DisplayableRedundancyNode extends DisplayableNode
{
return 24;
}
-
+
public function GetForRaphael($aContextDefs)
{
$aNode = array();
@@ -519,7 +519,7 @@ class DisplayableRedundancyNode extends DisplayableNode
$aNode['x'] = $this->x;
$aNode['y']= $this->y;
$aNode['label'] = $this->GetLabel();
- $aNode['id'] = $this->GetId();
+ $aNode['id'] = $this->GetId();
$fDiscOpacity = ($this->GetProperty('is_reached') ? 1 : 0.2);
$sColor = ($this->GetProperty('is_reached_count') > $this->GetProperty('threshold')) ? '#c33' : '#999';
$aNode['disc_attr'] = array('stroke-width' => 2, 'stroke' => '#000', 'fill' => $sColor, 'opacity' => $fDiscOpacity);
@@ -550,35 +550,35 @@ class DisplayableRedundancyNode extends DisplayableNode
$height = $oPdf->GetStringHeight(1000, $sLabel);
$xPos = (float)$this->x*$fScale - $width/2;
$yPos = (float)$this->y*$fScale - $height/2;
-
+
$oPdf->SetXY(($this->x - 16)*$fScale, ($this->y - 16)*$fScale);
-
+
$oPdf->Cell(32*$fScale, 32*$fScale, $sLabel, 0, 0, 'C', 0, '', 0, false, 'T', 'C');
}
-
+
/**
* @see DisplayableNode::GroupSimilarNeighbours()
*/
public function GroupSimilarNeighbours(DisplayableGraph $oGraph, $iThresholdCount, $bDirectionUp = false, $bDirectionDown = true)
{
parent::GroupSimilarNeighbours($oGraph, $iThresholdCount, $bDirectionUp, $bDirectionDown);
-
+
if ($bDirectionUp)
{
$aNodesPerClass = array();
foreach($this->GetIncomingEdges() as $oEdge)
{
$oNode = $oEdge->GetSourceNode();
-
+
if (($oNode->GetObjectClass() !== null) && (!$oNode->GetProperty('is_reached')))
- {
+ {
$this->AddToStats($oNode, $aNodesPerClass);
}
else
{
//$oNode->GroupSimilarNeighbours($oGraph, $iThresholdCount, $bDirectionUp, $bDirectionDown);
}
- }
+ }
foreach($aNodesPerClass as $sClass => $aDefs)
{
foreach($aDefs as $sStatus => $aGroupProps)
@@ -591,8 +591,8 @@ class DisplayableRedundancyNode extends DisplayableNode
$oNewNode->SetProperty('is_reached', ($sStatus == 'is_reached'));
$oNewNode->SetProperty('class', $sClass);
$oNewNode->SetProperty('count', count($aGroupProps['nodes']));
-
-
+
+
$sNewId = $this->GetId().'::'.$sClass.'/'.(($sStatus == 'reached') ? '_reached': '');
$oNewNode = $oGraph->GetNode($sNewId);
if ($oNewNode == null)
@@ -604,7 +604,7 @@ class DisplayableRedundancyNode extends DisplayableNode
$oNewNode->SetProperty('is_reached', ($sStatus == 'reached'));
$oNewNode->SetProperty('count', $aGroupProps['count']);
}
-
+
try
{
$oOutgoingEdge = new DisplayableEdge($oGraph, '-'.$this->GetId().'-'.$oNewNode->GetId().'/'.$sStatus, $oNewNode, $this);
@@ -613,7 +613,7 @@ class DisplayableRedundancyNode extends DisplayableNode
{
// Ignore this redundant egde
}
-
+
foreach($aGroupProps['nodes'] as $oNextNode)
{
$this->ReplaceNextNodeBy($oGraph, $oNextNode, $oNewNode, !$bDirectionUp);
@@ -631,7 +631,7 @@ class DisplayableRedundancyNode extends DisplayableNode
}
}
}
-
+
public function GetTooltip($aContextDefs)
{
$sHtml = '';
@@ -640,9 +640,9 @@ class DisplayableRedundancyNode extends DisplayableNode
$sHtml .= "| ".Dict::Format('UI:RelationTooltip:ImpactedItems_N_of_M' , $this->GetProperty('is_reached_count'), $this->GetProperty('min_up') + $this->GetProperty('threshold'))." |
";
$sHtml .= "| ".Dict::Format('UI:RelationTooltip:CriticalThreshold_N_of_M' , $this->GetProperty('threshold'), $this->GetProperty('min_up') + $this->GetProperty('threshold'))." |
";
$sHtml .= '';
- return $sHtml;
+ return $sHtml;
}
-
+
public function GetObjectCount()
{
@@ -666,7 +666,7 @@ class DisplayableEdge extends GraphEdge
}
$xStart = $oSourceNode->x * $fScale;
$yStart = $oSourceNode->y * $fScale;
-
+
$oSinkNode = $this->GetSinkNode();
if (($oSinkNode->x == null) || ($oSinkNode->y == null))
{
@@ -674,9 +674,9 @@ class DisplayableEdge extends GraphEdge
}
$xEnd = $oSinkNode->x * $fScale;
$yEnd = $oSinkNode->y * $fScale;
-
+
$bReached = ($this->GetSourceNode()->GetProperty('is_reached') && $this->GetSinkNode()->GetProperty('is_reached'));
-
+
$oPdf->setAlpha(1);
if ($bReached)
{
@@ -688,8 +688,8 @@ class DisplayableEdge extends GraphEdge
}
$oPdf->SetLineStyle(array('width' => 2*$fScale, 'cap' => 'round', 'join' => 'miter', 'dash' => 0, 'color' => $aColor));
$oPdf->Line($xStart, $yStart, $xEnd, $yEnd);
-
-
+
+
$vx = $xEnd - $xStart;
$vy = $yEnd - $yStart;
$l = sqrt($vx*$vx + $vy*$vy);
@@ -699,24 +699,24 @@ class DisplayableEdge extends GraphEdge
$uy = $vx;
$lPos = max($l/2, $l - 40*$fScale);
$iArrowSize = 5*$fScale;
-
+
$x = $xStart + $lPos * $vx;
$y = $yStart + $lPos * $vy;
$oPdf->Line($x, $y, $x + $iArrowSize * ($ux-$vx), $y + $iArrowSize * ($uy-$vy));
- $oPdf->Line($x, $y, $x - $iArrowSize * ($ux+$vx), $y - $iArrowSize * ($uy+$vy));
+ $oPdf->Line($x, $y, $x - $iArrowSize * ($ux+$vx), $y - $iArrowSize * ($uy+$vy));
}
}
class DisplayableGroupNode extends DisplayableNode
{
protected $aObjects;
-
+
public function __construct(SimpleGraph $oGraph, $sId, $x = 0, $y = 0)
{
parent::__construct($oGraph, $sId, $x, $y);
$this->aObjects = array();
}
-
+
public function AddObject(DBObject $oObj = null)
{
if (is_object($oObj))
@@ -729,12 +729,12 @@ class DisplayableGroupNode extends DisplayableNode
$this->aObjects[$oObj->GetKey()] = $oObj;
}
}
-
+
public function GetObjects()
{
return $this->aObjects;
}
-
+
public function GetWidth()
{
return 50;
@@ -760,7 +760,7 @@ class DisplayableGroupNode extends DisplayableNode
$aNode['tooltip'] = $this->GetTooltip($aContextDefs);
return $aNode;
}
-
+
public function RenderAsPDF(iTopPDF $oPdf, DisplayableGraph $oGraph, $fScale, $aContextDefs)
{
$bReached = $this->GetProperty('is_reached');
@@ -790,7 +790,7 @@ class DisplayableGroupNode extends DisplayableNode
$oPdf->SetTextColor(0, 0, 0);
$oPdf->Text($this->x * $fScale - $width / 2, ($this->y + 25) * $fScale, $this->GetProperty('label'));
}
-
+
public function GetTooltip($aContextDefs)
{
$iGroupIdx = $this->GetProperty('group_index');
@@ -823,7 +823,7 @@ class DisplayableGraph extends SimpleGraph
protected $aTempImages;
protected $aSourceObjects;
protected $aSinkObjects;
-
+
public function __construct()
{
parent::__construct();
@@ -831,14 +831,14 @@ class DisplayableGraph extends SimpleGraph
$this->aSourceObjects = array();
$this->aSinkObjects = array();
}
-
+
public function GetTempImageName()
{
$sNewTempName = tempnam(APPROOT.'data', 'img-');
$this->aTempImages[] = $sNewTempName;
return $sNewTempName;
}
-
+
public function __destruct()
{
foreach($this->aTempImages as $sTempFile)
@@ -918,7 +918,7 @@ class DisplayableGraph extends SimpleGraph
$oSinkNode = $oNewGraph->GetNode($oEdge->GetSinkNode()->GetId());
$oNewEdge = new DisplayableEdge($oNewGraph, $oEdge->GetId(), $oSourceNode, $oSinkNode);
}
-
+
// Remove duplicate edges between two nodes
$oEdgesIter = new RelationTypeIterator($oNewGraph, 'Edge');
$aEdgeKeys = array();
@@ -946,7 +946,7 @@ class DisplayableGraph extends SimpleGraph
}
}
}
-
+
$oNodesIter = new RelationTypeIterator($oNewGraph, 'Node');
foreach($oNodesIter as $oNode)
{
@@ -981,7 +981,7 @@ class DisplayableGraph extends SimpleGraph
}
}
}
-
+
// Remove duplicate edges between two nodes
$oEdgesIter = new RelationTypeIterator($oNewGraph, 'Edge');
$aEdgeKeys = array();
@@ -1010,10 +1010,10 @@ class DisplayableGraph extends SimpleGraph
}
}
set_time_limit(intval($iPreviousTimeLimit));
-
+
return $oNewGraph;
}
-
+
/**
* Initializes the positions by rendering using Graphviz in xdot format
* and parsing the output.
@@ -1026,7 +1026,7 @@ class DisplayableGraph extends SimpleGraph
{
throw new Exception($sDot);
}
-
+
$aChunks = explode(";", $sDot);
foreach($aChunks as $sChunk)
{
@@ -1035,7 +1035,7 @@ class DisplayableGraph extends SimpleGraph
$sId = $aMatches[1];
$xPos = $aMatches[2];
$yPos = $aMatches[3];
-
+
$oNode = $this->GetNode($sId);
if ($oNode !== null)
{
@@ -1049,7 +1049,7 @@ class DisplayableGraph extends SimpleGraph
}
}
}
-
+
public function GetBoundingBox()
{
$xMin = null;
@@ -1074,10 +1074,10 @@ class DisplayableGraph extends SimpleGraph
$yMax = max($yMax, $oNode->y + $oNode->GetHeight() / 2);
}
}
-
+
return array('xmin' => $xMin, 'xmax' => $xMax, 'ymin' => $yMin, 'ymax' => $yMax);
}
-
+
function Translate($dx, $dy)
{
$oIterator = new RelationTypeIterator($this, 'Node');
@@ -1085,9 +1085,9 @@ class DisplayableGraph extends SimpleGraph
{
$oNode->x += $dx;
$oNode->y += $dy;
- }
+ }
}
-
+
public function UpdatePositions($aPositions)
{
foreach($aPositions as $sNodeId => $aPos)
@@ -1107,7 +1107,7 @@ class DisplayableGraph extends SimpleGraph
function GetAsJSON($sContextKey)
{
$aContextDefs = static::GetContextDefinitions($sContextKey, false);
-
+
$aData = array('nodes' => array(), 'edges' => array(), 'groups' => array(), 'lists' => array());
$iGroupIdx = 0;
$oIterator = new RelationTypeIterator($this, 'Node');
@@ -1131,7 +1131,7 @@ class DisplayableGraph extends SimpleGraph
$aData['groups'][$iGroupIdx] = array('class' => $sClass, 'keys' => $aKeys);
$oNode->SetProperty('group_index', $iGroupIdx);
$iGroupIdx++;
-
+
if ($oNode->GetProperty('is_reached'))
{
// Also add the objects from this group into the 'list' tab
@@ -1139,11 +1139,11 @@ class DisplayableGraph extends SimpleGraph
{
$aData['lists'][$sClass] = $aKeys;
}
- else
+ else
{
$aData['lists'][$sClass] = array_merge($aData['lists'][$sClass], $aKeys);
}
-
+
}
}
if (($oNode instanceof DisplayableNode) && $oNode->GetProperty('is_reached') && is_object($oNode->GetProperty('object')))
@@ -1157,9 +1157,9 @@ class DisplayableGraph extends SimpleGraph
}
$aData['nodes'][] = $oNode->GetForRaphael($aContextDefs);
}
-
+
uksort($aData['lists'], array(get_class($this), 'SortOnClassLabel')); // sort on the localized names of the classes to provide a consistent and stable order
-
+
$oIterator = new RelationTypeIterator($this, 'Edge');
foreach($oIterator as $sId => $oEdge)
{
@@ -1171,7 +1171,7 @@ class DisplayableGraph extends SimpleGraph
$aEdge['attr'] = array('opacity' => $fOpacity, 'stroke' => '#000');
$aData['edges'][] = $aEdge;
}
-
+
return json_encode($aData);
}
@@ -1200,12 +1200,12 @@ class DisplayableGraph extends SimpleGraph
{
$aContextDefs = static::GetContextDefinitions($sContextKey, false); // No need to develop the parameters
$oPdf = $oPage->get_tcpdf();
-
+
$aBB = $this->GetBoundingBox();
$this->Translate(-$aBB['xmin'], -$aBB['ymin']);
-
+
$aMargins = $oPdf->getMargins();
-
+
if ($xMin == -1)
{
$xMin = $aMargins['left'];
@@ -1222,7 +1222,7 @@ class DisplayableGraph extends SimpleGraph
{
$yMax = $oPdf->getPageHeight() - $aMargins['bottom'];
}
-
+
$fBreakMargin = $oPdf->getBreakMargin();
$oPdf->SetAutoPageBreak(false);
$aRemainingArea = $this->RenderKey($oPdf, $sComments, $xMin, $yMin, $xMax, $yMax, $aContextDefs);
@@ -1230,19 +1230,19 @@ class DisplayableGraph extends SimpleGraph
$xMax = $aRemainingArea['xmax'];
$yMin = $aRemainingArea['ymin'];
$yMax = $aRemainingArea['ymax'];
-
+
//$oPdf->Rect($xMin, $yMin, $xMax - $xMin, $yMax - $yMin, 'D', array(), array(225, 50, 50));
-
+
$fPageW = $xMax - $xMin;
$fPageH = $yMax - $yMin;
-
- $w = $aBB['xmax'] - $aBB['xmin'];
+
+ $w = $aBB['xmax'] - $aBB['xmin'];
$h = $aBB['ymax'] - $aBB['ymin'] + 10; // Extra space for the labels which may appear "below" the icons
-
+
$fScale = min($fPageW / $w, $fPageH / $h);
$dx = ($fPageW - $fScale * $w) / 2;
$dy = ($fPageH - $fScale * $h) / 2;
-
+
$this->Translate(($xMin + $dx)/$fScale, ($yMin + $dy)/$fScale);
$oIterator = new RelationTypeIterator($this, 'Edge');
@@ -1264,7 +1264,7 @@ class DisplayableGraph extends SimpleGraph
$oPdf->SetAlpha(1);
$oPdf->SetTextColor(0, 0, 0);
}
-
+
/**
* Renders (in PDF) the key (legend) of the graphics vertically to the left of the specified zone (xmin,ymin, xmax,ymax),
* and the comment (if any) at the bottom of the page. Returns the position of remaining area.
@@ -1332,7 +1332,7 @@ class DisplayableGraph extends SimpleGraph
$yPos += $fIconSize + 2 * $fPadding;
}
$oPdf->Rect($xMin, $yMin, $fMaxWidth + $fIconSize + 3*$fPadding, $yMax - $yMin, 'D');
-
+
if ($sComments != '')
{
// Draw the comment text (surrounded by a rectangle)
@@ -1347,10 +1347,10 @@ class DisplayableGraph extends SimpleGraph
$oPdf->Rect($xPos, $yPos, $w + 2*$fPadding, $h + 2*$fPadding, 'D');
$yMax = $yPos - $fPadding;
}
-
+
return array('xmin' => $xMin + $fMaxWidth + $fIconSize + 4*$fPadding, 'xmax' => $xMax, 'ymin' => $yMin, 'ymax' => $yMax);
}
-
+
/**
* Get the context definitions from the parameters / configuration. The format of the "key" string is:
* /relation_context///
@@ -1372,7 +1372,7 @@ class DisplayableGraph extends SimpleGraph
else
{
$sLeafClass = $aLevels[2];
-
+
if (!MetaModel::IsValidClass($sLeafClass))
{
IssueLog::Warning("GetContextDefinitions: invalid 'sLeafClass' = '$sLeafClass'. A valid class name is expected in 3rd position inside '$sContextKey' !");
@@ -1387,7 +1387,7 @@ class DisplayableGraph extends SimpleGraph
$aContextDefs = array_merge($aContextDefs, $aRelationContext[$sClass][$aLevels[3]][$aLevels[4]]['items']);
}
}
-
+
// Check if the queries are valid
foreach($aContextDefs as $sKey => $sDefs)
{
@@ -1425,168 +1425,101 @@ class DisplayableGraph extends SimpleGraph
* @throws \CoreException
* @throws \DictExceptionMissingString
*/
- function Display(WebPage $oP, $aResults, $sRelation, ApplicationContext $oAppContext, $aExcludedObjects, $sObjClass, $iObjKey, $sContextKey, $aContextParams = array())
- {
- $aContextDefs = static::GetContextDefinitions($sContextKey, true, $aContextParams);
- $aExcludedByClass = array();
- foreach($aExcludedObjects as $oObj)
- {
- if (!array_key_exists(get_class($oObj), $aExcludedByClass))
- {
- $aExcludedByClass[get_class($oObj)] = array();
- }
- $aExcludedByClass[get_class($oObj)][] = $oObj->GetKey();
- }
- $sSftShort = Dict::S('UI:ElementsDisplayed');
- $sSearchToggle = Dict::S('UI:Search:Toggle');
- $oP->add("\n");
- $oUiSearchBlock = new Panel($sSftShort, [],Panel::ENUM_COLOR_SCHEME_CYAN, 'ds_flash');
- $oUiSearchBlock->SetCSSClasses(["ibo-search-form-panel", "display_block"]);
- $oUiSearchBlock->SetIsCollapsible(true);
- $oUiHtmlBlock = new Combodo\iTop\Application\UI\Base\Component\Html\Html(
-<<
- ");
- $oUiHtmlBlock->AddHtml("
");
- $oUiHtmlBlock->AddHtml(" \n");
- $oUiHtmlBlock->AddHtml("\n"); // class="not-printable"
+ function Display(WebPage $oP, $aResults, $sRelation, ApplicationContext $oAppContext, $aExcludedObjects, $sObjClass, $iObjKey, $sContextKey, $aContextParams = array(), bool $sLazyLoading = false)
+ {
+ list($aExcludedByClass, $aAdditionalContexts) = $this->DisplayFiltering($sContextKey, $aContextParams, $aExcludedObjects, $oP, $aResults, $sLazyLoading);
- $oUiSearchBlock->AddSubBlock($oUiHtmlBlock);
- $oP->AddUiBlock($oUiSearchBlock);
- $aAdditionalContexts = array();
- foreach($aContextDefs as $sKey => $aDefinition)
- {
- $aAdditionalContexts[] = array('key' => $sKey, 'label' => Dict::S($aDefinition['dict']), 'oql' => $aDefinition['oql'], 'default' => (array_key_exists('default', $aDefinition) && ($aDefinition['default'] == 'yes')));
- }
-
- $sDirection = utils::ReadParam('d', 'horizontal');
$iGroupingThreshold = utils::ReadParam('g', 5);
WebResourcesHelper::EnableSimpleGraphInWebPage($oP);
- try
- {
+ try {
$this->InitFromGraphviz();
- $sExportAsPdfURL = '';
$sExportAsPdfURL = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=relation_pdf&relation='.$sRelation.'&direction='.($this->bDirectionDown ? 'down' : 'up');
- $oAppcontext = new ApplicationContext();
$sContext = $oAppContext->GetForLink();
$sDrillDownURL = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=details&class=%1$s&id=%2$s&'.$sContext;
$sExportAsDocumentURL = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=relation_attachment&relation='.$sRelation.'&direction='.($this->bDirectionDown ? 'down' : 'up');
$sLoadFromURL = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=relation_json&relation='.$sRelation.'&direction='.($this->bDirectionDown ? 'down' : 'up');
$sAttachmentExportTitle = '';
- if (($sObjClass != null) && ($iObjKey != null))
- {
+ if (($sObjClass != null) && ($iObjKey != null)) {
$oTargetObj = MetaModel::GetObject($sObjClass, $iObjKey, false);
- if ($oTargetObj)
- {
+ if ($oTargetObj) {
$sAttachmentExportTitle = Dict::Format('UI:Relation:AttachmentExportOptions_Name', $oTargetObj->GetName());
}
}
-
+
$sId = 'graph';
$sStyle = '';
- if ($oP->IsPrintableVersion())
- {
+ if ($oP->IsPrintableVersion()) {
// Optimize for printing on A4/Letter vertically
$sStyle = 'margin-left:auto; margin-right:auto;';
$oP->add_ready_script("$('.simple-graph').width(18/2.54*96).resizable({ stop: function() { $(window).trigger('resized'); }});"); // Default width about 18 cm, since most browsers assume 96 dpi
}
$oP->add('');
$aParams = array(
- 'source_url' => $sLoadFromURL,
- 'sources' => ($this->bDirectionDown ? $this->aSourceObjects : $this->aSinkObjects),
- 'excluded' => $aExcludedByClass,
- 'grouping_threshold' => $iGroupingThreshold,
- 'export_as_pdf' => array('url' => $sExportAsPdfURL, 'label' => Dict::S('UI:Relation:ExportAsPDF')),
+ 'source_url' => $sLoadFromURL,
+ 'sources' => ($this->bDirectionDown ? $this->aSourceObjects : $this->aSinkObjects),
+ 'excluded' => $aExcludedByClass,
+ 'grouping_threshold' => $iGroupingThreshold,
+ 'export_as_pdf' => array('url' => $sExportAsPdfURL, 'label' => Dict::S('UI:Relation:ExportAsPDF')),
'export_as_attachment' => array('url' => $sExportAsDocumentURL, 'label' => Dict::S('UI:Relation:ExportAsAttachment'), 'obj_class' => $sObjClass, 'obj_key' => $iObjKey),
- 'drill_down' => array('url' => $sDrillDownURL, 'label' => Dict::S('UI:Relation:DrillDown')),
- 'labels' => array(
- 'export_pdf_title' => Dict::S('UI:Relation:PDFExportOptions'),
+ 'drill_down' => array('url' => $sDrillDownURL, 'label' => Dict::S('UI:Relation:DrillDown')),
+ 'labels' => array(
+ 'export_pdf_title' => Dict::S('UI:Relation:PDFExportOptions'),
'export_as_attachment_title' => $sAttachmentExportTitle,
- 'export' => Dict::S('UI:Button:Export'),
- 'cancel' => Dict::S('UI:Button:Cancel'),
- 'title' => Dict::S('UI:RelationOption:Title'),
- 'untitled' => Dict::S('UI:RelationOption:Untitled'),
- 'include_list' => Dict::S('UI:RelationOption:IncludeList'),
- 'comments' => Dict::S('UI:RelationOption:Comments'),
- 'grouping_threshold' => Dict::S('UI:RelationOption:GroupingThreshold'),
- 'refresh' => Dict::S('UI:Button:Refresh'),
- 'check_all' => Dict::S('UI:SearchValue:CheckAll'),
- 'uncheck_all' => Dict::S('UI:SearchValue:UncheckAll'),
- 'none_selected' => Dict::S('UI:Relation:NoneSelected'),
- 'nb_selected' => Dict::S('UI:SearchValue:NbSelected'),
- 'additional_context_info' => Dict::S('UI:Relation:AdditionalContextInfo'),
- 'zoom' => Dict::S('UI:Relation:Zoom'),
- 'loading' => Dict::S('UI:Loading'),
+ 'export' => Dict::S('UI:Button:Export'),
+ 'cancel' => Dict::S('UI:Button:Cancel'),
+ 'title' => Dict::S('UI:RelationOption:Title'),
+ 'untitled' => Dict::S('UI:RelationOption:Untitled'),
+ 'include_list' => Dict::S('UI:RelationOption:IncludeList'),
+ 'comments' => Dict::S('UI:RelationOption:Comments'),
+ 'grouping_threshold' => Dict::S('UI:RelationOption:GroupingThreshold'),
+ 'refresh' => Dict::S('UI:Button:Refresh'),
+ 'check_all' => Dict::S('UI:SearchValue:CheckAll'),
+ 'uncheck_all' => Dict::S('UI:SearchValue:UncheckAll'),
+ 'none_selected' => Dict::S('UI:Relation:NoneSelected'),
+ 'nb_selected' => Dict::S('UI:SearchValue:NbSelected'),
+ 'additional_context_info' => Dict::S('UI:Relation:AdditionalContextInfo'),
+ 'zoom' => Dict::S('UI:Relation:Zoom'),
+ 'loading' => Dict::S('UI:Loading'),
),
- 'page_format' => array(
- 'label' => Dict::S('UI:Relation:PDFExportPageFormat'),
+ 'page_format' => array(
+ 'label' => Dict::S('UI:Relation:PDFExportPageFormat'),
'values' => array(
- 'A3' => Dict::S('UI:PageFormat_A3'),
- 'A4' => Dict::S('UI:PageFormat_A4'),
+ 'A3' => Dict::S('UI:PageFormat_A3'),
+ 'A4' => Dict::S('UI:PageFormat_A4'),
'Letter' => Dict::S('UI:PageFormat_Letter'),
),
),
- 'page_orientation' => array(
- 'label' => Dict::S('UI:Relation:PDFExportPageOrientation'),
+ 'page_orientation' => array(
+ 'label' => Dict::S('UI:Relation:PDFExportPageOrientation'),
'values' => array(
'P' => Dict::S('UI:PageOrientation_Portrait'),
'L' => Dict::S('UI:PageOrientation_Landscape'),
),
),
- 'additional_contexts' => $aAdditionalContexts,
- 'context_key' => $sContextKey,
+ 'additional_contexts' => $aAdditionalContexts,
+ 'context_key' => $sContextKey,
);
- if (!extension_loaded('gd'))
- {
+ if (!extension_loaded('gd')) {
// PDF export requires GD
unset($aParams['export_as_pdf']);
}
- if (!extension_loaded('gd') || is_null($sObjClass) || is_null($iObjKey))
- {
+ if (!extension_loaded('gd') || is_null($sObjClass) || is_null($iObjKey)) {
// Export as Attachment requires GD (for building the PDF) AND a valid objclass/objkey couple
unset($aParams['export_as_attachment']);
}
- $oP->add_ready_script("$('#$sId').simple_graph(".json_encode($aParams).");");
+ if ($oP->IsPrintableVersion() || !$sLazyLoading) {
+ $oP->add_ready_script(" $('#$sId').simple_graph(".json_encode($aParams).");");
+ } else {
+ $oP->add_script("function Load(){var aExcluded = []; $('input[name^=excluded]').each( function() {if (!$(this).prop('checked')) { aExcluded.push($(this).val()); }} ); var params= $.extend(".json_encode($aParams).", {excluded_classes: aExcluded}); $('#$sId').simple_graph(params);}");
+ }
}
catch(Exception $e)
{
$oP->add(''.$e->getMessage().'
');
}
$oP->add_script(
-<<GetKey();
+ }
+ $sSftShort = Dict::S('UI:ElementsDisplayed');
+ $oP->add("\n");
+ $oUiSearchBlock = new Panel($sSftShort, [], Panel::ENUM_COLOR_SCHEME_CYAN, 'dh_flash');
+ $oUiSearchBlock->SetCSSClasses(["ibo-search-form-panel", "display_block"]);
+ $oUiSearchBlock->SetIsCollapsible(true);
+ $oUiHtmlBlock = new Combodo\iTop\Application\UI\Base\Component\Html\Html(
+ <<
+ ");
+ if ($sLazyLoading) {
+ $sOnCLick = "Load(); $('#ReloadMovieBtn').attr('onclick','DoReload()');$('#ReloadMovieBtn').html('".Dict::S('UI:Button:Refresh')."');";
+ $oUiHtmlBlock->AddHtml("
");
+ } else {
+ $sOnCLick = "DoReload()";
+ $oUiHtmlBlock->AddHtml(" ");
+ }
+ $oUiHtmlBlock->AddHtml("\n");
+ $oUiHtmlBlock->AddHtml("\n"); // class="not-printable"
+
+ $oUiSearchBlock->AddSubBlock($oUiHtmlBlock);
+ $oP->AddUiBlock($oUiSearchBlock);
+
+ $aAdditionalContexts = array();
+ foreach ($aContextDefs as $sKey => $aDefinition) {
+ $aAdditionalContexts[] = array('key' => $sKey, 'label' => Dict::S($aDefinition['dict']), 'oql' => $aDefinition['oql'], 'default' => (array_key_exists('default', $aDefinition) && ($aDefinition['default'] == 'yes')));
+ }
+
+ return array($aExcludedByClass, $aAdditionalContexts);
+ }
+
}
diff --git a/js/simple_graph.js b/js/simple_graph.js
index 41d5783a7..1e2980bc8 100644
--- a/js/simple_graph.js
+++ b/js/simple_graph.js
@@ -9,955 +9,961 @@ $(function()
// the widget definition, where "itop" is the namespace,
// "dashboard" the widget name
$.widget( "itop.simple_graph",
- {
- // default options
- options:
{
- align: 'center',
- 'vertical-align': 'middle',
- source_url: null,
- sources: {},
- excluded: {},
- export_as_pdf: null,
- page_format: { label: 'Page Format:', values: { A3: 'A3', A4: 'A4', Letter: 'Letter' }, 'default': 'A4'},
- page_orientation: { label: 'Page Orientation:', values: { P: 'Portait', L: 'Landscape' }, 'default': 'L' },
- labels: {
- export_pdf_title: 'PDF Export Options',
- cancel: 'Cancel', 'export': 'Export',
- title: 'Document Title',
- include_list: 'Include the list of objects',
- comments: 'Comments',
- grouping_threshold: 'Grouping Threshold',
- additional_context_info: 'Additional Context Info',
- refresh: 'Refresh',
- check_all: 'Check All',
- uncheck_all: 'Uncheck All',
- none_selected: 'None',
- nb_selected: '# selected',
- zoom: 'Zoom',
- loading: 'Loading...'
- },
- export_as_document: null,
- drill_down: null,
- grouping_threshold: 10,
- excluded_classes: [],
- attachment_obj_class: null,
- attachment_obj_key: null,
- additional_contexts: [],
- context_key: ''
- },
- css_classes:
- {
- has_focus: 'ibo-has-focus'
- },
- // the constructor
- _create: function()
- {
- var me = this;
- this.aNodes = [];
- this.aEdges = [];
- this.fZoom = 1.0;
- this.xOffset = 0;
- this.yOffset = 0;
- this.xPan = 0;
- this.yPan = 0;
- this.iTextHeight = 12;
- this.fSliderZoom = 1.0;
- this.bInUpdateSliderZoom = false;
- this.bRedrawNeeded = false;
-
- this.oPaper = Raphael(this.element.get(0), this.element.width(), screen.availHeight * 2 / 3);
-
- this.element
- .addClass('panel-resized')
- .addClass('itop-simple-graph')
- .addClass('graph');
-
- this._create_toolkit_menu();
- this._build_context_menus();
- this.sTabId = null;
- var jTabPanel = this.element.closest('.ui-tabs-panel');
- if (jTabPanel.length > 0) {
- // We are inside a tab, find out which one and hook its activation
- this.sTabId = jTabPanel.attr('id');
- var jTabs = this.element.closest('.ibo-tab-container');
- jTabs.on("tabsactivate", function (event, ui) {
- me._on_tabs_activate(ui);
- });
- }
- $(window).bind('resized', function () {
- var that = me;
- window.setTimeout(function () {
- that._on_resize();
- }, 50);
- });
- $('#dh_flash').bind('toggle_complete', function () {
- var that = me;
- window.setTimeout(function () {
- that._on_resize();
- }, 50);
- });
- this.element.on('mousewheel', function (event, delta, deltaX, deltaY) {
- return me._on_mousewheel(event, delta, deltaX, deltaY);
- });
- $(document).on('click', function (e) {
- if ($(e.target).closest(me.element).length === 0) {
- me.element.removeClass(me.css_classes.has_focus);
- } else {
- me.element.addClass(me.css_classes.has_focus);
- }
- });
- if (this.options.source_url != null) {
- this.load_from_url(this.options.source_url);
- }
- },
- // called when created, and later when changing options
- _refresh: function()
- {
- this.draw();
- },
- // events bound via _bind are removed automatically
- // revert other modifications here
- _destroy: function()
- {
- var sId = this.element.attr('id');
- this.element
- .removeClass('itop-simple-graph')
- .removeClass('graph');
-
- $('#tk_graph'+sId).remove();
- $('#graph_'+sId+'_export_as_pdf').remove();
-
- },
- // _setOptions is called with a hash of all options that are changing
- _setOptions: function()
- {
- this._superApply(arguments);
- },
- // _setOption is called for each individual option that is changing
- _setOption: function( key, value )
- {
- this._superApply(arguments);
- },
- draw: function()
- {
- this._updateBBox();
- this.auto_scale();
- this.oPaper.clear();
- this._reset
- this.oPaper.setViewBox(this.xPan, this.yPan, this.element.width(), this.element.height(), false);
- for(var k in this.aNodes)
- {
- this.aNodes[k].aElements = [];
- this._draw_node(this.aNodes[k]);
- }
- for(var k in this.aEdges)
- {
- this.aEdges[k].aElements = [];
- this._draw_edge(this.aEdges[k]);
- }
- var me = this;
- this.oBackground = this.oPaper
- .rect(-10000, -10000, 20000, 20000)
- .attr({fill: '#fff', opacity: 0, cursor: 'move'})
- .toBack()
- .drag(function(dx, dy, x, y, event) { me._on_background_move(dx, dy, x, y, event); }, function(x, y, event) { me._on_background_drag_start(x, y, event); }, function (event) { me._on_background_drag_end(event); });
- this._make_tooltips();
- },
- _draw_node: function(oNode)
- {
- var iWidth = oNode.width;
- var iHeight = 32;
- var iFontSize = 10;
- var fTotalZoom = this.fZoom * this.fSliderZoom;
- var xPos = Math.round(oNode.x * fTotalZoom + this.xOffset);
- var yPos = Math.round(oNode.y * fTotalZoom + this.yOffset);
- oNode.tx = 0;
- oNode.ty = 0;
- switch(oNode.shape)
- {
- case 'disc':
- oScaledAttr = {};
- for(k in oNode.disc_attr)
+ // default options
+ options:
{
- value = oNode.disc_attr[k]
- switch(k)
- {
- // Scalable attributes
- case 'stroke-width':
- value = value * fTotalZoom;
- break;
- }
- oScaledAttr[k] = value;
- }
- oNode.aElements.push(this.oPaper.circle(xPos, yPos, iWidth*fTotalZoom / 2).attr(oScaledAttr));
- var oText = this.oPaper.text(xPos, yPos, oNode.label);
- oNode.text_attr['font-size'] = iFontSize * fTotalZoom;
- oText.attr(oNode.text_attr);
- //oText.transform('s'+this.fZoom);
- oNode.aElements.push(oText);
- break;
-
- case 'group':
- oNode.aElements.push(this.oPaper.circle(xPos, yPos, iWidth*fTotalZoom / 2).attr({fill: '#fff', 'stroke-width':0}));
- oScaledAttr = {};
- for(k in oNode.disc_attr)
- {
- value = oNode.disc_attr[k]
- switch(k)
- {
- // Scalable attributes
- case 'stroke-width':
- value = value * fTotalZoom;
- break;
- }
- oScaledAttr[k] = value;
- }
- oNode.aElements.push(this.oPaper.circle(xPos, yPos, iWidth*fTotalZoom / 2).attr(oScaledAttr));
- var xIcon = xPos - 18 * fTotalZoom;
- var yIcon = yPos - 18 * fTotalZoom;
- oNode.aElements.push(this.oPaper.image(oNode.icon_url, xIcon, yIcon, 16*fTotalZoom, 16*fTotalZoom).attr(oNode.icon_attr));
- oNode.aElements.push(this.oPaper.image(oNode.icon_url, xIcon + 18*fTotalZoom, yIcon, 16*fTotalZoom, 16*fTotalZoom).attr(oNode.icon_attr));
- oNode.aElements.push(this.oPaper.image(oNode.icon_url, xIcon + 9*fTotalZoom, yIcon + 18*fTotalZoom, 16*fTotalZoom, 16*fTotalZoom).attr(oNode.icon_attr));
- var oText = this.oPaper.text(xPos, yPos +2, oNode.label);
- oNode.text_attr['font-size'] = iFontSize * fTotalZoom;
- oText.attr(oNode.text_attr);
- //oText.transform('s'+this.fZoom);
- var oBB = oText.getBBox();
- var dy = iHeight/2*fTotalZoom + oBB.height/2;
- oText.remove();
- oText = this.oPaper.text(xPos, yPos +dy +2, oNode.label);
- oText.attr(oNode.text_attr);
- //oText.transform('s'+this.fZoom);
- oNode.aElements.push(oText);
- oNode.aElements.push(this.oPaper.rect( xPos - oBB.width/2 -2, yPos - oBB.height/2 + dy, oBB.width +4, oBB.height).attr({fill: '#fff', stroke: '#fff', opacity: 0.9}));
- oText.toFront();
- break;
-
- case 'icon':
- if(Raphael.svg)
- {
- // the colorShift plugin works only in SVG
- oNode.aElements.push(this.oPaper.image(oNode.icon_url, xPos - iWidth * fTotalZoom/2, yPos - iHeight * fTotalZoom/2, iWidth*fTotalZoom, iHeight*fTotalZoom).colorShift('#fff', 1));
- }
- oNode.aElements.push(this.oPaper.image(oNode.icon_url, xPos - iWidth * fTotalZoom/2, yPos - iHeight * fTotalZoom/2, iWidth*fTotalZoom, iHeight*fTotalZoom).attr(oNode.icon_attr));
-
- var idx = 0;
- for(var i in oNode.context_icons)
- {
- var sgn = 2*(idx % 2) -1; // Suite: -1, 1, -1, 1, -1, 1, -1, etc.
- var coef = Math.floor((1+idx)/2) * sgn; // Suite: 0, 1, -1, 2, -2, 3, -3, etc.
- var alpha = coef*Math.PI/4 - Math.PI/2;
- var x = xPos + Math.cos(alpha) * 1.25*iWidth * fTotalZoom / 2;
- var y = yPos + Math.sin(alpha) * 1.25*iWidth * fTotalZoom / 2;
- var l = iWidth/3 * fTotalZoom;
- oNode.aElements.push(this.oPaper.image(oNode.context_icons[i], x - l/2, y - l/2, l , l).attr(oNode.icon_attr));
- idx++;
- }
- var oText = this.oPaper.text( xPos, yPos, oNode.label);
- oNode.text_attr['font-size'] = iFontSize * fTotalZoom;
- oText.attr(oNode.text_attr);
- //oText.transform('S'+fTotalZoom);
- var oBB = oText.getBBox();
- var dy = iHeight/2*fTotalZoom + oBB.height/2;
- oText.remove();
- oText = this.oPaper.text( xPos, yPos + dy, oNode.label);
- oText.attr(oNode.text_attr);
- //oText.transform('S'+fTotalZoom);
- oNode.aElements.push(oText);
- oNode.aElements.push(this.oPaper.rect( xPos - oBB.width/2 -2, yPos - oBB.height/2 + dy, oBB.width +4, oBB.height).attr({fill: '#fff', stroke: '#fff', opacity: 0.9}).toBack());
- break;
- }
- if (oNode.source)
- {
- oNode.aElements.push(this.oPaper.circle(xPos, yPos, 1.25*iWidth*fTotalZoom / 2).attr({stroke: '#c33', 'stroke-width': 3*fTotalZoom }).toBack());
- }
- if (oNode.sink)
- {
- oNode.aElements.push(this.oPaper.circle(xPos, yPos, 1.25*iWidth*fTotalZoom / 2).attr({stroke: '#33c', 'stroke-width': 3*fTotalZoom }).toBack());
- }
-
- var me = this;
- for(k in oNode.aElements)
- {
- var sNodeId = oNode.id;
- $(oNode.aElements[k].node).attr({'data-type': oNode.shape, 'data-id': oNode.id} ).attr('class', 'popupMenuTarget');
- oNode.aElements[k].drag(
- function(dx, dy, x, y, event) {
- clearTimeout($(this.node).data('openTimeoutId'));
- me._move(sNodeId, dx, dy, x, y, event);
+ align: 'center',
+ 'vertical-align': 'middle',
+ source_url: null,
+ sources: {},
+ excluded: {},
+ export_as_pdf: null,
+ page_format: { label: 'Page Format:', values: { A3: 'A3', A4: 'A4', Letter: 'Letter' }, 'default': 'A4'},
+ page_orientation: { label: 'Page Orientation:', values: { P: 'Portait', L: 'Landscape' }, 'default': 'L' },
+ labels: {
+ export_pdf_title: 'PDF Export Options',
+ cancel: 'Cancel', 'export': 'Export',
+ title: 'Document Title',
+ include_list: 'Include the list of objects',
+ comments: 'Comments',
+ grouping_threshold: 'Grouping Threshold',
+ additional_context_info: 'Additional Context Info',
+ refresh: 'Refresh',
+ check_all: 'Check All',
+ uncheck_all: 'Uncheck All',
+ none_selected: 'None',
+ nb_selected: '# selected',
+ zoom: 'Zoom',
+ loading: 'Loading...'
},
- function(x, y, event) {
- me._drag_start(sNodeId, x, y, event);
- },
- function (event) {
- me._drag_end(sNodeId, event);
- }
- );
- }
- },
- _move: function(sNodeId, dx, dy, x, y, event)
- {
- var fTotalZoom = this.fZoom * this.fSliderZoom;
- var origDx = dx / fTotalZoom;
- var origDy = dy / fTotalZoom;
-
- var oNode = this._find_node(sNodeId);
- oNode.x = oNode.xOrig + origDx;
- oNode.y = oNode.yOrig + origDy;
-
- for(k in oNode.aElements)
- {
- oNode.aElements[k].transform('t'+(oNode.tx + dx)+', '+(oNode.ty + dy));
-
- for(j in this.aEdges)
+ export_as_document: null,
+ drill_down: null,
+ grouping_threshold: 10,
+ excluded_classes: [],
+ attachment_obj_class: null,
+ attachment_obj_key: null,
+ additional_contexts: [],
+ context_key: ''
+ },
+ css_classes:
{
- var oEdge = this.aEdges[j];
- if ((oEdge.source_node_id == sNodeId) || (oEdge.sink_node_id == sNodeId))
- {
- var sPath = this._get_edge_path(oEdge);
- oEdge.aElements[0].attr({path: sPath});
- }
- }
- }
- },
- _drag_start: function(sNodeId, x, y, event)
- {
- var oNode = this._find_node(sNodeId);
- oNode.xOrig = oNode.x;
- oNode.yOrig = oNode.y;
-
- },
- _drag_end: function(sNodeId, event)
- {
- var fTotalZoom = this.fZoom * this.fSliderZoom;
- var oNode = this._find_node(sNodeId);
- oNode.tx += (oNode.x - oNode.xOrig) * fTotalZoom;
- oNode.ty += (oNode.y - oNode.yOrig) * fTotalZoom;
- oNode.xOrig = oNode.x;
- oNode.yOrig = oNode.y;
- this._updateBBox();
- },
- _updateBBox: function()
- {
- this.options.xmin = 9999;
- this.options.xmax = -9999;
- this.options.ymin = 9999;
- this.options.ymax = -9999;
- for(var k in this.aNodes)
+ has_focus: 'ibo-has-focus'
+ },
+ // the constructor
+ _create: function()
{
- this.options.xmin = Math.min(this.aNodes[k].x + this.aNodes[k].tx - this.aNodes[k].width/2, this.options.xmin);
- this.options.xmax = Math.max(this.aNodes[k].x + this.aNodes[k].tx + this.aNodes[k].width/2, this.options.xmax);
- this.options.ymin = Math.min(this.aNodes[k].y + this.aNodes[k].ty - this.aNodes[k].width/2, this.options.ymin);
- this.options.ymax = Math.max(this.aNodes[k].y + this.aNodes[k].ty + this.aNodes[k].width/2, this.options.ymax);
- }
- },
- _get_edge_path: function(oEdge)
- {
- var fTotalZoom = this.fZoom * this.fSliderZoom;
- var oStart = this._find_node(oEdge.source_node_id);
- var oEnd = this._find_node(oEdge.sink_node_id);
- var iArrowSize = 5;
-
- if ((oStart == null) || (oEnd == null)) return '';
-
- var xStart = Math.round(oStart.x * fTotalZoom + this.xOffset);
- var yStart = Math.round(oStart.y * fTotalZoom + this.yOffset);
- var xEnd = Math.round(oEnd.x * fTotalZoom + this.xOffset);
- var yEnd = Math.round(oEnd.y * fTotalZoom + this.yOffset);
+ var me = this;
+ this.aNodes = [];
+ this.aEdges = [];
+ this.fZoom = 1.0;
+ this.xOffset = 0;
+ this.yOffset = 0;
+ this.xPan = 0;
+ this.yPan = 0;
+ this.iTextHeight = 12;
+ this.fSliderZoom = 1.0;
+ this.bInUpdateSliderZoom = false;
+ this.bRedrawNeeded = false;
- var sPath = Raphael.format('M{0},{1}L{2},{3}', xStart, yStart, xEnd, yEnd);
- var vx = (xEnd - xStart);
- var vy = (yEnd - yStart);
- var l = Math.sqrt(vx*vx+vy*vy);
- vx = vx / l;
- vy = vy / l;
- var ux = -vy;
- var uy = vx;
- var lPos = Math.max(l/2, l - 40*fTotalZoom);
- var xArrow = xStart + vx * lPos;
- var yArrow = yStart + vy * lPos;
- sPath += Raphael.format('M{0},{1}l{2},{3}M{4},{5}l{6},{7}', xArrow, yArrow, fTotalZoom * iArrowSize *(-vx + ux), fTotalZoom * iArrowSize *(-vy + uy), xArrow, yArrow, fTotalZoom * iArrowSize *(-vx - ux), fTotalZoom * iArrowSize *(-vy - uy));
- return sPath;
- },
- _draw_edge: function(oEdge)
- {
- var fTotalZoom = this.fZoom * this.fSliderZoom;
- var fStrokeSize = Math.max(1, 2 * fTotalZoom);
- var sPath = this._get_edge_path(oEdge);
- var oAttr = $.extend(oEdge.attr);
- oAttr['stroke-linecap'] = 'round';
- oAttr['stroke-width'] = fStrokeSize;
- oEdge.aElements.push(this.oPaper.path(sPath).attr(oAttr).toBack());
- },
- _find_node: function(sId)
- {
- for(var k in this.aNodes)
- {
- if (this.aNodes[k].id == sId) return this.aNodes[k];
- }
- return null;
- },
- auto_scale: function()
- {
- var fMaxZoom = 1.5;
-
- iMargin = 10;
- xmin = this.options.xmin - iMargin;
- xmax = this.options.xmax + iMargin;
- ymin = this.options.ymin - iMargin;
- ymax = this.options.ymax + iMargin;
- var xScale = this.element.width() / (xmax - xmin);
- var yScale = this.element.height() / (ymax - ymin + this.iTextHeight);
+ this.oPaper = Raphael(this.element.get(0), this.element.width(), screen.availHeight * 2 / 3);
- this.fZoom = Math.min(xScale, yScale, fMaxZoom);
- switch(this.options.align)
- {
- case 'left':
- this.xOffset = -xmin * this.fZoom;
- break;
-
- case 'right':
- this.xOffset = (this.element.width() - (xmax - xmin) * this.fZoom);
- break;
-
- case 'center':
- this.xOffset = -xmin * this.fZoom + (this.element.width() - (xmax - xmin) * this.fZoom) / 2;
- break;
- }
- switch(this.options['vertical-align'])
- {
- case 'top':
- this.yOffset = -ymin * this.fZoom;
- break;
-
- case 'bottom':
- this.yOffset = this.element.height() - (ymax + this.iTextHeight) * this.fZoom;
- break;
-
- case 'middle':
- this.yOffset = -ymin * this.fZoom + (this.element.height() - (ymax - ymin + this.iTextHeight) * this.fZoom) / 2;
- break;
- }
- },
- add_node: function(oNode)
- {
- oNode.aElements = [];
- oNode.tx = 0;
- oNode.ty = 0;
- this.aNodes.push(oNode);
- },
- add_edge: function(oEdge)
- {
- oEdge.aElements = [];
- this.aEdges.push(oEdge);
- },
- show_group: function(sGroupId)
- {
- this._close_all_tooltips();
- // Activate the 3rd tab
- this.element.closest('[data-role="ibo-tab-container"]').tab_container("GetTabsWidget").option("active", 2);
- // Scroll into view the group
- if ($('#'+sGroupId).length > 0)
- {
- $('#'+sGroupId)[0].scrollIntoView();
- }
- },
- _create_toolkit_menu: function()
- {
- var sPopupMenuId = 'tk_graph'+this.element.attr('id');
- var sHtml = '';
- var sId = this.element.attr('id');
- sHtml += '
';
- if (this.options.additional_contexts.length > 0)
- {
- sHtml += '
'
- }
- sHtml += '
';
- sHtml += '
';
- sHtml += '
';
- sHtml += '
';
- sHtml += '
';
- sHtml += '
';
- sHtml += '';
- sHtml += '
';
- sHtml += '
';
+ this.element
+ .addClass('panel-resized')
+ .addClass('itop-simple-graph')
+ .addClass('graph');
-
- this.element.before(sHtml);
- $('#'+sPopupMenuId+'>ul').popupmenu();
-
-
- var me = this;
- $('#'+sPopupMenuId+'_pdf').on('click', function() { me.export_as_pdf(); });
- $('#'+sPopupMenuId+'_attachment').on('click', function() { me.export_as_attachment(); });
- $('#'+sId+'_zoom').slider({ min: 0, max: 5, value: 1, step: 0.25, change: function() { me._on_zoom_change( $(this).slider('value')); } });
- $('#'+sId+'_zoom_plus').on('click', function() { $('#'+sId+'_zoom').slider('value', 0.25 + $('#'+sId+'_zoom').slider('value')); return false; });
- $('#'+sId+'_zoom_minus').on('click', function() { $('#'+sId+'_zoom').slider('value', $('#'+sId+'_zoom').slider('value') - 0.25); return false; });
- $('#'+sId+'_contexts').multiselect({header: true, checkAllText: this.options.labels.check_all, uncheckAllText: this.options.labels.uncheck_all, noneSelectedText: this.options.labels.none_selected, selectedText: this.options.labels.nb_selected, selectedList: 1});
- $('#'+sId+'_refresh_btn').button().on('click', function() { me.reload(); });
- },
- _build_context_menus: function()
- {
- var sId = this.element.attr('id');
- var me = this;
-
- $.contextMenu({
- selector: '#'+sId+' .popupMenuTarget',
- build: function(trigger, e) {
- // this callback is executed every time the menu is to be shown
- // its results are destroyed every time the menu is hidden
- // e is the original contextmenu event, containing e.pageX and e.pageY (amongst other data)
- var sType = trigger.attr('data-type');
- var sNodeId = trigger.attr('data-id');
- var oNode = me._find_node(sNodeId);
- clearTimeout(trigger.data('openTimeoutId'));
-
- /*
- var sObjName = trigger.attr('data-class');
- var sIndex = trigger.attr('data-index');
- var originalEvent = e;
- var bHasItems = false;
- */
- var oResult = {callback: null, items: {}};
- switch(sType)
- {
- case 'group':
- var sGroupIndex = oNode.group_index;
- if( $('#relation_group_'+sGroupIndex).length > 0)
- {
- oResult = {
- callback: function(key, options) {
- var me = $('.itop-simple-graph').data('itopSimple_graph'); // need a live value
- me.show_group('relation_group_'+sGroupIndex);
- },
- items: { 'show': {name: me.options.drill_down.label } }
- };
- }
- break;
-
- case 'icon':
- var sObjClass = oNode.obj_class;
- var sObjKey = oNode.obj_key;
- oResult = {
- callback: function(key, options) {
- var me = $('.itop-simple-graph').data('itopSimple_graph'); // need a live value
- var sURL = me.options.drill_down.url.replace('%1$s', sObjClass).replace('%2$s', sObjKey);
- window.location.href = sURL;
- },
- items: { 'details': {name: me.options.drill_down.label } }
- };
- break;
-
- default:
- oResult = false; // No context menu
- }
- return oResult;
- }
- });
-
- },
- export_as_pdf: function()
- {
- this._export_dlg(this.options.labels.export_pdf_title, this.options.export_as_pdf.url, 'download_pdf');
- },
- _export_dlg: function(sTitle, sSubmitUrl, sOperation)
- {
- var sId = this.element.attr('id');
- var me = this;
- var oPositions = {};
- for(k in this.aNodes)
- {
- oPositions[this.aNodes[k].id] = {x: this.aNodes[k].x, y: this.aNodes[k].y };
- }
- var sHtmlForm = '