function GitRepoNode(gitRepo, parentNode, layout, streamUtilities, skin) { var mSkin = skin; var horizontalLayout = false; if( layout && layout=='ancestor' ) horizontalLayout = true; var mStreamUtilities = streamUtilities; this.stream = gitRepo; this.gitRepo = gitRepo; var shadowStroke = 2; var strokeWidth = 1; var showStateIcons = true; var scaleFactor = 1; var MINZOOMFACTOR = 0.2; var outlineWidth = 1; this.firmness = .6; this.selected = false; this.highlighted = false; this.mParent = parentNode; // these are used to calculate position, calculated once the tree is built this.mX = 0; // calculated final x position (init to 0) this.mCurPos = 0; // iterative position that approaches mX var imageWidth = 50; this.mWidth = imageWidth; this.mSubtreeIndex = 0; // this is set as the tree is built, but needed by the placement algorithm this.lowerChildren = new Array(); this.upperChildren = new Array(); this.mLeftSibling = null; var nodeList = new NodeList(mStreamUtilities); // how tall each circle is var BOX_HEIGHT = 80; // how much space a row consumes var ROW_HEIGHT = BOX_HEIGHT*2; if( mSkin != 'gumdrop' ) { BOX_HEIGHT = 135; ROW_HEIGHT = BOX_HEIGHT*.75; if( horizontalLayout ) ROW_HEIGHT = BOX_HEIGHT * .35; } if( horizontalLayout ) ROW_HEIGHT = BOX_HEIGHT * 1.40; this.getVisibleName = function() { var buf = this.stream.mName; if( this.stream.mType === mStreamUtilities.StreamType.gitRepo ) buf += ' (master)'; return buf; } this.RowHeight = function() { return ROW_HEIGHT; } this.position = function() { return new mStreamUtilities.Point(this.mX, (-1*this.mRow)*(ROW_HEIGHT)); } this.firmerThanParent = function() { return false; } this.isFirmType = function() { return false; } this.isMainline = function() { return false; } this.calcChildRow = function( parentNode, bypass) { if( !bypass ) { if (parentNode == null || parentNode.stream.mType == mStreamUtilities.StreamType.typeCount) return 0; // no parent implies mainline (row 0) //console.log('calChildRow( parentNode) parentNode: ' + parentNode + ' parentNode.stream.mType: ' + parentNode.stream.mType + ' this.stream: ' + this.stream + ' StreamType: ' + this.stream.mType ); var row = parentNode.mRow; if (!this.firmerThanParent()) return row - 1; else // must be "up" return row + 1; } } this.mRow = this.calcChildRow(this.mParent, false); this.row = function(){ return this.mRow; } this.subtreeIndex = function(){ return this.mSubtreeIndex; } var mAllChildren = new Array(); this.addChild = function( s ) { // main stores in both directions, other Streams just have "children" var debug = 'lower'; var dir = this.lowerChildren; if(s.stream && s.firmerThanParent()) { dir = this.upperChildren; debug = 'upper'; } // set the left sibling of s and the index in the parent list s.mLeftSibling = (dir.length > 0) ? dir[dir.length - 1] : null; s.mSubtreeIndex = dir.length; // add it to our list dir.push(s); mAllChildren.push(s); //console.log('adding ' + s.stream.mName + ' to ' + this.stream.mName + ' ' + debug + ' array: ' + dir.join()); } if (this.mParent) this.mParent.addChild(this); this.children = function( dir ) //const { if( !dir ) return mAllChildren; if (this.stream && (this.stream.mType == mStreamUtilities.StreamType.typeCount || dir == 0)) { //console.log('returning lowerChildren of: ' + this.stream.mName); return this.lowerChildren; } if(dir < 0) { //console.log('returning lowerChildren of: ' + this.stream.mName); return this.lowerChildren } else { //console.log('returning upperChildren of: ' + this.stream.mName); return this.upperChildren; } } this.x = function() { return this.mX; } this.nameWidth = function() { return mStreamUtilities.GetTextWidth(this.getVisibleName(), nameContext); } this.width = function() { var w = this.nameWidth(); var multiplier = .1; var workspaceWidth = 20; if( nodeList.count() > 0 ) { workspaceWidth = nodeList.width(); multiplier = .1; } var marg = imageWidth * multiplier; if( w > imageWidth + workspaceWidth ) return w + marg + workspaceWidth; return imageWidth + marg + workspaceWidth; } this.leftSibling = function() { return this.mLeftSibling; } this.isLeaf = function(dir){ return this.children(dir).length == 0; } this.leftmostChild = function(dir) { return (this.isLeaf(dir)) ? null : this.children(dir)[0]; } this.rightmostChild = function(dir) { return (this.isLeaf(dir)) ? null : this.children(dir)[this.children(dir).length - 1]; } this.leftmostSibling = function(dir) { return this.mParent.leftmostChild(dir); } this.isSibling = function( p, dir) { var kids = this.mParent.children(dir); for(var i = 0; i < kids.length; i++) if( kids[i] === p ) return true; return false; } var mSceneX = 0;//dg--this replaces moving the mGI scene stuff, one hopes... this.stepMove = function(moveRate) { if (this.stream && this.stream.mType != mStreamUtilities.StreamType.typeCount) { var pos = this.position(); var posParent = this.mParent.position(); var newPos = (pos.x - posParent.x)*moveRate; mSceneX = newPos; } // now all children for(var i = 0; i < this.lowerChildren.length; i++) this.lowerChildren[i].stepMove(moveRate); for(var i = 0; i < this.upperChildren.length; i++) this.upperChildren[i].stepMove(moveRate); } this.offsetX = 0; this.offsetY = 0; this.setOffset = function(point) { //console.log('offset.x: ' + point.x + ' offset.y: ' + point.y); this.offsetX = point.x; this.offsetY = point.y; this.LocationAndHeight(this.getX(), this.getY(), this.getHeight()); } this.getX = function() { return this.offsetX + this.mX + mSceneX; } this.getY = function() { return this.offsetY + -this.mRow*ROW_HEIGHT; } this.getHeight = function() { return BOX_HEIGHT; } var topLinkPoint; var bottomLinkPoint; var mClickListeners = new Array(); this.addClickListener = function(listener) { mClickListeners.push(listener); } function streamSelected(mouseEvt) { for(var i = 0; i < mClickListeners.length; i++) mClickListeners[i].nodeClicked(gitRepo, mouseEvt.x, mouseEvt.y, mouseEvt.shiftKey); } this.shapeCanvas = document.createElement( "canvas" ); this.shapeCanvas.style.position = "absolute"; document.getElementById( "streamGraph" ).appendChild( this.shapeCanvas ); //this.shapeCanvas.style.background = 'red'; this.shapeCanvas.onclick = function(evt) { streamSelected(evt); } var nameCanvas=document.createElement( "canvas" ); nameCanvas.style.position = "absolute"; document.getElementById( "streamGraph" ).appendChild( nameCanvas ); nameCanvas.onclick = function(evt) { streamSelected(evt); } this.workspaceNodes = function(workspaces) { nodeList.nodes(workspaces); } this.setMenu = function(menuId, menuHandler) { setContextMenu(this.shapeCanvas, menuId, menuHandler); setContextMenu(nameCanvas, menuId, menuHandler); } setContextMenu = function(element, menuId, menuHandler) { $(element).contextMenu( { menu: menuId }, menuHandler ); } this.LocationAndHeight = function(x, y, height) { this.shapeCanvas.style.left = x ; this.shapeCanvas.style.top = y ; this.shapeCanvas.width = this.mWidth; this.shapeCanvas.height = 35;//BOX_HEIGHT; shadowStroke = this.shapeCanvas.height/10; strokeWidth = (shadowStroke / 8) * scaleFactor; //now that we know the height and width of the background, we can place the name canvas var nameLeft = x + this.shapeCanvas.width * 0.5 + shadowStroke; nameCanvas.style.left = nameLeft; var nameCanvasTop = y + this.shapeCanvas.height - shadowStroke; nameCanvas.style.top = nameCanvasTop; nameCanvas.height = this.shapeCanvas.height * 0.75; //set the font size of the canvas so we can get an accurate width var nameFont = "normal " + nameCanvas.height * 0.5 + "px sans-serif"; nameContext.font = nameFont; if( this.stream ) nameCanvas.width = mStreamUtilities.GetTextWidth(this.getVisibleName(), nameContext, nameFont) + shadowStroke*2; //if the name canvas isn't at least as wide as the background canvas, make it so (plus a little, for aesthetics) if( nameCanvas.offsetLeft + nameCanvas.width < this.shapeCanvas.offsetLeft + this.shapeCanvas.width ) nameCanvas.width = ((this.shapeCanvas.offsetLeft + this.shapeCanvas.width) - nameCanvas.offsetLeft) * 1.2; this.CreateShapes(); nodeList.position(x + this.shapeCanvas.width, nameCanvasTop + nameCanvas.height); } var shapeContext = this.shapeCanvas.getContext( '2d' ); var nameContext = nameCanvas.getContext( '2d' ); this.GetColor = function() { //'rgb(30, 144, 255)' is dodgerblue var r = 120; var g = 180; var b = 255; var nodeColor = new mStreamUtilities.StreamColor(200, 200, 200, 1); //the multiplier keeps the color from hitting pure white var multiplier = 0.9; if (this.stream != null) { //if( !mStreamUtilities.isNonConformingRelationship(this.mParent, this) ) { r = Math.floor(r + (255 - r) * this.firmness * multiplier); g = Math.floor(g + (255 - g) * this.firmness * multiplier); b = Math.floor(b + (255 - b) * this.firmness * multiplier); var sColor = new mStreamUtilities.StreamColor(r,g,b,1); nodeColor = sColor; } } return nodeColor; } this.CreateNameShape = function(rectangle, context) { var x = rectangle.x; var y = rectangle.y; var width = rectangle.width; var height = rectangle.height; var radius = height/2; context.beginPath(); context.lineTo(x,y+height-radius);//start at lower left corner - the radius context.quadraticCurveTo(x,y+height,x+radius,y+height);//curve around to bottom context.lineTo(x+width-radius,y+height);//draw bottom line context.quadraticCurveTo(x+width,y+height,x+width,y+height-radius);//curve around to right side context.lineTo(x+width,y+radius);//draw right side context.quadraticCurveTo(x+width,y,x+width-radius,y);//curve around to top context.lineTo(x+radius,y);//draw top context.quadraticCurveTo(x,y,x,y+radius);//curve around to left context.closePath();//draws the left side } this.CreateShapes = function() { mStreamUtilities.clearCanvas(this.shapeCanvas); mStreamUtilities.clearCanvas(nameCanvas); var x = shadowStroke/2; var y = shadowStroke/2; var width = this.shapeCanvas.width - shadowStroke; var height= this.shapeCanvas.height - shadowStroke * 2; topLinkPoint = new mStreamUtilities.Vector( this.shapeCanvas.offsetLeft + this.shapeCanvas.width / 2, this.shapeCanvas.offsetTop + shadowStroke); bottomLinkPoint = new mStreamUtilities.Vector( this.shapeCanvas.offsetLeft + this.shapeCanvas.width / 2, this.shapeCanvas.offsetTop + y + height); //create the shapes, but don't fill it 'til later... this.CreateNameShape(new mStreamUtilities.Rectangle(x, y, nameCanvas.width - shadowStroke, nameCanvas.height - shadowStroke), nameContext); this.CreateStatusIcons(); //this.CreateChildAttachNodes(); } this.selectionColor = new mStreamUtilities.StreamColor(30, 144, 255, 1);// dodgerblue this.highlightColor = new mStreamUtilities.StreamColor(176, 196, 222, 1);//'lightsteelblue'; this.getOutlineColor = function() { var outlineColor = this.selectionColor; if(this.highlighted && !this.selected) outlineColor = this.highlightColor; //if( mStreamUtilities.isNonConformingRelationship(this.mParent, this) ) // outlineColor = new mStreamUtilities.StreamColor(128,128,128,1);//'gray'; return outlineColor; } this.draw = function(showStatus) { var color = this.GetColor(); mStreamUtilities.clearCanvas(this.shapeCanvas); var outlineColor = this.getOutlineColor(); var nonConforming = mStreamUtilities.isNonConformingRelationship(this.mParent, this); this.drawName(); if(showStatus) this.DrawStatusIcons(); if(nodeList) nodeList.draw(); var imageObj = new Image(); imageObj.onload = function() { shapeContext.drawImage(imageObj,0,0); } imageObj.src = "css/images/git-logo.png"; } this.getNameY = function() { return nameCanvas.offsetTop; } this.getNameHeight = function() { return nameCanvas.height; } this.drawName = function() { this.CreateNameShape(new mStreamUtilities.Rectangle(shadowStroke/2, shadowStroke/2, nameCanvas.width - shadowStroke, nameCanvas.height - shadowStroke), nameContext); //create a gradient brush to fill the name background var aliceBlue = new mStreamUtilities.StreamColor(240, 248, 255, 1); var nameLingrad = this.GetGradientFill(aliceBlue, nameContext, nameCanvas, true); nameContext.save(); nameContext.fillStyle = nameLingrad; nameContext.fill(); nameContext.restore(); //not sure why I have to re-set the font size here... nameContext.font = "normal " + nameCanvas.height * 0.5 + "px sans-serif"; nameContext.textBaseline = "middle"; nameContext.fillText(this.getVisibleName(), shadowStroke, nameCanvas.height/2 - nameCanvas.height * 0.02); nameContext.strokeStyle = this.getOutlineColor().rgba; nameContext.stroke(); } var expandNameWidth = 0; var expandNameLeft = 0; var initialNameSize = true; this.expandNameCanvas = function(width) { if( initialNameSize ) { expandNameWidth = nameCanvas.width; initialNameSize = false; } expandNameLeft += nameCanvas.offsetLeft; $(nameCanvas).animate({ left: '-=' + nameCanvas.offsetLeft + 'px', //width: '+=' + width }, 500 ); nameCanvas.width = width; this.drawName(); } this.reduceNameCanvas = function() { $(nameCanvas).animate({ left: '+=' + expandNameLeft + 'px', }, 500 ); expandNameLeft = 0; nameCanvas.width = expandNameWidth; initialNameSize = true; this.drawName(); } this.isAboveMainline = function() { return this.row() > 0; } this.DrawStatusIcons = function() { var mergeColor = 'lightgray'; var mergeStroke = 'gray'; if(this.ShowMergeAvailable()) mergeColor = getMergeColor(); var mergeImage = new Image(); mergeImage.onload = function() { mergeContext.drawImage(mergeImage,0,0); } var promoteImage = new Image(); promoteImage.onload = function() { promoteContext.drawImage(promoteImage,0,0); } if( !this.isMainline() && mSkin != 'gumdrop') { if( this.isFirmType() ) { if(this.isAboveMainline() ) { if( this.integToParent ) mergeImage.src = "css/images/mergedownneeded.png"; else mergeImage.src = "css/images/mergedown.png"; if( this.integFromParent ) { if( this.integToParent ) promoteImage.src = "css/images/promoteupconflict.png"; else promoteImage.src = "css/images/promoteupneeded.png"; } else { promoteImage.src = "css/images/promoteup.png"; } } else { if( this.integToParent ) mergeImage.src = "css/images/mergeupneeded.png"; else mergeImage.src = "css/images/mergeup.png"; if( this.integFromParent ) { if( this.integToParent ) promoteImage.src = "css/images/promotedownconflict.png"; else promoteImage.src = "css/images/promotedownneeded.png"; } else { promoteImage.src = "css/images/promotedown.png"; } } } else { if(this.isAboveMainline() ) { if( this.integFromParent ) mergeImage.src = "css/images/mergeupneeded.png"; else mergeImage.src = "css/images/mergeup.png"; if( this.integToParent ) { if( this.integFromParent ) promoteImage.src = "css/images/promotedownconflict.png"; else promoteImage.src = "css/images/promotedownneeded.png"; } else promoteImage.src = "css/images/promotedown.png"; } else { if( this.integFromParent ) mergeImage.src = "css/images/mergedownneeded.png"; else mergeImage.src = "css/images/mergedown.png"; if( this.integToParent ) { if( this.integFromParent ) promoteImage.src = "css/images/promoteupconflict.png"; else promoteImage.src = "css/images/promoteupneeded.png"; } else promoteImage.src = "css/images/promoteup.png"; } } } } this.GetGradientFill = function(color, context, canvas, whiteHighlight, stripes) { var lightColor = 'white'; var linearGradient = context.createLinearGradient(0,0,0,canvas.height); //console.log(this.firmness); if (!whiteHighlight) { var r = Math.floor(color.r + (255 - color.r)/1.2); var g = Math.floor(color.g + (255 - color.g)/1.2); var b = Math.floor(color.b + (255 - color.b)/1.2); lightColor = 'rgb(' + r + ',' + g + ',' + b + ')'; } { try { linearGradient.addColorStop(0, lightColor); linearGradient.addColorStop(0.3, color.rgba); linearGradient.addColorStop(0.6, color.rgba); linearGradient.addColorStop(1, lightColor); }catch(e) { console.log(e); } } return linearGradient; } this.integToParent = false; this.integFromParent = false; this.ShowMergeAvailable = function() { for( var i = 0; i < mAllChildren.length; i++ ) if( mAllChildren[i].integFromParent ) return true; return false; } function getMergeColor() { return 'rgba(175, 225, 100, 1)'; } this.GetTopLinkPoint = function() { return topLinkPoint; } this.GetBottomLinkPoint = function() { return bottomLinkPoint; } this.firstLinkCanvas; this.secondLinkCanvas; this.firstLinkCanvas = document.createElement( "canvas" ); this.firstLinkCanvas.style.position = "absolute"; this.firstLinkCanvas.style.zIndex = -10; document.getElementById( "streamGraph" ).appendChild( this.firstLinkCanvas ); this.secondLinkCanvas = document.createElement( "canvas" ); this.secondLinkCanvas.style.position = "absolute"; this.secondLinkCanvas.style.zIndex = -10; document.getElementById( "streamGraph" ).appendChild( this.secondLinkCanvas ); var mergeCanvas=document.createElement( "canvas" ); var mergeContext = mergeCanvas.getContext( '2d' ); mergeCanvas.onclick = function(evt) { streamSelected(evt); } var promoteCanvas=document.createElement( "canvas" ); var promoteContext = promoteCanvas.getContext( '2d' ); promoteCanvas.onclick = function(evt) { streamSelected(evt); } this.upperChildCanvas=document.createElement( "canvas" ); var upperChildContext = this.upperChildCanvas.getContext( '2d' ); var lowerChildCanvas=document.createElement( "canvas" ); var lowerChildContext = lowerChildCanvas.getContext( '2d' ); var alignNudge = 0; var animAlignTime = 0; this.alignWithOtherNode = function(otherNode, animTime) { animAlignTime = animTime; alignNudge = this.mX - otherNode.mX; moveElementHorizontally(this.shapeCanvas, alignNudge, animAlignTime); moveElementHorizontally(nameCanvas, alignNudge, animAlignTime); moveElementHorizontally(this.upperChildCanvas, alignNudge, animAlignTime); moveElementHorizontally(lowerChildCanvas, alignNudge, animAlignTime); this.mX -= alignNudge; } this.returnToOriginalPosition = function() { moveElementHorizontally(this.shapeCanvas, -alignNudge, animAlignTime); moveElementHorizontally(nameCanvas, -alignNudge, animAlignTime); moveElementHorizontally(this.upperChildCanvas, -alignNudge, animAlignTime); moveElementHorizontally(lowerChildCanvas, -alignNudge, animAlignTime); this.mX += alignNudge; } function moveElementHorizontally(element, units, animTime) { $(element).animate({ left: '-=' + units + 'px', }, animTime ); } var mZMoveIncrement = 0; this.moveForward = function(moveForwardIncrement) { mZMoveIncrement = moveForwardIncrement; this.shapeCanvas.style.zIndex += mZMoveIncrement; nameCanvas.style.zIndex += mZMoveIncrement; this.upperChildCanvas.style.zIndex += mZMoveIncrement; lowerChildCanvas.style.zIndex += mZMoveIncrement; } this.moveBack = function() { this.shapeCanvas.style.zIndex -= mZMoveIncrement; nameCanvas.style.zIndex -= mZMoveIncrement; this.upperChildCanvas.style.zIndex -= mZMoveIncrement; lowerChildCanvas.style.zIndex -= mZMoveIncrement; } this.toString = function() { if( this.stream ) return this.stream.mStream + "StreamNode"; return "undefined stream in StreamNode"; } this.clearLinks = function() { mStreamUtilities.clearCanvas(this.firstLinkCanvas); mStreamUtilities.clearCanvas(this.secondLinkCanvas); } this.linkType = function() { if( mSkin == 'gumdrop' ) return mStreamUtilities.LinkType.Parallel; return mStreamUtilities.LinkType.Default; } this.ShowSendMergeBadge = function() { return false; } this.ShowReceiveMergeBadge = function() { return true; } this.ShowSendPromotionBadge = function() { return true; } this.ShowReceivePromotionBadge = function() { return false; } this.CreateStatusIcons = function() { //mergeCanvas.style.background = 'green'; //promoteCanvas.style.background = 'red'; if (showStateIcons && scaleFactor >= MINZOOMFACTOR) { var stagingNudge = nameCanvas.height/6; var nudge = strokeWidth*2; var iconWidth = 18; var iconHeight = 18; var y; var connectY; if( horizontalLayout ) { if(this.isFirmType() ) { y = this.shapeCanvas.offsetTop + iconHeight/2; connectY = y + iconHeight - 1; } else { y = this.shapeCanvas.offsetTop + iconHeight/2; connectY = y + 1; } } else { if( this.isFirmType()/* this.isAboveMainline()*/ ) { y = this.shapeCanvas.offsetTop + this.shapeCanvas.height; connectY = y + iconHeight - 1; } else { y = this.shapeCanvas.offsetTop - (iconHeight); connectY = y + 1; } } if (this.ShowSendMergeBadge() && this.ShowReceivePromotionBadge()) { mergeCanvas.style.position = "absolute"; document.getElementById( "streamGraph" ).appendChild( mergeCanvas ); promoteCanvas.style.position = "absolute"; document.getElementById( "streamGraph" ).appendChild( promoteCanvas ); var rightX = this.shapeCanvas.offsetLeft; if( !horizontalLayout ) rightX += this.shapeCanvas.width / 6; else rightX -= iconWidth/1.5; var leftX = (rightX - iconWidth); mergeCanvas.style.top = y; mergeCanvas.style.left = leftX + 2 mergeCanvas.width = iconWidth; mergeCanvas.height = iconHeight; promoteCanvas.style.top = y; promoteCanvas.style.left = rightX - 2; promoteCanvas.width = iconWidth; promoteCanvas.height = iconHeight; this.mergePoint = new mStreamUtilities.Vector( leftX + 2 + iconWidth/2, connectY ); this.promotePoint = new mStreamUtilities.Vector( (rightX - 2) + iconWidth/2, connectY ); } else if (this.ShowReceiveMergeBadge() && this.ShowSendPromotionBadge()) { mergeCanvas.style.position = "absolute"; document.getElementById( "streamGraph" ).appendChild( mergeCanvas ); promoteCanvas.style.position = "absolute"; document.getElementById( "streamGraph" ).appendChild( promoteCanvas ); var rightX = this.shapeCanvas.offsetLeft; if( !horizontalLayout ) rightX += this.shapeCanvas.width / 5; else rightX -= iconWidth/1.5; var leftX = (rightX - iconWidth); mergeCanvas.style.top = y; mergeCanvas.style.left = leftX + 2; mergeCanvas.width = iconWidth; mergeCanvas.height = iconHeight; promoteCanvas.style.top = y; promoteCanvas.style.left = rightX - 2; promoteCanvas.width = iconWidth; promoteCanvas.height = iconHeight; this.mergePoint = new mStreamUtilities.Vector( leftX + 2 + iconWidth/2, connectY ); this.promotePoint = new mStreamUtilities.Vector( (rightX - 2) + iconWidth/2, connectY ); } else if( this.ShowReceiveMergeBadge() ) { mergeCanvas.style.position = "absolute"; document.getElementById( "streamGraph" ).appendChild( mergeCanvas ); var middleX = this.shapeCanvas.offsetLeft; if( !horizontalLayout ) middleX += this.shapeCanvas.width / 2 - iconWidth/2; else middleX -= iconWidth; mergeCanvas.style.top = y; mergeCanvas.style.left = middleX; mergeCanvas.width = iconWidth; mergeCanvas.height = iconHeight; this.mergePoint = new mStreamUtilities.Vector( middleX + iconWidth/2, connectY ); } else if ( this.ShowSendPromotionBadge() ) { promoteCanvas.style.position = "absolute"; document.getElementById( "streamGraph" ).appendChild( promoteCanvas ); var middleX = this.shapeCanvas.offsetLeft; if( !horizontalLayout ) middleX += this.shapeCanvas.width / 2 - iconWidth/2; else middleX -= iconWidth; promoteCanvas.style.top = y; promoteCanvas.style.left = middleX; promoteCanvas.width = iconWidth; promoteCanvas.height = iconHeight; this.promotePoint = new mStreamUtilities.Vector( middleX + iconWidth/2, connectY ); } else if( this.ShowSendMergeBadge() ) { mergeCanvas.style.position = "absolute"; document.getElementById( "streamGraph" ).appendChild( mergeCanvas ); var x = this.shapeCanvas.offsetLeft; if( !horizontalLayout ) x += this.shapeCanvas.width / 2 - iconWidth / 2; else x -= iconWidth; mergeCanvas.style.top = y; mergeCanvas.style.left = x mergeCanvas.width = iconWidth; mergeCanvas.height = iconHeight; this.mergePoint = new mStreamUtilities.Vector( x + iconWidth/2, connectY ); } else if( this.ShowReceivePromotionBadge() ) { promoteCanvas.style.position = "absolute"; document.getElementById( "streamGraph" ).appendChild( promoteCanvas ); var x = this.shapeCanvas.offsetLeft; if( !horizontalLayout ) x += this.shapeCanvas.width / 2 - iconWidth / 2; else x -= iconWidth; promoteCanvas.style.top = y; promoteCanvas.style.left = x promoteCanvas.width = iconWidth; promoteCanvas.height = iconHeight; this.promotePoint = new mStreamUtilities.Vector( x + iconWidth/2, connectY ); } else//this is the case where no badges are going to be shown. We still need the points set so a default line can be drawn { mergeCanvas.style.position = "absolute"; document.getElementById( "streamGraph" ).appendChild( mergeCanvas ); var x = this.shapeCanvas.offsetLeft; if( !horizontalLayout ) x += this.shapeCanvas.width / 2 - iconWidth / 2; mergeCanvas.style.top = y; mergeCanvas.style.left = x mergeCanvas.width = iconWidth; mergeCanvas.height = 0; if( this.isAboveMainline() ) this.mergePoint = new mStreamUtilities.Vector( x + iconWidth/2, connectY - iconHeight ); else this.mergePoint = new mStreamUtilities.Vector( x + iconWidth/2, connectY + iconHeight ); } } } return this; }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 8081 | David George |
Initial submit of JavaScript StreamGraph. Main functionality is: Change Trajectory (Change Flow), Timeline, and GitStreams. |