Current File : //usr/share/texlive/texmf-dist/tex/generic/pgf/modules/pgfmoduleanimations.code.tex |
% Copyright 2019 by Till Tantau
%
% This file may be distributed and/or modified
%
% 1. under the LaTeX Project Public License and/or
% 2. under the GNU Public License.
%
% See the file doc/generic/pgf/licenses/LICENSE for more details.
\ProvidesFileRCS{pgfmoduleanimations.code.tex}
% We need the animation system abstraction:
\input pgfsysanimations.code.tex
% Animate an attribute over time
%
% #1 = an attribute
% #2 = configuration keys
%
% This command adds animation commands for the attribute given in #1
% of some future object to the current graphic scope. For instance,
% when #1 is "fill opacity" then the fill opacity of the object will
% change over time. The object to which the command refers is
% specified using a special key in #2.
%
% The keys in #2 specify how the changes occur over time. There are a
% number of keys that have an effect on the animation "as a whole"
% (like "repeats") while the most central key is the entry key. This
% key takes two parameters: a time and a value. It specifies that at
% the given time the attribute should have the specified value. The
% times must be given in ascending order. Between the times given in
% this way, the values of the attribute will be interpolated; you can
% influence the details of how this interpolation is done using
% additional keys.
%
% The keys in #2 are given in key-value syntax and can be given in any
% order, except that the entry keys must be given in order of
% ascending times.
%
% The syntax of the second parameter of the entry key depends on
% #1. Currently, these are:
%
% Attribute Value Type
% ---------------------------------------
% fill opacity scalar
% stroke opacity scalar
% opacity scalar
% visible boolean
% line width dimension
% fill color
% stroke color
% motion motion
% translate point
% scale scaling
% rotate scalar
% xskew scalar
% yskew scalar
% path path
% softpath softpath
% view viewbox
% dash phase dimension
% dash pattern dashpattern
% none any
%
% Example:
%
% \pgfanimateattribute{fill opacity}{entry={0s}{1}, entry={2s}{0}}
\def\pgfanimateattribute#1#2{%
\pgfanimateattributecode{#1}{\pgfkeys{/pgf/animation/.cd,#2}}%
}%
% Variant of \pgfanimateattribute
%
% #1 = attribute
% #2 = code
%
% Description:
%
% A version of \pgfanimateattribute where instead of keys #2 you
% provide a code #2 that calls the animation keys itself.
\def\pgfanimateattributecode#1#2{%
{%
\pgfkeys{/pgf/@animation attributes/.cd,#1}%
#2%
\csname pgf@animation@check@\pgf@animation@attribute\endcsname%
\pgfsysanimate{\pgf@animation@attribute}%
}%
}%
% Create a time snapshot
%
% #1 = a time
%
% Description:
%
% This command should be called in a scope prior to all calls of
% animation commands in that scope. When called, all animations will
% be "intercepted" and, instead of creating the animation code, normal
% code will be generated that shows the state of the animation at the
% specified "moment" #1. Since no animation code is involved, this
% works with all drivers.
%
% The command \pgfsnapshotafter works the same way as \pgfsnapshot,
% only the timing is slightly different: Conceptually, #1 is
% interpreted as "#1+epsilon". For instance, if there are two values
% specified for the time #1, then \pgfsnapshot will use the first
% while \pgfsnapshotafter will use the second. Likewise, when an
% animation ends at time #1, \pgfsnapshot will still us the
% animation's value, while \pgfsnapshotafter will not.
%
% Example:
%
% {
% \pgfsnapshot{1.2s}
% \pgfanimateattribute{fill opacity}{entry={0s}{1}, entry={2s}{0}}
% \fill (0,0) rectangle (1,1);
% }
\def\pgfsnapshot#1{\pgfparsetime{#1}\expandafter\pgfsysanimsnapshot\expandafter{\pgftimeresult}}%
\def\pgfsnapshotafter#1{\pgfparsetime{#1}\expandafter\pgfsysanimsnapshotafter\expandafter{\pgftimeresult}}%
% The animation attributes
\pgfkeys{/pgf/@animation attributes/.cd,
visible/.code=\pgf@animate@attr{visibility}{mapped}\def\pgf@anim@map@true{visible}\def\pgf@anim@map@false{hidden},
stage/.code=\pgf@animate@attr{visibility}{mapped}\def\pgf@anim@map@true{visible}\def\pgf@anim@map@false{hidden}\pgfsysanimkeybase\pgfsysanimvaltext{hidden},
opacity/.code=\pgf@animate@attr{opacity}{scalar},
fill opacity/.code=\pgf@animate@attr{fillopacity}{scalar},
draw opacity/.code=\pgf@animate@attr{strokeopacity}{scalar},
stroke opacity/.style=draw opacity,
line width/.code=\pgf@animate@attr{linewidth}{dimension},
fill/.code=\pgf@animate@attr{fillcolor}{color},
draw/.code=\pgf@animate@attr{strokecolor}{color},
color/.code=\pgf@animate@attr{color}{color},
stroke/.style=draw,
motion/.code=\pgf@animate@attr{motion}{scalar},
translate/.code=\pgf@animate@attr{translate}{point},
scale/.code=\pgf@animate@attr{scale}{scaling},
rotate/.code=\pgf@animate@attr{rotate}{scalar},
xskew/.code=\pgf@animate@attr{skewx}{scalar},
yskew/.code=\pgf@animate@attr{skewy}{scalar},
skew x/.style=xskew,
skew y/.style=yskew,
path/.code=\pgf@animate@attr{path}{path},
softpath/.code=\pgf@animate@attr{path}{softpath},
view/.code=\pgf@animate@attr{viewbox}{viewbox},
dash/.code=\pgf@animate@attr{dash}{dash},
none/.code=\pgf@animate@attr{none}{none},
}%
\def\pgf@animate@attr#1#2{%
\def\pgf@animation@attribute{#1}%
\expandafter\let\expandafter\pgfanim@type@parser\csname pgfanim@parse@type@#2\endcsname%
}%
% The time parser
%
% #1 = a time
%
% This macro parses the time in #1, but adds some support for times:
%
% 1) The postfix operator "s" is added, which has no effect.
% 2) The postfix operator "ms" is added, which divides a number by
% 1000, so "2ms" equals "0.002".
% 3) The postfix operator "min" is added, which multiplies a number by
% 60.
% 4) The postfix operator "h" is added, which multiplies a number by
% 3600.
% 5) The infix operator ":" is redefined, so that it multiplies its
% first argument by 60 and adds the second. This implies that
% "1:20" equals "80" and "01:00:00" equals "3600".
% 6) The parsing of octal numbers is switched off to allow things like
% "01:08" for 68s.
\def\pgfparsetime#1{%
\begingroup%
\pgfmathdeclareoperator{s}{@seconds}{1}{postfix}{600}%
\pgfmathdeclareoperator{m}{m@encountered}{1}{postfix}{600}%
\pgfmathdeclareoperator{i}{i@encountered}{1}{postfix}{600}%
\pgfmathdeclareoperator{n}{@minutes}{1}{postfix}{600}%
\pgfmathdeclareoperator{h}{@hours}{1}{postfix}{600}%
\pgfmathdeclareoperator{:}{time@colon}{2}{infix}{50}%
\pgfmath@octalparsingfalse%
\pgfmathparse{#1}%
\expandafter\endgroup%
\expandafter\def\expandafter\pgftimeresult\expandafter{\pgfmathresult}%
}%
\newif\ifpgfanim@m@encountered
\newif\ifpgfanim@i@encountered
\pgfmathdeclarefunction{@seconds}{1}{%
\begingroup%
\expandafter\pgfmath@x#1pt\relax%
\ifpgfanim@m@encountered%
\divide\pgfmath@x by1000\relax%
\fi%
\global\pgfanim@m@encounteredfalse%
\pgfmath@returnone\pgfmath@x%
\endgroup%
}%
\pgfmathdeclarefunction{m@encountered}{1}{%
\global\pgfanim@m@encounteredtrue%
\begingroup%
\expandafter\pgfmath@x#1pt\relax%
\pgfmath@returnone\pgfmath@x%
\endgroup%
}%
\pgfmathdeclarefunction{i@encountered}{1}{%
\ifpgfanim@m@encountered%
\global\pgfanim@m@encounteredfalse%
\global\pgfanim@i@encounteredtrue%
\else%
\pgfmath@error{Unexpected i}{}%
\fi%
\begingroup%
\expandafter\pgfmath@x#1pt\relax%
\pgfmath@returnone\pgfmath@x%
\endgroup%
}%
\pgfmathdeclarefunction{@minutes}{1}{%
\ifpgfanim@i@encountered%
\global\pgfanim@i@encounteredfalse%
\else%
\pgfmath@error{Unexpected n}{}%
\fi%
\begingroup%
\expandafter\pgfmath@x#1pt\relax%
\pgfmath@x60\pgfmath@x\relax%
\pgfmath@returnone\pgfmath@x%
\endgroup%
}%
\pgfmathdeclarefunction{@hours}{1}{%
\begingroup%
\expandafter\pgfmath@x#1pt\relax%
\pgfmath@x3600\pgfmath@x\relax%
\pgfmath@returnone\pgfmath@x%
\endgroup%
}%
\pgfmathdeclarefunction{time@colon}{2}{%
\begingroup%
\pgfmath@x=#1pt\relax%
\pgfmath@x=60\pgfmath@x\relax%
\pgfmath@y=#2pt\relax%
\advance\pgfmath@x by\pgfmath@y%
\pgfmath@returnone\pgfmath@x%
\endgroup%
}%
% Sets general animation attributes
%
% #1 = key-value pairs that are executed for the path /pgf/animation/
\def\pgfanimationset{\pgfqkeys{/pgf/animation}}%
% Sets the target animation scope that should be animated.
%
% #1 = A name that will be used with an idscope.
%
% Example:
%
% \pgfanimateattribute{fill opacity}{whom=some scope, entry={0s}{1}, entry={1s}{0}}
% \begin{scope}[name=some scope]
% \draw (0,0) -- (1,1);
% \draw (1,0) -- (2,1);
% \end{scope}
\pgfanimationset{
whom/.code={%
\pgf@anim@decomp{#1}%
\pgfidrefnextuse\pgf@anim@id\pgf@anim@id@name%
\expandafter\expandafter\expandafter\pgfsysanimkeywhom\expandafter\expandafter\expandafter{\expandafter\pgf@anim@id\expandafter}\expandafter{\pgf@anim@type}%
\let\pgf@anim@whom@id\pgf@anim@id%
\let\pgf@anim@whom@type\pgf@anim@type%
}
}%
\def\pgf@anim@decomp#1{%
\edef\pgf@temp{#1}%
\expandafter\pgfutil@in@\expandafter.\expandafter{\pgf@temp}%
\ifpgfutil@in@%
\expandafter\pgf@anim@decomp@\pgf@temp\pgf@stop%
\else%
\expandafter\pgf@anim@decomp@\pgf@temp.\pgf@stop%
\fi%
}%
\def\pgf@anim@decomp@#1.#2\pgf@stop{%
\def\pgf@anim@id@name{#1}%
\def\pgf@anim@type{#2}%
}%
% Assigns a name to this animation so that it can be used as an event
% id in another animation
%
% #1 = A name
%
% The name "previous" is special and always refers to the most recent
% animation before the animation currently being constructed.
%
% Example:
%
% \pgfanimateattribute{fill opacity}{name=anim 1, entry={0s}{1}, entry={1s}{0}}
% \pgfanimateattribute{fill opacity}{begin on={end,of=anim 1}, entry={0s}{1}, entry={1s}{0}}
\pgfanimationset{
name/.code=\pgfuseid{#1},
}%
% Configures whether an animation can be restarted
%
% Some animations can restart when certain events take place. This key
% configures this. Setting it to
%
% "true" allows a restart at any time,
% "false" does not allow a restart,
% "when not active" allows a restart only, when the element is not
% active.
%
% Example:
%
% \pgfanimateattribute{fill opacity}{entry={0s}{1}, entry={1s}{0}, restart=false}
\pgfanimationset{
restart/.is choice,
restart/.default=true,
restart/true/.code=\pgfsysanimkeyrestartalways,
restart/false/.code=\pgfsysanimkeyrestartnever,
restart/never/.code=\pgfsysanimkeyrestartnever,
restart/when not active/.code=\pgfsysanimkeyrestartwhennotactive,
}%
% Sets the number times an animation should repeat
%
% #1 = A string of the following form:
%
% [<empty> | <number> | for <time>] ["accumulating"]
%
% When empty (the default value) the animation repeats forever.
%
% When a <number> is provided, the animation will repeat <number>
% times, which need not be an integer.
%
% When a <time> is given, the repeating will stop after this much time.
%
% When the optional "accumulating" is specified, the repeat
% accumulates, otherwise each repeat begins with the original start
% value.
%
% Example:
%
% \pgfanimateattribute{fill opacity}{repeats, entry={0s}{1}, entry={6s}{0}}
% \pgfanimateattribute{fill opacity}{repeats=2, entry={0s}{1}, entry={6s}{0}}
% \pgfanimateattribute{fill opacity}{repeats=2 accumulating, entry={0s}{1}, entry={6s}{0}}
% \pgfanimateattribute{fill opacity}{repeats=for 15s, entry={0s}{1}, entry={6s}{0}}
\pgfanimationset{
repeats/.code={%
\pgfutil@in@{accumulating\pgf@stop}{#1\pgf@stop}%
\ifpgfutil@in@%
\pgfsysanimkeyaccumulate%
\pgfanim@parse@acc#1\pgf@stop%
\else%
\pgfsysanimkeynoaccumulate%
\pgfanim@parse@noacc{#1}%
\fi%
},
repeats/.default=,
repeat/.style={repeats={#1}},
repeat/.default=,
}%
\def\pgfanim@parse@acc#1accumulating\pgf@stop{%
\pgfanim@parse@noacc{#1}%
}%
\def\pgfanim@parse@noacc#1{%
\pgfutil@in@{\pgf@stop for}{\pgf@stop#1}%
\ifpgfutil@in@%
\pgfanim@parse@for#1\pgf@stop%
\else%
\def\pgf@temp{#1}%
\ifx\pgf@temp\pgfutil@empty%
\pgfsysanimkeyrepeatindefinite%
\else%
\pgfmathparse{#1}%
\expandafter\pgfsysanimkeyrepeat\expandafter{\pgfmathresult}%
\fi%
\fi%
}%
\def\pgfanim@parse@for for#1\pgf@stop{\pgfparsetime{#1}\expandafter\pgfsysanimkeyrepeatdur\expandafter{\pgftimeresult}}%
% Specifies that an animation should begin or end at a certain time
% (relative to the current context). The "begin..." options may be
% used multiple times and their effects accumulate, likewise for the
% "end..." options.
%
% #1 = A time
%
% Example:
%
% \pgfanimateattribute{fill opacity}{begin=2s, end=2.5s, entry={0s}{1}, entry={1s}{0}}
\pgfanimationset{
begin/.code=\pgfparsetime{#1}\expandafter\pgfsysanimkeyoffset\expandafter{\pgftimeresult}{begin},
end/.code=\pgfparsetime{#1}\expandafter\pgfsysanimkeyoffset\expandafter{\pgftimeresult}{end},
}%
% Specifies that an animation should begin (or end) when a certain
% event takes place.
%
% #1 = A list of key-value pairs.
%
% The following keys are allowed:
%
% event=some event : The begin / end is triggered by that event. The
% list of allowed events is defined in the SVG
% standard.
% of=some name : The event does not refer to the current group,
% but to the object named "some name", which must
% previously have been named \pgfuseid. If some
% name contains a period, the part before the
% period must be the name of the id, the part
% following it the type of the id.
% key=some key : The trigger is some key being pressed
% repeat=number : The trigger is that an animation has been
% repeated number times.
% delay=time : A delay, may be negative.
%
% These keys are executed with the path prefix /pgf/animation/events.
%
% Some of them are predefined:
%
% "click" is a shorthand for "event=click"
% "focus in" is a shorthand for "event=focusin"
% "focus out" is a shorthand for "event=focusout"
% "activate" is a shorthand for "event=activate"
% "mouse down" is a shorthand for "event=mousedown"
% "mouse up" is a shorthand for "event=mouseup"
% "mouse over" is a shorthand for "event=mouseover"
% "mouse move" is a shorthand for "event=mousemove"
% "mouse out" is a shorthand for "event=mouseout"
% "begin" is a shorthand for "event=begin"
% "end" is a shorthand for "event=end"
%
% Example:
%
% % Begin after 5s or when clicked:
% \pgfanimateattribute{fill opacity}{begin=5s, begin on=click, entry={0s}{1}, entry={1s}{0}}
%
% % Begin, when an object named "button" is clicked
% \pgfanimateattribute{fill opacity}{begin on={click, of=button}, entry={0s}{1}, entry={1s}{0}, name=another animation}
%
% % Begin 1s after some other animation ends
% \pgfanimateattribute{fill opacity}{begin on={end, of=another animation, delay=1s}, entry={0s}{1}, entry={1s}{0}}
\pgfanimationset{
begin on/.code={\pgfanim@make@event{#1}{begin}},%
end on/.code={\pgfanim@make@event{#1}{end}},
}%
\def\pgfanim@make@event#1#2{%
\let\pgfanim@event@event\pgfutil@empty%
\let\pgf@anim@id\pgfutil@empty%
\let\pgf@anim@type\pgfutil@empty%
\let\pgfanim@event@key\pgfutil@empty%
\let\pgfanim@event@repeat\pgfutil@empty%
\let\pgfanim@event@delay\pgfutil@empty%
\pgfkeys{/pgf/animation/events/.cd,#1}%
\ifx\pgfanim@event@key\pgfutil@empty%
\ifx\pgfanim@event@repeat\pgfutil@empty%
\ifx\pgfanim@event@event\pgfutil@empty%
\pgferror{No event specified}%
\else%
\pgfsysanimkeyevent{\pgf@anim@id}{\pgf@anim@type}{\pgfanim@event@event}{\pgfanim@event@delay}{#2}%
\fi%
\else%
\pgfsysanimkeyrepeatevent{\pgf@anim@id}{\pgf@anim@type}{\pgfanim@event@repeat}{\pgfanim@event@delay}{#2}%
\fi%
\else%
\pgfsysanimkeyaccesskey{\pgfanim@event@key}{\pgfanim@event@delay}{#2}%
\fi%
}%
\pgfkeys{/pgf/animation/events/.cd,
event/.store in=\pgfanim@event@event,
of/.code={%
\pgf@anim@decomp{#1}%
\pgfidrefprevuse\pgf@anim@id\pgf@anim@id@name%
\ifx\pgf@anim@id\pgfutil@empty%
\pgferror{Unknown object/node name '\pgf@anim@id@name'. Did you
mean 'of next=\pgf@anim@id@name'?}%
\fi%
},
of next/.code={%
\pgf@anim@decomp{#1}%
\pgfidrefnextuse\pgf@anim@id\pgf@anim@id@name%
},
of id/.code=\def\pgf@anim@id{#1},
key/.store in=\pgfanim@event@key,
repeat/.code=\pgfmathparse{#1}\let\pgfanim@event@repeat\pgfmathresult,
delay/.code=\pgfparsetime{#1}\let\pgfanim@event@delay\pgftimeresult,
click/.style={event=click},
focus in/.style={event=focusin},
focus out/.style={event=focusout},
mouse down/.style={event=mousedown},
mouse up/.style={event=mouseup},
mouse over/.style={event=mouseover},
mouse move/.style={event=mousemove},
mouse out/.style={event=mouseout},
begin/.style={event=begin},
end/.style={event=end},
}%
% Specifies the timeline start for a snapshot
%
% #1 = a time
%
% Description:
%
% What a snapshot is taken of an animation (using \pgfsnapshot), all
% animations normally start at time 0s. When this key is used, the
% animation's timeline start is considered to be at moment #1
% instead.
\pgfanimationset{
begin snapshot/.code=
\pgfparsetime{#1}\expandafter\pgfsysanimkeysnapshotstart\expandafter{\pgftimeresult}
}%
% Specifies the origin for transforming animations
%
% #1 = a pgf point
%
% Specifies the origin of transformations (for instance, a rotate will
% rotate around this point).
%
% Example:
%
% \pgfanimateattribute{rotate}{entry={0s}{0}, entry={1s}{90}, origin=\pgfpoint{1cm}{1cm}}
\pgfanimationset{
origin/.code={%
\pgf@process{#1}%
\edef\pgf@marshal{%
\noexpand\pgfsysanimkeycanvastransform%
{\noexpand\pgftransformshift{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}{\noexpand\pgflowlevelsynccm}}%
{\noexpand\pgftransforminvert\noexpand\pgflowlevelsynccm}%
\noexpand\pgf@anim@save@transform{\noexpand\pgftransformshift{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}}%
}%
\pgf@marshal%
},
}%
\pgfsysanimkeycanvastransform{{\pgflowlevelsynccm}}{\pgftransforminvert\pgflowlevelsynccm}%
% Specifies the transforming for the animation coordinate system
%
% #1 = code that changes the pgf coordinate system
%
% Specifies an additional transformation of the coordinate system for
% animations.
%
% Example:
%
% \pgfanimateattribute{shift}{entry={0s}{\pgfpointorigin}, entry={1s}{\pgfpoint{1cm}{0cm}}, transform=\pgftransformrotate{30}}
\pgfanimationset{
transform/.code={%
\pgfsysanimkeycanvastransform{#1{\pgflowlevelsynccm}}{\pgftransforminvert\pgflowlevelsynccm}%
\pgf@anim@save@transform{#1}%
},
}%
% Specifies a motion path.
%
% #1 = pgf commands for constructing a path
%
% Use this key to specify a motion path for the motion attribute. The
% values of the "entry" key specify fractions along this path.
%
% Example:
%
% \pgfanimateattribute{motion}{
% entry={0s}{0}, entry={1s}{1},
% along=\pgfpathmoveto{\pgfpointorigin} \pgfpathlineto{\pgfpoint{1cm}{1cm}}
% }
\pgfanimationset{
along/.code=%
{%
\pgfsyssoftpath@getcurrentpath\pgfanim@save@path%
\pgfsyssoftpath@setcurrentpath\pgfutil@empty%
#1%
\pgfsyssoftpath@getcurrentpath\pgfanim@the@path%
\global\let\pgfanim@the@path\pgfanim@the@path%
\pgfsyssoftpath@setcurrentpath\pgfanim@save@path%
}%
\expandafter\pgf@anim@protocol@path@size\pgfanim@the@path\pgf@stop%
\expandafter\pgfsysanimkeymovealong\expandafter{\pgfanim@the@path}%
}%
% Specifies a motion soft path.
%
% #1 = a pgf soft path (result of calling \pgfsyssoftpath@getcurrentpath)
%
% Use this key to specify a motion path for the motion attribute when
% a softpath has already been constructed.
%
% Example:
%
% \pgfanimateattribute{motion}{entry={0s}{0}, entry={1s}{1},
% along softpath=\pgfsyssoftpath@movetotoken {0pt}{0pt}\pgfsyssoftpath@linetotoken {10pt}{10pt}}
\pgfanimationset{
along softpath/.code=%
\pgf@anim@protocol@path@size#1\pgf@stop%
\pgfsysanimkeymovealong{#1}%
}%
\def\pgf@anim@protocol@path@size{%
\pgfutil@ifnextchar\pgf@stop\relax\pgf@anim@protocol@path@size@%
}%
\def\pgf@anim@protocol@path@size@#1#2#3{%
\pgf@protocolanimsizes@direct{#2}{#3}%
\pgf@anim@protocol@path@size%
}%
% Configures whether the motion is rotated along the path.
%
% Example:
%
% \pgfanimateattribute{motion}{rotate along, entry={0s}{0}, entry={1s}{1},
% along=\pgfpathmoveto{\pgfpointorigin} \pgfpathlineto{\pgfpoint{1cm}{1cm}}}
\pgfanimationset{
rotate along/.is choice,
rotate along/.default=true,
rotate along/true/.code=\pgfsysanimkeyrotatealong,
rotate along/false/.code=\pgfsysanimkeynorotatealong,
}%
% Specifies an entry
%
% #1 = A time. This time will be parsed using \pgfparsetime
% #2 = A value. The format of this value depends on the current type
% of the animation attribute. (So for an animation of the "fill
% opacity", #1 must be a scalar value, for an animation of the "fill"
% color, #1 must be a color, and so on.)
% If #2 is the special text "current value", then the current
% value will be used. For SVG, this is allowed only when exactly
% two entries are specified and this special value is used for
% the first one.
%
% Example:
%
% \pgfanimateattribute{fill opacity}{entry={0s}{0}, entry={1s}{1}}
\pgfanimationset{entry/.code 2 args=\pgf@anim@entry{#1}{#2}}%
\def\pgf@anim@entry#1#2{%
\pgf@anim@entry@giventrue%
\pgfparsetime{#1}%
\edef\pgf@marshal{\noexpand\pgfsysanimkeytime{\pgftimeresult}\pgf@anim@entry@spline\pgf@anim@exit@spline}%
\pgf@marshal%
\def\pgf@temp{#2}%
\ifx\pgf@temp\pgf@special@current@text%
\pgfsysanimvalcurrent%
\else%
\pgfanim@type@parser{#2}%
\fi%
}%
\def\pgf@special@current@text{current value}%
\newif\ifpgf@anim@entry@given
% Specifies a base value
%
% #1 = A value. The format is as for the entry key.
%
% Description:
%
% Will set the "base" value of the animation, which is a value that is
% used when the animation is not active.
%
% Example:
%
% \pgfanimateattribute{fill opacity}{base = 0.5, entry={0s}{0.5}, entry={1s}{1}}
\pgfanimationset{base/.code=\pgf@anim@base{#1}}%
\def\pgf@anim@base#1{%
\pgfsysanimkeybase%
\pgfanim@type@parser{#1}%
}%
% Specifies that there is an entry "at infinity".
%
% When an animation ends, its "effect" can either persist or it can be
% removed. Setting "freeze at end" to true will cause it to persist,
% otherwise it will be removed.
%
% Example:
%
% \pgfanimateattribute{fill opacity}{entry={0s}{1}, entry={1s}{0}, freeze at end}
\pgfanimationset{
freeze at end/.is choice,
freeze at end/.default=true,
freeze at end/true/.code=\pgfsysanimkeyfreezeatend,
freeze at end/false/.code=\pgfsysanimkeyremoveatend,
}%
% Specifies an entry or exit spline control
%
% #1 = time fraction
% #2 = attribute fraction
%
% Description:
%
% Suppose that an animation is supposed to interpolate a attribute's
% value between the two values "50" and "100" over a time of 10s. The
% simplest way of doing so is to do a linear interpolation, where the
% value as, say, 1s is 55, at 2s it is 60, and so on.
%
% Unfortunately, the linear interpolation does not "look" nice in many
% cases since the acceleration of a linear interpolation is zero
% during the animation, but infinite at the beginning and at the end;
% which looks "jerky".
%
% To avoid this, you can specify that the time--attribute curve should
% not be a straight line, but rather a curve. You specify this curve
% using a spline.
%
% The most logical "coordinate rectangle" used for this spline in our
% example would be (0s,50) and (10s,100) and we would like to specify
% something like "(0s,50) .. controls (5s,50) and (9s,100)
% .. (10s,100)". This would result in a time--attribute curve where
% the attribute at 50 changes slowly at 0s and also arrives slowly at
% 100 at 10s, but speeds up between these values.
%
% We call the first control point (5s,50) the "exit control" and call
% (9s,100) the "entry control": The first control dictates how quickly
% or slowly a time point is left, the second dictates how quickly or
% slowly we enter the next one.
%
% The control points are, however, not specified in the coordinate
% system indicated above. Rather, the rectangle (0s,50) to (10s, 100),
% gets normalized to (0,0) to (1,1). The control point (5s,50) would
% thus become (0.5,0) and (9s,100) becomes (0.9,1).
%
% Example:
%
% \pgfanimateattribute{rotate}{
% exit control={0.5}{0},
% entry control={0.9}{1},
% entry={0s}{50},
% entry={10s}{100}}
\pgfanimationset{
entry control/.code 2 args={%
\pgfmathsetmacro\pgf@temp@t{#1}%
\pgfmathsetmacro\pgf@temp@a{#2}%
\edef\pgf@anim@entry@spline{{\pgf@temp@t}{\pgf@temp@a}}%
},
exit control/.code 2 args={%
\pgfmathsetmacro\pgf@temp@t{#1}%
\pgfmathsetmacro\pgf@temp@a{#2}%
\edef\pgf@anim@exit@spline{{\pgf@temp@t}{\pgf@temp@a}}%
},
stay/.code=\let\pgf@anim@exit@spline\pgfsys@stay@text,%
jump/.code=\let\pgf@anim@entry@spline\pgfsys@jump@text,%
linear/.style={entry control={1}{1},exit control={0}{0}},
}%
\def\pgf@anim@entry@spline@base{{1}{1}}%
\def\pgf@anim@exit@spline@base{{0}{0}}%
\def\pgf@anim@reset@linear{\let\pgf@anim@entry@spline\pgf@anim@entry@spline@base\let\pgf@anim@exit@spline\pgf@anim@exit@spline@base}%
\pgf@anim@reset@linear
% Specifies how much arrow tips should be shortened (as in
% \pgfsetshortenstart)
%
% #1 = an additional shortening distance the path start.
%
% Description:
%
% Works like \pgfsetshortenstart, only for animated paths.
\pgfanimationset{
shorten </.code={%
\ifpgf@anim@entry@given%
\pgferror{You must specify shorten < prior to the path entries}%
\else%
\pgfmathsetmacro\pgf@anim@marker@extra@shorten@start{#1}%
\edef\pgf@anim@marker@extra@shorten@start{\pgf@anim@marker@extra@shorten@start pt}%
\fi%
},
shorten >/.code={%
\ifpgf@anim@entry@given%
\pgferror{You must specify shorten < prior to the path entries}%
\else%
\pgfmathsetmacro\pgf@anim@marker@extra@shorten@end{#1}%
\edef\pgf@anim@marker@extra@shorten@end{\pgf@anim@marker@extra@shorten@end pt}%
\fi%
},
}%
\def\pgf@anim@marker@extra@shorten@start{0pt}%
\def\pgf@anim@marker@extra@shorten@end{0pt}%
\def\pgf@anim@marker@shorten@start{0pt}%
\def\pgf@anim@marker@shorten@end{0pt}%
% Specifies the arrow tips used for path animations
%
% #1 = an arrow specification of the form <start>-<end> as for the
% command \pgfsetarrows
%
% Description:
%
% Specifies arrow tips that are used in a path animation. Note that in
% order to set the arrow tips of a path that is animated, you always
% have to use this command. In particular, you should *not* set arrow
% tips for the to-be-animated path, but use this key and the base key
% to install a base path with arrow tips.
\pgfanimationset{
arrows/.code={%
\ifpgf@anim@entry@given%
\pgferror{You must specify animation arrows prior to the path entries}%
\else%
\pgf@anim@parser@arrows#1\pgf@stop%
\fi%
},
}%
\def\pgf@anim@parser@arrows#1-#2\pgf@stop{%
\pgf@anim@prepare@arrow@start{#1}%
\pgf@anim@prepare@arrow@end{#2}%
\expandafter\expandafter\expandafter\pgfsysanimkeytipmarkers\expandafter\expandafter\expandafter{\expandafter\pgf@anim@marker@id@start\expandafter}\expandafter{\pgf@anim@marker@id@end}%
}%
\def\pgf@anim@prepare@arrow@start#1{%
\def\pgf@anim@temp{#1}%
\ifx\pgf@anim@temp\pgfutil@empty%
\let\pgf@anim@marker@id@start\pgfutil@empty%
\def\pgf@anim@marker@shorten@start{0pt}%
\else%
{%
\pgfsetarrowsstart{#1}%
\pgf@anim@prep@marker@arrow\pgf@start@tip@sequence\pgf@anim@marker@id\pgf@anim@marker@shorten%
\global\let\pgf@anim@marker@id@start\pgf@anim@marker@id%
\global\let\pgf@anim@temp\pgf@anim@marker@shorten%
}%
\let\pgf@anim@marker@shorten@start\pgf@anim@temp%
\fi%
}%
\def\pgf@anim@prepare@arrow@end#1{%
\def\pgf@anim@temp{#1}%
\ifx\pgf@anim@temp\pgfutil@empty%
\let\pgf@anim@marker@id@end\pgfutil@empty%
\def\pgf@anim@marker@shorten@end{0pt}%
\else%
{%
\pgfsetarrowsend{#1}%
\pgf@anim@prep@marker@arrow\pgf@end@tip@sequence\pgf@anim@marker@id\pgf@anim@marker@shorten%
\global\let\pgf@anim@marker@id@end\pgf@anim@marker@id%
}%
\let\pgf@anim@marker@shorten@end\pgf@anim@marker@shorten%
\fi%
}%
% Draw an arrow using markers
\def\pgf@anim@prep@marker@arrow#1#2#3{%
% #1 = tip sequence
% #2 = macro for storing marker code
% #3 = macro for storing shortening length
%
% First, compute id's:
{%
\let\pgf@arrow@handle\pgf@anim@marker@id@test%
\let\pgf@arrow@handle@dot\relax%?
\global\let\pgf@anim@marker@id@list\pgfutil@empty%
#1%
}%
\expandafter\let\expandafter#2\csname pgfanim@marker@cache@\pgf@anim@marker@id@list\endcsname%
\expandafter\let\expandafter#3\csname pgfanim@marker@cachel@\pgf@anim@marker@id@list\endcsname%
\ifx#2\relax% ok, have to create it!
\pgf@relevantforpicturesizefalse%
\pgfinterruptpath%
\pgf@arrow@compute@shortening{#1}%
\xdef#3{\the\pgf@xa}%
{%
\let\pgf@arrow@handle\pgf@anim@drawer@marker
\let\pgf@arrow@handle@dot\relax%
\pgfsys@marker@declare#2{%
\pgftransformxshift{-\pgf@xb}%
\pgftransformxshift{\pgf@xa}%
#1%
}%
}%
\endpgfinterruptpath%
\expandafter\global\expandafter\let\csname pgfanim@marker@cache@\pgf@anim@marker@id@list\endcsname#2%
\expandafter\global\expandafter\let\csname pgfanim@marker@cachel@\pgf@anim@marker@id@list\endcsname#3%
\fi%
}%
\def\pgf@anim@marker@id@test#1#2{%
\pgfarrows@getid{#1}{#2}%
\expandafter\expandafter\expandafter\pgf@arrow@drawer@shift\csname pgf@ar@ends@\pgf@arrow@id\endcsname%
\xdef\pgf@anim@marker@id@list{\pgf@anim@marker@id@list:\pgf@arrow@id\ifpgfarrowswap s\else n\fi\pgfarrows@slant w\the\pgf@xc}%
}%
\def\pgf@anim@drawer@marker#1#2{%
% Prepare:
{%
\pgfarrows@getid{#1}{#2}%
% Do shift:
\expandafter\expandafter\expandafter\pgf@arrow@drawer@shift\csname pgf@ar@ends@\pgf@arrow@id\endcsname%
% Do slant:
\ifdim\pgfarrows@slant pt=0pt%
\else%
\pgftransformxslant{\pgfarrows@slant}%
\fi%
% do swap:
\ifpgfarrowswap%
\pgftransformyscale{-1}%
\fi%
{%
\csname pgf@ar@saves@\pgf@arrow@id\endcsname%
\pgfsys@beginscope%
\pgf@arrows@color@setup%
\pgflowlevelsynccm\csname pgf@ar@cache@\pgf@arrow@id\endcsname%
\pgfsys@endscope%
}%
\expandafter}%
% Transform to next tip:
\expandafter\pgftransformxshift\expandafter{\the\pgf@xc}%
}%
% The parsers
% Parse no value
%
% #1 is ignored
%
% Example:
%
% entry = {0s}{5+6}
\def\pgfanim@parse@type@none#1{%
\pgfsysanimvalnone%
}%
% Parse a scalar
%
% #1 is a number parsed using \pgfmathparse
%
% Example:
%
% entry = {0s}{5+6}
\def\pgfanim@parse@type@scalar#1{%
\pgfmathparse{#1}%
\expandafter\pgfsysanimvalscalar\expandafter{\pgfmathresult}%
}%
% Parse a dimension
%
% #1 is a number parsed using \pgfmathparse
%
% Example:
%
% entry = {0s}{5cm + 2pt}
\def\pgfanim@parse@type@dimension#1{%
\pgfmathparse{#1}%
\expandafter\pgfsysanimvaldimension\expandafter{\pgfmathresult pt}%
}%
% Parse a mapped text
%
% #1 is a text. It is looked up in \pgf@anim@map@#1 and gets replaced
% by what this macro expands to.
%
% Example:
%
% entry = {0s}{true}
\def\pgfanim@parse@type@mapped#1{%
{%
\expandafter\let\expandafter\pgf@temp\csname pgf@anim@map@#1\endcsname\relax%
\ifx\pgf@temp\relax%
\pgferror{Value '#1' not allowed for an animation for this attribute}%
\let\pgf@temp\pgfutil@empty%
\fi%
\expandafter}%
\expandafter\pgfsysanimvaltext\expandafter{\pgf@temp}%
}%
% Parse a color
%
% #1 is a color
%
% entry = {0s}{blue!20}
\def\pgfanim@parse@type@color#1{%
\pgfsysanimvalcolor{#1}%
}%
% Parse a path
%
% #1 is a sequence of pgf path construction commands
%
% entry = {0s}{\pgfpathmoveto{\pgfpointorigin} \pgfpathlineto{\pgfpoint{1cm}{1cm}}}
\def\pgfanim@parse@type@path#1{%
{%
\pgfsyssoftpath@getcurrentpath\pgfanim@save@path%
\pgfsyssoftpath@setcurrentpath\pgfutil@empty%
#1%
\pgfsyssoftpath@getcurrentpath\pgfanim@the@path%
\pgfprocessround{\pgfanim@the@path}{\pgfanim@the@path}%
\global\let\pgfanim@the@path\pgfanim@the@path%
\pgfsyssoftpath@setcurrentpath\pgfanim@save@path%
}%
\expandafter\pgfanim@parse@type@softpath\expandafter{\pgfanim@the@path}%
}%
% Parse a softpath
%
% #1 is a sequence of pgf softpath token commands
%
% entry = {0s}{\pgfsyssoftpath@movetotoken {0pt}{0pt}\pgfsyssoftpath@linetotoken {10pt}{10pt}}
\def\pgfanim@parse@type@softpath#1{%
{%
\def\pgf@anim@path{#1}%
% Shorten?
\pgf@worryfalse%
\pgf@xb=\pgf@anim@marker@extra@shorten@start%
\advance\pgf@xb by\pgf@anim@marker@shorten@start%
\pgf@xc=\pgf@anim@marker@extra@shorten@end%
\advance\pgf@xc by\pgf@anim@marker@shorten@end%
\ifdim\pgf@xb=0pt\else\pgf@worrytrue\fi%
\ifdim\pgf@xc=0pt\else\pgf@worrytrue\fi%
\ifpgf@worry%
\edef\pgf@path@shortening@distance@end{\the\pgf@xc}%
\edef\pgf@path@shortening@distance@start{\the\pgf@xb}%
% Yes! Need to shorten.
\pgf@anim@shorten@path%
\fi%
\expandafter}%
\expandafter\pgfsysanimvalpath\expandafter{\pgf@anim@path}%
}%
\def\pgf@anim@shorten@path{%
\pgf@precise@shorteningfalse%
\let\pgf@path@shortening@distance\pgf@path@shortening@distance@end%
%
% Step 1: Split
%
\pgfprocesssplitpath{\pgf@anim@path}%
\pgfprocesssplitsubpath{\pgfprocessresultpathsuffix}%
%
% Step 2: extract
%
\expandafter\pgf@parse@end\pgfprocessresultsubpathsuffix\pgf@stop\pgf@stop\pgf@stop%
%
% Step 3: prep end
%
\pgf@prep@end%
%
% Step 4: shorten end
%
\ifdim\pgf@path@shortening@distance=0pt\else\pgf@do@shorten@end\fi%
%
\let\pgf@path@shortening@distance\pgf@path@shortening@distance@start%
%
% Step 5: extract
%
\expandafter\pgf@parse@start\pgfprocessresultpathsuffix\pgf@stop\pgf@stop\pgf@stop%
%
% Step 6: prep start
%
\pgf@prep@start%
%
% Step 7: shorten start
%
\ifdim\pgf@path@shortening@distance=0pt\else\pgf@do@shorten@start\fi%
\expandafter\expandafter\expandafter\def%
\expandafter\expandafter\expandafter\pgf@anim@path%
\expandafter\expandafter\expandafter{\expandafter\pgfprocessresultpathprefix\pgfprocessresultpathsuffix}%
}%
% Parse a point
%
% #1 is a point
%
% entry = {0s}{\pgfpoint{1cm}{2cm}}
\def\pgfanim@parse@type@point#1{%
\pgf@process{#1}%
\pgf@protocolanimsizes\pgf@x\pgf@y%
\expandafter\expandafter\expandafter\pgfsysanimvaltranslate\expandafter\expandafter\expandafter{\expandafter\the\expandafter\pgf@x\expandafter}\expandafter{\the\pgf@y}%
}%
% Parse a scaling
%
% #1 = if #1 contains a comma, the two parts are passed to
% pgfmathparse, otherwise the whole thing is passed to pgfmathparse.
%
% entry = {0s}{2}
% entry = {0s}{2,1}
\def\pgfanim@parse@type@scaling#1{%
\pgfutil@in@{,}{#1}%
\ifpgfutil@in@%
\pgfanim@unpack@comma#1\pgf@stop%
\else%
\pgfmathparse{#1}%
\expandafter\pgfsysanimvalscale\expandafter{\pgfmathresult}{\pgfmathresult}%
\fi%
}%
\def\pgfanim@unpack@comma#1,#2\pgf@stop{%
\pgfmathsetmacro{\pgf@anim@temp@x}{#1}%
\pgfmathsetmacro{\pgf@anim@temp@y}{#2}%
\expandafter\expandafter\expandafter\pgfsysanimvalscale\expandafter\expandafter\expandafter{\expandafter\pgf@anim@temp@x\expandafter}\expandafter{\pgf@anim@temp@y}%
}%
% Parse a viewbox
%
% #1 consists of two points, each in parentheses
%
% entry = {0s}{{\pgfpoint{1cm}{2cm}}{\pgfpoint{3cm}{4cm}}}
\def\pgfanim@parse@type@viewbox#1{%
{%
\pgfanim@unpack@viewbox#1%
\xdef\pgf@anim@caller{\noexpand\pgfsysanimvalviewbox{\the\pgf@x}{\the\pgf@y}{\the\pgf@xa}{\the\pgf@ya}}%
}%
\pgf@anim@caller%
}%
\def\pgfanim@unpack@viewbox#1#2{%
\pgfpointtransformed{#2}%
\pgf@xa\pgf@x%
\pgf@ya\pgf@y%
\pgfpointtransformed{#1}%
\ifdim\pgf@xa<\pgf@x% swap needed
\pgf@xb=\pgf@x%
\pgf@x=\pgf@xa%
\pgf@xa=\pgf@xb%
\fi%
\ifdim\pgf@ya<\pgf@y% swap needed
\pgf@yb=\pgf@y%
\pgf@y=\pgf@ya%
\pgf@ya=\pgf@yb%
\fi%
}%
% Parse a dash pattern
%
% #1,#2 is a dash pattern as in \pgfsetdash
%
% entry = {0s}{{{1pt}{2pt}{3pt}{1pt}}{1pt}}
\def\pgfanim@parse@type@dash#1{\pgfanim@parse@type@dash@#1}%
\def\pgfanim@parse@type@dash@#1#2{%
\def\pgf@temp{}%
\def\pgf@next{\pgf@strip}%
\pgf@strip#1{pgf@stop}%
\expandafter\pgfsysanimvaldash\expandafter{\pgf@temp}{#2}%
}%
%
%
% Bounding box adjustments in animations.
%
%
\def\pgf@protocolanimsizes#1#2{%
\edef\pgf@temp{\noexpand\pgf@anim@handle@point{\the#1}{\the#2}}%
\expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter\pgf@protocolanim@list\expandafter\expandafter\expandafter{\expandafter\pgf@protocolanim@list\pgf@temp}%
}%
\def\pgf@protocolanimsizes@direct#1#2{%
\expandafter\def\expandafter\pgf@protocolanim@list\expandafter{\pgf@protocolanim@list\pgf@anim@handle@point{#1}{#2}}%
}%
\let\pgf@protocolanim@list\pgfutil@empty
\def\pgf@animation@check@translate{%
\ifx\pgf@protocolanim@list\pgfutil@empty%
\else%
\expandafter\expandafter\expandafter\pgf@animation@check@translate@\expandafter\expandafter\expandafter{\expandafter\pgf@protocolanim@list\expandafter}\expandafter{\pgf@anim@saved@transform}%
\fi%
}%
\let\pgf@animation@check@motion\pgf@animation@check@translate
\def\pgf@animation@check@translate@#1#2{%
\pgfsys@attach@to@id\pgf@anim@whom@id\pgf@anim@whom@type{%
\pgf@size@hookedtrue%
{%
% Compute bounding box in local coordinate system
#2%
\pgf@pt@x0pt%
\pgf@pt@y0pt%
\pgf@picmaxx=-16000pt\relax%
\pgf@picminx=16000pt\relax%
\pgf@picmaxy=-16000pt\relax%
\pgf@picminy=16000pt\relax%
#1%
\edef\pgf@temp{{\the\pgf@picminx}{\the\pgf@picminy}{\the\pgf@picmaxx}{\the\pgf@picmaxy}}%
\expandafter%
}\expandafter%
\def\expandafter\pgf@temp\expandafter{\pgf@temp}%
\expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter\pgf@path@size@hook\expandafter\expandafter\expandafter{%
\expandafter\pgf@path@size@hook\expandafter\pgf@anim@bb\pgf@temp}%
}{}%
}%
\def\pgf@anim@handle@point#1#2{%
\pgf@x#1\pgf@y#2%
\pgf@pos@transform\pgf@x\pgf@y%
\ifdim\pgf@x<\pgf@picminx\pgf@picminx\pgf@x\fi%
\ifdim\pgf@x>\pgf@picmaxx\pgf@picmaxx\pgf@x\fi%
\ifdim\pgf@y<\pgf@picminy\pgf@picminy\pgf@y\fi%
\ifdim\pgf@y>\pgf@picmaxy\pgf@picmaxy\pgf@y\fi%
}%
\newdimen\pgf@anim@dim
\def\pgf@anim@bb#1#2#3#4{% (#1,#2) lower left, (#3, #4) upper right
\pgf@anim@dim\pgf@size@hook@x%
\advance\pgf@anim@dim by#1\relax%
\ifdim\pgf@anim@dim<\pgf@picminx\global\pgf@picminx\pgf@anim@dim\fi%
\pgf@anim@dim\pgf@size@hook@x%
\advance\pgf@anim@dim by#3\relax%
\ifdim\pgf@anim@dim>\pgf@picmaxx\global\pgf@picmaxx\pgf@anim@dim\fi%
\pgf@anim@dim\pgf@size@hook@y%
\advance\pgf@anim@dim by#2\relax%
\ifdim\pgf@anim@dim<\pgf@picminy\global\pgf@picminy\pgf@anim@dim\fi%
\pgf@anim@dim\pgf@size@hook@y%
\advance\pgf@anim@dim by#4\relax%
\ifdim\pgf@anim@dim>\pgf@picmaxy\global\pgf@picmaxy\pgf@anim@dim\fi%
}%
\def\pgf@anim@save@transform#1{%
\def\pgf@anim@saved@transform{#1}%
}%
\let\pgf@anim@saved@transform\pgfutil@empty%
\endinput