是否可以声明,无论线条是否在背景层,线条上的节点都在主层上?例如:
具有以下 MWE:
\documentclass[12pt,tikz,border=3mm]{standalone}
\usetikzlibrary{arrows,arrows.meta,%
backgrounds,positioning}
\pgfdeclarelayer{foreground}
\pgfdeclarelayer{background}
\pgfsetlayers{background,main,foreground}
\usepackage{amsmath}
\begin{document}
\begin{tikzpicture}[
node distance = 0mm,
LC/.style = {draw=#1,
line width=1mm,
arrows={-Stealth[fill=#1,inset=0pt,length=0pt 1.6,angle'=90]},
},
X/.style = {draw, very thin, fill=white, fill opacity=0.75,
font=\scriptsize,
text=black, text opacity=1, align=left,
inner sep=2pt, sloped, anchor=west,pos=0.07},
]\sffamily
%---
\linespread{0.8}
%-------
\coordinate (a0) at (0,0);
\coordinate[right=77mm of a0] (b0);
\foreach \i [count=\xi from 0] in {1,2,...,4}
{
\coordinate[below=7mm of a\xi] (a\i);
\coordinate[below=7mm of b\xi] (b\i);
}
\draw[|->] (a0) -- (a3) node[above left] {$t$};
\draw[|->] (b0) -- (b3) node[above right] {$t$};
\draw[LC=gray] (a1)
to node[X] {data\\
$(\text{SeqNum}=0,\ell=1000)$}
(b2);
%-------
\begin{scope}[ X/.append style={anchor=east},
LC/.append style={transform canvas={yshift=-2mm}},
on background layer]
\draw[LC=teal] (b1)
to node[X] {ACK(AckNum$=$1000)}
(a2);
\end{scope}
%----------------
\end{tikzpicture}
\end{document}
我得到:
我通过两次绘制第二条线来获得第一幅图:第一条线是线,第二条是看不见的线,上面有节点。由于我的实际图表有多达十几条这样的线,所以我在寻找更方便的解决方案来声明,即使线在背景中,节点也在主平面中。
答案1
我们来玩盒子吧。
在某个时候,TikZ 引入了键behind path
和in front of path
(切换回来)基本上指定放置节点的一个或另一个路径框。当最终绘制路径时(在;
路径末尾内),这些框会被“使用”:
- 背景图 (
\tikz@figbox@bg
) - 实际路径被绘制
- 前台 (
\tikz@figbox
,这是节点的默认设置)
当 TikZ 在路径上找到一个节点时,它实际上并不只是绘制它,它在这两个框中的一个上绘制节点。
这些框在路径的开始处被重置。这些框是节点被放置在其路径顶部的原因(尽管它们一开始就是它们自己的路径)。
随着PGF 层,会发生一些非常类似的事情,但不只是一个节点,\begin{pgfonlayer}
和之间的所有内容\end{pgfonlayer}
都将放置在该框内。
在图片的最后,这些盒子被“使用”。(还有一些额外的整理工作,我认为是为了嵌套图片。)
;
现在,我们不再需要将节点放在 TikZ 使用的框中,而是尝试将其直接放置在其中一个图层上。
由于这发生在几个组的深处,所以这需要是全局的(并且事实上\pgfonlayer
它也是全局的,因为它可以在某个范围内使用 - 而且当你使用时它确实会这样on background layer
)。
为了实现这一点,我将一个\setbox
(幸运的是第一个)换成一个自定义的\tikz@setbox@which
- 让它\setbox
像往常一样工作 - 在将节点放置在路径的那个框上的宏里面。
关键node on layer
是让它成为\tikz@setbox@which
一个全局变量\setbox
,并且该框是其中一个层而不是路径框之一。
现在你可以说
\begin{scope}[
X/.append style={anchor=east},
LC'/.style={yshift=-2mm}, % no transform canvas
on background layer]
\draw[LC=teal] ([LC'] b1) % ........ ←
to node[X, node on layer=foreground] {ACK(AckNum$=$1000)} ([LC'] a2);
\end{scope}
这已经显示了什么不起作用:
无法选择该
main
图层(它是一个特殊的图层,无法用\pgfonlayer
任何方式选择)。transform canvas
不起作用(但也不适用于behind path
)。可能有解决方法,但手册建议:简而言之,除非您真正知道自己在做什么,否则不应该使用画布转换。
我要补充一下…除非你真的需要它。
LC
我已经用键内的正常变换替换了您的添加,LC'
该变换手动添加到每个坐标。(我确实希望有某种方法可以“取消固定”坐标/节点,以便它们充当正常坐标,并且变换也适用于它们,但即使是手册也只提供一个 @-ridden 的解决方法。
此外,不要将它与节点以外的其他东西一起使用。 “decider” 宏\tikz@whichbox
不仅用于节点,还用于边、绘图标记、矩阵、子节点(与普通节点不同)和图片。\node on layer
在那里使用不会起作用,最多您的边、绘图标记、矩阵、子节点和图片不会显示。 (因为无论如何在当前路径之后都会忘记添加到框中。)必须为此进行更多修补。
也就是说,您也可以沿路径放置一个空节点/坐标(以保存位置和旋转),然后在所有线条绘制的末尾放置实际节点时引用该节点。不过,这需要一些很好的管理才能使其易于使用。
然后还有整个延迟节点定位首先“创建”一个节点,然后放置它(由forest
图形绘制库使用)。不过,这也不是很直接。(更多框!)
代码
\documentclass[12pt, tikz, border=3mm]{standalone}
\usetikzlibrary{arrows, arrows.meta, backgrounds, positioning}
\pgfdeclarelayer{foreground}\pgfdeclarelayer{background}
\pgfsetlayers{background,main,foreground}
\makeatletter\ExplSyntaxOn % replace only first one
\tl_replace_once:Nnn \tikz@fig@continue { \setbox } { \tikz@setbox@which }
\ExplSyntaxOff
\let\tikz@setbox@which\setbox
\tikzset{node on layer/.code={%
\expandafter\def\expandafter\tikz@whichbox\expandafter
{\csname pgf@layerbox@#1\endcsname}%
\def\tikz@setbox@which{\global\setbox}}}
\makeatother
\usepackage{amsmath}
\begin{document}
\begin{tikzpicture}[
node distance = 0mm,
LC/.style = {draw=#1, line width=1mm,
arrows={-Stealth[fill=#1,inset=0pt,length=0pt 1.6,angle'=90]}},
X/.style = {draw, very thin, fill=white, fill opacity=0.75,
font=\scriptsize, text=black, text opacity=1, align=left,
inner sep=2pt, sloped, anchor=west,pos=0.07}]
\sffamily\linespread{0.8}
\coordinate (a0) at (0,0);
\coordinate[right=77mm of a0] (b0);
\foreach \i [count=\xi from 0] in {1,2,...,4}
\coordinate[below=7mm of a\xi] (a\i)
coordinate[below=7mm of b\xi] (b\i);
\draw[|->] (a0) -- (a3) node[above left] {$t$};
\draw[|->] (b0) -- (b3) node[above right] {$t$};
\draw[LC=gray] (a1) to node[X] {data\\$(\text{SeqNum}=0,\ell=1000)$} (b2);
\begin{scope}[
X/.append style={anchor=east},
LC'/.style={yshift=-2mm}, % no transform canvas
on background layer]
\draw[LC=teal] ([LC'] b1)
to node[X, node on layer=foreground] {ACK(AckNum$=$1000)} ([LC'] a2);
\end{scope}
\end{tikzpicture}
\end{document}
输出
答案2
如何使用后续路径命令将节点放置在前层:
\path (b1) to node[X,anchor=east,yshift=-2mm] {ACK(AckNum$=$1000)} (a2);
以下是完整文档:
\documentclass[12pt,tikz,border=3mm]{standalone}
\usetikzlibrary{arrows,arrows.meta,backgrounds,positioning}
\pgfdeclarelayer{foreground}
\pgfdeclarelayer{background}
\pgfsetlayers{background,main,foreground}
\usepackage{amsmath}
\begin{document}
\begin{tikzpicture}
[
node distance = 0mm,
LC/.style = {draw=#1,
line width=1mm,
arrows={-Stealth[fill=#1,inset=0pt,length=0pt 1.6,angle'=90]},
},
X/.style = {draw,
very thin,
fill=white,
fill opacity=0.75,
font=\scriptsize,
text=black,
text opacity=1,
align=left,
inner sep=2pt,
sloped,
anchor=west,
pos=0.07},
]
\sffamily
%---
\linespread{0.8}
%-------
\coordinate (a0) at (0,0);
\coordinate[right=77mm of a0] (b0);
\foreach \i [count=\xi from 0] in {1,2,...,4}
{
\coordinate[below=7mm of a\xi] (a\i);
\coordinate[below=7mm of b\xi] (b\i);
}
\draw[|->] (a0) -- (a3) node[above left] {$t$};
\draw[|->] (b0) -- (b3) node[above right] {$t$};
\draw[LC=gray] (a1)
to
node[X] {data\\
$(\text{SeqNum}=0,\ell=1000)$}
(b2);
%-------
\begin{scope}[X/.append style={anchor=east},
LC/.append style={transform canvas={yshift=-2mm}},
on background layer]
\draw[LC=teal] (b1)
to
(a2);
\end{scope}
%----------------
\path (b1) to node[X,anchor=east,yshift=-2mm] {ACK(AckNum$=$1000)} (a2);
\end{tikzpicture}
\end{document}