Fossil

Check-in [01d8bf97]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Improvements to the display of the "Context" graph on check-in /info pages.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 01d8bf97e206fc8eeae4c59e6046a9ae148d6ba8a3e56a17782904ab84199869
User & Date: drh 2019-05-14 13:47:21
Context
2019-05-14
14:33
The dotted vertical lines in the graph should use the default color, not the foreground color of the node. check-in: 47b08087 user: drh tags: trunk
13:47
Improvements to the display of the "Context" graph on check-in /info pages. check-in: 01d8bf97 user: drh tags: trunk
13:46
Fix the graph on the /finfo page - apparently broken by check-in [8e2b8b027bc2d62a1]. check-in: aa149371 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/default_css.txt.

187
188
189
190
191
192
193






194
195
196
197
198
199
200
  margin-left: 1px;
  border-width: 3px 0;
  border-left: 7px solid #600000;
}
.tl-line.warp {
  background: #600000;
}






span.tagDsp {
  font-weight: bold;
}
span.wikiError {
  font-weight: bold;
  color: red;
}







>
>
>
>
>
>







187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
  margin-left: 1px;
  border-width: 3px 0;
  border-left: 7px solid #600000;
}
.tl-line.warp {
  background: #600000;
}
.tl-line.dotted {
  width: 0px;
  border-top: 0px dotted #888;
  border-left: 2px dotted #888;
  background: rgba(255,255,255,0);
}
span.tagDsp {
  font-weight: bold;
}
span.wikiError {
  font-weight: bold;
  color: red;
}

Changes to src/graph.c.

47
48
49
50
51
52
53

54
55
56
57
58
59
60
..
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
...
475
476
477
478
479
480
481




















482
483
484
485
486
487
488
  GraphRow *pPrev;            /* Previous row */

  int idx;                    /* Row index.  First is 1.  0 used for "none" */
  int idxTop;                 /* Direct descendent highest up on the graph */
  GraphRow *pChild;           /* Child immediately above this node */
  u8 isDup;                   /* True if this is duplicate of a prior entry */
  u8 isLeaf;                  /* True if this is a leaf node */

  u8 hasNormalOutMerge;       /* Is parent of at laest 1 non-cherrypick merge */
  u8 timeWarp;                /* Child is earlier in time */
  u8 bDescender;              /* True if riser from bottom of graph to here. */
  i8 iRail;                   /* Which rail this check-in appears on. 0-based.*/
  i8 mergeOut;                /* Merge out to this rail.  -1 if no merge-out */
  u8 mergeIn[GR_MAX_RAIL];    /* Merge in from non-zero rails */
  int aiRiser[GR_MAX_RAIL];   /* Risers from this node to a higher row. */
................................................................................
};

/* Context while building a graph
*/
struct GraphContext {
  int nErr;                  /* Number of errors encountered */
  int mxRail;                /* Number of rails required to render the graph */
  GraphRow *pFirst;          /* First row in the list */
  GraphRow *pLast;           /* Last row in the list */
  int nBranch;               /* Number of distinct branches */
  char **azBranch;           /* Names of the branches */
  int nRow;                  /* Number of rows */
  int nHash;                 /* Number of slots in apHash[] */
  GraphRow **apHash;         /* Hash table of GraphRow objects.  Key: rid */
};

................................................................................
       continue;                                       /* Time-warp */
    }
    if( pRow->idxTop < pParent->idxTop ){
      pParent->pChild = pRow;
      pParent->idxTop = pRow->idxTop;
    }
  }





















  /* Identify rows where the primary parent is off screen.  Assign
  ** each to a rail and draw descenders to the bottom of the screen.
  **
  ** Strive to put the "trunk" branch on far left.
  */
  zTrunk = persistBranchName(p, "trunk");







>







 







|
|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
..
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
...
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
  GraphRow *pPrev;            /* Previous row */

  int idx;                    /* Row index.  First is 1.  0 used for "none" */
  int idxTop;                 /* Direct descendent highest up on the graph */
  GraphRow *pChild;           /* Child immediately above this node */
  u8 isDup;                   /* True if this is duplicate of a prior entry */
  u8 isLeaf;                  /* True if this is a leaf node */
  u8 isStepParent;            /* pChild is actually a step-child */
  u8 hasNormalOutMerge;       /* Is parent of at laest 1 non-cherrypick merge */
  u8 timeWarp;                /* Child is earlier in time */
  u8 bDescender;              /* True if riser from bottom of graph to here. */
  i8 iRail;                   /* Which rail this check-in appears on. 0-based.*/
  i8 mergeOut;                /* Merge out to this rail.  -1 if no merge-out */
  u8 mergeIn[GR_MAX_RAIL];    /* Merge in from non-zero rails */
  int aiRiser[GR_MAX_RAIL];   /* Risers from this node to a higher row. */
................................................................................
};

/* Context while building a graph
*/
struct GraphContext {
  int nErr;                  /* Number of errors encountered */
  int mxRail;                /* Number of rails required to render the graph */
  GraphRow *pFirst;          /* First row in the list.  Top row of graph. */
  GraphRow *pLast;           /* Last row in the list. Bottom row of graph. */
  int nBranch;               /* Number of distinct branches */
  char **azBranch;           /* Names of the branches */
  int nRow;                  /* Number of rows */
  int nHash;                 /* Number of slots in apHash[] */
  GraphRow **apHash;         /* Hash table of GraphRow objects.  Key: rid */
};

................................................................................
       continue;                                       /* Time-warp */
    }
    if( pRow->idxTop < pParent->idxTop ){
      pParent->pChild = pRow;
      pParent->idxTop = pRow->idxTop;
    }
  }

  /* If a node has no pChild, and there is a later node (a node higher
  ** up on the graph) in the same branch that has no parent, then make
  ** the lower node a step-child of the upper node.
  */
  for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
    if( pRow->pChild ) continue;
    for(pLoop=pRow->pPrev; pLoop; pLoop=pLoop->pPrev){
      if( pLoop->nParent>0
       && pLoop->zBranch==pRow->zBranch
       && hashFind(p,pLoop->aParent[0])==0
      ){
        pRow->pChild = pLoop;
        pRow->idxTop = pLoop->idxTop;
        pRow->isStepParent = 1;
        pLoop->aParent[0] = pRow->rid;
        break;
      }
    }
  }

  /* Identify rows where the primary parent is off screen.  Assign
  ** each to a rail and draw descenders to the bottom of the screen.
  **
  ** Strive to put the "trunk" branch on far left.
  */
  zTrunk = persistBranchName(p, "trunk");

Changes to src/graph.js.

90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
...
113
114
115
116
117
118
119

120
121
122
123
124
125
126
...
194
195
196
197
198
199
200






201
202
203
204
205
206
207
...
234
235
236
237
238
239
240

241
242
243
244
245
246
247
    canvasDiv.style.position = "absolute";
    parent.appendChild(canvasDiv);
  
    var elems = {};
    var elemClasses = [
      "rail", "mergeoffset", "node", "arrow u", "arrow u sm", "line",
      "arrow merge r", "line merge", "arrow warp", "line warp",
      "line cherrypick"
    ];
    for( var i=0; i<elemClasses.length; i++ ){
      var cls = elemClasses[i];
      var elem = document.createElement("div");
      elem.className = "tl-" + cls;
      if( cls.indexOf("line")==0 ) elem.className += " v";
      canvasDiv.appendChild(elem);
................................................................................
    arrowSmall = elems.arrow_u_sm;
    line = elems.line;
    mArrow = elems.arrow_merge_r;
    mLine = elems.line_merge;
    cpLine = elems.line_cherrypick;
    wArrow = elems.arrow_warp;
    wLine = elems.line_warp;

  
    var minRailPitch = Math.ceil((node.w+line.w)/2 + mArrow.w + 1);
    if( window.innerWidth<400 ){
      railPitch = minRailPitch;
    }else{
      if( tx.iRailPitch>0 ){
        railPitch = tx.iRailPitch;
................................................................................
    var y0 = from.y + node.h/2;
    var y1 = Math.ceil(to.y + node.h + arw.h/2);
    drawLine(line,color,x,y0,null,y1);
    x = to.x + (node.w-arw.w)/2;
    var n = drawBox(arw.cls,null,x,y);
    if(color) n.style.borderBottomColor = color;
  }






  /* Draw thin horizontal or vertical lines representing merges */
  function drawMergeLine(x0,y0,x1,y1){
    drawLine(mLine,null,x0,y0,x1,y1);
  }
  function drawCherrypickLine(x0,y0,x1,y1){
    drawLine(cpLine,null,x0,y0,x1,y1);
  }
................................................................................
      var e = document.getElementById("mc"+p.id);
      if(e) e.style.backgroundColor = p.bg;
      e = document.getElementById("md"+p.id);
      if(e) e.style.backgroundColor = p.bg;
    }
    if( p.r<0 ) return;
    if( p.u>0 ) drawUpArrow(p,tx.rowinfo[p.u-tx.iTopRow],p.fg);

    var cls = node.cls;
    if( p.hasOwnProperty('mi') && p.mi.length ) cls += " merge";
    if( p.f&1 ) cls += " leaf";
    var n = drawBox(cls,p.bg,p.x,p.y);
    n.id = "tln"+p.id;
    n.onclick = clickOnNode;
    n.style.zIndex = 10;







|







 







>







 







>
>
>
>
>
>







 







>







90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
...
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
...
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
...
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
    canvasDiv.style.position = "absolute";
    parent.appendChild(canvasDiv);
  
    var elems = {};
    var elemClasses = [
      "rail", "mergeoffset", "node", "arrow u", "arrow u sm", "line",
      "arrow merge r", "line merge", "arrow warp", "line warp",
      "line cherrypick", "line dotted"
    ];
    for( var i=0; i<elemClasses.length; i++ ){
      var cls = elemClasses[i];
      var elem = document.createElement("div");
      elem.className = "tl-" + cls;
      if( cls.indexOf("line")==0 ) elem.className += " v";
      canvasDiv.appendChild(elem);
................................................................................
    arrowSmall = elems.arrow_u_sm;
    line = elems.line;
    mArrow = elems.arrow_merge_r;
    mLine = elems.line_merge;
    cpLine = elems.line_cherrypick;
    wArrow = elems.arrow_warp;
    wLine = elems.line_warp;
    dotLine = elems.line_dotted;
  
    var minRailPitch = Math.ceil((node.w+line.w)/2 + mArrow.w + 1);
    if( window.innerWidth<400 ){
      railPitch = minRailPitch;
    }else{
      if( tx.iRailPitch>0 ){
        railPitch = tx.iRailPitch;
................................................................................
    var y0 = from.y + node.h/2;
    var y1 = Math.ceil(to.y + node.h + arw.h/2);
    drawLine(line,color,x,y0,null,y1);
    x = to.x + (node.w-arw.w)/2;
    var n = drawBox(arw.cls,null,x,y);
    if(color) n.style.borderBottomColor = color;
  }
  function drawUpDotted(from,to,color){
    var x = to.x + (node.w-line.w)/2;
    var y0 = from.y + node.h/2;
    var y1 = Math.ceil(to.y + node.h);
    drawLine(dotLine,color,x,y0,null,y1);
  }
  /* Draw thin horizontal or vertical lines representing merges */
  function drawMergeLine(x0,y0,x1,y1){
    drawLine(mLine,null,x0,y0,x1,y1);
  }
  function drawCherrypickLine(x0,y0,x1,y1){
    drawLine(cpLine,null,x0,y0,x1,y1);
  }
................................................................................
      var e = document.getElementById("mc"+p.id);
      if(e) e.style.backgroundColor = p.bg;
      e = document.getElementById("md"+p.id);
      if(e) e.style.backgroundColor = p.bg;
    }
    if( p.r<0 ) return;
    if( p.u>0 ) drawUpArrow(p,tx.rowinfo[p.u-tx.iTopRow],p.fg);
    if( p.sb>0 ) drawUpDotted(p,tx.rowinfo[p.sb-tx.iTopRow],p.fg);
    var cls = node.cls;
    if( p.hasOwnProperty('mi') && p.mi.length ) cls += " merge";
    if( p.f&1 ) cls += " leaf";
    var n = drawBox(cls,p.bg,p.x,p.y);
    n.id = "tln"+p.id;
    n.onclick = clickOnNode;
    n.style.zIndex = 10;

Changes to src/info.c.

279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
        rid, rid
      );
    }
  }
  blob_append_sql(&sql, " AND event.objid IN ok ORDER BY mtime DESC");
  db_prepare(&q, "%s", blob_sql_text(&sql));
  www_print_timeline(&q,
       TIMELINE_DISJOINT
         |TIMELINE_GRAPH
         |TIMELINE_NOSCROLL
         |TIMELINE_CHPICK,
       0, 0, rid, 0);
  db_finalize(&q);
}

/*







<
|







279
280
281
282
283
284
285

286
287
288
289
290
291
292
293
        rid, rid
      );
    }
  }
  blob_append_sql(&sql, " AND event.objid IN ok ORDER BY mtime DESC");
  db_prepare(&q, "%s", blob_sql_text(&sql));
  www_print_timeline(&q,

          TIMELINE_GRAPH
         |TIMELINE_NOSCROLL
         |TIMELINE_CHPICK,
       0, 0, rid, 0);
  db_finalize(&q);
}

/*

Changes to src/timeline.c.

877
878
879
880
881
882
883




884
885
886
887
888
889
890
...
909
910
911
912
913
914
915



916

917
918
919
920
921
922
923
    **   mu:  The id of the row which is the top of the merge-out arrow.
    **        Only exists if "mo" exists.
    **   cu:  Extend the mu merge arrow up to this row as a cherrypick
    **        merge line, if this value exists.
    **    u:  Draw a thick child-line out of the top of this node and up to
    **        the node with an id equal to this value.  0 if it is straight to
    **        the top of the page, -1 if there is no thick-line riser.




    **    f:  0x01: a leaf node.
    **   au:  An array of integers that define thick-line risers for branches.
    **        The integers are in pairs.  For each pair, the first integer is
    **        is the rail on which the riser should run and the second integer
    **        is the id of the node upto which the riser should run. If there
    **        are no risers, this array does not exist.
    **   mi:  "merge-in".  An array of integer rail positions from which
................................................................................
        cgi_printf("\"mo\":%d,",      pRow->mergeOut);
        if( pRow->mergeUpto==0 ) pRow->mergeUpto = pRow->idx;
        cgi_printf("\"mu\":%d,",      pRow->mergeUpto);
        if( pRow->cherrypickUpto>0 && pRow->cherrypickUpto<pRow->mergeUpto ){
          cgi_printf("\"cu\":%d,",    pRow->cherrypickUpto);
        }
      }



      cgi_printf("\"u\":%d,",       pRow->aiRiser[pRow->iRail]);

      k = 0;
      if( pRow->isLeaf ) k |= 1;
      cgi_printf("\"f\":%d,",k);
      for(i=k=0; i<GR_MAX_RAIL; i++){
        if( i==pRow->iRail ) continue;
        if( pRow->aiRiser[i]>0 ){
          if( k==0 ){







>
>
>
>







 







>
>
>
|
>







877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
...
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
    **   mu:  The id of the row which is the top of the merge-out arrow.
    **        Only exists if "mo" exists.
    **   cu:  Extend the mu merge arrow up to this row as a cherrypick
    **        merge line, if this value exists.
    **    u:  Draw a thick child-line out of the top of this node and up to
    **        the node with an id equal to this value.  0 if it is straight to
    **        the top of the page, -1 if there is no thick-line riser.
    **   sb:  Draw a dotted child-line out of the top of this node up to the
    **        node with the id equal to the value.  This is like "u" except
    **        that the line is dotted instead of solid and has no arrow.
    **        Mnemonic: "Same Branch".
    **    f:  0x01: a leaf node.
    **   au:  An array of integers that define thick-line risers for branches.
    **        The integers are in pairs.  For each pair, the first integer is
    **        is the rail on which the riser should run and the second integer
    **        is the id of the node upto which the riser should run. If there
    **        are no risers, this array does not exist.
    **   mi:  "merge-in".  An array of integer rail positions from which
................................................................................
        cgi_printf("\"mo\":%d,",      pRow->mergeOut);
        if( pRow->mergeUpto==0 ) pRow->mergeUpto = pRow->idx;
        cgi_printf("\"mu\":%d,",      pRow->mergeUpto);
        if( pRow->cherrypickUpto>0 && pRow->cherrypickUpto<pRow->mergeUpto ){
          cgi_printf("\"cu\":%d,",    pRow->cherrypickUpto);
        }
      }
      if( pRow->isStepParent ){
        cgi_printf("\"sb\":%d,",      pRow->aiRiser[pRow->iRail]);
      }else{
        cgi_printf("\"u\":%d,",       pRow->aiRiser[pRow->iRail]);
      }
      k = 0;
      if( pRow->isLeaf ) k |= 1;
      cgi_printf("\"f\":%d,",k);
      for(i=k=0; i<GR_MAX_RAIL; i++){
        if( i==pRow->iRail ) continue;
        if( pRow->aiRiser[i]>0 ){
          if( k==0 ){