function TrajectoryView(parentElementId, streamNodes, layout, streamUtilities) { var mStreamUtilities = streamUtilities; var mStreamNodeHash = new Array(); var mStreamToTrajectoryNode = new Array(); var mChangelistTrajectoryLinks = new Array(); var mChangeOriginationHash = new Object(); var mChanges = null; function loadStreamNodeHash() { for( var i = 0; i < streamNodes.length; i++ ) { if(streamNodes[i]) mStreamNodeHash[streamNodes[i].stream.mStream] = streamNodes[i]; } } loadStreamNodeHash(); this.streamNodes = streamNodes; var mSelectedChangeRow; function changeListRowClick(e, row) { mSelectedChangeRow = row; if( mSelectedChangeRow ) { var selectedChange = mSelectedChangeRow[0].changelist; if (document.getElementById('originRadio').checked) showChangeOriginationPath(selectedChange); else showChangePropagationPath(selectedChange); } } this.switchTrajectoryDirection = function() { changeListRowClick(null, mSelectedChangeRow); } $( "#changeTypeRadio" ).buttonset(); $( "#originRadio").click(this.switchTrajectoryDirection); $( "#propagateRadio").click(this.switchTrajectoryDirection); this.Show = function() { $( "#trajectoryDialog" ).dialog( "open" ); } this.loadTable = function(changes) { mChanges = changes; var trajectoryDialog = document.getElementById('trajectoryDialog'); //get rid of the old table, flexigrid isn't good at removing single rows for(var i = trajectoryDialog.childElementCount; i > 0 ; i--) { var child = trajectoryDialog.children[i - 1]; if( !(child.getAttribute('class') == 'nodelete') ) trajectoryDialog.removeChild(trajectoryDialog.children[i - 1]); } var table = document.createElement('table'); table.setAttribute('id', 'changeTable'); //populate the table for (var i = 0; i < mChanges.length; i++) { var changelist = mChanges[i]; var row = table.insertRow(table.rows.length); row.changelist = changelist; var cellChange = row.insertCell(row.cells.length) cellChange.width = 40; cellChange.innerHTML = changelist.Change; row.insertCell(row.cells.length).innerHTML = changelist.Description; row.insertCell(row.cells.length).innerHTML = changelist.User; } trajectoryDialog.appendChild(table); $('#changeTable').flexigrid ( { colModel : [ {display: 'Change', name : 'change', width : 60, sortable : true, align: 'center'}, {display: 'Description', name : 'description', width : 200, sortable : true, align: 'left'}, {display: 'User', name : 'user', width : 130, sortable : true, align: 'left'} ], sortname: "change", sortorder: "asc", usepager: false, useRp: false, singleSelect: true, height:260, width:'auto', onRowSelect: changeListRowClick } ); //console.log('done with changeDataCallback'); } function clear() { for( var i in mStreamToTrajectoryNode ) mStreamToTrajectoryNode[i].close(); for( var i in mChangelistTrajectoryLinks ) mChangelistTrajectoryLinks[i].close(); } function showChangeOriginationPath(selectedChange) { clear(); mStreamToTrajectoryNode = new Array(); mChangelistTrajectoryLinks = new Array(); var streams = new Array(); for(var j = 0; j < selectedChange.history.length; j++ ) streams.push(selectedChange.history[j].stream); setHighlightedStreams(streams, selectedChange.stream); for(var i = 0; i < streamNodes.length; i++) if( streamNodes[i] ) streamNodes[i].draw(false); highlightOriginatingPaths(selectedChange); draw(); } function draw() { //console.log('layout: ' + layout); var horizontal = layout == 'ancestor'; for(var i = 0; i < mChangelistTrajectoryLinks.length; i++ ) mChangelistTrajectoryLinks[i].draw(horizontal); for(var i in mStreamToTrajectoryNode) mStreamToTrajectoryNode[i].draw(horizontal); } function highlightOriginatingPaths(changeList) { var histString = 'Changelist history: '; //each changelist has a history of changelists that it came from (derived from the command: 'changes -i changeNum@changeNum) if( changeList.history.length > 1 ) { for(var histCount = 0; histCount < changeList.history.length; histCount++) { var change = changeList.history[histCount]; //mChangeOriginationHash contains all the streams that a change is associated with, derived from the 'integrated' command if( mChangeOriginationHash[change.Change] ) { //get the node for the stream that this history change happened in var streamNode = mStreamNodeHash[change.stream]; if( streamNode ) { histString += ' [' + change.Change + ' streamNode: ' + streamNode.stream.mName; //now cycle through the stream nodes that this change has been integrated from for( var originCount = 0; originCount < mChangeOriginationHash[change.Change].length; originCount++ ) { var terminatingNode = mStreamNodeHash[ mChangeOriginationHash[change.Change][originCount] ];//hash! if( terminatingNode ) { var arrowDirection = mStreamUtilities.ArrowDirection.bottom; if( streamNode.mRow > terminatingNode.mRow ) arrowDirection = mStreamUtilities.ArrowDirection.top; histString += ' <-- terminatingNode: ' + terminatingNode.stream.mName; //console.log('XXXXXXXXXXXXXXXXXXXXXX terminating node: ' + change.Change); addTrajectoryDataPoint(change);//new mChangelistTrajectoryLinks.push( new TrajectoryLink(streamNode, terminatingNode, arrowDirection, change, mStreamUtilities ) ); } else//this can happen if the change occurred in a non-stream or outside of this depot { //console.log('@@@@@@@@@@@@@@@@@@@@@@@@@@@'); addTrajectoryDataPoint(change); //return; } } } } else { //console.log('***************************change without integration history: ' + change.Change); addTrajectoryDataPoint(change); } //histString += ']'; } } else { //console.log('Single change that has no history: ' + changeList.Change); addTrajectoryDataPoint(changeList); } //console.log(histString); } this.setChangeOriginationData = function(data) { mChangeOriginationHash = data; } function showChangePropagationPath(selectedChange) { clear(); mStreamToTrajectoryNode = new Array(); mChangelistTrajectoryLinks = new Array(); var forwardHistory = new Array(); for(var i = 0; i < mChanges.length; i++) { var change = mChanges[i]; for(var histCount = 0; histCount < change.history.length; histCount++) { if( selectedChange.Change == change.history[histCount].Change ) { forwardHistory.push(change); continue; } } } for(var i = 0; i < mChanges.length; i++) { if( mChanges[i].Change == selectedChange.Change ) { var streams = new Array(); for(var j = 0; j < forwardHistory.length; j++ ) streams.push(forwardHistory[j].stream); setHighlightedStreams(streams, mChanges[i].stream); for( var j = 0; j < streamNodes.length; j++ ) if( streamNodes[i] ) streamNodes[j].draw(false); break; } } var forward = ''; for( var i = forwardHistory.length - 1; -1 < i; i-- ) { var change = forwardHistory[i]; if( change.Change != selectedChange.Change && mChangeOriginationHash[change.Change] ) { var streamNode = mStreamNodeHash[change.stream]; if( streamNode ) { for( var originCount = 0; originCount < mChangeOriginationHash[change.Change].length; originCount++ ) { var originatingNode = mStreamNodeHash[ mChangeOriginationHash[change.Change][originCount] ]; if( streamNode && originatingNode ) { var arrowDirection = mStreamUtilities.ArrowDirection.bottom; if( streamNode.mRow > originatingNode.mRow ) arrowDirection = mStreamUtilities.ArrowDirection.top; //mChangelistTrajectoryLinks.push( streamNode.drawChangeTrajectoryLink(originatingNode, arrowDirection, change ) ); addTrajectoryDataPoint(change);//new mChangelistTrajectoryLinks.push( new TrajectoryLink(streamNode, originatingNode, arrowDirection, change, mStreamUtilities ) ); } } } } else { addTrajectoryDataPoint(change); } forward += forwardHistory[i].Change + ' '; } draw(); //console.log( 'change: ' + selectedChange + ' forward: ' + forward); } function addTrajectoryDataPoint(changeList) { var streamNode = mStreamNodeHash[ changeList.stream ]; if( !streamNode ) { alert('The attempt to show change ' + changeList.Change + ' was unsuccessful. It is associated with a stream, ' + changeList.stream + ', that does not appear to exist.' ); return; } if( !mStreamToTrajectoryNode[streamNode] ) mStreamToTrajectoryNode[streamNode] = new TrajectoryNode(parentElementId, streamNode, mStreamUtilities); var trajectoryNode = mStreamToTrajectoryNode[streamNode]; trajectoryNode.addChange(changeList); } function setHighlightedStreams(streams, selectedStream) { for(var i = 0; i < streamNodes.length; i++) { if(streamNodes[i]) { streamNodes[i].highlighted = false; for(var j = 0; j < streams.length; j++) if( streamNodes[i].stream.mStream == streams[j] ) streamNodes[i].highlighted = true; streamNodes[i].selected = streamNodes[i].stream.mStream == selectedStream; } } } }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#9 | 8124 | David George |
Updated some of the calls to ClientKit to sync up with it's refactoring. Commented out the diagnostic time-tracking stuff in TrajectoryModel. Refactored TrajectoryView so that it once again has a asynchronous progress bar. |
||
#8 | 8123 | David George |
More optimization. This time, I took out code that didn't actually do anything but take up cycles, and removed calls to the server for changelist history if that call has previously been made. |
||
#7 | 8116 | David George | Interim checkin so Jaimen can test against ClientKit. | ||
#6 | 8110 | David George | This is a fairly unstable checkin that is a first attempt at getting the StreamGraph to work with the refactored ClientKit. | ||
#5 | 8092 | David George | Added stuff so the reload button works on the trajectory dialog. | ||
#4 | 8091 | David George | Added handling on the changelist flexigrid for changing the number of rows per page. | ||
#3 | 8090 | David George |
More optimization of the changelist trajectory dialog. Updated the third-party flexigrid. Updated jquery. Added timeTracker, a temporary object that'll assist me in tracking time for optimization purposes. |
||
#2 | 8084 | David George |
Began work on optimizing the changelist trajectory algorithm. By using lazy loading, it's now about 4x faster. Refactored TrajectoryView and TrajectoryModel so that the model doesn't know about the view (I know, should never have known about it in the first place. I figured out how to create a Listener pattern in JavaScript so that I could do this a little more elegantly). |
||
#1 | 8081 | David George |
Initial submit of JavaScript StreamGraph. Main functionality is: Change Trajectory (Change Flow), Timeline, and GitStreams. |