function DefaultStreamNode(stream, parentNode, layout, streamUtilities) { var horizontalLayout = false; if( layout && layout=='ancestor' ) horizontalLayout = true; var mStreamUtilities = streamUtilities; this.stream = stream; 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 this.mWidth = 135; this.typeIconWidth = 36; 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); this.selectionColor = new mStreamUtilities.StreamColor(213, 184, 133, 1); this.highlightColor = new mStreamUtilities.StreamColor(176, 196, 222, 1); // how tall each circle is var BOX_HEIGHT = 135; // how much space a row consumes var ROW_HEIGHT = BOX_HEIGHT*.75; if( horizontalLayout ) ROW_HEIGHT = BOX_HEIGHT * .35; this.RowHeight = function() { return ROW_HEIGHT; } var shapeHeight = 35; var nameFont = "normal " + shapeHeight * 0.4 + "px sans-serif"; this.position = function() { return new mStreamUtilities.Point(this.mX, (-1*this.mRow)*(ROW_HEIGHT)); } this.firmerThanParent = function() { //console.log('isUpperStream() type: ' + this.mType); if( this.stream ) return this.stream.mFirmerThanParent; return false; } this.isFirmType = function() { return this.stream.type() == mStreamUtilities.StreamType.release || this.stream.type() == mStreamUtilities.StreamType.staging; } this.isAboveMainline = function() { return this.row() > 0; } this.isMainline = function() { if( this.stream ) return this.stream.mType == mStreamUtilities.StreamType.mainLine; return false; } if( this.isFirmType() ) this.selectionColor = new mStreamUtilities.StreamColor(213, 184, 133, 1); else if( this.isMainline() ) this.selectionColor = new mStreamUtilities.StreamColor(167, 167, 167, 1); else this.selectionColor = new mStreamUtilities.StreamColor(167, 188, 213, 1); 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.stream.mName, nameContext); } this.width = function() { var workspaceWidth = 0; if( nodeList.count() > 0 ) workspaceWidth = nodeList.width(); return this.mWidth + 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(stream, mouseEvt.x, mouseEvt.y, mouseEvt.shiftKey); } this.backgroundCanvas = document.createElement( "canvas" ); this.backgroundCanvas.style.position = "absolute"; document.getElementById( "streamGraph" ).appendChild( this.backgroundCanvas ); $(this.backgroundCanvas).hide(); 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"; nameCanvas.width = this.mWidth - this.typeIconWidth; document.getElementById( "streamGraph" ).appendChild( nameCanvas ); nameCanvas.onclick = function(evt) { streamSelected(evt); } 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' ); this.workspaceNodes = function(workspaces) { nodeList.nodes(workspaces); } this.setMenu = function(menuId, menuHandler) { setContextMenu(this.shapeCanvas, menuId, menuHandler); setContextMenu(nameCanvas, menuId, menuHandler); setContextMenu(mergeCanvas, menuId, menuHandler); setContextMenu(promoteCanvas, menuId, menuHandler); setContextMenu(this.upperChildCanvas, menuId, menuHandler); setContextMenu(lowerChildCanvas, menuId, menuHandler); } setContextMenu = function(element, menuId, menuHandler) { $(element).contextMenu( { menu: menuId }, menuHandler ); } this.ShowSendMergeBadge = function() { if( !this.stream ) return false; if(this.stream.mType == mStreamUtilities.StreamType.release) return this.stream.mChangeFlowsToParent; return false; } this.ShowReceiveMergeBadge = function() { if( !this.stream ) return false; if(this.stream.mType == mStreamUtilities.StreamType.development) return this.stream.mChangeFlowsFromParent; return false; } this.ShowSendPromotionBadge = function() { if( !this.stream ) return false; if(this.stream.mType == mStreamUtilities.StreamType.development) return this.stream.mChangeFlowsToParent; return false; } this.ShowReceivePromotionBadge = function() { if( !this.stream ) return false; if(this.stream.mType == mStreamUtilities.StreamType.release) return this.stream.mChangeFlowsFromParent; return false; } this.getBadgePoint = function() { var nudge = 5 return new mStreamUtilities.Point( this.getX() + this.mWidth/2 + nudge, this.getY() + this.shapeCanvas.height/1.5 + nudge); } this.CreateChildAttachNodes = function() { //this.upperChildCanvas.style.background = 'green'; //lowerChildCanvas.style.background = 'red'; //strokeWidth = outlineWidth * scaleFactor; var diameter = this.shapeCanvas.width/6; if (this.isFirmType()) { this.upperChildCanvas.style.position = "absolute"; document.getElementById( "streamGraph" ).appendChild( this.upperChildCanvas ); this.upperChildCanvas.onclick = function(evt) { streamSelected(evt); } this.upperChildCanvas.style.top = this.shapeCanvas.offsetTop - diameter/4; this.upperChildCanvas.width = diameter; this.upperChildCanvas.height = diameter; this.upperChildCanvas.style.left = this.shapeCanvas.offsetLeft + this.shapeCanvas.width/2 - diameter/2; upperChildContext.beginPath(); upperChildContext.arc(this.upperChildCanvas.width/2, this.upperChildCanvas.width/2, this.upperChildCanvas.width/2 - strokeWidth, 0, Math.PI*2, true); upperChildContext.closePath(); //topLinkPoint = new mStreamUtilities.Vector( this.upperChildCanvas.offsetLeft + diameter / 2, this.upperChildCanvas.offsetTop + strokeWidth); bottomLinkPoint = new mStreamUtilities.Vector( this.shapeCanvas.offsetLeft + this.shapeCanvas.width / 2, this.upperChildCanvas.offsetTop + this.shapeCanvas.height); } else if(this.isMainline()) { this.upperChildCanvas.style.position = "absolute"; document.getElementById( "streamGraph" ).appendChild( this.upperChildCanvas ); this.upperChildCanvas.onclick = function(evt) { streamSelected(evt); } this.upperChildCanvas.style.top = this.shapeCanvas.offsetTop - diameter/4; this.upperChildCanvas.width = diameter; this.upperChildCanvas.height = diameter; this.upperChildCanvas.style.left = this.shapeCanvas.offsetLeft + this.shapeCanvas.width/2 - diameter/2; upperChildContext.beginPath(); upperChildContext.arc(this.upperChildCanvas.width/2, this.upperChildCanvas.width/2, this.upperChildCanvas.width/2 - strokeWidth, 0, Math.PI*2, true); upperChildContext.closePath(); lowerChildCanvas.style.position = "absolute"; document.getElementById( "streamGraph" ).appendChild( lowerChildCanvas ); lowerChildCanvas.onclick = function(evt) { streamSelected(evt); } lowerChildCanvas.style.top = this.shapeCanvas.offsetTop + this.shapeCanvas.height - diameter*1.3; lowerChildCanvas.width = diameter; lowerChildCanvas.height = diameter; lowerChildCanvas.style.left = this.shapeCanvas.offsetLeft + this.shapeCanvas.width/2 - diameter/2; lowerChildContext.beginPath(); lowerChildContext.arc(lowerChildCanvas.width/2, lowerChildCanvas.width/2, lowerChildCanvas.width/2 - strokeWidth, 0, Math.PI*2, true); lowerChildContext.closePath(); topLinkPoint = new mStreamUtilities.Vector( this.upperChildCanvas.offsetLeft + diameter / 2, this.upperChildCanvas.offsetTop + strokeWidth); bottomLinkPoint = new mStreamUtilities.Vector( lowerChildCanvas.offsetLeft + lowerChildCanvas.width / 2, lowerChildCanvas.offsetTop + lowerChildCanvas.height + strokeWidth); } else { lowerChildCanvas.style.position = "absolute"; document.getElementById( "streamGraph" ).appendChild( lowerChildCanvas ); lowerChildCanvas.onclick = function(evt) { streamSelected(evt); } lowerChildCanvas.style.top = this.shapeCanvas.offsetTop + this.shapeCanvas.height - diameter; lowerChildCanvas.width = diameter; lowerChildCanvas.height = diameter; lowerChildCanvas.style.left = this.shapeCanvas.offsetLeft + this.shapeCanvas.width/2 - diameter/2; lowerChildContext.beginPath(); lowerChildContext.arc(lowerChildCanvas.width/2, lowerChildCanvas.width/2, lowerChildCanvas.width/2 - strokeWidth, 0, Math.PI*2, true); lowerChildContext.closePath(); //topLinkPoint = new mStreamUtilities.Vector( this.shapeCanvas.offsetLeft + this.shapeCanvas.width / 2, this.upperChildCanvas.offsetTop); bottomLinkPoint = new mStreamUtilities.Vector( lowerChildCanvas.offsetLeft + lowerChildCanvas.width / 2, lowerChildCanvas.offsetTop + lowerChildCanvas.height + strokeWidth); //bottomLinkPoint = new mStreamUtilities.Vector( this.shapeCanvas.offsetLeft + this.shapeCanvas.width / 2, this.shapeCanvas.offsetTop + y + height); } } this.mergePoint = null; this.promotePoint = null; 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 / 2; 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 / 2; 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 ); } } } this.LocationAndHeight = function(x, y, height) { this.backgroundCanvas.style.left = x ; this.backgroundCanvas.style.top = y ; this.backgroundCanvas.width = height; this.backgroundCanvas.height = height; this.shapeCanvas.style.left = x ; this.shapeCanvas.style.top = y ; this.shapeCanvas.width = this.mWidth;// height; this.shapeCanvas.height = shapeHeight;//height; shadowStroke = this.shapeCanvas.height/10; strokeWidth = (shadowStroke/2) * scaleFactor; //now that we know the height and width of the background, we can place the name canvas nameCanvas.style.left = x + this.typeIconWidth; var nameCanvasTop; nameCanvasTop = y + this.shapeCanvas.height / 5;//in the middle nameCanvas.style.top = nameCanvasTop; nameCanvas.height = this.shapeCanvas.height * 0.6; //set the font size of the canvas so we can get an accurate width nameContext.font = nameFont; if( this.stream ) nameCanvas.width = this.shapeCanvas.width - this.typeIconWidth; this.CreateShapes(); nodeList.position(x + this.shapeCanvas.width, nameCanvasTop + nameCanvas.height); } var backgroundContext = this.backgroundCanvas.getContext( '2d' ); var shapeContext = this.shapeCanvas.getContext( '2d' ); var nameContext = nameCanvas.getContext( '2d' ); this.GetColor = function() { var nodeColor = new mStreamUtilities.StreamColor(200, 200, 200, 1); if (this.stream.mType == mStreamUtilities.StreamType.release || this.stream.mType == mStreamUtilities.StreamType.staging ) nodeColor = new mStreamUtilities.StreamColor(255, 221, 160, 1); else if (this.stream.mType == mStreamUtilities.StreamType.development ) nodeColor = new mStreamUtilities.StreamColor(200, 225, 255, 1); return nodeColor; } this.CreateStreamShape = function(rectangle, context) { if (this.stream != null) mStreamUtilities.CreateRoundedRectangle(rectangle.x, rectangle.y, rectangle.width, rectangle.height, rectangle.height/4, context); } 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.backgroundCanvas); 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; var linkX = this.shapeCanvas.width / 2; var linkY = 0; if( horizontalLayout ) { linkX = this.shapeCanvas.width ; linkY = this.shapeCanvas.height / 4; } topLinkPoint = new mStreamUtilities.Vector( this.shapeCanvas.offsetLeft + linkX, this.shapeCanvas.offsetTop + shadowStroke + linkY); bottomLinkPoint = new mStreamUtilities.Vector( this.shapeCanvas.offsetLeft + linkX, this.shapeCanvas.offsetTop + y + height - linkY); //create the shapes, but don't fill it 'til later... this.CreateStreamShape(new mStreamUtilities.Rectangle(x, y, width, height), backgroundContext); this.CreateStreamShape(new mStreamUtilities.Rectangle(x, y, width, height), shapeContext); this.CreateNameShape(new mStreamUtilities.Rectangle(x, y, nameCanvas.width - shadowStroke, nameCanvas.height - shadowStroke), nameContext); this.CreateStatusIcons(); //this.CreateChildAttachNodes(); } this.getOutlineColor = function() { var outlineColor = this.selectionColor; if(this.highlighted && !this.selected) outlineColor = this.highlightColor; return outlineColor; } this.draw = function(showStatus) { var color = this.GetColor(); mStreamUtilities.clearCanvas(this.backgroundCanvas); mStreamUtilities.clearCanvas(this.shapeCanvas); var outlineColor = this.getOutlineColor(); //this.DrawShadow(backgroundContext, shadowStroke); this.DrawShadow(shapeContext, shadowStroke); //this.DrawChildAttachNodes(outlineColor, strokeWidth); backgroundContext.fillStyle = this.GetGradientFill(new mStreamUtilities.StreamColor(200, 200, 200, .1), backgroundContext, this.backgroundCanvas); backgroundContext.fill(); if( this.selected || this.highlighted ) shapeContext.fillStyle = 'rgba(' + color.r + ',' + color.g + ',' + color.b + ',' + color.a +')'; else shapeContext.fillStyle = this.GetGradientFill(color, shapeContext, this.shapeCanvas); shapeContext.fill(); //this.shapeCanvas.style.background = 'blue'; this.drawName(); //draw a thick white outline shapeContext.strokeStyle = 'white'; shapeContext.lineWidth = strokeWidth * 3; shapeContext.stroke(); //draw a thinner colored outline over the white outline shapeContext.strokeStyle = outlineColor.rgba; shapeContext.lineWidth = strokeWidth; shapeContext.stroke(); //console.log('drawing: ' + this.stream.mName + " x: " + this.shapeCanvas.offsetLeft + " y: " + this.shapeCanvas.offsetTop + " sceneX: " + mSceneX); if(showStatus) this.DrawStatusIcons(); if(nodeList) nodeList.draw(); var imageObj = new Image(); imageObj.onload = function() { shapeContext.drawImage(imageObj,9,8); } if(this.isFirmType() ) imageObj.src = "css/images/relicon.png"; else if(this.isMainline() ) imageObj.src = "css/images/mainicon.png"; else imageObj.src = "css/images/devicon.png"; } this.getNameY = function() { return nameCanvas.offsetTop; } this.getNameHeight = function() { return nameCanvas.height; } var showNameBackground = false; this.drawName = function() { mStreamUtilities.clearCanvas(nameCanvas); this.CreateNameShape(new mStreamUtilities.Rectangle(shadowStroke/2, shadowStroke/2, nameCanvas.width - shadowStroke, nameCanvas.height - shadowStroke), nameContext); if( showNameBackground ) { //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(); nameContext.strokeStyle = this.getOutlineColor().rgba; nameContext.stroke(); } //not sure why I have to re-set the font size here... nameContext.font = nameFont; nameContext.textBaseline = "middle"; nameContext.fillText( mStreamUtilities.ElideTextToWidth( this.stream.mName, nameCanvas.width, nameCanvas, nameFont ), shadowStroke, nameCanvas.height/2 - nameCanvas.height * 0.02); } var expandNameWidth = 0; var expandNameLeft = 0; var initialNameSize = true; this.expandNameCanvas = function(width) { showNameBackground = true; 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() { showNameBackground = false; $(nameCanvas).animate({ left: '+=' + expandNameLeft + 'px', }, 500 ); expandNameLeft = 0; nameCanvas.width = expandNameWidth; initialNameSize = true; this.drawName(); } this.DrawChildAttachNodes = function(outlineColor, strokeWidth) { if (this.isFirmType()) { upperChildContext.fillStyle = 'white'; upperChildContext.fill(); upperChildContext.strokeStyle = outlineColor.rgba; upperChildContext.lineWidth = strokeWidth; upperChildContext.stroke(); } else if(this.isMainline()) { upperChildContext.fillStyle = 'white'; upperChildContext.fill(); upperChildContext.strokeStyle = outlineColor.rgba; upperChildContext.lineWidth = strokeWidth; upperChildContext.stroke(); lowerChildContext.fillStyle = 'white'; lowerChildContext.fill(); lowerChildContext.strokeStyle = outlineColor.rgba; lowerChildContext.lineWidth = strokeWidth; lowerChildContext.stroke(); } else { lowerChildContext.fillStyle = 'white'; lowerChildContext.fill(); lowerChildContext.strokeStyle = outlineColor.rgba; lowerChildContext.lineWidth = strokeWidth; lowerChildContext.stroke(); } } this.getMergeNeededColor = function() { return 'rgba(175, 225, 100, 1)'; } this.DrawStatusIcons = function() { 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() ) { 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 ) { var lightColor = 'white'; var linearGradient = context.createLinearGradient(0,0,0,canvas.height); //console.log(this.firmness); try { linearGradient.addColorStop(0, lightColor); linearGradient.addColorStop(0.5, color.rgba); linearGradient.addColorStop(0.5, color.rgba); linearGradient.addColorStop(1, lightColor); }catch(e) { console.log(e); } return linearGradient; } this.DrawShadow = function( context, width ) { context.save(); var hue = 230; context.lineJoin = 'round'; context.strokeStyle = 'rgba(' + hue + ',' + hue + ',' + hue + ',0.16)'; for(var i = 0; i < width; ++i) { context.lineWidth = i; context.stroke(); } context.restore(); } this.integToParent = false; this.integFromParent = false; this.ShowMergeAvailable = function() { if(this.isFirmType()) { return this.integToParent; } else if(!this.isMainline()) { return this.integFromParent; } return false; } this.ShowPromotionsAvailable = function() { if(this.isFirmType()) { return this.integFromParent; } else if(!this.isMainline()) { return this.integToParent; } return false; } 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 alignNudge = 0; var animAlignTime = 0; this.alignWithOtherNode = function(otherNode, animTime) { animAlignTime = animTime; $(this.backgroundCanvas).hide(); alignNudge = this.mX - otherNode.mX; moveElementHorizontally(this.shapeCanvas, alignNudge, animAlignTime); moveElementHorizontally(nameCanvas, alignNudge, animAlignTime); moveElementHorizontally(mergeCanvas, alignNudge, animAlignTime); moveElementHorizontally(promoteCanvas, alignNudge, animAlignTime); moveElementHorizontally(this.upperChildCanvas, alignNudge, animAlignTime); moveElementHorizontally(lowerChildCanvas, alignNudge, animAlignTime); $(this.backgroundCanvas).show('fade', animTime); this.mX -= alignNudge; } this.returnToOriginalPosition = function() { moveElementHorizontally(this.shapeCanvas, -alignNudge, animAlignTime); moveElementHorizontally(nameCanvas, -alignNudge, animAlignTime); moveElementHorizontally(mergeCanvas, -alignNudge, animAlignTime); moveElementHorizontally(promoteCanvas, -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; mergeCanvas.style.zIndex += mZMoveIncrement; promoteCanvas.style.zIndex += mZMoveIncrement; this.upperChildCanvas.style.zIndex += mZMoveIncrement; lowerChildCanvas.style.zIndex += mZMoveIncrement; } this.moveBack = function() { this.shapeCanvas.style.zIndex -= mZMoveIncrement; nameCanvas.style.zIndex -= mZMoveIncrement; mergeCanvas.style.zIndex -= mZMoveIncrement; promoteCanvas.style.zIndex -= mZMoveIncrement; this.upperChildCanvas.style.zIndex -= mZMoveIncrement; lowerChildCanvas.style.zIndex -= mZMoveIncrement; } this.toString = function() { if( this.stream ) return this.stream.mStream + "DefaultStreamNode"; return "undefined stream in StreamNode"; } this.clearLinks = function() { mStreamUtilities.clearCanvas(this.firstLinkCanvas); mStreamUtilities.clearCanvas(this.secondLinkCanvas); } this.linkType = function() { return mStreamUtilities.LinkType.Default; } 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. |