我想将 3 个投影仪块放在一个框架上并按循环顺序连接它们。
我尝试使用 TikZ 进行一些操作,但没有效果。
主要问题是以下代码中的点n1.south
和n2.south
实际上位于块的末尾。
\documentclass[aspectratio=169]{beamer}
\usepackage{tikz}
\usetheme{Frankfurt}
\tikzset{
every overlay node/.style={
%draw=black,fill=white,rounded corners,
anchor=north west,
},
}
% Usage:
% \tikzoverlay at (-1cm,-5cm) {content};
% or
% \tikzoverlay[text width=5cm] at (-1cm,-5cm) {content};
\def\tikzoverlay{%
\tikz[baseline,overlay]\node[every overlay node]
}%
\begin{document}
\begin{frame}
\tikzoverlay (n1) at (8cm,2cm) {
\begin{minipage}{0.4\textwidth}
\begin{block}{title1}
{Text1}
\end{block}
\end{minipage}
};
\tikzoverlay (n2) at (0cm,2cm) {
\begin{minipage}{0.4\textwidth}
\begin{block}{title2}
Text2
\end{block}
\end{minipage}
};
\tikzoverlay (n3) at (5cm,0cm) {
\begin{minipage}{0.4\textwidth}
\begin{block}{Title3}
Text3
\end{block}
\end{minipage}
};
\begin{tikzpicture}[overlay]
\path [line width=0.3cm,->] (n1.south) edge (n3.south);
\path [line width=0.3cm,->] (n3.north) edge (n2.south);
\path [line width=0.3cm,->] (n2.east) edge (n1.west);
\end{tikzpicture}
\end{frame}
\end{document}
答案1
我在某些方面修复了你的代码:
- 最重要的是,您还必须
remember picture
为覆盖提供选项。如果没有它,每个节点的名称就不会引用正确的坐标,因为它们是不同 tikz 图片中的节点。 baseline
在这种情况下,实际上不需要该选项。inner sep
对于块节点,设置为零%
在某些行的末尾添加以防止垂直空格(这种情况仍然会发生,我不知道为什么,可以通过取消注释样式的第一行来使其可见every overlay node
。
最终的代码如下:
\documentclass[aspectratio=169]{beamer}
\usepackage{tikz}
\usetheme{Frankfurt}
\tikzset{
every overlay node/.style={
%draw=black,fill=white,rounded corners,
anchor=north west, inner sep=0pt,
},
}
% Usage:
% \tikzoverlay at (-1cm,-5cm) {content};
% or
% \tikzoverlay[text width=5cm] at (-1cm,-5cm) {content};
\def\tikzoverlay{%
\tikz[remember picture, overlay]\node[every overlay node]
}%
\begin{document}
\begin{frame}
\tikzoverlay (n1) at (8cm,2cm) {%
\begin{minipage}{0.4\textwidth}%
\begin{block}{title1}%
{Text1}
\end{block}
\end{minipage}
};
\tikzoverlay (n2) at (0cm,2cm) {%
\begin{minipage}{0.4\textwidth}%
\begin{block}{title2}%
Text2
\end{block}
\end{minipage}
};
\tikzoverlay (n3) at (5cm,0cm) {%
\begin{minipage}{0.4\textwidth}%
\begin{block}{Title3}%
Text3
\end{block}
\end{minipage}
};
\begin{tikzpicture}[remember picture, overlay]
\path [line width=0.3cm,->] (n1.south) edge (n3.south);
\path [line width=0.3cm,->] (n3.north) edge (n2.south);
\path [line width=0.3cm,->] (n2.east) edge (n1.west);
\end{tikzpicture}
\end{frame}
\end{document}
产生(之后编译两次):
在我看来,这很丑陋,但我想这就是你想要的。
编辑:
当我编写上述代码时,我没有注意绘制每个节点的坐标值。我假设节点 2 与节点 1 处于不同级别的结果是故意的。但 OP 注释让我意识到两个节点确实使用相同的 y 坐标,那么,为什么它们不对齐呢?
原因是它们不是在同一个 中绘制的tikzpicture
,因此它们不共享坐标空间。每个tikzpicture
(或\tikz
命令)都启动自己的坐标系。因此,新的问题是“那么为什么几乎工作了?
原因是每个图形都有选项overlay
,这意味着无论图片实际绘制什么,tex 为该图片保留的空间都是零。它是一个无量纲点。该点就是图形的原点。
因此,如果我们有三个图形,中间没有空格,由于每个图形在 tex 中都被视为无量纲点,因此这三个图形将绘制在“同一点”,因此它们的坐标系将匹配。但如果图形被文字分隔开,那么每个图形都有自己的原点。
就你的情况而言,分开通过空格甚至`\par,因为源代码中有空行,并且图形之间有行尾。
解决方案是删除所有不需要的空间,方法是删除图形之间的空行并注释掉每个图形末尾的回车符(否则会产生空格):
\documentclass[aspectratio=169]{beamer}
\usepackage{tikz}
\usetheme{Frankfurt}
\tikzset{
every overlay node/.style={
%draw=black,fill=white,rounded corners,
anchor=north west, inner sep=0pt,
},
}
% Usage:
% \tikzoverlay at (-1cm,-5cm) {content};
% or
% \tikzoverlay[text width=5cm] at (-1cm,-5cm) {content};
\def\tikzoverlay{%
\tikz[remember picture, overlay]\node[every overlay node]
}%
\begin{document}
\begin{frame}
\tikzoverlay (n1) at (8cm,2cm) {%
\begin{minipage}{0.4\textwidth}%
\begin{block}{title1}%
{Text1}
\end{block}
\end{minipage}
};%
\tikzoverlay (n2) at (0cm,2cm) {%
\begin{minipage}{0.4\textwidth}%
\begin{block}{title2}%
Text2
\end{block}
\end{minipage}
};%
\tikzoverlay (n3) at (5cm,0cm) {%
\begin{minipage}{0.4\textwidth}%
\begin{block}{Title3}%
Text3
\end{block}
\end{minipage}
};%
%
\begin{tikzpicture}[remember picture, overlay]
\path [line width=0.3cm,->] (n1.south) edge (n3.south);
\path [line width=0.3cm,->] (n3.north) edge (n2.south);
\path [line width=0.3cm,->] (n2.east) edge (n1.west);
\end{tikzpicture}
\end{frame}
\end{document}
结果:
答案2
JLDiaz 向您解释了如何修复代码,但结果还有待改进。我建议的解决方案可能并不完美,因为需要多加注意,但在我看来,它提供了更好的结果。
它基于包textpos
将方块放置在更改投影仪中块的默认宽度自定义块宽度并在\tikzmark
宏上识别块。
实际上,您的解决方案中有趣的是,您识别块并将其放入 TikZ 节点中,以便稍后使用节点的锚点将它们连接起来的机制。然而,此解决方案使用textpos
因此:如何识别整个区块?这就是需要的原因\tikzmark
。请注意,使用textpos
有助于避免出现垂直错位等问题。
构建\tikzmark
方式使得节点可以在其宽度和高度上扩展(这是需要小心的部分):请注意,块的高度最终取决于您的内容,所以我的建议是 1)先写内容 2)稍后修复其高度。
所标识的点mark
恰好位于块标题的中心并且节点标识了比块更大的区域:
从图中可以看出,通过构建的节点有一半\tikzmark
是空的:这样做是为了确保连接平行块,箭头可以通过类似的东西实现
\path[line width=0.2cm](n2.east)edge[bend left](n1.west);
因此,上部仍为空,如果您在块顶部绘制开始/结束的连接,则应该注意此行为。此问题已通过特殊锚点以特殊方式修复。
显示所有内容的代码:
\documentclass[aspectratio=169]{beamer}
\usepackage{lmodern}
\usepackage{tikz}
\usepackage[overlay]{textpos}
\usetheme{Frankfurt}
\newcommand{\tikzmark}[2][minimum width=6cm,minimum height=1.5cm]{
\tikz[remember picture,overlay]
\node[anchor=west,
inner sep=0pt,
outer sep=6pt,
xshift=-0.5em,
yshift=-3ex,
#1](#2){};
}
\newcommand{\shownode}[1]{
\tikz[remember picture,overlay]\draw[red](#1.south east)rectangle(#1.north west);
}
\newcommand{\showanchor}[1]{
\tikz[remember picture,overlay]\draw[red,thick,mark=x] plot coordinates{(#1)};
}
% original code from Stefan Kottwitz
% https://tex.stackexchange.com/a/12551/13304
\newenvironment<>{varblock}[2][.9\textwidth]{%
\setlength{\textwidth}{#1}
\begin{actionenv}#3%
\def\insertblocktitle{#2}%
\par%
\usebeamertemplate{block begin}%
}
{\par%
\usebeamertemplate{block end}%
\end{actionenv}}
\newenvironment{myblock}[1]{\begin{textblock*}{500pt}(#1)}{\end{textblock*}}
% special way to reach the top of the block
\def\newabove(#1){
([yshift=1.5ex]#1.center)
}
\begin{document}
\begin{frame}
\begin{myblock}{0.55\textwidth, -0.2\textheight}
\tikzmark{n1}
\shownode{n1}
%remove the previous line: just used to see where the invisible node is placed
\begin{varblock}[6cm]{title1}
text1
\end{varblock}
\showanchor{n1}
%remove also this: just used to see where n1 is positioned
\end{myblock}
\begin{myblock}{0em, -0.2\textheight}
\tikzmark{n2}
\shownode{n2}
\begin{varblock}[6cm]{title2}
text2
\end{varblock}
\showanchor{n2}
\end{myblock}
\begin{myblock}{0.3\textwidth, 0.2\textheight}
\tikzmark[minimum width=5cm,minimum height=2.25cm]{n3} % customization of width and height
\shownode{n3}
\begin{varblock}[5cm]{title3}
text3\\
text
\end{varblock}
\showanchor{n3}
\end{myblock}
\begin{tikzpicture}[remember picture,overlay,-stealth]
\path[line width=0.2cm](n2.east)edge[bend left](n1.west);
\path[line width=0.2cm](n1.south)edge[bend left](n3.east);
\path[line width=0.2cm](n3.west)edge[bend left](n2.south);
% in case you need to connect some block from ``north''
%\path[line width=0.2cm](n3.north)edge[bend left](n1.south west); % is wrong
\path[line width=0.2cm]\newabove(n3) edge[bend left](n1.south west);
\end{tikzpicture}
\end{frame}
\end{document}
删除所有内容以使节点和锚点可见,以及显示如何到达块顶部的特殊路径,最终得到:
我想这就是你想要的。
如何处理区块的高度问题
由于这可能是该程序的一个缺点,让我们举一个例子。
首先,我们应该关心块的内容,而不要考虑高度或其他东西。例如:
\documentclass[aspectratio=169]{beamer}
\usepackage{lmodern}
\usepackage{tikz}
\usetheme{Frankfurt}
\usepackage[overlay]{textpos}
\newcommand{\tikzmark}[2][minimum width=6cm,minimum height=1.5cm]{
\tikz[remember picture,overlay]
\node[anchor=west,
inner sep=0pt,
outer sep=6pt,
xshift=-0.5em,
yshift=-3ex,
#1](#2){};
}
\newcommand{\shownode}[1]{
\tikz[remember picture,overlay]\draw[red](#1.south east)rectangle(#1.north west);
}
\newcommand{\showanchor}[1]{
\tikz[remember picture,overlay]\draw[red,thick,mark=x] plot coordinates{(#1)};
}
% original code from Stefan Kottwitz
% https://tex.stackexchange.com/a/12551/13304
\newenvironment<>{varblock}[2][.9\textwidth]{%
\setlength{\textwidth}{#1}
\begin{actionenv}#3%
\def\insertblocktitle{#2}%
\par%
\usebeamertemplate{block begin}%
}
{\par%
\usebeamertemplate{block end}%
\end{actionenv}}
\newenvironment{myblock}[1]{\begin{textblock*}{500pt}(#1)}{\end{textblock*}}
% special way to reach the top of the block
\def\newabove(#1){
([yshift=1.5ex]#1.center)
}
\begin{document}
\begin{frame}
\begin{myblock}{0cm,-2.5cm}
\tikzmark{n1}
\begin{varblock}[6cm]{title1}
Hello! :) This is the text of my block. Here I want to say
that the height of the blocks is not so problematic.
\end{varblock}
\end{myblock}
\begin{myblock}{8cm,-2.5cm}
\tikzmark{n2}
\begin{varblock}[6cm]{title2}
This is my very long block with even an equation:
\[\Delta_n=
\begin{cases}
1 \quad q_n>0\\
0 \quad q_n=0
\end{cases}
\]
\end{varblock}
\end{myblock}
% I can leave all blank lines I want
\begin{myblock}{8cm,2cm}
\tikzmark{n3}
\begin{varblock}[6cm]{title3}
Short text
\end{varblock}
\end{myblock}
\begin{myblock}{0cm,2cm}
\tikzmark{n4}
\begin{varblock}[6cm]{title4}
Short text
\end{varblock}
\end{myblock}
\begin{tikzpicture}[remember picture,overlay,-stealth,line width=0.2cm]
\draw (n1.east)--(n2.west);
\draw (n2.south)--\newabove(n3);
\draw (n3.west)--(n4.east);
\draw \newabove(n4)--(n1.south);
\end{tikzpicture}
\end{frame}
\end{document}
请注意,我故意留下了一些空行。经过两次编译运行后,我们得到:
哦.. 区块 1 和 2 有问题。为什么?因为高度不对;使用我们的\shownode
,\showanchor
可以理解原因:
现在请注意,默认值是1.5cm
高度。因此,类似于0.75cm
带有标题和正文一行的块。
在区块 1 中,我们有 4 行+标题,因此粗略地说,我们有标准高度的三倍:0.75cm x 3=2.25cm
。然而,这只是区块,因此要获得整个节点,我们应该再次乘以二。总计:4.5cm
。
现在看第二个块:它只是比块 1 高一点。我猜那是1cm
更高,所以我们把它放上去5.5cm
。
所以我们必须更新:
\begin{myblock}{0cm,-2.5cm}
\tikzmark[minimum width=6cm, minimum height=4.5cm]{n1}
\shownode{n1}
\begin{varblock}[6cm]{title1}
Hello! :) This is the text of my block. Here I want to say
that the height of the blocks is not so problematic.
\end{varblock}
\showanchor{n1}
\end{myblock}
\begin{myblock}{8cm,-2.5cm}
\tikzmark[minimum width=6cm, minimum height=5.5cm]{n2}
\shownode{n2}
\begin{varblock}[6cm]{title2}
This is my very long block with even an equation:
\[\Delta_n=
\begin{cases}
1 \quad q_n>0\\
0 \quad q_n=0
\end{cases}
\]
\end{varblock}
\showanchor{n2}
\end{myblock}
这提供了:
差不多我们完成了。但我对区块 2 仍不满意:它不够精确。我想我们需要0.25cm
更多。因此:
\begin{myblock}{8cm,-2.5cm}
\tikzmark[minimum width=6cm, minimum height=5.75cm]{n2}
\shownode{n2}
\begin{varblock}[6cm]{title2}
This is my very long block with even an equation:
\[\Delta_n=
\begin{cases}
1 \quad q_n>0\\
0 \quad q_n=0
\end{cases}
\]
\end{varblock}
\showanchor{n2}
\end{myblock}
得出:
哦……糟糕。太多了!好吧,我们把它缩短一点5.7cm
。这肯定是正确的。总结一下: