Fossil

Check-in [8e922935fe]
Login

Check-in [8e922935fe]

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

Overview
Comment:Proof-of-concept for how to pop up a tooltip when mousing over one of the branch arrows in a timeline graph.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | tooltips
Files: files | file ages | folders
SHA3-256: 8e922935feb9445af9eedc88f086ac6810f95d238e56870cda64ba0e111a1bfc
User & Date: drh 2019-05-17 16:45:29.063
Context
2019-05-17
17:48
Add tooltips to more elements. Click to jump to the branch displayed by the tooltip - except clicking no a node toggles the node selection on and off as it always has. ... (check-in: 804dbe0d5b user: drh tags: tooltips)
16:45
Proof-of-concept for how to pop up a tooltip when mousing over one of the branch arrows in a timeline graph. ... (check-in: 8e922935fe user: drh tags: tooltips)
13:54
Merge the %j string formatter enhancement from trunk. ... (check-in: 78d812e24d user: drh tags: graph-improvements)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/default_css.txt.
193
194
195
196
197
198
199











200
201
202
203
204
205
206
}
.tl-line.dotted.v {
  width: 0px;
  border-left-width: 2px;
  border-left-style: dotted;
  background: rgba(255,255,255,0);
}











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







>
>
>
>
>
>
>
>
>
>
>







193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
}
.tl-line.dotted.v {
  width: 0px;
  border-left-width: 2px;
  border-left-style: dotted;
  background: rgba(255,255,255,0);
}
.tl-tooltip {
  background-color: #fecd4b;
  color: black;
  text-align: center;
  padding: 5px 1em;
  border: 1px solid black;
  border-radius: 6px;
  position: absolute;
  z-index: 100;
}

span.tagDsp {
  font-weight: bold;
}
span.wikiError {
  font-weight: bold;
  color: red;
}
Changes to src/graph.js.
70
71
72
73
74
75
76




77
78
79
80
81
82
83
  if( css!=="" ){
    var style = document.createElement("style");
    style.textContent = css;
    document.querySelector("head").appendChild(style);
  }
  amendCssOnce = 0;
}





function TimelineGraph(tx){
  var topObj = document.getElementById("timelineTable"+tx.iTableId);
  amendCss(tx.circleNodes, tx.showArrowheads);
  var canvasDiv;
  var railPitch;
  var mergeOffset;







>
>
>
>







70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
  if( css!=="" ){
    var style = document.createElement("style");
    style.textContent = css;
    document.querySelector("head").appendChild(style);
  }
  amendCssOnce = 0;
}
var tooltipObj = document.createElement("span");
tooltipObj.className = "tl-tooltip";
tooltipObj.style.visibility = "hidden";
document.getElementsByTagName("BODY")[0].appendChild(tooltipObj);

function TimelineGraph(tx){
  var topObj = document.getElementById("timelineTable"+tx.iTableId);
  amendCss(tx.circleNodes, tx.showArrowheads);
  var canvasDiv;
  var railPitch;
  var mergeOffset;
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197



198
199
200
201
202
203
204
205
206
      cls += "v";
    }else{
      y1 = y0+elem.w;
      cls += "h";
    }
    return drawBox(cls,color,x0,y0,x1,y1);
  }
  function drawUpArrow(from,to,color){
    var y = to.y + node.h;
    var arrowSpace = from.y - y + (!from.id || from.r!=to.r ? node.h/2 : 0);
    var arw = arrowSpace < arrow.h*1.5 ? arrowSmall : arrow;
    var x = to.x + (node.w-line.w)/2;
    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 drawDotted(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);
    var n = drawLine(dotLine,null,x,y0,null,y1)







|






|
>
>
>

|







187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
      cls += "v";
    }else{
      y1 = y0+elem.w;
      cls += "h";
    }
    return drawBox(cls,color,x0,y0,x1,y1);
  }
  function drawUpArrow(from,to,color,id){
    var y = to.y + node.h;
    var arrowSpace = from.y - y + (!from.id || from.r!=to.r ? node.h/2 : 0);
    var arw = arrowSpace < arrow.h*1.5 ? arrowSmall : arrow;
    var x = to.x + (node.w-line.w)/2;
    var y0 = from.y + node.h/2;
    var y1 = Math.ceil(to.y + node.h + arw.h/2);
    var n = drawLine(line,color,x,y0,null,y1);
    n.onmouseenter = tooltipEnter
    n.onmouseleave = tooltipLeave
    n.setAttribute("data-id",id)
    x = to.x + (node.w-arw.w)/2;
    n = drawBox(arw.cls,null,x,y);
    if(color) n.style.borderBottomColor = color;
  }
  function drawDotted(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);
    var n = drawLine(dotLine,null,x,y0,null,y1)
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
    if( p.bg ){
      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 ) drawDotted(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;
    if( !tx.omitDescenders ){
      if( p.u==0 ){
        if( p.hasOwnProperty('mo') && p.r==p.mo ){
          var ix = p.hasOwnProperty('cu') ? p.cu : p.mu;
          var top = tx.rowinfo[ix-tx.iTopRow]
          drawUpArrow(p,{x: p.x, y: top.y-node.h}, p.fg);
        }else if( p.y>100 ){
          drawUpArrow(p,{x: p.x, y: p.y-50}, p.fg);
        }else{
          drawUpArrow(p,{x: p.x, y: 0},p.fg);
        }
      }
      if( p.hasOwnProperty('d') ){
        if( p.y + 150 >= btm ){
          drawUpArrow({x: p.x, y: btm - node.h/2},p,p.fg);
        }else{
          drawUpArrow({x: p.x, y: p.y+50},p,p.fg);
          drawDotted({x: p.x, y: p.y+63},{x: p.x, y: p.y+50-node.h/2},p.fg);
        }
      }
    }
    if( p.hasOwnProperty('mo') ){
      var x0 = p.x + node.w/2;
      var x1 = p.mo*railPitch + node.w/2;







|
|












|

|

|




|

|







248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
    if( p.bg ){
      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,p.id);
    if( p.sb>0 ) drawDotted(p,tx.rowinfo[p.sb-tx.iTopRow],p.fg,p.id);
    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;
    if( !tx.omitDescenders ){
      if( p.u==0 ){
        if( p.hasOwnProperty('mo') && p.r==p.mo ){
          var ix = p.hasOwnProperty('cu') ? p.cu : p.mu;
          var top = tx.rowinfo[ix-tx.iTopRow]
          drawUpArrow(p,{x: p.x, y: top.y-node.h}, p.fg, p.id);
        }else if( p.y>100 ){
          drawUpArrow(p,{x: p.x, y: p.y-50}, p.fg, p.id);
        }else{
          drawUpArrow(p,{x: p.x, y: 0},p.fg, p.id);
        }
      }
      if( p.hasOwnProperty('d') ){
        if( p.y + 150 >= btm ){
          drawUpArrow({x: p.x, y: btm - node.h/2},p,p.fg,p.id);
        }else{
          drawUpArrow({x: p.x, y: p.y+50},p,p.fg,p.id);
          drawDotted({x: p.x, y: p.y+63},{x: p.x, y: p.y+50-node.h/2},p.fg);
        }
      }
    }
    if( p.hasOwnProperty('mo') ){
      var x0 = p.x + node.w/2;
      var x1 = p.mo*railPitch + node.w/2;
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
          x0 = Math.ceil(x0);
          x1 += line.w;
        }
        var y0 = p.y + (node.h-line.w)/2;
        var u = tx.rowinfo[p.au[i+1]-tx.iTopRow];
        if( u.id<p.id ){
          drawLine(line,u.fg,x0,y0,x1,null);
          drawUpArrow(p,u,u.fg);
        }else{
          var y1 = u.y + (node.h-line.w)/2;
          drawLine(wLine,u.fg,x0,y0,x1,null);
          drawLine(wLine,u.fg,x1-line.w,y0,null,y1+line.w);
          drawLine(wLine,u.fg,x1,y1,u.x-wArrow.w/2,null);
          var x = u.x-wArrow.w;
          var y = u.y+(node.h-wArrow.h)/2;







|







331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
          x0 = Math.ceil(x0);
          x1 += line.w;
        }
        var y0 = p.y + (node.h-line.w)/2;
        var u = tx.rowinfo[p.au[i+1]-tx.iTopRow];
        if( u.id<p.id ){
          drawLine(line,u.fg,x0,y0,x1,null);
          drawUpArrow(p,u,u.fg,u.id);
        }else{
          var y1 = u.y + (node.h-line.w)/2;
          drawLine(wLine,u.fg,x0,y0,x1,null);
          drawLine(wLine,u.fg,x1-line.w,y0,null,y1+line.w);
          drawLine(wLine,u.fg,x1,y1,u.x-wArrow.w/2,null);
          var x = u.x-wArrow.w;
          var y = u.y+(node.h-wArrow.h)/2;
406
407
408
409
410
411
412














413
414
415
416
417
418
419
      if( tx.fileDiff ){
        location.href=tx.baseUrl + "/fdiff?v1="+selRow.h+"&v2="+p.h
      }else{
        location.href=tx.baseUrl + "/vdiff?from="+selRow.h+"&to="+p.h
      }
    }
  }














  function changeDisplay(selector,value){
    var x = document.getElementsByClassName(selector);
    var n = x.length;
    for(var i=0; i<n; i++) {x[i].style.display = value;}
  }
  function changeDisplayById(id,value){
    var x = document.getElementById(id);







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







413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
      if( tx.fileDiff ){
        location.href=tx.baseUrl + "/fdiff?v1="+selRow.h+"&v2="+p.h
      }else{
        location.href=tx.baseUrl + "/vdiff?from="+selRow.h+"&to="+p.h
      }
    }
  }
  function tooltipEnter(e){
    var id = this.getAttribute("data-id")
    tooltipObj.textContent = tx.rowinfo[id-tx.iTopRow].br
    tooltipObj.style.display = "inline"
    tooltipObj.style.position = "absolute"
    var x = e.x + 4 + window.pageXOffset
    tooltipObj.style.left = x+"px"
    var y = e.y + window.pageYOffset - tooltipObj.clientHeight - 4
    tooltipObj.style.top = y+"px"
    tooltipObj.style.visibility = "visible"
  }
  function tooltipLeave(e){
    tooltipObj.style.display = "none"
  }
  function changeDisplay(selector,value){
    var x = document.getElementsByClassName(selector);
    var n = x.length;
    for(var i=0; i<n; i++) {x[i].style.display = value;}
  }
  function changeDisplayById(id,value){
    var x = document.getElementById(id);
Changes to src/timeline.c.
900
901
902
903
904
905
906

907
908
909
910
911
912
913
    **        negative, then the rail position is the absolute value of mi[]
    **        and a thin merge-arrow descender is drawn to the bottom of
    **        the screen. This array is omitted if there are no inbound
    **        merges.
    **   ci:  "cherrypick-in". Like "mi" except for cherrypick merges.
    **        omitted if there are no cherrypick merges.
    **    h:  The artifact hash of the object being graphed

    */
    for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){
      int k = 0;
      cgi_printf("{\"id\":%d,",     pRow->idx);
      cgi_printf("\"bg\":\"%s\",",  pRow->zBgClr);
      cgi_printf("\"r\":%d,",       pRow->iRail);
      if( pRow->bDescender ){







>







900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
    **        negative, then the rail position is the absolute value of mi[]
    **        and a thin merge-arrow descender is drawn to the bottom of
    **        the screen. This array is omitted if there are no inbound
    **        merges.
    **   ci:  "cherrypick-in". Like "mi" except for cherrypick merges.
    **        omitted if there are no cherrypick merges.
    **    h:  The artifact hash of the object being graphed
    *    br:  The branch to which the artifact belongs
    */
    for(pRow=pGraph->pFirst; pRow; pRow=pRow->pNext){
      int k = 0;
      cgi_printf("{\"id\":%d,",     pRow->idx);
      cgi_printf("\"bg\":\"%s\",",  pRow->zBgClr);
      cgi_printf("\"r\":%d,",       pRow->iRail);
      if( pRow->bDescender ){
973
974
975
976
977
978
979

980
981
982
983
984
985
986
          }
          k++;
          cgi_printf("%c%d", cSep, mi);
          cSep = ',';
        }
      }
      if( k ) cgi_printf("],");

      cgi_printf("\"h\":\"%!S\"}%s",
                 pRow->zUuid, pRow->pNext ? ",\n" : "]\n");
    }
    @ }</script>
    style_graph_generator();
    graph_free(pGraph);
  }







>







974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
          }
          k++;
          cgi_printf("%c%d", cSep, mi);
          cSep = ',';
        }
      }
      if( k ) cgi_printf("],");
      cgi_printf("\"br\":\"%j\",", pRow->zBranch ? pRow->zBranch : "");
      cgi_printf("\"h\":\"%!S\"}%s",
                 pRow->zUuid, pRow->pNext ? ",\n" : "]\n");
    }
    @ }</script>
    style_graph_generator();
    graph_free(pGraph);
  }