/**************************************************************** ** Licensed Materials - Property of IBM ** ** IBM Cognos Products: mdsrv ** ** (C) Copyright IBM Corp. 2008, 2014 ** ** US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. *****************************************************************/ //*********************************************************************************************** // Copyright (C) 2008 Cognos ULC, an IBM Company. All rights reserved. // Cognos (R) is a trademark of Cognos ULC, (formerly Cognos Incorporated). // // Component: Graph control //*********************************************************************************************** //var DG = {}; // The diagram namespace var DG = new CNamespace(); // The diagram namespace //=============================================================================================== // Global Variables & Consts //=============================================================================================== DG.DebugOutputOn = false; DG.nObjectCounter = 0; // Required to generate the objects' unique Id DG.nLineCounter = 0; // Required to generate the lines' sequential Id //----------------------------------------------------------------------------------------------- DG.sSelectedObjectName = ''; // Persists the Selected Object between graph refreshes DG.sSelectedObjectType = ''; DG.CookieMgr = new CCookieMgr (); DG.sCookieSelObjectName = "graphSelectedObjectName"; DG.sCookieSelObjectType = "graphSelectedObjectType"; //----------------------------------------------------------------------------------------------- DG.DragDrop = new CDragDrop(); //----------------------------------------------------------------------------------------------- DG.typeGObject = { eNone: 0, eNode: 1, eItem: 2, eConnection: 3, getTypeString: function( type ) { return getPropertyName( this, type ); } }; //----------------------------------------------------------------------------------------------- DG.mapCssClasses = []; DG.mapCssClasses[ DG.typeGObject.eItem ] = 'classGraphItem'; DG.mapCssClasses[ DG.typeGObject.eNode ] = 'classGraphNode'; DG.mapCssClasses[ DG.typeGObject.eConnection ] = 'classGraphConnection'; //----------------------------------------------------------------------------------------------- // Colors' Default values DG.colorDefaults = { colorTextStandard: "Black", colorTextSelected: "White", colorBkSelTarget: "RGB(219,226,234)", colorSelectedScope: "Yellow", colorScope: "Blue", colorBkScope: "LightYellow", colorShortcut: "Red", colorBkShortcut: "White", colorLineStandard: "#999999", colorLineSelected: "#3085a5", /*Blue*/ colorBkStandard: "#f6f6f6", colorBkSelected: "#325C88", colorBorderStandard: "DarkGray", // colorBorderExternal: "DarkGray", colorBorderExternal: "Blue", colorBorderInternal: "LightGrey", colorShadow: "DarkGray" }; // Graph Default values DG.nRefResolution = { width: 1600 , height: 1200 }; DG.graphDefaults = { nNodeWidth: 130, nItemHeight: 18, nItemWidth: 170, nNodeOffsetX: 50, nNodeOffsetY: 40, nLineInOffsetY: 2, nLineOutOffsetY: -2, nIconSize: 16, nShadowWidth: 3, nPenWidth: 1, nLineWidthStandard: 1, nLineWidthSelected: 2, nArrowSize: 8, styleLine: 'solid', styleBorder: 'solid', styleShortcut: 'dotted', opacityCaption: 0.8, opacityBody: 0.8, opacityShadow: 0.5, nItemFontSize: 10, nNodeFontSize: 10, sBkImageSelected: 'Gradient2.png', sBkImageUnSelected: 'Gradient1.png', sActionIcon: 'action_custom.gif', sActionIconTooltip: '', sCurrentDir: '.', sImageSubdir: '/images/', getImagePath: function () { return this.sCurrentDir + this.sImageSubdir; }, bUseShadows: true, bInclParentProperties: false, bShowActionLinks: false }; //----------------------------------------------------------------------- DG.nScreenResolution = GetScreenResolution(); if ( DG.nScreenResolution.width > 0 ) { DG.graphDefaults.nScreenRatioWidth = DG.nScreenResolution.width / DG.nRefResolution.width; DG.graphDefaults.nNodeWidth *= DG.graphDefaults.nScreenRatioWidth; DG.graphDefaults.nNodeOffsetX *= DG.graphDefaults.nScreenRatioWidth; } if ( DG.nScreenResolution.height > 0 ) { DG.graphDefaults.nScreenRatioHeight = DG.nScreenResolution.height / DG.nRefResolution.height; DG.graphDefaults.nNodeOffsetY *= DG.graphDefaults.nScreenRatioHeight; } // alert( "nNodeWidth = " + DG.graphDefaults.nNodeWidth + ", nNodeOffsetX = " + DG.graphDefaults.nNodeOffsetX ); //--------------------------------------------------------------------- // Optimisation hack - Preload images var bkImageReg = new Image(30,400); bkImageReg.src = DG.graphDefaults.getImagePath() + DG.graphDefaults.sBkImageUnSelected; var bkImageSel = new Image(30,400); bkImageSel.src = DG.graphDefaults.getImagePath() + DG.graphDefaults.sBkImageSelected; //*********************************************************************************************** // Class CGraphControl //*********************************************************************************************** DG.CGraphControl = function ( controller, id_canvas, propertyManager ) { // Parameters Verification ASSERT( controller, "CGraphControl: controller is NOT valid !" ); ASSERT( id_canvas, "CGraphControl: id_canvas is NOT valid !" ); ASSERT( propertyManager, "CGraphControl: propertyManager is NOT valid !" ); // Members this.controller = controller; this.m_gdi = new gdi ( id_canvas, 100 ); this.m_name = ""; this.m_nodeList = []; this.m_connectionList = []; this.m_iconList = []; this.m_selTargetList = []; this.m_selObject = null; // implies single selection this.m_selNode = null; // if an item is selected -> this is its parent node this.m_mapGObjectIds = []; // the map of all graph's objects by their graph unique Ids (contains all graph objects) this.m_mapMObjectIds = []; // the map of graph's objects by their model unique Ids (contains only graph objects with valid model object) this.m_bCreated = false; this.m_isDragAllowed = true; this.m_isDragHorzAllowed = true; this.m_isDragVertAllowed = true; this.m_propertyManager = propertyManager; // Hookup event handlers this.m_gdi.canvas.graph = this; addEvent( this.m_gdi.canvas, 'click', processOnClick, false ); addEvent( this.m_gdi.canvas, 'dblclick', processOnDblClick, false ); addEvent( this.m_gdi.canvas, 'mousedown', processOnMouseDown, false ); addEvent( this.m_gdi.canvas, 'selectstart', processOnSelectStart, false ); // API this.getId = function () { return this.m_gdi.id; } this.setZoom = function ( zoom ) { this.m_gdi.setZoom (zoom); } this.getZoom = function () { return this.m_gdi.getZoom (); } this.setName = function ( sName ) { this.m_name = sName; } this.getIcon = function ( nIndex ) { return DG.graphDefaults.getImagePath() + this.m_iconList[ nIndex ]; } this.getActionIcon = function () { return DG.graphDefaults.getImagePath() + DG.graphDefaults.sActionIcon; } this.getIconIndex = function (icon) { var index = -1; var size = this.m_iconList.length; for ( var i = 0; i < size; i++ ) { if ( this.m_iconList[i] === icon ) { index = i; break; } } if ( index >= 0 ) return index; this.m_iconList.push (icon); return this.m_iconList.length - 1; } //---------------------------------------------------------------------------- // @VIRTUAL METHODS - should be overridden by the controller //---------------------------------------------------------------------------- this.getObjectIcon = function ( modelObject ) { if ( this.controller.getObjectIcon ) { return this.controller.getObjectIcon( modelObject ); } else { ASSERT( false, "getObjectIcon is VIRTUAL METHOD - OVERRIDE it !!!!" ); return ""; } } this.isShowItemIcon = function ( modelObject ) { if ( this.controller.isShowItemIcon ) { return this.controller.isShowItemIcon( modelObject ); } else { ASSERT( false, "isShowItemIcon is VIRTUAL METHOD - OVERRIDE it !!!!" ); return false; } } this.OnActionClick = function( modelObject ) { if ( this.controller.OnActionClick ) { return this.controller.OnActionClick( modelObject ); } else { ASSERT( false, "OnActionClick is VIRTUAL METHOD - OVERRIDE it !!!!" ); return false; } } //---------------------------------------------------------------------------- this.getNode = function ( nIndex ) { ASSERT( nIndex < this.m_nodeList.length, "getNode: node index is NOT valid !" ); var gNode = this.m_nodeList[ nIndex ]; return gNode; } this.getNodeByName = function ( sName ) { ASSERT( sName, "getNodeByName: sName is NOT valid !" ); var cNodes = this.m_nodeList.length; for ( var i = 0; i < cNodes; i++ ) { if ( this.m_nodeList[i].modelObject.getName() === sName ) return this.m_nodeList[i]; } return null; } this.addNode = function ( gNode ) { ASSERT( gNode, "addNode: node is NOT valid !" ); this.m_nodeList.push ( gNode ); gNode.calculateSize (); } this.addConnection = function (connection) { ASSERT( connection, "addConnection: connection is NOT valid !" ); this.m_connectionList.push (connection); } this.init = function () { var cNodes = this.m_nodeList.length; for ( var i = 0; i < cNodes; i++ ) { var gNode = this.m_nodeList[i]; gNode.restoreDefaults (); gNode.setZIndex ( false ); var cItems = gNode.itemList.length; for ( var j = 0; j < cItems; j++ ) { var gItem = gNode.itemList[j]; if ( gItem.isInScope || gItem.isShortcut ) { var cssHelper = UTIL.ElementHelper.setElem ( gItem.getObjectElem() ); cssHelper.setFontStyle ( 'italic' ); } } } var cConnections = this.m_connectionList.length; for ( var j2 = 0; j2 < cConnections; j2++ ) { this.m_connectionList[j2].setZIndex ( false ); } } this.onPostPaint = function () { var timeStart = new Date().getTime(); this.init (); DG.sSelectedObjectName = DG.CookieMgr.getCookie( DG.sCookieSelObjectName ); DG.sSelectedObjectType = DG.CookieMgr.getCookie( DG.sCookieSelObjectType ); if ( DG.sSelectedObjectName ) { var selObject = null; if ( DG.sSelectedObjectType === DG.typeGObject.getTypeString ( DG.typeGObject.eNode ) ) selObject = this.getNodeByName ( DG.sSelectedObjectName ); else selObject = this.findGItemByName ( DG.sSelectedObjectName ); if ( selObject ) { this.m_selObject = selObject; } } this.SelectObject ( this.m_selObject ); // alertTimeDiff ( timeStart, "CGraphControl.onPostPaint" ); } this.getClientSize = function () { var cssHelper = UTIL.ElementHelper.setElem ( this.m_gdi.canvas ); var sizeGraph = cssHelper.getClientSize (); return sizeGraph; } this.paint = function () { var timeStart = new Date().getTime(); this.m_gdi.init (); if ( this.m_name ) this.m_gdi.drawString ( this.m_name, "Lavender", 20, 80, 1200, 200, "", 80, "bold, italic" ); // alert( "CGraphControl.paint: Nodes = " + this.m_nodeList.length + ", Connections = " + this.m_connectionList.length ); // Paint connections var cConnections = this.m_connectionList.length; for ( var i = 0; i < cConnections; i++ ) { this.m_connectionList[i].paint ( this.m_gdi ); } // Paint nodes var cNodes = this.m_nodeList.length; for ( var j = 0; j < cNodes; j++ ) { this.m_nodeList[j].paint ( this.m_gdi ); } //---------------------------------------------------------------- // Refresh is inserting the accumulated HTML into the GRAPH area //---------------------------------------------------------------- this.m_gdi.refresh (); // alertTimeDiff ( timeStart, "DG.CGraphControl.paint" ); this.m_bCreated = true; //---------------------------------------------------------------- // At this point all GRAPH elements are ready for post-processing //---------------------------------------------------------------- this.onPostPaint(); } this.refreshConnections = function () { var cConnections = this.m_connectionList.length; for ( var i = 0; i < cConnections; i++) { var conn = this.m_connectionList[i]; conn.refresh ( this.m_gdi ); } } this.refreshConnectionsForNode = function ( gNode ) { var cConnections = this.m_connectionList.length; for ( var i = 0; i < cConnections; i++ ) { var conn = this.m_connectionList[i]; if ( conn.m_left === gNode || conn.m_right === gNode ) { conn.refresh ( this.m_gdi ); } } } this.findConnectionElbowOffsetX = function ( oConnection ) { var nElbowOffset = -1; var cConnections = this.m_connectionList.length; for ( var i = 0; i < cConnections; i++ ) { var oConn = this.m_connectionList[i]; if ( oConn !== oConnection ) { if ( ( oConn.gItemLeft && ( oConn.gItemLeft === oConnection.gItemLeft ) ) || ( oConn.gItemRight && ( oConn.gItemRight === oConnection.gItemRight ) ) ) { if ( oConn.m_left !== oConn.m_right && oConnection.m_left !== oConnection.m_right ) { nElbowOffset = 0; break; } } else if ( ( ! oConn.gItemLeft && ! oConnection.gItemLeft && oConn.m_left === oConnection.m_left ) || ( ! oConn.gItemRight && ! oConnection.gItemRight && oConn.m_right === oConnection.m_right ) ) { nElbowOffset = 0; break; } } } return nElbowOffset; } this.findGItem = function ( id ) { var gObject = this.m_mapGObjectIds[ id ]; if ( gObject && gObject.type !== DG.typeGObject.eItem ) { gObject = null; } return gObject; } this.findGNode = function ( id ) { var gObject = this.m_mapGObjectIds[ id ]; if ( gObject && gObject.type !== DG.typeGObject.eNode ) { gObject = null; } return gObject; } this.findGObject = function ( id ) { return this.m_mapGObjectIds[ id ]; } this.findGObjectByModelObjectId = function ( modelObjectId ) { var gObject = this.m_mapMObjectIds[ modelObjectId ]; return gObject; } this.findGItemByName = function ( sName ) { var gItem = null; for ( var i = 0; i < this.m_nodeList.length; i++ ) { gItem = this.m_nodeList[i].findItemByName ( sName ); if ( gItem ) break; } return gItem; } this.findGObjectByName = function ( sName ) { // First check if it's a node for ( var i = 0; i < this.m_nodeList.length; i++ ) { if ( this.m_nodeList[i].getName() === sName ) return this.m_nodeList[i]; } // Second check if it's an item var gItem = this.findGItemByName ( sName ); return gItem; } this.SelectConnections = function( gObject_clicked ) { var cConnections = this.m_connectionList.length; for ( var i = 0; i < cConnections; i++ ) { with ( this.m_connectionList[i] ) { select ( false ); } } if ( ! gObject_clicked ) return; // The selection logic depends on the type of Object clicked var bSelected = false; for ( var i = 0; i < cConnections; i++ ) { bSelected = false; var conn = this.m_connectionList[i]; if ( gObject_clicked.type === DG.typeGObject.eNode ) { if ( conn.m_left === gObject_clicked ) { bSelected = true; } } else if ( gObject_clicked.type === DG.typeGObject.eItem ) { if ( conn.gItemLeft === gObject_clicked ) { bSelected = true; } } if ( bSelected ) { conn.select ( true ); } } } this.SelectObject = function ( gObject_clicked ) { // alert ( gObject_clicked ? ( "Clicked Object Type " + gObject_clicked.type ) : "Empty space" ); var timeStart = new Date().getTime(); for ( var i = 0; i < this.m_selTargetList.length; i++ ) { this.m_selTargetList[i].update(); } this.m_selTargetList.length = 0; for ( var i = 0; i < this.m_nodeList.length; i++ ) { this.m_nodeList[i].select( false ); } for ( var i = 0; i < this.m_nodeList.length; i++ ) { var gNode = this.m_nodeList[i]; if ( gNode === gObject_clicked ) { gNode.select( true ); if ( DG.DebugOutputOn ) { var elem = gNode.getObjectElem(); alert( elem.innerHTML ); alert( elem.outerHTML ); } } else { for ( var j = 0; j < gNode.itemList.length; j++ ) { var gItem = gNode.itemList[j]; if ( gItem === gObject_clicked ) { gItem.select( true ); if ( DG.DebugOutputOn ) { var domItemNode = document.getElementById( gItem.id ); // domItemNode.style.overflow = 'visible'; alert( domItemNode.innerHTML ); alert( domItemNode.outerHTML ); } } else gItem.select( false ); } } } if ( gObject_clicked ) { this.m_selObject = gObject_clicked; this.m_selNode = this.m_selObject.isTypeOf ( DG.typeGObject.eItem ) ? this.m_selObject.getParentObj() : this.m_selObject; } else { this.m_selObject = null; this.m_selNode = null; } this.SelectConnections( gObject_clicked ); // Set Properties if ( gObject_clicked ) { DG.sSelectedObjectName = gObject_clicked.getName (); DG.sSelectedObjectType = DG.typeGObject.getTypeString ( gObject_clicked.type ); DG.CookieMgr.setCookie( DG.sCookieSelObjectName, DG.sSelectedObjectName ); DG.CookieMgr.setCookie( DG.sCookieSelObjectType, DG.sSelectedObjectType ); var Query = null; var Item = null; if ( gObject_clicked.type === DG.typeGObject.eNode ) { Query = gObject_clicked; Item = null; } else if ( gObject_clicked.type === DG.typeGObject.eItem ) { Query = DG.graphDefaults.bInclParentProperties ? gObject_clicked.parentGObj : null; Item = gObject_clicked; } this.m_propertyManager.updateObjects ( Query ? Query.modelObject : null, Item ? Item.modelObject : null ); } else { DG.CookieMgr.deleteCookie ( DG.sCookieSelObjectName ); DG.CookieMgr.deleteCookie ( DG.sCookieSelObjectType ); this.m_propertyManager.updateObjects ( null, null ); } // alertTimeDiff ( timeStart, "CGraphControl.SelectObject" ); } this.processKeyEvent = function ( keyEvent ) { ASSERT( this.m_selNode, "processKeyEvent: NO selected nodes !" ); if ( ! this.m_selNode ) return true; //--------------------------------------------------------------- var bProcessed = false; var evt = new CKeyboardEvent ( keyEvent ); // if ( keyEvent.shiftKey || keyEvent.ctrlKey || keyEvent.altKey ) // alert( "ALT !" ); var cNodes = this.m_nodeList.length; var selSize = this.m_selNode.getScreenSize(); var nextObject = null; if ( evt.key === UTIL.KEYCODE_ARROW_LEFT ) { // alert( 'Left Arrow pressed !' ); if ( keyEvent.ctrlKey ) { bProcessed = true; var nextSize = null; for ( var i = 0; i < cNodes; i++ ) { var size = this.m_nodeList[i].getScreenSize(); if ( size.x < selSize.x ) { if ( ! nextSize ) { nextSize = new CSize(); nextSize.clone( size ); nextObject = this.m_nodeList[i]; } else if ( size.x > nextSize.x ) { nextSize.clone( size ); nextObject = this.m_nodeList[i]; } } } } } else if ( evt.key === UTIL.KEYCODE_ARROW_RIGHT ) { // alert( 'Right Arrow pressed !' ); if ( keyEvent.ctrlKey ) { bProcessed = true; var nextSize = null; for ( var i = 0; i < cNodes; i++ ) { var size = this.m_nodeList[i].getScreenSize(); if ( size.x > selSize.x ) { if ( ! nextSize ) { nextSize = new CSize(); nextSize.clone( size ); nextObject = this.m_nodeList[i]; } else if ( size.x < nextSize.x ) { nextSize.clone( size ); nextObject = this.m_nodeList[i]; } } } } } else if ( evt.key === UTIL.KEYCODE_ARROW_UP ) { // alert( 'Up Arrow pressed !' ); if ( keyEvent.altKey || keyEvent.ctrlKey ) bProcessed = true; if ( keyEvent.altKey ) { var nextItem = this.m_selNode.getPrevItem ( this.m_selObject ); if ( nextItem ) { nextObject = nextItem; } else { nextObject = this.m_selNode; } } else if ( keyEvent.ctrlKey ) { var size_closest = null; for ( var i = 0; i < cNodes; i++ ) { var size = this.m_nodeList[i].getScreenSize(); if ( size.x == selSize.x ) { if ( size.y < selSize.y ) { if ( ! size_closest || size.y > size_closest.y ) { size_closest = size; nextObject = this.m_nodeList[i]; } } } } if ( ! nextObject ) // a case when an item was selected -> select the node nextObject = this.m_selNode; } } else if ( evt.key === UTIL.KEYCODE_ARROW_DOWN ) { // alert( 'Down Arrow pressed !' ); if ( keyEvent.altKey || keyEvent.ctrlKey ) bProcessed = true; if ( keyEvent.altKey ) { var nextItem = this.m_selNode.getNextItem ( this.m_selObject ); if ( nextItem ) { nextObject = nextItem; } } else if ( keyEvent.ctrlKey ) { var size_closest = null; for ( var i = 0; i < cNodes; i++ ) { var size = this.m_nodeList[i].getScreenSize(); if ( size.x == selSize.x ) { if ( size.y > selSize.y ) { if ( ! size_closest || size.y < size_closest.y ) { size_closest = size; nextObject = this.m_nodeList[i]; } } } } } } if ( nextObject ) { this.SelectObject ( nextObject ); } return bProcessed; } //************************************************************************* // Diagram Event handlers //************************************************************************* function processOnClick ( ev ) { // alert ( ' processOnClick !!!' ); var evtObj = new CMouseEvent ( ev ); var gNode = getGNode ( evtObj ); if ( gNode ) stopEvent( evtObj.evt ); cancelEvent ( evtObj.evt ); stopEvent ( evtObj.evt ); return false; } function processOnDblClick ( ev ) { // alert ( ' processOnDblClick !!!' ); var evtObj = new CMouseEvent ( ev ); cancelEvent ( evtObj.evt ); stopEvent ( evtObj.evt ); return false; } function processOnSelectStart ( ev ) { // alert ( ' SELECT_START !!!' ); var evtObj = new CMouseEvent ( ev ); cancelEvent ( evtObj.evt ); stopEvent ( evtObj.evt ); return false; } function processOnMouseDown ( ev ) { var evtObj = new CMouseEvent ( ev ); // alert ( ' processOnMouseDown: ObjId = ' + evtObj.target.id ); var gObject = getGObject( evtObj ); // alert ( ' MOUSE_DOWN - ctrlKey: ' + evtObj.evt.ctrlKey ); if ( gObject ) { gObject.graph.SelectObject( gObject ); if ( evtObj.target.id === '_action' ) { gObject.graph.OnActionClick( gObject.modelObject ); cancelEvent ( evtObj.evt ); stopEvent ( evtObj.evt ); return false; } } //-------------------------------------------------------- var obj = getObjectElem ( evtObj ); if ( obj ) { var graph = obj.parentNode.graph; if ( graph && graph.m_isDragAllowed ) { DG.DragDrop.dragObject = obj; DG.DragDrop.originalPosition = new CPosition( parseInt( obj.offsetLeft ), parseInt( obj.offsetTop ) ); DG.DragDrop.originalMousePosition = new CPosition( evtObj.x, evtObj.y ); addEvent( graph.m_gdi.canvas, 'mousemove', processOnMouseMove, true ); addEvent( graph.m_gdi.canvas, 'mouseup', processOnMouseUp, true ); // graph.m_gdi.canvas.onmousemove = processOnMouseMove; // graph.m_gdi.canvas.onmouseup = processOnMouseUp; } stopEvent( evtObj.evt ); } else { cancelEvent ( evtObj.evt ); stopEvent ( evtObj.evt ); } return false; } function processOnMouseMove ( ev ) { var evtObj = new CMouseEvent ( ev ); if ( DG.DragDrop.dragObject ) { var graph = DG.DragDrop.dragObject.parentNode.graph; if ( graph ) { if ( graph.m_isDragAllowed ) { var gNode = graph.findGNode ( DG.DragDrop.dragObject.id ); if ( gNode ) { if ( ! graph.m_isDragHorzAllowed ) evtObj.x = DG.DragDrop.originalMousePosition.x; if ( ! graph.m_isDragVertAllowed ) evtObj.y = DG.DragDrop.originalMousePosition.y; var deltax = evtObj.x - DG.DragDrop.originalMousePosition.x; var deltay = evtObj.y - DG.DragDrop.originalMousePosition.y; if ( Math.abs( deltax ) > 5 || Math.abs( deltay ) > 5 ) { gNode.move ( ( DG.DragDrop.originalPosition.x + deltax) * 100 / graph.getZoom (), ( DG.DragDrop.originalPosition.y + deltay) * 100 / graph.getZoom (), true ); //gNode.paint(this.graph.m_gdi); //this.graph.m_gdi.refreshObject (DG.DragDrop.dragObject.id); // Hack to repaint the element //var el = document.getElementById ( DG.DragDrop.dragObject.id ); //if ( el ) //{ // var t = el.ownerDocument.createTextNode(' '); // el.appendChild(t); // setTimeout(function() { el.removeChild(t); }, 0); //} } cancelEvent ( evtObj.evt ); stopEvent ( evtObj.evt ); } } } } else cancelEvent( evtObj.evt ); return false; } function processOnMouseUp ( ev ) { var evtObj = new CMouseEvent ( ev ); var graph = DG.DragDrop.dragObject ? DG.DragDrop.dragObject.parentNode.graph : null; if ( graph ) { var gNode = graph.findGNode ( DG.DragDrop.dragObject.id ); if ( gNode ) { if ( graph.m_isDragAllowed ) { var deltax = evtObj.x - DG.DragDrop.originalMousePosition.x; var deltay = evtObj.y - DG.DragDrop.originalMousePosition.y; } gNode.restoreDefaults(); } removeEvent ( graph.m_gdi.canvas, 'mousemove', processOnMouseMove, true ); removeEvent ( graph.m_gdi.canvas, 'mouseup', processOnMouseUp, true ); // addEvent( graph.m_gdi.canvas, 'mousemove', null, false ); // addEvent( graph.m_gdi.canvas, 'mouseup', null, false ); // graph.m_gdi.canvas.onmousemove = null; // graph.m_gdi.canvas.onmouseup = null; } DG.DragDrop.dragObject = null; cancelEvent( evtObj.evt ); return false; } function getGNode ( evtObj ) { var elem = evtObj.target; if ( elem ) { while ( elem.id === "" || elem.id.charAt (0) === '_' ) { elem = elem.parentNode; } if ( elem ) { graph = elem.parentNode.graph; if ( graph ) return graph.findGNode ( elem.id ); } } return null; } function getGObject ( evtObj ) { var gObject = null; if ( evtObj.evt ) { var elem = evtObj.target; if ( elem && typeof elem.id === "string" ) { while ( elem.id === "" || elem.id.charAt (0) === '_' ) { elem = elem.parentNode; } if ( elem ) { var parent_elem = elem; while ( typeof parent_elem.graph === "undefined" ) { parent_elem = parent_elem.parentNode; } var graph = parent_elem.graph; if ( typeof graph !== "undefined" ) { gObject = graph.findGObject( elem.id ); } } } } return gObject; } function getObjectElem ( evtObj ) { var elem = evtObj.target; if ( elem ) { while ( elem && ( elem.id === "" || elem.id.charAt (0) === '_') ) { elem = elem.parentNode; } return elem; } return null; } this.layout = function() { var layout = new Autolayout ( this.m_nodeList, this.m_connectionList ); layout.doIt (); } } //*********************************************************************************************** // Class CGraphObject - the base object for all diagram objects //*********************************************************************************************** DG.CGraphObject = function ( type, graph, modelObject ) { // ASSERT( type, "CGraphObject: type is NOT valid !" ); // ASSERT( graph, "CGraphObject: graph is NOT valid !" ); if ( ! type || ! graph ) return; CSize.call (); // constructor chaining // Assemble the object's unique Id this.nUniqueId = ++DG.nObjectCounter; this.id = 'id' + this.nUniqueId; this.type = type; this.id += '_' + DG.typeGObject.getTypeString( this.type ); // Register in the Graph Hash table graph.m_mapGObjectIds[ this.id ] = this; this.container = false; this.parentGObj = null; this.graph = graph; this.modelObject = modelObject; this.icon = 0; this.bShowIcon = true; this.elemObject = null; this.sCssClass = DG.mapCssClasses[this.type]; this.isSelected = false; this.isInScope = false; this.colorText = DG.colorDefaults.colorTextStandard; this.colorBk = DG.colorDefaults.colorBkStandard; this.colorBorderExternal = DG.colorDefaults.colorBorderExternal; this.colorBorderInternal = DG.colorDefaults.colorBorderInternal; this.thickness = DG.graphDefaults.nPenWidth; this.zOrderRegular = 0; this.zOrderSelected = 0; // Icon selection if ( this.modelObject ) { this.icon = this.graph.getObjectIcon ( this.modelObject ); graph.m_mapMObjectIds[ this.modelObject.getId() ] = this; } } DG.CGraphObject.inherits( CSize ); //-------------------------------------------------------------------- // CGraphObject API //-------------------------------------------------------------------- DG.CGraphObject.prototype.isTypeOf = function ( type ) { return ( type === this.type ); } DG.CGraphObject.prototype.getId = function () { return ( this.id ); } DG.CGraphObject.prototype.getTextId = function () { return ( '_' + this.id + '_text' ); } DG.CGraphObject.prototype.getRectId = function () { return ( '_' + this.id + '_rect' ); } DG.CGraphObject.prototype.getActionId = function () { return ( '_action' ); } DG.CGraphObject.prototype.getParentObj = function () { return this.parentGObj; } DG.CGraphObject.prototype.getObjectElem = function () { var elem = this.id; if ( ! this.elemObject ) { if ( this.graph.m_bCreated ) this.elemObject = document.getElementById( this.id ); } if ( this.elemObject ) { elem = this.elemObject; } return elem; } DG.CGraphObject.prototype.equals = function ( gObject ) { if ( ! gObject ) return false; return ( this.type === gObject.type ) && ( this.getId() === gObject.getId() ); } DG.CGraphObject.prototype.show = function ( bShow ) { var cssHelper = UTIL.ElementHelper.setElem ( this.getObjectElem() ); cssHelper.show ( bShow ); } DG.CGraphObject.prototype.isShown = function () { var cssHelper = UTIL.ElementHelper.setElem ( this.getObjectElem() ); var bShown = cssHelper.isShown (); return bShown; } DG.CGraphObject.prototype.setZIndex = function ( bSelect ) { var cssHelper = UTIL.ElementHelper.setElem ( this.getObjectElem() ); cssHelper.setZIndex ( bSelect ? this.zOrderSelected : this.zOrderRegular ); } DG.CGraphObject.prototype.setZIndexFn = function ( zOrder ) { var cssHelper = UTIL.ElementHelper.setElem ( this.getObjectElem() ); cssHelper.setZIndex ( zOrder ); } DG.CGraphObject.prototype.getName = function () { var name = ""; if ( this.modelObject ) name = this.modelObject.getName(); return name; } DG.CGraphObject.prototype.setText = function ( sText ) { var cssHelper = UTIL.ElementHelper.setElem ( this.getTextId() ); cssHelper.setText ( sText ); } DG.CGraphObject.prototype.setTextColors = function () { var cssHelper = UTIL.ElementHelper.setElem ( this.getTextId() ); cssHelper.setColors ( this.colorText, this.colorBk ); } DG.CGraphObject.prototype.setTextBold = function () { var cssHelper = UTIL.ElementHelper.setElem ( this.getTextId() ); cssHelper.setTextBold (); } DG.CGraphObject.prototype.setBorderStyle = function ( sStyle ) { var cssHelper = UTIL.ElementHelper.setElem ( this.getRectId() ); cssHelper.setBorderStyle ( sStyle ); } DG.CGraphObject.prototype.select = function ( bSelect ) { this.isSelected = bSelect; } DG.CGraphObject.prototype.getScreenSize = function () { var cssHelper = UTIL.ElementHelper.setElem ( this.getObjectElem() ); var size = cssHelper.getScreenSize(); return size; } //*********************************************************************************************** // Class CGraphItem //*********************************************************************************************** DG.CGraphItem = function ( parentGObj, modelObject, graph ) { ASSERT( graph, "CGraphItem: graph is NOT valid !" ); ASSERT( modelObject,"CGraphItem: modelObject is NOT valid !" ); // First, invoke the superclass constructor on the new object so that it can initialize its members. // We use the call method so that we invoke the constructor as a method of the object to be initialized. // This is called constructor chaining DG.CGraphObject.call( this, DG.typeGObject.eItem, graph, modelObject ); // constructor chaining // Members this.parentGObj = parentGObj; this.zOrderRegular = 5; this.zOrderSelected = 6; this.cInConnections = 0; this.cOutConnections = 0; } DG.CGraphItem.inherits( DG.CGraphObject ); //-------------------------------------------------------------------- // CGraphItem API //-------------------------------------------------------------------- DG.CGraphItem.prototype.getTextId = function () { return ( this.id ); } DG.CGraphItem.prototype.getRectId = function () { return ( this.id ); } DG.CGraphItem.prototype.setCurrColors = function () { this.colorText = DG.colorDefaults.colorTextStandard; this.colorBk = DG.colorDefaults.colorBkStandard; if ( this.isShortcut ) { this.colorText = DG.colorDefaults.colorShortcut; this.colorBk = DG.colorDefaults.colorBkShortcut; } else if ( this.isInScope ) { this.colorText = DG.colorDefaults.colorScope; this.colorBk = DG.colorDefaults.colorBkScope; } if ( this.isSelected ) { this.colorText = this.isInScope ? DG.colorDefaults.colorSelectedScope : DG.colorDefaults.colorTextSelected; this.colorBk = DG.colorDefaults.colorBkSelected; } } DG.CGraphItem.prototype.paint = function ( gdi ) { var x = this.x + 1; var width = gdi.ie ? this.parentGObj.width - 3 : this.parentGObj.width - 5; if ( this.graph.isShowItemIcon( this.modelObject ) ) { gdi.drawIcon ( this.graph.getIcon ( this.icon ), x, this.y + 1, DG.graphDefaults.nIconSize, DG.graphDefaults.nIconSize ); x += DG.graphDefaults.nIconSize; width -= DG.graphDefaults.nIconSize; } gdi.startContainer ( this.sCssClass, x, this.y + 1, width, this.height - 1, this.getId(), "hidden", this.modelObject.getName() ); gdi.addText ( this.modelObject.getName() ); if ( DG.graphDefaults.bShowActionLinks ) if ( this.modelObject.bPackageDataSourceObject ) gdi.drawActionIcon( this.graph.getActionIcon (), width - DG.graphDefaults.nIconSize, 1, DG.graphDefaults.nIconSize, DG.graphDefaults.nIconSize, this.getActionId(), DG.graphDefaults.sActionIconTooltip ); gdi.endContainer (); } DG.CGraphItem.prototype.update = function () { var oRect = document.getElementById ( this.getRectId() ); var oText = document.getElementById ( this.getTextId() ); this.setCurrColors (); oText.style.color = this.colorText; oRect.style.backgroundColor = this.colorBk; } DG.CGraphItem.prototype.select = function ( bSelect ) { if ( this.isSelected === bSelect ) return; this.isSelected = bSelect; this.update(); if ( this.isSelected ) this.parentGObj.setZIndex ( true ); // Restore parent Z-order } DG.CGraphItem.prototype.PaintTarget = function () { if ( this.isSelected ) return; var oRect = document.getElementById ( this.getRectId() ); if ( oRect ) { oRect.style.backgroundColor = DG.colorDefaults.colorBkSelTarget; } } //*********************************************************************************************** // Class CGraphNode //*********************************************************************************************** DG.CGraphNode = function ( modelObject, graph ) { ASSERT( graph, "CGraphNode: graph is NOT valid !" ); ASSERT( modelObject,"CGraphNode: modelObject is NOT valid !" ); // First, invoke the superclass constructor on the new object so that it can initialize its members. // We use the call method so that we invoke the constructor as a method of the object to be initialized. // This is called constructor chaining DG.CGraphObject.call( this, DG.typeGObject.eNode, graph, modelObject ); // constructor chaining // Members this.itemList = []; this.titleHeight = 22; this.width = DG.graphDefaults.nNodeWidth; this.zOrderRegular = 10; this.zOrderSelected = 100; this.colorBk = 'transparent'; this.elemCaption = null; this.bUpdateConnections = true; this.mapGItemsByName = []; // the map of all node's items by their graph name // Populating Children var y_item = this.titleHeight; var cItems = this.modelObject.getItemCount(); for ( var i = 0; i < cItems; i++ ) { var gItem = new DG.CGraphItem ( this, this.modelObject.getItem(i), graph ); this.mapGItemsByName [ gItem.getName()] = gItem; gItem.SetPosition( 1, y_item, this.width, DG.graphDefaults.nItemHeight ); this.itemList.push( gItem ); y_item += DG.graphDefaults.nItemHeight; } } DG.CGraphNode.inherits( DG.CGraphObject ); //-------------------------------------------------------------------- // CGraphNode API //-------------------------------------------------------------------- DG.CGraphNode.prototype.getCaptionId = function () { return ( '_' + this.id + '_caption' ); } // DG.CGraphNode.prototype.getTextId = function () { return this.getCaptionId(); } DG.CGraphNode.prototype.findItemByName = function ( sName ) { return this.mapGItemsByName [ sName ]; } DG.CGraphNode.prototype.getItemOffset = function ( gItem ) { if ( ! gItem ) return 0; var nOffset = 0; for ( var i = 0; i < this.itemList.length; i++ ) { if ( this.itemList[i] === gItem ) { nOffset = this.titleHeight + DG.graphDefaults.nItemHeight * i + DG.graphDefaults.nItemHeight / 2; break; } } return nOffset; } DG.CGraphNode.prototype.getItemPosition = function ( gItem ) { if ( ! gItem ) return null; var pos = null; for ( var i = 0; i < this.itemList.length; i++ ) { if ( this.itemList[i] === gItem ) { var nItemOffset = this.getItemOffset ( gItem ); pos = new CPosition ( this.x, this.y + nItemOffset ); break; } } return pos; } DG.CGraphNode.prototype.getConnectPoint = function ( pointFrom ) { var x = this.getCenterX (); var y = this.getCenterY (); var pointNew = new CPoint( x, y ); if ( pointFrom ) { if ( pointFrom.x > pointNew.x ) pointNew.x = this.x + this.width; else if ( pointFrom.x < pointNew.x ) pointNew.x = this.x; else if ( pointFrom.y > pointNew.y ) pointNew.y = this.y + this.height; else if ( pointFrom.y < pointNew.y ) pointNew.y = this.y; } return pointNew; } DG.CGraphNode.prototype.setCurrColors = function () { this.colorText = DG.colorDefaults.colorTextStandard; if ( this.isSelected ) { this.colorText = DG.colorDefaults.colorTextSelected; } } DG.CGraphNode.prototype.paint = function ( gdi ) { var nTextWidth = this.width - 28; if ( DG.graphDefaults.bShowActionLinks ) if ( this.modelObject.bPackageDataSourceObject ) this.width += DG.graphDefaults.nIconSize + 12 / DG.graphDefaults.nScreenRatioWidth; // increase width to make space for an action icon gdi.startContainer ( this.sCssClass, this.x, this.y, this.width + DG.graphDefaults.nShadowWidth, this.height + DG.graphDefaults.nShadowWidth, this.getId(), "visible" ); this.setCurrColors (); var width = gdi.ie ? this.width - 3 : this.width - 7; width -= DG.graphDefaults.nIconSize; var height = this.titleHeight - 3; gdi.drawBackgroundImage ( DG.graphDefaults.getImagePath() + ( this.isSelected ? DG.graphDefaults.sBkImageSelected : DG.graphDefaults.sBkImageUnSelected ), 1, 1, this.width - 1, this.titleHeight - 2, this.getCaptionId() ); // gdi.drawCaptionRect ( this.getCaptionId(), 'classGraphCaption', this.modelObject.getName(), 1, 1, width, height, DG.graphDefaults.nPenWidth, DG.graphDefaults.sBkImageUnSelected ); // Full Rect Background // gdi.fillRectangle ( this.colorBk, 1, this.titleHeight, this.width - 2, this.height - this.titleHeight - 1, DG.graphDefaults.opacityBody ); // Line under title gdi.drawHorzLine ( this.colorBorderInternal, 1, DG.graphDefaults.styleBorder, 1, this.titleHeight - 1, this.width - 2 ); // Full Rect gdi.drawRectangle ( this.colorBorderExternal, 0, 0, this.width, this.height - 1, DG.graphDefaults.styleBorder, DG.graphDefaults.nPenWidth, this.getRectId() ); // Title gdi.drawString ( this.modelObject.getName(), this.colorText, 20, 3, nTextWidth, 14, "", DG.graphDefaults.nNodeFontSize, "normal", this.getTextId(), this.modelObject.getName() ); // Icon var nIconOffset = ( this.titleHeight - DG.graphDefaults.nIconSize ) / 2; gdi.drawIcon ( this.graph.getIcon ( this.icon ), nIconOffset, nIconOffset, DG.graphDefaults.nIconSize, DG.graphDefaults.nIconSize ); if ( DG.graphDefaults.bShowActionLinks ) if ( this.modelObject.bPackageDataSourceObject ) gdi.drawActionIcon( this.graph.getActionIcon (), width + 1, 3, DG.graphDefaults.nIconSize, DG.graphDefaults.nIconSize, this.getActionId(), DG.graphDefaults.sActionIconTooltip ); // Paint children for ( var i = 0; i < this.itemList.length; i++ ) { this.itemList[i].paint( gdi ); } if ( DG.graphDefaults.bUseShadows ) { gdi.fillRectangle ( DG.colorDefaults.colorShadow, this.width+1, DG.graphDefaults.nShadowWidth + 2, DG.graphDefaults.nShadowWidth, this.height - 2, DG.graphDefaults.opacityShadow ); gdi.fillRectangle ( DG.colorDefaults.colorShadow, DG.graphDefaults.nShadowWidth + 2, this.height, this.width - DG.graphDefaults.nShadowWidth - 1, DG.graphDefaults.nShadowWidth, DG.graphDefaults.opacityShadow ); } gdi.endContainer (); } DG.CGraphNode.prototype.select = function ( bSelect ) { if ( this.isSelected === bSelect ) return; for ( var i = 0; i < this.itemList.length; i++ ) { this.itemList[ i ].select( false ); } var elem = document.getElementById ( this.getCaptionId() ); this.isSelected = bSelect; elem.src = DG.graphDefaults.getImagePath(); if ( this.isSelected ) elem.src += DG.graphDefaults.sBkImageSelected; else elem.src += DG.graphDefaults.sBkImageUnSelected; this.setZIndex ( this.isSelected ); this.setCurrColors (); this.setTextColors (); } DG.CGraphNode.prototype.calculateSize = function () { if ( this.width === 0 ) this.width = 120; if ( this.height === 0 ) { var cItems = this.itemList.length; this.height = this.titleHeight + cItems * DG.graphDefaults.nItemHeight + ( cItems > 0 ? 3 : 0 ); } } DG.CGraphNode.prototype.move = function ( newx, newy, bByDrag ) { if ( newx < 0 || newy < 0 ) return; if ( ! this.elemObject ) this.elemObject = document.getElementById ( this.getId() ); if ( ! this.elemCaption ) this.elemCaption = document.getElementById ( this.getCaptionId() ); if ( this.elemObject ) { if ( bByDrag ) { this.elemObject.style.cursor = 'move'; this.elemCaption.style.cursor = 'move'; } this.SetPosition( newx, newy ); this.graph.m_gdi.moveObject ( this.elemObject, newx, newy ); if ( ! bByDrag || this.bUpdateConnections ) this.graph.refreshConnectionsForNode ( this ); this.bUpdateConnections = ! this.bUpdateConnections; // Hack to make the node more responsive during move } } DG.CGraphNode.prototype.refresh = function () { this.move ( this.x, this.y ); } DG.CGraphNode.prototype.restoreDefaults = function () { if ( ! this.elemObject ) this.elemObject = document.getElementById ( this.getId() ); if ( ! this.elemCaption ) this.elemCaption = document.getElementById ( this.getCaptionId() ); if ( this.elemObject ) { this.elemObject.style.cursor = 'default'; this.elemCaption.style.cursor = 'move'; this.graph.refreshConnectionsForNode ( this ); } } DG.CGraphNode.prototype.getItemIndex = function ( gItem ) { var nItem = -1; for ( var index = 0; index < this.itemList.length; index++ ) { if ( this.itemList[index] === gItem ) { nItem = index; break; } } return nItem; } DG.CGraphNode.prototype.getNextItem = function ( gItem ) { var gNextItem = null; var nNextItem = -1; var nItem = this.getItemIndex( gItem ); if ( nItem === -1 ) nNextItem = this.itemList.length > 0 ? 0 : -1; else nNextItem = nItem < ( this.itemList.length - 1 ) ? ( nItem + 1 ) : -1; if ( nNextItem !== -1 ) gNextItem = this.itemList[ nNextItem ]; return gNextItem; } DG.CGraphNode.prototype.getPrevItem = function ( gItem ) { var gPrevItem = null; var nPrevItem = -1; var nItem = this.getItemIndex( gItem ); if ( nItem === -1 ) nPrevItem = this.itemList.length > 0 ? 0 : -1; else nPrevItem = nItem > 0 ? ( nItem - 1 ) : -1; if ( nPrevItem !== -1 ) gPrevItem = this.itemList[ nPrevItem ]; return gPrevItem; } //*********************************************************************************************** // Class CGraphConnection //*********************************************************************************************** DG.CGraphConnection = function ( left, right, graph ) { ASSERT( left, "CGraphConnection: left end is NOT valid !" ); ASSERT( right, "CGraphConnection: right end is NOT valid !" ); DG.CGraphObject.call( this, DG.typeGObject.eConnection, graph, null ); // constructor chaining //----------------------------------------------------------- // Members //----------------------------------------------------------- this.isValid = true; this.nIndex = ++DG.nLineCounter; this.thickness = DG.graphDefaults.nLineWidthStandard; this.nElbowOffset = 0; if ( ! left || ! right ) { this.isValid = false; return; } left.isInScope = false; right.isInScope = false; //------------------------------------------------------------------------------------ // Determine the real Left and Right nodes //------------------------------------------------------------------------------------ var bIsLeftGraphObject = left instanceof DG.CGraphObject; // An alternative way to check for object inheritence // var bIsLeftGraphObject = DG.CGraphObject.prototype.isPrototypeOf ( left ); if ( ! bIsLeftGraphObject ) { // It means the LEFT object is a model object and we need to find its GObject container var gObject = graph.findGObjectByModelObjectId ( left ); if ( gObject ) { left = gObject; } else { this.isValid = false; ASSERT( false, "CGraphConnection: left node " + left + "is NOT found !" ); } } var bIsRightGraphObject = right instanceof DG.CGraphObject; if ( ! bIsRightGraphObject ) { // It means the RIGHT object is a model object and we need to find its GObject container var gObject = graph.findGObjectByModelObjectId ( right ); if ( gObject ) { right = gObject; } else { this.isValid = false; ASSERT( false, "CGraphConnection: right node " + right + "is NOT found !" ); } } if ( ! this.isValid ) { this.isValid = false; return; } // By now, the LEFT & RIGHT object must be graph objects ASSERT( left && left.type, "CGraphConnection: left node is NOT valid !" ); ASSERT( right && right.type, "CGraphConnection: right node is NOT valid !" ); // A special case for object shortcuts if ( left.modelObject.getShortcutTo() === right.modelObject ) { this.isShortcut = true; left.isShortcut = true; } if ( right.modelObject.getShortcutTo() === left.modelObject ) { this.isShortcut = true; right.isShortcut= true; } //------------------------------------------------------------------------------- if ( left.isTypeOf ( DG.typeGObject.eNode ) ) { this.gItemLeft = null; this.m_left = left; } else if ( left.isTypeOf ( DG.typeGObject.eItem ) ) { this.gItemLeft = left; this.m_left = left.parentGObj; this.gItemLeft.cInConnections++; } else ASSERT( null, "CGraphConnection: left object type is unknown !" ); if ( right.isTypeOf ( DG.typeGObject.eNode ) ) { this.gItemRight = null; this.m_right = right; } else if ( right.isTypeOf ( DG.typeGObject.eItem ) ) { this.gItemRight = right; this.m_right = right.parentGObj; this.gItemRight.cOutConnections++; } else ASSERT( null, "CGraphConnection: right object type is unknown !" ); this.color = DG.colorDefaults.colorLineStandard; this.colorBk = DG.colorDefaults.colorBkStandard; this.zOrderRegular = 2; this.zOrderSelected = 200; } DG.CGraphConnection.inherits( DG.CGraphObject ); //----------------------------------------------------------- // CGraphConnection API //----------------------------------------------------------- DG.CGraphConnection.prototype.setZIndexLine = function ( bSelect ) { // Set the line's DIV z-index this.setZIndex ( this.isSelected ); // Set z-index for all segments var elem = this.getObjectElem(); var nodeList = elem.childNodes; if ( nodeList === null ) { return; } for ( var current = 0; current < nodeList.length; current++ ) { var node = nodeList.item ( current ); node.style.zIndex = bSelect ? this.zOrderSelected : this.zOrderRegular; } } DG.CGraphConnection.prototype.setColor = function ( color ) { this.color = color; var elem = this.getObjectElem(); // NodeList nodeList = elem.getChildNodes(); var nodeList = elem.childNodes; if ( nodeList === null ) { return; } for ( var current = 0; current < nodeList.length; current++ ) { var node = nodeList.item ( current ); node.style.backgroundColor = 'transparent'; node.style.borderTopColor = color; node.style.borderLeftColor = color; } } DG.CGraphConnection.prototype.paint = function ( gdi ) { var sizeClient = this.graph.getClientSize(); // gdi.startContainer ( this.sCssClass, 0, 0, sizeClient.width, sizeClient.height, this.getId(), 'visible' ); gdi.startContainer ( this.sCssClass, 0, 0, 1, 1, this.getId(), 'visible' ); this.paintContent ( gdi, this.m_left, this.m_right ); gdi.endContainer (); } DG.CGraphConnection.prototype.paintContent = function ( gdi, nodeL, nodeR ) { var sLineStyle = this.isShortcut ? DG.graphDefaults.styleShortcut : DG.graphDefaults.styleLine; if ( nodeL === nodeR ) { ASSERT ( this.gItemLeft && this.gItemRight, "Connection: items for the same nod NOT valid !" ); // A Special case for self-referencing nodes var posL = this.m_left.getItemPosition ( this.gItemLeft ); var posR = this.m_right.getItemPosition ( this.gItemRight ); posL.y += DG.graphDefaults.nLineOutOffsetY; posR.y += DG.graphDefaults.nLineInOffsetY; this.nElbowOffset = - ( this.nIndex % 3 ) * 3; gdi.drawVertAngledLineToPoint ( this.color, this.thickness, sLineStyle, posL, posR, this.nElbowOffset ); return; } if ( nodeL.HasIntersection( nodeR ) ) { // alert ( "Connection: Intersection !!" ); return; // no space to paint the connection } // Ensure that the left node is really left on the X axis var itemLeft = this.gItemLeft; var itemRight = this.gItemRight; if ( nodeL.x > nodeR.x ) { var nodeTemp = nodeL; nodeL = nodeR; nodeR = nodeTemp; itemLeft = this.gItemRight; itemRight = this.gItemLeft; } if ( nodeL.x + nodeL.width >= nodeR.x ) { // alert ( "Connection: Straight Line !!" ); // A Special case for nodes overlapping on the X axis var xIntersect = nodeL.x + nodeL.width - nodeR.x; var xLine = nodeR.x + xIntersect / 2; var nodeTop = nodeL.y < nodeR.y ? nodeL : nodeR; var bLeftEndIsOnTop = nodeTop === this.m_left; var yTopEnd = nodeL.y + nodeL.height < nodeR.y ? nodeL.y + nodeL.height : nodeR.y + nodeR.height; var yBottomEnd = nodeL.y + nodeL.height > nodeR.y ? nodeL.y : nodeR.y; var ptTop = new CPoint ( xLine, yTopEnd ); var ptBottom = new CPoint ( xLine, yBottomEnd ); if ( ! bLeftEndIsOnTop ) { gdi.drawArrowUp ( this.color, xLine, yTopEnd, sLineStyle, DG.graphDefaults.nArrowSize ); } gdi.drawVertLineToPoint ( this.color, this.thickness, sLineStyle, ptTop, ptBottom ); if ( bLeftEndIsOnTop ) { gdi.drawArrowDown ( this.color, xLine, yBottomEnd, sLineStyle, DG.graphDefaults.nArrowSize ); } return; } // The rest is a case for nodes NOT overlapping on the X axis, i.e. one on the left & another on the right var nodeLeft = nodeL.x < nodeR.x ? nodeL : nodeR; var bSourceIsOnLeft = nodeLeft === this.m_left; var xLeft = nodeL.x + nodeL.width; var yLeft = nodeL.y + nodeL.height / 2; var xRight = nodeR.x; var yRight = nodeR.y + nodeR.height / 2; var lItemOffset = nodeL.getItemOffset ( itemLeft ); if ( lItemOffset !== 0 ) yLeft = nodeL.y + lItemOffset; var rItemOffset = nodeR.getItemOffset ( itemRight ); if ( rItemOffset !== 0 ) yRight = nodeR.y + rItemOffset; var ptLeft = new CPoint ( xLeft, yLeft ); var ptRight = new CPoint ( xRight, yRight ); if ( bSourceIsOnLeft ) { if ( ! itemLeft || ( itemLeft.cOutConnections > 1 || itemLeft.cInConnections > 1 ) ) ptLeft.y += DG.graphDefaults.nLineOutOffsetY; if ( ! itemRight || ( itemRight.cOutConnections > 1 || itemRight.cInConnections > 1 ) ) ptRight.y += DG.graphDefaults.nLineInOffsetY; } else { if ( ! itemLeft || ( itemLeft.cOutConnections > 1 || itemLeft.cInConnections > 1 ) ) ptLeft.y += DG.graphDefaults.nLineInOffsetY; if ( ! itemRight || ( itemRight.cOutConnections > 1 || itemRight.cInConnections > 1 ) ) ptRight.y += DG.graphDefaults.nLineOutOffsetY; } this.nElbowOffset = this.graph.findConnectionElbowOffsetX ( this ); if ( this.nElbowOffset === -1 ) this.nElbowOffset = 10 - ( this.nIndex % 7 ) * 3; gdi.drawLinePointToPoint ( this.color, this.thickness, sLineStyle, ptLeft, ptRight, this.nElbowOffset ); if ( bSourceIsOnLeft ) gdi.drawArrowRight ( this.color, ptRight.x, ptRight.y, sLineStyle, DG.graphDefaults.nArrowSize ); else { // if ( DG.graphDefaults.bUseShadows ) // ptLeft.x += DG.graphDefaults.nShadowWidth - 3; gdi.drawArrowLeft ( this.color, ptLeft.x, ptLeft.y, sLineStyle, DG.graphDefaults.nArrowSize ); } } DG.CGraphConnection.prototype.select = function ( bSelect ) { if ( this.isSelected === bSelect ) return; this.isSelected = bSelect; this.color = bSelect ? DG.colorDefaults.colorLineSelected : DG.colorDefaults.colorLineStandard; this.thickness = bSelect ? DG.graphDefaults.nLineWidthSelected : DG.graphDefaults.nLineWidthStandard; this.refresh ( this.graph.m_gdi ); this.setZIndex ( bSelect ); if ( bSelect && this.gItemRight ) { this.gItemRight.PaintTarget(); this.graph.m_selTargetList.push( this.gItemRight ); } } DG.CGraphConnection.prototype.refresh = function ( gdi ) { if ( ! this.m_left.isShown() || ! this.m_right.isShown() ) { this.show ( false ); } else { if ( ! this.m_left.bShowConnections || ! this.m_right.bShowConnections ) { this.show ( false ); } else { this.show ( true ); this.paintContent ( gdi, this.m_left, this.m_right ); gdi.refreshObject ( this.getId() ); } } } //----------------------------------------------------------------------------------------------