function StreamLink(parentNode, childNode, showStatus, layout, streamUtilities) { var mStreamUtilities = streamUtilities; var horizontalLayout = false; if( layout && layout=='ancestor' ) horizontalLayout = true; function drawDefaultLinks() { childNode.firstLinkCanvas.width = childNode.firstLinkCanvas.width;//resets the canvas's properties childNode.secondLinkCanvas.width = childNode.secondLinkCanvas.width;//resets the canvas's properties //console.log('parentNode: ' + parentNode.stream.mName + ' other: ' + otherStreamNode.stream.mName); var conflictColor = new mStreamUtilities.StreamColor(214,120,68,1); var mergeNeededColor = new mStreamUtilities.StreamColor(170,215,70,1); var promoteNeededColor = new mStreamUtilities.StreamColor(170,215,70,1); var fineColor = new mStreamUtilities.StreamColor(220, 220, 220,1); var plainColor = new mStreamUtilities.StreamColor(240,240,240,1); var promoteZIndex = -3; var mergeZIndex = -3; var nonConforming = mStreamUtilities.isNonConformingRelationship( parentNode, childNode ); if( nonConforming ) { promoteZIndex = 3; mergeZIndex = 3; } var childMergePoint = childNode.mergePoint; var childPromotePoint = childNode.promotePoint; var parentNodeLinkPoint = ( parentNode.isMainline() && childNode.isFirmType ()) || parentNode.isFirmType() ? parentNode.GetTopLinkPoint() : parentNode.GetBottomLinkPoint(); var otherStreamIsHigher = parentNode.row() < childNode.row(); var mergeX = 0; var promoteX = 0; var y = 0 var height = 0; var mergeWidth = 0; var promoteWidth = 0; var mergeBottomToTop = true; var promoteBottomToTop = true; var noStatusNudge = 18; if( showStatus ) noStatusNudge = 0; var mergeXGreaterThanParent; var promoteXGreaterThanParent; if( childMergePoint ) mergeXGreaterThanParent = childMergePoint.X > parentNodeLinkPoint.X; if( childPromotePoint ) promoteXGreaterThanParent = childPromotePoint.X > parentNodeLinkPoint.X; //the plan here is to build one of four different rectangles relative to parentNode node: // A B // ____ ____ // | || | // | || | // ---- ---- // parentNode // ____ ____ // | || | // | || | // ---- ---- // C D var point = 'no point specified'; if( childMergePoint ) { if( otherStreamIsHigher && !mergeXGreaterThanParent )//A { point = 'A'; mergeX = childMergePoint.X; y = childMergePoint.Y - noStatusNudge; height = (parentNodeLinkPoint.Y - childMergePoint.Y) + noStatusNudge; mergeWidth = parentNodeLinkPoint.X - childMergePoint.X; mergeBottomToTop = false; } else if( otherStreamIsHigher && mergeXGreaterThanParent )//B { point = 'B'; mergeX = parentNodeLinkPoint.X; y = childMergePoint.Y - noStatusNudge; height = (parentNodeLinkPoint.Y - childMergePoint.Y) + noStatusNudge; mergeWidth = childMergePoint.X - parentNodeLinkPoint.X; mergeBottomToTop = true; } else if( !otherStreamIsHigher && !mergeXGreaterThanParent )//C { point = 'C'; mergeX = childMergePoint.X; y = parentNodeLinkPoint.Y; height = (childMergePoint.Y - parentNodeLinkPoint.Y) + noStatusNudge; mergeWidth = parentNodeLinkPoint.X - childMergePoint.X; mergeBottomToTop = true; } else if( !otherStreamIsHigher && mergeXGreaterThanParent )//D { point = 'D'; mergeX = parentNodeLinkPoint.X; y = parentNodeLinkPoint.Y; height = (childMergePoint.Y - parentNodeLinkPoint.Y) + noStatusNudge; mergeWidth = childMergePoint.X - parentNodeLinkPoint.X; mergeBottomToTop = false; } } if( childPromotePoint ) { if( otherStreamIsHigher && !promoteXGreaterThanParent )//A { point = 'A'; promoteX = childPromotePoint.X; y = childPromotePoint.Y - noStatusNudge; height = (parentNodeLinkPoint.Y - childPromotePoint.Y) + noStatusNudge; promoteWidth = parentNodeLinkPoint.X - childPromotePoint.X; promoteBottomToTop = false; } else if( otherStreamIsHigher && promoteXGreaterThanParent )//B { point = 'B'; promoteX = parentNodeLinkPoint.X; y = childPromotePoint.Y - noStatusNudge; height = (parentNodeLinkPoint.Y - childPromotePoint.Y) + noStatusNudge; promoteWidth = childPromotePoint.X - parentNodeLinkPoint.X; promoteBottomToTop = true; } else if( !otherStreamIsHigher && !promoteXGreaterThanParent )//C { point = 'C'; promoteX = childPromotePoint.X; y = parentNodeLinkPoint.Y; height = (childPromotePoint.Y - parentNodeLinkPoint.Y) + noStatusNudge; promoteWidth = parentNodeLinkPoint.X - childPromotePoint.X; promoteBottomToTop = true; } else if( !otherStreamIsHigher && promoteXGreaterThanParent )//D { point = 'D'; promoteX = parentNodeLinkPoint.X; y = parentNodeLinkPoint.Y; height = (childPromotePoint.Y - parentNodeLinkPoint.Y) + noStatusNudge; promoteWidth = childPromotePoint.X - parentNodeLinkPoint.X; promoteBottomToTop = false; } } var mergeColor = fineColor; var promoteColor = fineColor; //console.log('DrawLinkToChild stream: ' + parentNode.stream + ' other: ' + otherStreamNode.stream.mName + ' x: ' + x + ' y: ' + y + ' width: ' + width + ' heigth: ' + height); if( childNode.isFirmType() ) { if( childNode.integToParent ) { mergeColor = mergeNeededColor; if( nonConforming ) mergeZIndex = 4; else mergeZIndex = -2; } if( childNode.integToParent && childNode.integFromParent ) { promoteColor = conflictColor; if( nonConforming ) promoteZIndex = 5; else promoteZIndex = -1; } else if( childNode.integFromParent ) { promoteColor = promoteNeededColor; if( nonConforming ) promoteZIndex = 4; else promoteZIndex = -2; } if( showStatus ) { if (childNode.ShowSendMergeBadge() && childNode.ShowReceivePromotionBadge()) { //merge link childNode.firstLinkCanvas.style.left = mergeX; childNode.firstLinkCanvas.style.top = y; childNode.firstLinkCanvas.width = mergeWidth; childNode.firstLinkCanvas.height = height; mStreamUtilities.DrawColorBezier(childNode.firstLinkCanvas, mergeColor, mergeBottomToTop, mStreamUtilities.ArrowDirection.none, mStreamUtilities.LinkThickness.thin, mergeZIndex, parentNode.shapeCanvas, horizontalLayout); //promote link childNode.secondLinkCanvas.style.left = promoteX; childNode.secondLinkCanvas.style.top = y; childNode.secondLinkCanvas.width = promoteWidth; childNode.secondLinkCanvas.height = height; mStreamUtilities.DrawColorBezier(childNode.secondLinkCanvas, promoteColor, promoteBottomToTop, mStreamUtilities.ArrowDirection.none, mStreamUtilities.LinkThickness.thin, promoteZIndex, parentNode.shapeCanvas, horizontalLayout); } else if( childNode.ShowSendMergeBadge() ) { childNode.firstLinkCanvas.style.left = mergeX; childNode.firstLinkCanvas.style.top = y; childNode.firstLinkCanvas.width = mergeWidth; childNode.firstLinkCanvas.height = height; mStreamUtilities.DrawColorBezier(childNode.firstLinkCanvas, mergeColor, mergeBottomToTop, mStreamUtilities.ArrowDirection.none, mStreamUtilities.LinkThickness.thin, mergeZIndex, parentNode.shapeCanvas, horizontalLayout); } else if( childNode.ShowReceivePromotionBadge() ) { childNode.secondLinkCanvas.style.left = promoteX; childNode.secondLinkCanvas.style.top = y; childNode.secondLinkCanvas.width = promoteWidth; childNode.secondLinkCanvas.height = height; mStreamUtilities.DrawColorBezier(childNode.secondLinkCanvas, promoteColor, promoteBottomToTop, mStreamUtilities.ArrowDirection.none, mStreamUtilities.LinkThickness.thin, promoteZIndex, parentNode.shapeCanvas, horizontalLayout); } else { childNode.firstLinkCanvas.style.left = mergeX; childNode.firstLinkCanvas.style.top = y; childNode.firstLinkCanvas.width = mergeWidth; childNode.firstLinkCanvas.height = height; mStreamUtilities.DrawColorBezier(childNode.firstLinkCanvas, plainColor, mergeBottomToTop, mStreamUtilities.ArrowDirection.none, mStreamUtilities.LinkThickness.thin, -10, parentNode.shapeCanvas, horizontalLayout); } } else { childNode.firstLinkCanvas.style.left = mergeX; childNode.firstLinkCanvas.style.top = y; childNode.firstLinkCanvas.width = mergeWidth; childNode.firstLinkCanvas.height = height; mStreamUtilities.DrawColorBezier(childNode.firstLinkCanvas, plainColor, mergeBottomToTop, mStreamUtilities.ArrowDirection.none, mStreamUtilities.LinkThickness.thin, -10, parentNode.shapeCanvas, horizontalLayout); } } else { if( childNode.integFromParent ) { mergeColor = mergeNeededColor; if( nonConforming ) mergeZIndex = 4; else mergeZIndex = -2; } if( childNode.integToParent && childNode.integFromParent ) { promoteColor = conflictColor; if( nonConforming ) promoteZIndex = 5; else promoteZIndex = -1; } else if( childNode.integToParent ) { promoteColor = promoteNeededColor; if( nonConforming ) promoteZIndex = 4; else promoteZIndex = -2; } if( showStatus ) { if (childNode.ShowReceiveMergeBadge() && childNode.ShowSendPromotionBadge()) { //merge link childNode.firstLinkCanvas.style.left = mergeX; childNode.firstLinkCanvas.style.top = y; childNode.firstLinkCanvas.width = mergeWidth; childNode.firstLinkCanvas.height = height; mStreamUtilities.DrawColorBezier(childNode.firstLinkCanvas, mergeColor, mergeBottomToTop, mStreamUtilities.ArrowDirection.none, mStreamUtilities.LinkThickness.thin, mergeZIndex, parentNode.shapeCanvas, horizontalLayout); //promote link childNode.secondLinkCanvas.style.left = promoteX; childNode.secondLinkCanvas.style.top = y; childNode.secondLinkCanvas.width = promoteWidth; childNode.secondLinkCanvas.height = height; mStreamUtilities.DrawColorBezier(childNode.secondLinkCanvas, promoteColor, promoteBottomToTop, mStreamUtilities.ArrowDirection.none, mStreamUtilities.LinkThickness.thin, promoteZIndex, parentNode.shapeCanvas, horizontalLayout); } else if( childNode.ShowReceiveMergeBadge() ) { childNode.firstLinkCanvas.style.left = mergeX; childNode.firstLinkCanvas.style.top = y; childNode.firstLinkCanvas.width = mergeWidth; childNode.firstLinkCanvas.height = height; mStreamUtilities.DrawColorBezier(childNode.firstLinkCanvas, mergeColor, mergeBottomToTop, mStreamUtilities.ArrowDirection.none, mStreamUtilities.LinkThickness.thin, mergeZIndex, parentNode.shapeCanvas, horizontalLayout); } else if ( childNode.ShowSendPromotionBadge() ) { childNode.secondLinkCanvas.style.left = promoteX; childNode.secondLinkCanvas.style.top = y; childNode.secondLinkCanvas.width = promoteWidth; childNode.secondLinkCanvas.height = height; mStreamUtilities.DrawColorBezier(childNode.secondLinkCanvas, promoteColor, promoteBottomToTop, mStreamUtilities.ArrowDirection.none, mStreamUtilities.LinkThickness.thin, promoteZIndex, parentNode.shapeCanvas, horizontalLayout); } else { childNode.firstLinkCanvas.style.left = mergeX; childNode.firstLinkCanvas.style.top = y; childNode.firstLinkCanvas.width = mergeWidth; childNode.firstLinkCanvas.height = height; mStreamUtilities.DrawColorBezier(childNode.firstLinkCanvas, plainColor, mergeBottomToTop, mStreamUtilities.ArrowDirection.none, mStreamUtilities.LinkThickness.thin, -10, parentNode.shapeCanvas, horizontalLayout); } } else { childNode.firstLinkCanvas.style.left = mergeX; childNode.firstLinkCanvas.style.top = y; childNode.firstLinkCanvas.width = mergeWidth; childNode.firstLinkCanvas.height = height; mStreamUtilities.DrawColorBezier(childNode.firstLinkCanvas, plainColor, mergeBottomToTop, mStreamUtilities.ArrowDirection.none, mStreamUtilities.LinkThickness.thin, -10, parentNode.shapeCanvas, horizontalLayout); } } } function drawParallelLinks() { childNode.firstLinkCanvas.width = childNode.firstLinkCanvas.width;//resets the canvas's properties childNode.secondLinkCanvas.width = childNode.secondLinkCanvas.width;//resets the canvas's properties //console.log('parentNode: ' + parentNode.stream.mName + ' other: ' + childNode.stream.mName); var conflictColor = new mStreamUtilities.StreamColor(240,128,128,1);//'LightCoral'; var mergeNeededColor = new mStreamUtilities.StreamColor(240,230,140,1);//'Khaki'; var promoteNeededColor = new mStreamUtilities.StreamColor(240,230,140,1);//'Khaki'; var fineColor = new mStreamUtilities.StreamColor(156, 196, 235,1); var plainColor = new mStreamUtilities.StreamColor(240,240,240,1); var promoteZIndex = -3; var mergeZIndex = -3; var childLinkPoint = childNode.GetTopLinkPoint(); //var parentNodeLinkPoint = parentNode.GetBottomLinkPoint(); var parentNodeLinkPoint = ( parentNode.isMainline() && childNode.isFirmType ()) || parentNode.isFirmType() ? parentNode.GetTopLinkPoint() : parentNode.GetBottomLinkPoint(); var nonConforming = mStreamUtilities.isNonConformingRelationship(parentNode, childNode); if( nonConforming ) { promoteZIndex = 30; mergeZIndex = 30; fineColor = new mStreamUtilities.StreamColor(146, 186, 225,1);//a little darker because it has to be drawn over other blue areas //console.log('nonConforming, parent: ' + parentNode.stream.mName + ' other: ' + childNode.stream.mName); } var otherStreamIsHigher = parentNode.row() < childNode.row(); if( layout == 'ancestor' ) { if( parentNode.isMainline () ) { if( childNode.isFirmType() ) parentNodeLinkPoint = parentNode.GetTopLinkPoint(); else parentNodeLinkPoint = parentNode.GetBottomLinkPoint(); } else { if( parentNode.isFirmType() ) parentNodeLinkPoint = parentNode.GetTopLinkPoint(); else parentNodeLinkPoint = parentNode.GetBottomLinkPoint(); } if(childNode.isFirmType() ) childLinkPoint = childNode.GetBottomLinkPoint(); else childLinkPoint = childNode.GetTopLinkPoint(); } else if(otherStreamIsHigher) { childLinkPoint = childNode.GetBottomLinkPoint(); } var x = 0; var y = 0 var height = 0; var width = 0; var bottomToTop = true; var otherXGreaterThanParent = childLinkPoint.X > parentNodeLinkPoint.X; //the plan here is to build one of four different rectangles relative to parentNode node: // A B // ____ ____ // | || | // | || | // ---- ---- // parentNode // ____ ____ // | || | // | || | // ---- ---- // C D var point = 'no point specified'; if( otherStreamIsHigher && !otherXGreaterThanParent )//A { point = 'A'; x = childLinkPoint.X; y = childLinkPoint.Y; height = parentNodeLinkPoint.Y - childLinkPoint.Y; width = parentNodeLinkPoint.X - childLinkPoint.X; bottomToTop = false; } else if( otherStreamIsHigher && otherXGreaterThanParent )//B { point = 'B'; x = parentNodeLinkPoint.X; y = childLinkPoint.Y; height = parentNodeLinkPoint.Y - childLinkPoint.Y; width = childLinkPoint.X - parentNodeLinkPoint.X; bottomToTop = true; } else if( !otherStreamIsHigher && !otherXGreaterThanParent )//C { point = 'C'; x = childLinkPoint.X; y = parentNodeLinkPoint.Y; height = childLinkPoint.Y - parentNodeLinkPoint.Y; width = parentNodeLinkPoint.X - childLinkPoint.X; bottomToTop = true; } else if( !otherStreamIsHigher && otherXGreaterThanParent )//D { point = 'D'; x = parentNodeLinkPoint.X; y = parentNodeLinkPoint.Y; height = childLinkPoint.Y - parentNodeLinkPoint.Y; width = childLinkPoint.X - parentNodeLinkPoint.X; bottomToTop = false; } //console.log( '***' + parentNode.stream.mName + ' and ' + childNode.stream.mName + ' point: ' + point + ' otherStreamIsHigher: ' + otherStreamIsHigher ); var perpVector = mStreamUtilities.GetNormalizedPerpendicularVector(parentNodeLinkPoint, childLinkPoint); perpVector.X *= 2; perpVector.Y *= 2; var mergeColor = fineColor; var promoteColor = fineColor; //console.log('DrawLinkToChild stream: ' + parentNode.stream + ' other: ' + childNode.stream.mName + ' x: ' + x + ' y: ' + y + ' width: ' + width + ' heigth: ' + height); if( childNode.isFirmType() ) { if( childNode.integToParent ) { mergeColor = mergeNeededColor; if( nonConforming ) mergeZIndex = 4; else mergeZIndex = -2; } if( childNode.integToParent && childNode.integFromParent ) { promoteColor = conflictColor; if( nonConforming ) promoteZIndex = 5; else promoteZIndex = -1; } else if( childNode.integFromParent ) { promoteColor = promoteNeededColor; if( nonConforming ) promoteZIndex = 4; else promoteZIndex = -2; } if( showStatus ) { if (childNode.ShowSendMergeBadge() && childNode.ShowReceivePromotionBadge()) { //merge link childNode.firstLinkCanvas.style.left = x + perpVector.X; childNode.firstLinkCanvas.style.top = y + perpVector.Y; childNode.firstLinkCanvas.width = width; childNode.firstLinkCanvas.height = height; mStreamUtilities.DrawColorBezier(childNode.firstLinkCanvas, mergeColor, bottomToTop, mStreamUtilities.ArrowDirection.none, mStreamUtilities.LinkThickness.thin, mergeZIndex, parentNode.shapeCanvas, horizontalLayout); //promote link childNode.secondLinkCanvas.style.left = x - perpVector.X; childNode.secondLinkCanvas.style.top = y - perpVector.Y; childNode.secondLinkCanvas.width = width; childNode.secondLinkCanvas.height = height; mStreamUtilities.DrawColorBezier(childNode.secondLinkCanvas, promoteColor, bottomToTop, mStreamUtilities.ArrowDirection.none, mStreamUtilities.LinkThickness.thin, promoteZIndex, parentNode.shapeCanvas, horizontalLayout); } else if( childNode.ShowSendMergeBadge() ) { childNode.firstLinkCanvas.style.left = x; childNode.firstLinkCanvas.style.top = y; childNode.firstLinkCanvas.width = width; childNode.firstLinkCanvas.height = height; mStreamUtilities.DrawColorBezier(childNode.firstLinkCanvas, mergeColor, bottomToTop, mStreamUtilities.ArrowDirection.none, mStreamUtilities.LinkThickness.thin, mergeZIndex, parentNode.shapeCanvas, horizontalLayout); } else if( childNode.ShowReceivePromotionBadge() ) { childNode.secondLinkCanvas.style.left = x; childNode.secondLinkCanvas.style.top = y; childNode.secondLinkCanvas.width = width; childNode.secondLinkCanvas.height = height; mStreamUtilities.DrawColorBezier(childNode.secondLinkCanvas, promoteColor, bottomToTop, mStreamUtilities.ArrowDirection.none, mStreamUtilities.LinkThickness.thin, promoteZIndex, parentNode.shapeCanvas, horizontalLayout); } else { childNode.firstLinkCanvas.style.left = x; childNode.firstLinkCanvas.style.top = y; childNode.firstLinkCanvas.width = width; childNode.firstLinkCanvas.height = height; mStreamUtilities.DrawColorBezier(childNode.firstLinkCanvas, plainColor, bottomToTop, mStreamUtilities.ArrowDirection.none, mStreamUtilities.LinkThickness.thin, -10, parentNode.shapeCanvas, horizontalLayout); } } else { childNode.firstLinkCanvas.style.left = x; childNode.firstLinkCanvas.style.top = y; childNode.firstLinkCanvas.width = width; childNode.firstLinkCanvas.height = height; mStreamUtilities.DrawColorBezier(childNode.firstLinkCanvas, plainColor, bottomToTop, mStreamUtilities.ArrowDirection.none, mStreamUtilities.LinkThickness.thin, -10, parentNode.shapeCanvas, horizontalLayout); } } else { if( childNode.integFromParent ) { mergeColor = mergeNeededColor; if( nonConforming ) mergeZIndex = 4; else mergeZIndex = -2; } if( childNode.integToParent && childNode.integFromParent ) { promoteColor = conflictColor; if( nonConforming ) promoteZIndex = 5; else promoteZIndex = -1; } else if( childNode.integToParent ) { promoteColor = promoteNeededColor; if( nonConforming ) promoteZIndex = 4; else promoteZIndex = -2; } if( showStatus ) { if (childNode.ShowReceiveMergeBadge() && childNode.ShowSendPromotionBadge()) { //merge link childNode.firstLinkCanvas.style.left = x - perpVector.X; childNode.firstLinkCanvas.style.top = y - perpVector.Y; childNode.firstLinkCanvas.width = width; childNode.firstLinkCanvas.height = height; mStreamUtilities.DrawColorBezier(childNode.firstLinkCanvas, mergeColor, bottomToTop, mStreamUtilities.ArrowDirection.none, mStreamUtilities.LinkThickness.thin, mergeZIndex, parentNode.shapeCanvas, horizontalLayout); //promote link childNode.secondLinkCanvas.style.left = x + perpVector.X; childNode.secondLinkCanvas.style.top = y + perpVector.Y; childNode.secondLinkCanvas.width = width; childNode.secondLinkCanvas.height = height; mStreamUtilities.DrawColorBezier(childNode.secondLinkCanvas, promoteColor, bottomToTop, mStreamUtilities.ArrowDirection.none, mStreamUtilities.LinkThickness.thin, promoteZIndex, parentNode.shapeCanvas, horizontalLayout); } else if( childNode.ShowReceiveMergeBadge() ) { childNode.firstLinkCanvas.style.left = x; childNode.firstLinkCanvas.style.top = y; childNode.firstLinkCanvas.width = width; childNode.firstLinkCanvas.height = height; mStreamUtilities.DrawColorBezier(childNode.firstLinkCanvas, mergeColor, bottomToTop, mStreamUtilities.ArrowDirection.none, mStreamUtilities.LinkThickness.thin, mergeZIndex, parentNode.shapeCanvas, horizontalLayout); } else if ( childNode.ShowSendPromotionBadge() ) { childNode.secondLinkCanvas.style.left = x; childNode.secondLinkCanvas.style.top = y; childNode.secondLinkCanvas.width = width; childNode.secondLinkCanvas.height = height; mStreamUtilities.DrawColorBezier(childNode.secondLinkCanvas, promoteColor, bottomToTop, mStreamUtilities.ArrowDirection.none, mStreamUtilities.LinkThickness.thin, promoteZIndex, parentNode.shapeCanvas, horizontalLayout); } else { childNode.firstLinkCanvas.style.left = x; childNode.firstLinkCanvas.style.top = y; childNode.firstLinkCanvas.width = width; childNode.firstLinkCanvas.height = height; mStreamUtilities.DrawColorBezier(childNode.firstLinkCanvas, plainColor, bottomToTop, mStreamUtilities.ArrowDirection.none, mStreamUtilities.LinkThickness.thin, -10, parentNode.shapeCanvas, horizontalLayout); } } else { childNode.firstLinkCanvas.style.left = x; childNode.firstLinkCanvas.style.top = y; childNode.firstLinkCanvas.width = width; childNode.firstLinkCanvas.height = height; mStreamUtilities.DrawColorBezier(childNode.firstLinkCanvas, plainColor, bottomToTop, mStreamUtilities.ArrowDirection.none, mStreamUtilities.LinkThickness.thin, -10, parentNode.shapeCanvas, horizontalLayout); } } } this.draw = function() { var type = childNode.linkType(); //console.log( 'type: ' + type ); if( type && type == mStreamUtilities.LinkType.Parallel ) drawParallelLinks(); else drawDefaultLinks(); } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 8081 | David George |
Initial submit of JavaScript StreamGraph. Main functionality is: Change Trajectory (Change Flow), Timeline, and GitStreams. |