HTML 在文本后面画箭头
HTML draw arrows behind text
html5canvas可以做到以下几点吗?如果是,如何...
- 置于底层HTML文本后面
- 无论浏览器缩放大小还是换行,您能否准确找到指定坐标 HTML 文本(可能用
span
ID 标识)
我正在尝试使用 HTML/CSS/JS 创建以下内容:
(请原谅绿色波浪下划线)
突出显示的文本显然可以设置 background-color:
棘手的部分是将突出显示的文本与箭头连接起来,我认为它可以用 HTLM canvas 完成,但我愿意接受任何想法。
另外一个不错的小奖励是 highlighting/arrows 出现在悬停或关闭按钮上。
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
这只是一个 "conceptual" 答案,表明您可以跟踪 HTML 以同步 canvas 元素。
以下代码在 HTML 中的 <pre>
标记中包含文本本身。后台有一个canvas,大小固定。 canvas 在滚动时更新,因此框是相对于页面绘制的(它也应该在调整大小时更新,未显示)。
因为我们可以跟踪您可以看到的文本,所以我们也可以放置任何其他与其相关的图形,例如箭头和线条。我没有在这里展示它,因为我觉得它太宽泛了,但你应该了解它的要点,因为它展示了如何计算文本行和字符位置。
依据是:
- 获取
<pre>
标签的绝对位置
- 计算行数(注意将文本放在标签后面而不是换行,并将结束标签放在与最后一个文本行相同的行)
- 将绝对高度除以行数将得出每行的行高(以像素为单位)
- 使用
measureText()
of context 来测量每行的宽度,方法是将 context 设置为使用与 <pre>
标签相同的字体和大小
- 使用上一个预标记的矩形偏移行位置的 x 和 y。
- 每个字符都是使用当前字符之前的字符计算的,使用 measureText()(单元格是这个位置和下一个字符的位置)。
背景中的 canvas 标记区域使文本保持可选状态。
请注意,文本行中的特殊字符可能会影响 measureText(例如示例文本中的 &&)。在测量之前必须对这些字符进行编码或替换。对于本例中的等宽字体,替换不是问题。
演示
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;
}
canvas {position:fixed;left:0;top:0;z-index:-1}
pre {font:14px monospace}
<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>
html5canvas可以做到以下几点吗?如果是,如何...
- 置于底层HTML文本后面
- 无论浏览器缩放大小还是换行,您能否准确找到指定坐标 HTML 文本(可能用
span
ID 标识)
我正在尝试使用 HTML/CSS/JS 创建以下内容:
突出显示的文本显然可以设置 background-color:
棘手的部分是将突出显示的文本与箭头连接起来,我认为它可以用 HTLM canvas 完成,但我愿意接受任何想法。
另外一个不错的小奖励是 highlighting/arrows 出现在悬停或关闭按钮上。
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
这只是一个 "conceptual" 答案,表明您可以跟踪 HTML 以同步 canvas 元素。
以下代码在 HTML 中的 <pre>
标记中包含文本本身。后台有一个canvas,大小固定。 canvas 在滚动时更新,因此框是相对于页面绘制的(它也应该在调整大小时更新,未显示)。
因为我们可以跟踪您可以看到的文本,所以我们也可以放置任何其他与其相关的图形,例如箭头和线条。我没有在这里展示它,因为我觉得它太宽泛了,但你应该了解它的要点,因为它展示了如何计算文本行和字符位置。
依据是:
- 获取
<pre>
标签的绝对位置 - 计算行数(注意将文本放在标签后面而不是换行,并将结束标签放在与最后一个文本行相同的行)
- 将绝对高度除以行数将得出每行的行高(以像素为单位)
- 使用
measureText()
of context 来测量每行的宽度,方法是将 context 设置为使用与<pre>
标签相同的字体和大小 - 使用上一个预标记的矩形偏移行位置的 x 和 y。
- 每个字符都是使用当前字符之前的字符计算的,使用 measureText()(单元格是这个位置和下一个字符的位置)。
背景中的 canvas 标记区域使文本保持可选状态。
请注意,文本行中的特殊字符可能会影响 measureText(例如示例文本中的 &&)。在测量之前必须对这些字符进行编码或替换。对于本例中的等宽字体,替换不是问题。
演示
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;
}
canvas {position:fixed;left:0;top:0;z-index:-1}
pre {font:14px monospace}
<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>