| | @@ -21,34 +21,44 @@ |
| 21 | 21 | ** The rowinfo field is an array of structures, one per entry in the timeline, |
| 22 | 22 | ** where each structure has the following fields: |
| 23 | 23 | ** |
| 24 | 24 | ** id: The id of the <div> element for the row. This is an integer. |
| 25 | 25 | ** to get an actual id, prepend "m" to the integer. The top node |
| 26 | | -** is iTopRow and numbers increase moving down the graph. |
| 26 | +** is iTopRow and numbers increase moving down the timeline. |
| 27 | 27 | ** bg: The background color for this row |
| 28 | 28 | ** r: The "rail" that the node for this row sits on. The left-most |
| 29 | 29 | ** rail is 0 and the number increases to the right. |
| 30 | | -** d: True if there is a "descender" - an arrow coming from the bottom |
| 31 | | -** of the page straight up to this node. |
| 32 | | -** mo: "merge-out". If non-negative, this is the rail position |
| 30 | +** d: If exists and true then there is a "descender" - an arrow |
| 31 | +** coming from the bottom of the page straight up to this node. |
| 32 | +** mo: "merge-out". If it exists, this is the rail position |
| 33 | 33 | ** for the upward portion of a merge arrow. The merge arrow goes up |
| 34 | | -** to the row identified by mu:. If this value is negative then |
| 34 | +** to the row identified by mu:. If this value is omitted then |
| 35 | 35 | ** node has no merge children and no merge-out line is drawn. |
| 36 | 36 | ** mu: The id of the row which is the top of the merge-out arrow. |
| 37 | +** Only exists if "mo" exists. |
| 38 | +** cu: The id of the top row of the merge-out arrow for a cherrypick |
| 39 | +** merge arrow that extends beyond the main merge arrow. Only |
| 40 | +** exists if "mo" exists and if there is a cherrpick merge that is |
| 41 | +** higher than "mu". |
| 37 | 42 | ** u: Draw a thick child-line out of the top of this node and up to |
| 38 | 43 | ** the node with an id equal to this value. 0 if it is straight to |
| 39 | 44 | ** the top of the page, -1 if there is no thick-line riser. |
| 40 | 45 | ** f: 0x01: a leaf node. |
| 46 | +** 0x02: all output merges are cherrypicks |
| 41 | 47 | ** au: An array of integers that define thick-line risers for branches. |
| 42 | 48 | ** The integers are in pairs. For each pair, the first integer is |
| 43 | 49 | ** is the rail on which the riser should run and the second integer |
| 44 | | -** is the id of the node upto which the riser should run. |
| 50 | +** is the id of the node upto which the riser should run. If there |
| 51 | +** are no risers, this array does not exist. |
| 45 | 52 | ** mi: "merge-in". An array of integer rail positions from which |
| 46 | 53 | ** merge arrows should be drawn into this node. If the value is |
| 47 | 54 | ** negative, then the rail position is the absolute value of mi[] |
| 48 | 55 | ** and a thin merge-arrow descender is drawn to the bottom of |
| 49 | | -** the screen. |
| 56 | +** the screen. This array is omitted if there are no inbound |
| 57 | +** merges. |
| 58 | +** ci: "cherrypick-in". Like "mi" except for cherrypick merges. |
| 59 | +** omitted if there are no cherrypick merges. |
| 50 | 60 | ** h: The artifact hash of the object being graphed |
| 51 | 61 | */ |
| 52 | 62 | var amendCssOnce = 1; // Only change the CSS one time |
| 53 | 63 | function amendCss(circleNodes,showArrowheads){ |
| 54 | 64 | if( !amendCssOnce ) return; |
| | @@ -244,20 +254,36 @@ |
| 244 | 254 | if( p.hasOwnProperty('mo') ){ |
| 245 | 255 | var x0 = p.x + node.w/2; |
| 246 | 256 | var x1 = p.mo*railPitch + node.w/2; |
| 247 | 257 | var u = tx.rowinfo[p.mu-tx.iTopRow]; |
| 248 | 258 | var y1 = miLineY(u); |
| 249 | | - var drawMethod = (p.f&2) ? drawCherrypickLine : drawMergeLine; |
| 250 | 259 | if( p.u<0 || p.mo!=p.r ){ |
| 251 | 260 | x1 += mergeLines[p.mo] = -mLine.w/2; |
| 252 | 261 | var y0 = p.y+2; |
| 253 | | - if( p.r!=p.mo ) drawMethod(x0,y0,x1+(x0<x1 ? mLine.w : 0),null); |
| 254 | | - drawMethod(x1,y0+mLine.w,null,y1); |
| 262 | + if( p.mu==p.id ){ |
| 263 | + drawCherrypickLine(x0,y0,x1+(x0<x1 ? mLine.w : 0),null); |
| 264 | + y1 = y0; |
| 265 | + }else{ |
| 266 | + drawMergeLine(x0,y0,x1+(x0<x1 ? mLine.w : 0),null); |
| 267 | + drawMergeLine(x1,y0+mLine.w,null,y1); |
| 268 | + } |
| 269 | + if( p.hasOwnProperty('cu') ){ |
| 270 | + var u2 = tx.rowinfo[p.cu-tx.iTopRow]; |
| 271 | + var y2 = miLineY(u2); |
| 272 | + drawCherrypickLine(x1,y1,null,y2); |
| 273 | + } |
| 255 | 274 | }else if( mergeOffset ){ |
| 256 | 275 | mergeLines[p.mo] = u.r<p.r ? -mergeOffset-mLine.w : mergeOffset; |
| 257 | 276 | x1 += mergeLines[p.mo]; |
| 258 | | - drawMethod(x1,p.y+node.h/2,null,y1); |
| 277 | + if( p.mo<p.id ){ |
| 278 | + drawMergeLine(x1,p.y+node.h/2,null,y1); |
| 279 | + } |
| 280 | + if( p.hasOwnProperty('cu') ){ |
| 281 | + var u2 = tx.rowinfo[p.cu-tx.iTopRow]; |
| 282 | + var y2 = miLineY(u2); |
| 283 | + drawCherrypickLine(x1,y1,null,y2); |
| 284 | + } |
| 259 | 285 | }else{ |
| 260 | 286 | delete mergeLines[p.mo]; |
| 261 | 287 | } |
| 262 | 288 | } |
| 263 | 289 | if( p.hasOwnProperty('au') ){ |
| | @@ -291,29 +317,34 @@ |
| 291 | 317 | var rail = p.mi[i]; |
| 292 | 318 | if( rail<0 ){ |
| 293 | 319 | rail = -rail; |
| 294 | 320 | mergeLines[rail] = -mLine.w/2; |
| 295 | 321 | var x = rail*railPitch + (node.w-mLine.w)/2; |
| 296 | | - drawMergeLine(x,miLineY(p),null,btm); |
| 322 | + var y = miLineY(p); |
| 323 | + drawMergeLine(x,y,null,mergeBtm[rail]); |
| 324 | + mergeBtm[rail] = y; |
| 297 | 325 | } |
| 298 | 326 | drawMergeArrow(p,rail,0); |
| 299 | 327 | } |
| 300 | 328 | } |
| 301 | | - if( p.hasOwnProperty('cpi') ){ |
| 302 | | - for( var i=0; i<p.cpi.length; i++ ){ |
| 303 | | - var rail = p.cpi[i]; |
| 329 | + if( p.hasOwnProperty('ci') ){ |
| 330 | + for( var i=0; i<p.ci.length; i++ ){ |
| 331 | + var rail = p.ci[i]; |
| 304 | 332 | if( rail<0 ){ |
| 305 | 333 | rail = -rail; |
| 306 | 334 | mergeLines[rail] = -mLine.w/2; |
| 307 | 335 | var x = rail*railPitch + (node.w-mLine.w)/2; |
| 308 | | - drawCherrypickLine(x,miLineY(p),null,btm); |
| 336 | + var y = miLineY(p); |
| 337 | + drawCherrypickLine(x,y,null,mergeBtm[rail]); |
| 338 | + mergeBtm[rail] = y; |
| 309 | 339 | } |
| 310 | 340 | drawMergeArrow(p,rail,1); |
| 311 | 341 | } |
| 312 | 342 | } |
| 313 | 343 | } |
| 314 | 344 | var mergeLines; |
| 345 | + var mergeBtm = new Array; |
| 315 | 346 | function renderGraph(){ |
| 316 | 347 | mergeLines = {}; |
| 317 | 348 | canvasDiv.innerHTML = ""; |
| 318 | 349 | var canvasY = absoluteY(canvasDiv); |
| 319 | 350 | for(var i=0; i<tx.rowinfo.length; i++ ){ |
| | @@ -324,10 +355,11 @@ |
| 324 | 355 | var tlBtm = document.querySelector(".timelineBottom"); |
| 325 | 356 | if( tlBtm.offsetHeight<node.h ){ |
| 326 | 357 | tlBtm.style.height = node.h + "px"; |
| 327 | 358 | } |
| 328 | 359 | var btm = absoluteY(tlBtm) - canvasY + tlBtm.offsetHeight; |
| 360 | + for( var i=0; i<tx.nrail; i++) mergeBtm[i] = btm; |
| 329 | 361 | for( var i=tx.rowinfo.length-1; i>=0; i-- ){ |
| 330 | 362 | drawNode(tx.rowinfo[i], btm); |
| 331 | 363 | } |
| 332 | 364 | } |
| 333 | 365 | var selRow; |
| 334 | 366 | |