Можно ли объявить, что узлы на линиях находятся на основном слое, независимо от того, что линии находятся на фоновом слое? Например:
Со следующими показателями 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 обходной путь.)
Кроме того, не используйте его ни с чем, кроме узлов. Макрос «решающий» \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}