Como definir o nó on-line em uma camada diferente da linha?

Como definir o nó on-line em uma camada diferente da linha?

É possível declarar que os nós nas linhas estão na camada principal independentemente das linhas estarem na camada de fundo? Por exemplo: insira a descrição da imagem aqui

Com o seguinte 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}

Eu recebo:

insira a descrição da imagem aqui

A primeira imagem obtenho desenhando duas segundas linhas: primeiro como linha e sobre ela novamente uma linha invisível com nó. Como meus diagramas reais têm até uma dúzia dessas linhas, procuro soluções mais convenientes para declarar que os nós estão no plano principal, mesmo que a linha esteja em segundo plano.

Responder1

Vamos brincar com caixas.

Em algum momento, TikZ apresenta as chavesbehind pathe in front of path(para voltar) que basicamente especifica uma ou outra caixa de caminho em que os nós são colocados. Quando o caminho é finalmente desenhado (dentro do ;final dos caminhos) estas caixas são “usadas”:

  1. o de fundo ( \tikz@figbox@bg)
  2. o caminho real é desenhado
  3. o de primeiro plano ( \tikz@figbox, que é o padrão para nós)

Quando o TikZ encontra um nó no caminho, na verdade não apenasempatesele desenha o nó em uma dessas duas caixas.

Essas caixas são redefinidas no início do caminho. Essas caixas são a razão pela qual os nós são colocados no topo de seus caminhos (embora, para começar, sejam seus próprios caminhos).


Com oCamadas PGF, algo muito semelhante acontece, mas em vez de apenas um nó, tudo entre \begin{pgfonlayer}e \end{pgfonlayer}será colocado dentro dessa caixa.

No final da foto essas caixas ficam “usadas”. (Há algumas tarefas domésticas adicionais que acredito serem para aninhar fotos.)

Agora, em vez de colocar o nó na caixa que é usado pelo TikZ no ;podemostentarpara colocá-lo diretamente em uma das camadas.

Como isso acontece em algum lugar profundo em alguns grupos, isso precisa ser global (e de fato \pgfonlayertambém é global, já que isso pode ser usado dentro de um escopo em algum lugar - e de fato será quando você usar on background layer).


Para implementar isso, troco um \setbox(felizmente o primeiro) por um customizado \tikz@setbox@which- que é deixado \setboxfuncionar como normalmente funcionaria - dentro daquela macro que coloca o nó naquela caixa para o caminho.

A node on layerchave apenas faz com que \tikz@setbox@whichseja global \setboxe que a caixa seja uma das camadas e não uma das caixas de caminho.

Agora você pode dizer

\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}

E isso já mostra o que não funciona com isso:

  • A maincamada não pode ser escolhida (é uma camada especial que \pgfonlayertambém não pode ser escolhida).

  • transform canvasnão funcionará (mas também não funciona com behind path). Pode haver maneiras de contornar isso, mas o manual recomenda:

    Resumindo, você não deve usar transformações de canvas a menos que realmente saiba o que está fazendo.

    e vou adicionar… a menos que você realmente precise.

    Substituí sua adição por LCuma transformação normal dentro da LC'chave que é adicionada manualmente a cada coordenada. (Eu gostaria que houvesse alguma maneira de “desfixar” coordenadas/nós para que eles atuassem como coordenadas normais e as transformações se aplicassem a eles também, mas mesmo o manual oferece apenasuma solução alternativa @-ridden.)

Além disso, não o use com outra coisa além de nós. A macro “decisora” \tikz@whichboxnão é usada apenas para nós, mas também para arestas, marcas de plotagem, matrizes, nós filhos (não o mesmo que nós simples) e fotos. Usar \node on layerlá não vai funcionar, na melhor das hipóteses suas bordas, marcas de plotagem, matriz, filhos e fotos simplesmente não aparecerão. (Porque a adição à caixa é esquecida após o caminho atual de qualquer maneira.) Mais patches precisam ser feitos para isso.


Dito isto, você também pode simplesmente colocar um nó/coordenada vazio ao longo do caminho (para salvar a posição e a rotação) e depois fazer referência a isso colocando o nó real no final de todo o desenho de linha. Porém, isso exigirá uma boa manutenção para torná-lo fácil de usar.

E então há o todoPosicionamento de nó diferidoonde você primeiro “faz” um nó, mas o coloca depois (usado pela forestbiblioteca de desenho gráfico). Isso também não é muito simples. (Mais caixas!)

Código

\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}

Saída

insira a descrição da imagem aqui

Responder2

Que tal colocar o nó na camada frontal com um comando de caminho de acompanhamento:

\path (b1) to node[X,anchor=east,yshift=-2mm] {ACK(AckNum$=$1000)} (a2);

Aqui está o documento completo:

\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}

insira a descrição da imagem aqui

informação relacionada