基本解决方案

基本解决方案

我有一个使用 绘制的图形tikz。我正在尝试添加一个图例,它由两种具有不同含义的箭头组成。我的问题是如何在带有箭头的节点之间添加正确的垂直空间。

在 MWE 中,我有一个参考节点,其中的文本由 分隔\\。如何用箭头对齐节点,后者保持节点(n2)(n3)内的文本之间的垂直空间相同(n1)

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{calc}

\begin{document}
\begin{tikzpicture}
    \node[align=right,inner ysep=0pt] (n1) {BLA\\ BLB};
    \draw[->,red,align=center] ($(n1.north east)+(1cm,0cm)$) -- ++(0:8pt) node[at end,anchor=west] (n2) {BLA BLA};
    \draw[<-,red] ($(n1.north east)+(1cm,-\baselineskip)$) -- ++(0:8pt) node[at end,anchor=west] (n3) {BLA BLB};
\end{tikzpicture}
\end{document}

答案1

基本解决方案

该解决方案提供了两个密钥:

  • line
  • line default font

该键接受带或不带line的参数。如果给出了冒号,则该值将简单地转发到内部键,该键使用冒号之前的部分作为字体参数(希望设置正确)。 之后的部分是行号,即底线。::@line\baselineskip:1

冒号是否存在,其值line default font将被转发到@line并将用作字体参数。

代码

\documentclass[tikz,convert=false]{standalone}
\makeatletter
\tikzset{
  line default font/.initial=\normalsize,
  line/.code=\pgfutil@in@{:}{#1}%
    \ifpgfutil@in@
      \pgfkeysalso{@line={#1}}\else
      \pgfkeysalso{@line={\pgfkeysvalueof{/tikz/line default font}:#1}}%
    \fi,
  @line/.code args={#1:#2}{% internal
    \begingroup
      #1%
      \pgfutil@tempcnta#2\relax
      \advance\pgfutil@tempcnta-1\relax
      \pgf@xa\pgfutil@tempcnta\baselineskip\relax
      \pgfmath@returnone\pgf@xa
    \endgroup
    \pgftransformshift{\pgfqpoint{0pt}{\pgfmathresult pt}}%
  }
}
\begin{document}
\begin{tikzpicture}
    \node[align=right, font=\small, draw=lightgray] (n1) {BL\\ BLB};
    \draw[->] ([line=\small:2,xshift=1cm] n1.base east) -- ++(0:8pt)
                                        node[at end,anchor=base west] (n2) {Line 2};
    \draw[<-] ([line=1,       xshift=1cm] n1.base east) -- ++(0:8pt)
                                            node[at end,anchor=base west] (n3) {Line 1};
    \tikzset{line default font=\small, radius=.6pt}
    \fill ([line=1] n1.base west) circle[]
          ([line=2] n1.base west) circle[] [red];
    \fill ([line=1] n1.base)      circle[]
          ([line=2] n1.base)      circle[];
    \fill ([line=1] n1.text)      circle[]
          ([line=2] n1.text)      circle[] [blue];
    \fill ([line=1] n1.base east) circle[]
          ([line=2] n1.base east) circle[] [green];
\end{tikzpicture}
\end{document}

输出

在此处输入图片描述

完善的解决方案

该解决方案包括:

  • save baseline在宏中保存\baselineskip节点末尾的长度的键(在样式中包含这种样式可能会有所帮助)every node

  • 以键的形式添加到显式节点坐标系中line(它检查是否save baseline已在节点上使用);以及

  • 隐式节点坐标的补充。线与锚点之间由字符分隔'(不能使用:,,但可以.再次使用)。

无法line在没有锚点的情况下使用键(无论是隐式还是显式)。这个问题可以修复。我建议不要'在节点名称中使用(特别是如果可以'在没有锚点的情况下使用该线)。

缺点

不要變身!

说真的,如果节点旋转了,或者使用线锚的路径旋转了,或者其中一个scaleings 处于活动状态,那么我无法保证任何事情。

代码

\documentclass[tikz,convert=false]{standalone}
\makeatletter
\tikzset{
  save baseline/.style={
    execute at end node=\expandafter\xdef\csname pgf@sh@bls@\tikz@fig@name\endcsname{\the\baselineskip}
  }
}
\pgfqkeys{/tikz/cs}{%
  line/.store in=\tikz@cs@line,% addition
  anchor/.store in=\tikz@cs@angle% small fix to reduce the code of the 'node' cs
}
\tikzdeclarecoordinatesystem{node}{%
  \tikzset{cs/.cd,name=,anchor=none,line=none,#1}%
  \ifx\tikz@cs@angle\tikz@nonetext%
    \expandafter\ifx\csname pgf@sh@ns@\tikz@cs@node\endcsname\tikz@coordinate@text%
    \else
      \aftergroup\tikz@shapebordertrue%
      \edef\tikz@shapeborder@name{\tikz@cs@node}%
    \fi%
    \pgfpointanchor{\tikz@cs@node}{center}%
  \else%
    \ifx\tikz@cs@line\tikz@nonetext
      \pgfpointanchor{\tikz@cs@node}{\tikz@cs@angle}%
    \else
      \expandafter\ifx\csname pgf@sh@bls@\tikz@cs@node\endcsname\relax
        \PackageError{TikZ}{The \tikz@cs@node\space has no saved baseline, use the 'save baseline' option}{}
        \pgfpointanchor{\tikz@cs@node}{\tikz@cs@angle}
      \else
        \pgfutil@tempcnta=\tikz@cs@line\relax
        \advance\pgfutil@tempcnta-1\relax
        \pgfutil@tempdima=\csname pgf@sh@bls@\tikz@cs@node\endcsname
        \pgfpointadd{\pgfpointanchor{\tikz@cs@node}{\tikz@cs@angle}}
                    {\pgfqpoint{0pt}{\pgfutil@tempcnta\pgfutil@tempdima}}%
      \fi
    \fi
  \fi%
}
\def\tikz@calc@anchor#1.#2\tikz@stop{%
  \pgfutil@in@{'}{#2}
  \ifpgfutil@in@
    \expandafter\ifx\csname pgf@sh@bls@#1\endcsname\relax
      \PackageError{TikZ}{The #1 has no saved baseline, use the 'save baseline' option}{}
      \pgfpointanchor{#1}{#2}
    \else
      \tikz@calc@anchor@line#1.#2\tikz@stop
    \fi
  \else
    \pgfpointanchor{#1}{#2}%
  \fi
}
\def\tikz@calc@anchor@line#1.#2'#3\tikz@stop{%
  \pgfutil@tempcnta=#3\relax
  \advance\pgfutil@tempcnta-1\relax
  \pgfutil@tempdima=\csname pgf@sh@bls@#1\endcsname
  \pgfpointadd{\pgfpointanchor{#1}{#2}}
              {\pgfqpoint{0pt}{\pgfutil@tempcnta\pgfutil@tempdima}}%
}
\makeatother
\begin{document}
\begin{tikzpicture}
    \node[align=right, font=\small, draw=lightgray, save baseline] (n1) {BL\\ BLB};
    \draw[->] (node cs: name=n1, anchor=base east, line=2) -- ++(0:8pt)
                                        node[at end,anchor=base west] (n2) {Line 2};
    \draw[<-] (node cs: name=n1, anchor=base east) -- ++(0:8pt)
                                            node[at end,anchor=base west] (n3) {Line 1};
    \tikzset{radius=.6pt}
    \fill (n1.base west'1) circle[]
          (n1.base west'2) circle[] [red];
    \fill (n1.base'1)      circle[]
          (n1.base'2)      circle[];
    \fill (n1.text'1)      circle[]
          (n1.text'2)      circle[] [blue];
    \fill (n1.base east'1) circle[]
          (n1.base east'2) circle[] [green];
\end{tikzpicture}
\end{document}

输出

在此处输入图片描述

相关内容