我正在尝试制作一个 tikz 图,其中我可以将带有长文本的节点一个接一个地放置,这样我就可以指定要居中的部分(然后拖动这些部分之外的内容)并使用垂直箭头连接居中部分的中心。
这有点混乱,所以举个例子,我想要这样的东西:
\begin{tikzpicture}
\node (a) at (0,1) {really long stuff \centerthis{blahh} other stuff};
\node (b) at (0,0) {more stuff \centerthis{blah blah blah} possibly other stuff};
\draw[->] (a) -- (b);
\end{tikzpicture}
自动生成以下代码:
really long stuff (blahh) other stuff
|
|
v
more stuff (blah blah blah) possibly other stuff
因此 的中心(blahh)
位于 (0,1) 并且 的中心(blah blah blah)
位于 (0,0)。
我在解决方案中寻找的主要内容是
- 我想避免任何距离或尺寸的手动调整。
- 我希望所有内容都出现在同一个基线上。例如,我尝试制作 6 个节点,分别用于左上、左下、中间和右,当其中一个节点有下降项而其他的则没有,这看起来不对劲。也许有办法解决这个问题?
抱歉,我没有更多可以提供,但我就是被困在这个问题上了。当然,上面我使用的假设代码只是一个想法,如果你看到其他解决方案(我相信有很多),也请发布它。
答案1
如果你能用 6 个节点(几乎)正确对齐
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{positioning}
\begin{document}
\begin{tikzpicture}[every node/.style={outer sep=0,inner sep=0,text depth=0.3ex},
node distance=0.3em]
\node (a) at (0,1) {Blaaaahh};
\node[left=of a.west] {really long stuff};
\node[right=of a.east] {other stuff};
\node[below= 1 cmof a] (b) {blah blah blah};
\node[left=of b.west] {asymmetric};
\node[right=of b.east] {lipsum stuff};
\draw[-latex] (a) -- (b);
\end{tikzpicture}
\end{document}
否则,\tikzmark
答案可能就在眼前。
答案2
解决方案“复杂”
此解决方案计算两个节点必须移动的量xshift
,以使中心部分的中间部分位于该at (x,y)
点上。然后,
这些xshift
量再次用于要绘制的箭头。
该解决方案使用calc
包装。
该解决方案提供:
- Style
CenterLCRa
/b
接受三个参数:- 文本的左侧部分,
- 文本的中心部分(仅用于 的定义
\LCR
,见下文)和 - 文本的正确部分。
\LCR
使用样式CenterLCRa
/后设置的宏b
。它仅包含节点的文本,因此无需再次输入。LCR
在(新)中心之间绘制线的路径样式。- 内部:长度
\WidthOfLeft
、\WidthOfRight
和\xShiftA
/B
、宏\tikzCenterLCRa
/b
和 TikZ 样式centerLCRa
/b
代码
\documentclass[tikz,border=2pt]{standalone}
\usepackage{tikz,calc}
\newlength{\WidthOfLeft}
\newlength{\WidthOfRight}
\newlength{\xShiftA}
\newlength{\xShiftB}
\newcommand{\tikzCenterLCRa}[3]{% #1 = L, #2 = C, #3 = R
\setlength{\WidthOfLeft}{\widthof{#1}}%
\setlength{\WidthOfRight}{\widthof{#3}}%
\setlength{\xShiftA}{-.5\WidthOfLeft+.5\WidthOfRight}
\global\xShiftA=\xShiftA\relax%
\def\LCR{#1#2#3}
}
\newcommand{\tikzCenterLCRb}[3]{% #1 = L, #2 = C, #3 = R
\setlength{\WidthOfLeft}{\widthof{#1}}%
\setlength{\WidthOfRight}{\widthof{#3}}%
\setlength{\xShiftB}{-.5\WidthOfLeft+.5\WidthOfRight}
\global\xShiftB=\xShiftB\relax
\def\LCR{#1#2#3}
}
\tikzset{
centerLCRa/.code n args={3}{\tikzCenterLCRa{#1}{#2}{#3}},
CenterLCRa/.style n args={3}{
centerLCRa={#1}{#2}{#3},
xshift=\the\xShiftA
},
centerLCRb/.code n args={3}{\tikzCenterLCRb{#1}{#2}{#3}},
CenterLCRb/.style n args={3}{
centerLCRb={#1}{#2}{#3},
xshift=\the\xShiftB
},
LCR/.style={
to path={
([xshift=-\the\xShiftA]\tikztostart) -- ([xshift=-\the\xShiftB]\tikztotarget) \tikztonodes
}
}
}
\begin{document}
\begin{tikzpicture}[every node/.style=draw]
\node[CenterLCRa={really long stuff }{xxx}{ other stuff}] (a) at (0,1) {\LCR};
\node[CenterLCRb={more stuff }{blah xxx blah}{ possibly other stuff}] (b) at (0,0) {\LCR};
\draw[->] (a.south) to[LCR] (b.north);
\end{tikzpicture}
\end{document}
输出
“肮脏”的解决方案
节点大于其内容
该解决方案的缺点是使用的框比其内容更大,因此最终的节点将比平常更宽(边界框,draw
机制)。
代码
\documentclass[tikz,border=2pt]{standalone}
\usepackage{calc}
\newlength{\WidthOfLeft}
\newlength{\WidthOfRight}
\newcommand{\centerLCR}[3]{%
\settowidth{\WidthOfLeft}{#1}%
\settowidth{\WidthOfRight}{#3}%
\ifdim\WidthOfLeft<\WidthOfRight\relax%
\setlength{\WidthOfLeft}{\WidthOfRight}%
\fi%
\makebox[\WidthOfLeft][r]{#1}#2\makebox[\WidthOfLeft][l]{#3}%
}
\begin{document}
\begin{tikzpicture}
\node (a) at (0,1) {\centerLCR{really long stuff }{blahh}{ other stuff}};
\node (b) at (0,0) {\centerLCR{more stuff }{blah blah blah}{ possibly other stuff}};
\draw[->] (a) -- (b);
\end{tikzpicture}
\begin{tikzpicture}[every node/.style=draw]
\node (a) at (0,1) {\centerLCR{really long stuff }{blahh}{ other stuff}};
\node (b) at (0,0) {\centerLCR{more stuff }{blah blah blah}{ possibly other stuff}};
\draw[->] (a) -- (b);
\end{tikzpicture}
\end{document}
输出
节点小于其内容
如果盒子使用较小的宽度,即
\ifdim\WidthOfLeft>\WidthOfRight\relax% > instead of <
那么边界框就更糟糕了。(请参见输出中截断的“她的东西”。)
如果这些节点周围有更多东西,这不会成为问题。
输出