投影机中物体跳跃的问题很常见,(参见避免投影机跳帧)我们时不时在这里看到它(我想这边的“相关”列表会很长!)。对于 TikZ 图片,解决这个问题的一种方法是手动指定边界框。我想把那句话中的“手动”这个词去掉!
这应该不太难实现,我想象的方案将涉及将最终的边界框写入文件,.aux
以便它可以在 tikzpicture 环境启动时使用。
第一个问题:有人已经实现这个了吗?
如果(我怀疑)不是的话,我会喜欢第二个问题是“有人能帮我做吗?”但这不符合网站的精神。因此,以下是我的想法:
- 在每一帧的幻灯片上,tikzpicture 都会保存其边界框。
- 在帧的末尾,tikzpicture 将最大的边界框写入文件
.aux
(请注意,最大的可能不是最后一个)。 - 在后续运行中,边界框的写出方式会告诉 tikzpicture 它的边界框应该是什么,并据此绘制一条
\useasboundingbox
路径(在图片的开始处)。
所以第二个问题,有点开放式,但希望我能回答清楚:上述内容的缺陷是什么。
第三个问题(是的,我在这里确实有点夸大其词):如果有人认为上述内容中有一部分恰巧知道,请将代码放在答案中。我对我的 TeX 技能很有信心,我能够把这些部分拼凑在一起,也可以调整这些部分。所以我不是要求任何人为我编写这个代码,只需帮助我找到所需的部分。
(尽管如果有人做编码...)
这里有一个非常简单的例子来说明我的意思(不过你必须编译它才能看到)。众所周知,地球绕着太阳转。但不是这演示。根据这个演示,宇宙学有点奇怪。
\documentclass{beamer}
\usepackage{tikz}
\begin{document}
\begin{frame}
\begin{tikzpicture}
\foreach \k in {1,...,8}
{
\fill<\k>[orange] (0,0) circle[radius=.5];
\fill<\k>[blue] (\k * 45:3) circle[radius=.2] coordinate (a);
}
\draw (0,0) -- (a);
\end{tikzpicture}
\end{frame}
\end{document}
笔记:上面的例子是一个非常简单的例子,它是不是一个活生生的例子。我不想要一个解决这个特定例子的答案,我正在寻找一个修复系统每一个可能的例子。
答案1
我终于 (!) 有时间实现这个了。它现在是软件包的一部分尺子指南针,因为它看起来对于该包特别有用。
这是我的代码:
\documentclass{beamer}
% \url{http://tex.stackexchange.com/q/18704/86}
\usepackage{tikz}
\newcounter{jumping}
\resetcounteronoverlays{jumping}
\makeatletter
\tikzset{
stop jumping/.style={
execute at end picture={%
\stepcounter{jumping}%
\immediate\write\pgfutil@auxout{%
\noexpand\jump@setbb{\the\value{jumping}}{\noexpand\pgfpoint{\the\pgf@picminx}{\the\pgf@picminy}}{\noexpand\pgfpoint{\the\pgf@picmaxx}{\the\pgf@picmaxy}}
},
\csname jump@\the\value{jumping}@maxbb\endcsname
\path (\the\pgf@x,\the\pgf@y);
\csname jump@\the\value{jumping}@minbb\endcsname
\path (\the\pgf@x,\the\pgf@y);
},
}
}
\def\jump@setbb#1#2#3{%
\@ifundefined{jump@#1@maxbb}{%
\expandafter\gdef\csname jump@#1@maxbb\endcsname{#3}%
}{%
\csname jump@#1@maxbb\endcsname
\pgf@xa=\pgf@x
\pgf@ya=\pgf@y
#3
\pgfmathsetlength\pgf@x{max(\pgf@x,\pgf@xa)}%
\pgfmathsetlength\pgf@y{max(\pgf@y,\pgf@ya)}%
\expandafter\xdef\csname jump@#1@maxbb\endcsname{\noexpand\pgfpoint{\the\pgf@x}{\the\pgf@y}}%
}
\@ifundefined{jump@#1@minbb}{%
\expandafter\gdef\csname jump@#1@minbb\endcsname{#2}%
}{%
\csname jump@#1@minbb\endcsname
\pgf@xa=\pgf@x
\pgf@ya=\pgf@y
#2
\pgfmathsetlength\pgf@x{min(\pgf@x,\pgf@xa)}%
\pgfmathsetlength\pgf@y{min(\pgf@y,\pgf@ya)}%
\expandafter\xdef\csname jump@#1@minbb\endcsname{\noexpand\pgfpoint{\the\pgf@x}{\the\pgf@y}}%
}
}
\makeatother
\begin{document}
\begin{frame}
\begin{tikzpicture}[stop jumping]
\foreach \k in {1,...,7}
{
\fill<\k>[orange] (0,0) circle[radius=.5];
\fill<\k>[blue] (\k * 45:\k) circle[radius=.2] coordinate (a);
}
\draw (0,0) -- (a);
\end{tikzpicture}
\end{frame}
\end{document}
它的工作原理如下。我们有一个全局计数器,jumping
它在覆盖下是稳定的。也就是说,beamer
通过多次重新处理代码来实现覆盖。通常,每次执行都会导致计数器递增,但只要beamer
被告知,它就可以考虑到这一点并在每次运行时重置计数器。这样做的结果是,这个计数器可以用来标记(非技术意义上的) ,tikzpicture
这样不同幻灯片上图片的不同副本就会获得相同的标签。
我们使用该标签将图片每个版本的边界框保存到文件中aux
。我们在图片末尾执行此操作以确保获得正确的边界框。aux
下次读取文件时,它会计算此图片各个边界框的最大和最小延伸,并将其保存为 PGF 点。回到图片中,我们使用这些计算出的点将边界框调整到最大程度。
进一步说明:
我们保存每张图片的边界框前将其与保存的最大值进行比较。这意味着最大值始终是根据图片的实际大小计算的,而不考虑任何先前的最大值。这意味着它对图片的变化很敏感,这是理所当然的。
通过在图片中放置坐标来调整边界框。这是为了确保图片不会在框内跳来跳去。只需重置边界框长度即可确保图片在每张幻灯片上占用相同的空间,但图片不会停留在框中的同一位置。
答案2
这\overprint
,\onslide
二重奏似乎也能完成这个工作:
\documentclass{beamer}
\usepackage{tikz}
\begin{document}
\begin{frame}
\begin{overprint}
\begin{tikzpicture}
\foreach \k in {1,...,8}
{
\onslide<\k>{\fill[orange] (0,0) circle[radius=.5];
\fill[blue] (\k * 45:3) circle[radius=.2];}
}
\end{tikzpicture}
\end{overprint}
\end{frame}
\end{document}
编辑:事实上,在这个特定的例子中,没有必要使用overprint
。
答案3
此解决方案已更新在另一篇文章中。
Andrew 的 MWE 的一个特殊性是元素的位置在每张幻灯片上都会发生变化,这确实使计算最终的边界框变得困难——而他自己的答案完美地涵盖了这一点。
然而,在许多情况下,目标只是某种分段揭示投影仪图形的元素。在这种情况下,我已停止使用命令本身的叠加规范(\node<...>
,\fill<...>
),而是总是绘制所有元素,但隐藏。为了指定可见性,我使用visible on=<...>
TikZ 样式,如下所示:
\documentclass{beamer}
\usepackage{tikz}
% Keys to support piece-wise uncovering of elements in TikZ pictures:
% \node[visible on=<2->](foo){Foo}
%
% Internally works by setting opacity=0 when invisible, which has the
% adavantage (compared to \node<2->(foo){Foo} that the node is always there, hence
% always consumes space that (foo) is always available.
%
% The actual command that implements the invisibility can be overriden
% by altering the style invisible. For instance \tikzsset{invisible/.style={opacity=0.2}}
% would dim the "invisible" parts. Alternatively, the color might be set to white, if the
% output driver does not support transparencies (e.g., PS)
%
\tikzset{
invisible/.style={opacity=0},
alt/.code args={<#1>#2#3}{%
\alt<#1>{\pgfkeysalso{#2}}{\pgfkeysalso{#3}}
},
visible on/.style={alt={#1{}{invisible}}},
}
\begin{document}
\begin{frame}{Uncovering TikZ elements piecewise (1)}
Invisble –– but already taking space:
\par
\bigskip
\fbox{ % to visualize bounding box
\begin{tikzpicture}[every node/.style={fill=red!30, draw=red}]
\node{Foo}
child[visible on=<2->]{node {Bar}}
child[visible on=<3->]{node {Baz}}
;
\end{tikzpicture}
}
\end{frame}
\begin{frame}{Uncovering TikZ elements piecewise (2)}
% Change "invsibility" style to dimmed
\tikzset{invisible/.style={opacity=0.3}}
Dimmed –– and obviously taking space:
\par
\bigskip
\fbox{ % to visualize bounding box
\begin{tikzpicture}[every node/.style={fill=red!30, draw=red}]
\node{Foo}
child[visible on=<2->]{node {Bar}}
child[visible on=<3->]{node {Baz}}
;
\end{tikzpicture}
}
\end{frame}
\end{document}
visible on=< ovspec >
通过将样式应用于invisible
不包含在ovspec。默认实现invisible
只是设置opacity=0
;但是,如示例中所示,这可以轻松更改,以便轻松安装其他类型的“不可见性”(调光、灰色填充,...)。
笔记:如果ovspec本身包含逗号,它或完整的参数必须放在花括号内(如 invisible on=<{1,3-4,8}>
或 `visible on={<1,3-4,8>}),以免混淆 pgfkeys 解析器。
这种方法(除了在我看来可读性更好之外)还有另一个优点:所有命名元素(尤其是节点)始终存在,因此您可以使用它们进行坐标计算,即使在幻灯片上它们不可见。
答案4
这几乎不能算是一个答案,但我们还是想说:
没问题。我认为你可以
execute at end picture
在这里使用密钥。我能想到的唯一缺陷是幻灯片编号出奇地难以获得。请参阅我的答案:LaTeX Beamer:如何在使用覆盖时获取不同的页码?。由于 beamer 扩展帧代码的方式不标准,我认为在帧末尾执行代码很困难。但您可以在第 1 步中解决这个问题,方法是在第一张幻灯片中将边界框线写入辅助文件,然后每次边界框都会变大。然后,当读取辅助文件时,最后一个边界框线是最大的。
这应该也不是问题。我会试试这个
execute at begin picture
钥匙。