HTML在文本后面绘制箭头

时间:2015-06-05 20:38:02

标签: html5 html5-canvas jcl

html5画布可以执行以下操作吗?如果是,那怎么......

  1. 位于HTML文本后面的底层位置
  2. 您可以准确地找到指定的HTML文本坐标(可能用span ID标识),无论浏览器缩放大小或换行符
  3. 我正在尝试使用HTML / CSS / JS创建以下内容:

    html highlight image (请原谅绿色波浪形的下划线)

    突出显示的文字显然可以使用background-color:

    进行设置

    棘手的部分是用箭头连接突出显示的文本,我认为它可以用HTLM画布完成,但我对任何想法持开放态度。

    同样漂亮的小奖励是悬停时可能会突出显示/箭头,也可能是关闭按钮。

    PS有点背景,文本是一些简化的JCL(大型机的一种脚本语言),突出显示的项目是文件。我试图通过作业(脚本)更容易跟踪数据流。这是非常简单的版本,但许多作业可能是100多行,有很多细节,这使得很难追踪彼此相关的步骤。如果有其他想法或工具来帮助跟踪JCL中的数据流,请告诉我。

    //COBLPGM  EXEC PGM=COBLPGM
    //INPUT    DD DSN=&&SORT,DISP=(OLD,DELETE)
    //NACHA    DD DSN=NODE.OPER.COBLPGM.OUT(+1)
    
    //SORT2    EXEC PGM=SORT
    //SORTIN   DD DSN=NODE.OPER.COBLPGM.OUT(+1)
    //SORTOUT  DD DSN=&&SORT2,DISP=(,PASS)
    //SYSIN    DD DSN=NODE.OPER.PROCLIB(MEM)
    
    //UNRELATE EXEC PGM=UNPGM
    //INPUT    DD DSN=NODE.OPER.UNRELATED.FILE
    //REPORT   DD DSN=&&REPORT
    
    //TSTEMPT1 EXEC PGM=SPOPNCLO
    //IN       DD DSN=&&SORT2,DISP=(OLD,DELETE)
    
    //    IF TSTEMPT1.RC=0 THEN
    
    //SORT3    EXEC PGM=SORT
    //SORTIN   DD DSN=NODE.OPER.COBLPGM.OUT(+1)
    //SORTOUT  DD DSN=&&SORT3,DISP=(,PASS),LRECL=141
    //SYSIN    DD DSN=NODE.OPER.CNTRLCDS(PARM)
    
    //    ENDIF
    

1 个答案:

答案 0 :(得分:2)

这只是一个"概念"回答显示您可以跟踪HTML以同步画布元素。

以下代码将文本本身放在HTML中的<pre>标记中。背景中有一个画布,大小固定。画布在滚动时更新,因此相对于页面绘制框(它也应在调整大小时更新,未显示)。

由于我们可以跟踪文本,您可以看到我们也可以放置相对于它的任何其他图形,例如箭头和线条。我没有在这里展示,因为我觉得它太宽泛,但你应该得到它的要点,因为它显示了如何计算文本行和字符位置。

依据是:

  • 获取<pre>代码
  • 的绝对位置
  • 计算行数(小心将文本放在标记之后而不是在新行上,以及将结束标记放在与最后一行文本行相同的行)
  • 在行数上划分绝对高度将为每行提供行高(以像素为单位)
  • 使用measureText()上下文通过设置上下文来衡量每行的宽度,以使用与<pre>标记相同的字体和大小
  • 使用上一个预标签中的矩形来偏移行和x的位置。
  • 每个char都使用当前前面的字符计算,其中measureText()(单元格是此位置和下一个字符的位置)。

文本可以选择,背景中的画布标记区域。

请注意,文本行中的特殊字符可能会抛出measureText(例如&amp;&amp; in示例文本中)。在测量之前,必须对这些字符进行编码或替换。使用等宽字体替换不是问题,例如在这种情况下。

演示

&#13;
&#13;
var pre = document.querySelector("pre"),          // get pre ele,ent
    rect = pre.getBoundingClientRect(),           // get its absolute position
    lines = pre.innerHTML.split("\n"),            // split text lines
    count = lines.length,                         // count lines
    lineH = rect.height / count,                  // line height
    
    canvas = document.querySelector("canvas"),    // setup canvas
    ctx = canvas.getContext("2d");

canvas.width = window.innerWidth;                 // todo: update on resize
canvas.height = window.innerHeight;

ctx.font = "14px monospace";                      // use same font in canvas as for pre
ctx.strokeStyle = "#d00";
ctx.translate(0.5, 0.5);                          // makes lines sharper for demo

window.onscroll = drawBoxes;                      // we need to track scrolling
drawBoxes();

function drawBoxes() {                            // render line boxes (y)
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  for(var i = 0; i < count; i++) {
    var w = ctx.measureText(lines[i]).width;
    if (w) ctx.strokeRect(rect.left, rect.top + i * lineH - window.scrollY, w, lineH - 1);
    showChars(lines[i], rect.top + i * lineH - window.scrollY, lineH); 
  }
}
function showChars(line, y, h) {                  // render char lines (x)
  ctx.beginPath();
  for(var i = 0, ch, x, s = ""; ch = line[i]; i++) {
    s += ch;
    x = ctx.measureText(s).width;
    ctx.moveTo(x, y); ctx.lineTo(x, y + h - 1);
  }
  ctx.globalAlpha = 0.2;
  ctx.stroke();
  ctx.globalAlpha = 1;
}
&#13;
canvas {position:fixed;left:0;top:0;z-index:-1}
pre {font:14px monospace}
&#13;
<canvas></canvas>
<pre>//COBLPGM  EXEC PGM=COBLPGM
//INPUT    DD DSN=SORT,DISP=(OLD,DELETE)
//NACHA    DD DSN=NODE.OPER.COBLPGM.OUT(+1)

//SORT2    EXEC PGM=SORT
//SORTIN   DD DSN=NODE.OPER.COBLPGM.OUT(+1)
//SORTOUT  DD DSN=SORT2,DISP=(,PASS)
//SYSIN    DD DSN=NODE.OPER.PROCLIB(MEM)

//UNRELATE EXEC PGM=UNPGM
//INPUT    DD DSN=NODE.OPER.UNRELATED.FILE
//REPORT   DD DSN=REPORT

//TSTEMPT1 EXEC PGM=SPOPNCLO
//IN       DD DSN=SORT2,DISP=(OLD,DELETE)

//    IF TSTEMPT1.RC=0 THEN

//SORT3    EXEC PGM=SORT
//SORTIN   DD DSN=NODE.OPER.COBLPGM.OUT(+1)
//SORTOUT  DD DSN=SORT3,DISP=(,PASS),LRECL=141
//SYSIN    DD DSN=NODE.OPER.CNTRLCDS(PARM)

//    ENDIF</pre>
&#13;
&#13;
&#13;