Как установить узел на линии на другом слое, нежели линия?

Как установить узел на линии на другом слое, нежели линия?

Можно ли объявить, что узлы на линиях находятся на основном слое, независимо от того, что линии находятся на фоновом слое? Например: введите описание изображения здесь

Со следующими показателями 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(чтобы переключиться обратно), который в основном определяет тот или иной блок пути, на котором размещаются узлы. Когда путь окончательно нарисован (внутри ;в конце путей), эти блоки «используются»:

  1. фоновый ( \tikz@figbox@bg)
  2. фактический путь рисуется
  3. передний план ( \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}

введите описание изображения здесь

Связанный контент