2

In beamer, the standard overlay specification seems to be onslide. In below code, \item<2-> reserves space for the second item on all slides. Inside a tikz environment, however, the standard overlay specification is only, which does not reserve space and causes these "jumping" or "dancing" slides. Is there a way to change the standard overlay specification to onslide so that the rest of the slide does not shift between slides 2 and 3?

I know I could use an overlayarea with sufficiently large height or, equivalently, draw an invisible rectangle on slides 1-2, but that requires manual effort that can accumulate to be quite costly in a lifetime of creating lecture slides. The overlay option for the tikzpicture has the desired effect only if there is no other content on the slide. I could use \onslide<3->{\draw (0, 0) rectangle (-1, -1);} instead, which has the desired effect, but is rather ugly. Is there no way to change the default behavior of the \draw and other beamer commands so that \draw<> ... produces \onslide<>{\draw ...}?

\documentclass{beamer}
\usepackage{tikz}

\begin{document}

\begin{frame}
\begin{center}
\begin{tikzpicture}
\draw (0, 0) rectangle (1, 1);
\draw<3-> (0, 0) rectangle (-1, -1);
\end{tikzpicture}
\end{center}

\begin{itemize}
\item Some text
\item<2-> More text
\end{itemize}
\end{frame}

\end{document}
2
  • Does this answer, to a similar question help you at all: tex.stackexchange.com/a/55849/118712 Apparently it resulted in a package dedicated to doing what you seem to require: ctan.org/pkg/aobs-tikz
    – Markus G.
    Commented Jun 2, 2021 at 8:41
  • Not quite. I suppose I am not asking how to achieve the effect. I know there are many ways that can do that, including many that I did not list in my post. I am simply wondering if there is a way to redefine the standard behavior in TikZ because that would be the cleanest solution of all. Commented Jun 2, 2021 at 14:10

2 Answers 2

1

An easy solution is to use \path to replace the missing \draw features. You can also use [opacity=0] for nodes or even an entire scope.

\documentclass{beamer}
\usepackage{tikz}

\begin{document}

\begin{frame}
\begin{center}
\begin{tikzpicture}
\draw (0, 0) rectangle (1, 1);
\draw<3-> (0, 0) rectangle (-1, -1);
\path (0, 0) rectangle (-1, -1);%***** added line *****
\end{tikzpicture}
\end{center}

\begin{itemize}
\item Some text
\item<2-> More text
\end{itemize}
\end{frame}

\end{document}
3
  • I was not looking for different ways of achieving the same result. Mostly, I was wondering why onslide is not the standard behavior in tikz and whether there is a way to patch that. It seems to be an odd choice to me since Till Tantau created both tikz and beamer, and \onslide is the standard for beamer. Even though I am not looking for alternate ways to recreate the effect, this approach will not work if the drawn path is, say, very thick. Also, duplication of code is required. I'd say using \onslide explicitly or the oabs-tikz package are superior. Commented Jun 2, 2021 at 14:18
  • I suspect that oabs-tikz does automatically the same thing: running the code twice and saving the bounding box from the invisible run. Commented Jun 2, 2021 at 20:01
  • It's drawn with opacity 0 so stroke widths are accounted for. Commented Jun 3, 2021 at 5:39
0

I figured it out. Posting this as an answer in the hope that others will find it useful. TikZ resets the \draw and similar commands to \path[draw] in the beginning of every tikzpicture to prevent the user from accidentally overwriting it. This allows us to simply redefine \draw and others within an every picture/.code, checking whether there is an overlay specification with \futurelet and, if there is one, parsing it with \def. I think this solution should be quite robust and quite quick.

\documentclass{beamer}
\usepackage{tikz}

\makeatletter
\newcommand{\fixtikzpath}[1]{
    \expandafter\def\csname #1@standard@btkz\endcsname{\path[#1]}
    \expandafter\def\csname #1@gobble@btkz\endcsname<##1>##2;{
        \def\overlay@btkz{<##1>}
        \expandafter\onslide\overlay@btkz{\path[#1] ##2;}
    }
    \expandafter\def\csname #1@check@btkz\endcsname{
        \ifx\next@btkz<
            \expandafter\expandafter\csname #1@gobble@btkz\endcsname
        \else
            \expandafter\expandafter\csname #1@standard@btkz\endcsname
        \fi
    }
    \expandafter\def\csname #1\endcsname{\expandafter\futurelet\expandafter\next@btkz\csname #1@check@btkz\endcsname}
}
\newcommand{\fixtikznode}{
    \def\node@standard@btkz{\tikz@path@overlay{node}}
    \def\node@gobble@btkz<##1>##2;{
        \def\overlay@btkz{<##1>}
        \expandafter\onslide\overlay@btkz{\tikz@path@overlay{node} ##2;}
    }
    \def\node@check@btkz{
        \ifx\next@btkz<
            \expandafter\node@gobble@btkz
        \else
            \expandafter\node@standard@btkz
        \fi
    }
    \def\node{\futurelet\next@btkz\node@check@btkz}
}
\tikzset{every picture/.code={
    \fixtikzpath{draw}
    \fixtikzpath{fill}
    \fixtikzpath{clip}
    \fixtikznode
}}
\makeatother

\begin{document}
\begin{frame}
\begin{center}
\begin{tikzpicture}
\draw (0, 0) rectangle (1, 1);
\draw<2-> (0, 0) rectangle (1.2, -1.2);
\fill<3-> (0, 0) rectangle (-1.4, -1.4);
\node<4-> at (-1.4, 1.4) {It works};
\end{tikzpicture}
\end{center}
\end{frame}
\end{document}

enter image description hereenter image description here enter image description hereenter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .