动机这个最近问题tikz
,我尝试使用答案中提供的代码来编写一个基于解决方案这个问题。更准确地说,我尝试编写与 中的pstricks
\rnode
和\ncline
命令等效的命令tikz
。这是我得到的:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\newsavebox{\tempbox}
\newcommand{\tikznode}[2]{\relax\ifmmode\savebox{\tempbox}{\ensuremath{#2}}
\makebox[\wd\tempbox]{\tikz[overlay,remember picture,baseline=-0.8ex]%
\node[minimum width=\wd\tempbox] (#1) {\ensuremath{#2}};}
\else\savebox{\tempbox}{#2}
\makebox[0.5\wd\tempbox]{\tikz[overlay,remember picture,baseline=-0.8ex,minimum width=\wd\tempbox]%
\node[minimum width=\wd\tempbox] (#1) {#2};}\fi}
\tikzset{
ncbar angle/.initial=-90,
ncbar/.style={
to path=(\tikztostart)
-- ($(\tikztostart)!#1!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztotarget)$)
-- ($(\tikztotarget)!($(\tikztostart)!#1!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztotarget)$)!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztostart)$)
-- (\tikztotarget)
},
ncbar/.default=0.5cm
}
\begin{document}
blabla \tikznode{A}{A}\tikznode{B}{B}\tikznode{C}{C} blabla
\tikznode{X}{X}\tikznode{Y}{Y}\tikznode{Z}{Z} blabla
\tikz[overlay,remember picture]{\draw[->] (A) to [ncbar=0.4] (X);}%
\tikz[overlay,remember picture]{\draw[->] (B) to [ncbar=0.5] (Y);}%
\tikz[overlay,remember picture]{\draw[->] (C) to [ncbar=0.6] (Z);}%
\end{document}
它产生:
这看起来并非完全不合理。但是,它似乎过于复杂,我认为存在更优雅、更稳定的解决方案。例如,我需要使用 手动移动基线baseline=-0.8ex
。这似乎不对。我还需要计算文本的宽度并将其乘以任意因子 0.5,这再次显得很奇怪。最后但并非最不重要的一点是,我必须区分数学和文本模式。(是的,我知道原则上可以\mathchoice
使用,但我觉得我选择了一种不必要的复杂方法,所以我没有将其内置。)我的问题是是否有人知道如何使其更优雅,特别是更稳定。
答案1
我可能会这么做
\newcommand{\tikznode}[2]{%
\ifmmode%
\tikz[remember picture,baseline=(#1.base),inner sep=0pt] \node (#1) {$#2$};%
\else
\tikz[remember picture,baseline=(#1.base),inner sep=0pt] \node (#1) {#2};%
\fi}
通过将基线设置为base
节点的锚点,您不必使用某些特定值。这样inner sep=0pt
您就不会在节点中的文本周围获得任何额外的空间。
还请注意,我删除了该overlay
选项。该选项意味着您将获得一个零大小的边界框,而这并非您想要的。
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\newcommand{\tikznode}[2]{%
\ifmmode%
\tikz[remember picture,baseline=(#1.base),inner sep=0pt] \node (#1) {$#2$};%
\else
\tikz[remember picture,baseline=(#1.base),inner sep=0pt] \node (#1) {#2};%
\fi}
\tikzset{
ncbar angle/.initial=-90,
ncbar/.style={
to path=(\tikztostart)
-- ($(\tikztostart)!#1!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztotarget)$)
-- ($(\tikztotarget)!($(\tikztostart)!#1!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztotarget)$)!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztostart)$)
-- (\tikztotarget)
},
ncbar/.default=0.5cm
}
\begin{document}
blabla \tikznode{A}{A}$\tikznode{B}{B}$\tikznode{C}{C} blabla
\tikznode{X}{X}\tikznode{Y}{Y}\tikznode{Z}{Z} blabla
\begin{tikzpicture}[overlay,remember picture]
\draw[->] (A) to [ncbar=0.4] (X);
\draw[->] (B) to [ncbar=0.5] (Y);
\draw[->] (C) to [ncbar=0.6] (Z);
\end{tikzpicture}
\end{document}
如果你想实现\mathchoice
这个,你会遇到问题,因为所有四个不同的选择都是排版的。因此,简单的实现
\newcommand{\tikznode}[2]{%
\ifmmode%
\mathchoice
{\tikz[remember picture,baseline=(#1.base),inner sep=0pt] \node (#1) {$\displaystyle #2$};}%
{\tikz[remember picture,baseline=(#1.base),inner sep=0pt] \node (#1) {$\textstyle #2$};}%
{\tikz[remember picture,baseline=(#1.base),inner sep=0pt] \node (#1) {$\scriptstyle #2$};}%
{\tikz[remember picture,baseline=(#1.base),inner sep=0pt] \node (#1) {$\scriptscriptstyle #2$};}%
\else
\tikz[remember picture,baseline=(#1.base),inner sep=0pt] \node (#1) {#2};%
\fi}
不起作用,因为节点名称将始终引用脚本版本,而在其他三种样式中根本不使用。因此,对于上面的示例,当B
在 textstyle 中时,您将获得一个指向页面外的箭头。
不过,也许并不令人意外的是,之前有人曾想过这个问题,Heiko Oberdiek 在mathchoice 和 tikz 的记忆图片。refmathstyle
不过,他制作的软件包尚未在 CTAN 上发布,并且该答案中的链接已失效,因此这里是非软件包版本:
\documentclass{article}
\usepackage{tikz}
\usepackage{refcount}
\usetikzlibrary{calc}
% from https://tex.stackexchange.com/questions/122415/mathchoice-and-tikzs-remember-picture
\makeatletter
\newcounter{tikznode}
\renewcommand*{\thetikznode}{tikznode@\the\value{tikznode}}
\newcommand*{\tikznodestyle}{%
\refused{\thetikznode}%
\ifcase\getrefbykeydefault{\thetikznode}{}{0} %
\displaystyle
\or\textstyle
\or\scriptstyle
\or\scriptscriptstyle
\fi
}
\newcommand{\tikznode}[2]{%
\ifmmode%
\stepcounter{tikznode}%
\mathchoice
{\def\@currentlabel{0}\label{\thetikznode}}%
{\def\@currentlabel{1}\label{\thetikznode}}%
{\def\@currentlabel{2}\label{\thetikznode}}%
{\def\@currentlabel{3}\label{\thetikznode}}%
\tikz[remember picture,baseline=(#1.base),inner sep=0pt] \node (#1) {$\tikznodestyle #2$};
\else
\tikz[remember picture,baseline=(#1.base),inner sep=0pt] \node (#1) {#2};%
\fi}
\makeatother
% from https://tex.stackexchange.com/questions/55068/is-there-a-tikz-equivalent-to-the-pstricks-ncbar-command
\tikzset{
ncbar angle/.initial=-90,
ncbar/.style={
to path=(\tikztostart)
-- ($(\tikztostart)!#1!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztotarget)$)
-- ($(\tikztotarget)!($(\tikztostart)!#1!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztotarget)$)!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztostart)$)
-- (\tikztotarget)
},
ncbar/.default=0.5cm
}
\begin{document}
blabla
$\displaystyle\tikznode{A}{A}\textstyle\tikznode{B}{B}_{\tikznode{C}{C}_{\tikznode{D}{D}}}$
blabla
\tikznode{X}{X}\tikznode{Y}{Y}\tikznode{Z}{Z}\tikznode{W}{W}
blabla
\begin{tikzpicture}[overlay,remember picture]
\draw[->] (A) to [ncbar=0.4] (X);
\draw[->] (B) to [ncbar=0.5] (Y);
\draw[->] (C) to [ncbar=0.6] (Z);
\draw[->] (D) to [ncbar=0.6] (W);
\end{tikzpicture}
\end{document}
答案2
由于它被埋在 Torbjørn 的答案的评论中,因此这只是为了指出这现在是tikzmark
包,并正确处理不同的数学模式。以下是演示:
\documentclass{article}
%\url{https://tex.stackexchange.com/q/402462/86}
\usepackage{tikz}
\usetikzlibrary{tikzmark,calc}
\tikzset{
ncbar angle/.initial=-90,
ncbar/.style={
to path=(\tikztostart)
-- ($(\tikztostart)!#1!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztotarget)$)
-- ($(\tikztotarget)!($(\tikztostart)!#1!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztotarget)$)!\pgfkeysvalueof{/tikz/ncbar angle}:(\tikztostart)$)
-- (\tikztotarget)
},
ncbar/.default=0.5cm
}
\begin{document}
blabla \tikzmarknode{A}{A}\(\tikzmarknode{B}{B}^{\tikzmarknode{C}{C}}\) blabla
\tikzmarknode{X}{X}\tikzmarknode{Y}{Y}\tikzmarknode{Z}{Z} blabla
\begin{tikzpicture}[overlay,remember picture]
\draw[->] (A) to [ncbar=0.4] (X);
\draw[->] (B) to [ncbar=0.5] (Y);
\draw[->] (C) to [ncbar=0.6] (Z);
\end{tikzpicture}
\end{document}
C
从到 的线条Z
是有角度的,因为节点的底部处于不同的水平。我不知道原始 PSTricksncline
在这种情况下会做什么,所以我保留了 Torbjørn 答案中的代码。