tikz.dev / pgfgantt Manual
\(\newcommand{\footnotename}{footnote}\) \(\def \LWRfootnote {1}\) \(\newcommand {\footnote }[2][\LWRfootnote ]{{}^{\mathrm {#1}}}\) \(\newcommand {\footnotemark }[1][\LWRfootnote ]{{}^{\mathrm {#1}}}\) \(\let \LWRorighspace \hspace \) \(\renewcommand {\hspace }{\ifstar \LWRorighspace \LWRorighspace }\) \(\newcommand {\TextOrMath }[2]{#2}\) \(\newcommand {\mathnormal }[1]{{#1}}\) \(\newcommand \ensuremath [1]{#1}\) \(\newcommand {\LWRframebox }[2][]{\fbox {#2}} \newcommand {\framebox }[1][]{\LWRframebox } \) \(\newcommand {\setlength }[2]{}\) \(\newcommand {\addtolength }[2]{}\) \(\newcommand {\setcounter }[2]{}\) \(\newcommand {\addtocounter }[2]{}\) \(\newcommand {\arabic }[1]{}\) \(\newcommand {\number }[1]{}\) \(\newcommand {\noalign }[1]{\text {#1}\notag \\}\) \(\newcommand {\cline }[1]{}\) \(\newcommand {\directlua }[1]{\text {(directlua)}}\) \(\newcommand {\luatexdirectlua }[1]{\text {(directlua)}}\) \(\newcommand {\protect }{}\) \(\def \LWRabsorbnumber #1 {}\) \(\def \LWRabsorbquotenumber "#1 {}\) \(\newcommand {\LWRabsorboption }[1][]{}\) \(\newcommand {\LWRabsorbtwooptions }[1][]{\LWRabsorboption }\) \(\def \mathchar {\ifnextchar "\LWRabsorbquotenumber \LWRabsorbnumber }\) \(\def \mathcode #1={\mathchar }\) \(\let \delcode \mathcode \) \(\let \delimiter \mathchar \) \(\def \oe {\unicode {x0153}}\) \(\def \OE {\unicode {x0152}}\) \(\def \ae {\unicode {x00E6}}\) \(\def \AE {\unicode {x00C6}}\) \(\def \aa {\unicode {x00E5}}\) \(\def \AA {\unicode {x00C5}}\) \(\def \o {\unicode {x00F8}}\) \(\def \O {\unicode {x00D8}}\) \(\def \l {\unicode {x0142}}\) \(\def \L {\unicode {x0141}}\) \(\def \ss {\unicode {x00DF}}\) \(\def \SS {\unicode {x1E9E}}\) \(\def \dag {\unicode {x2020}}\) \(\def \ddag {\unicode {x2021}}\) \(\def \P {\unicode {x00B6}}\) \(\def \copyright {\unicode {x00A9}}\) \(\def \pounds {\unicode {x00A3}}\) \(\let \LWRref \ref \) \(\renewcommand {\ref }{\ifstar \LWRref \LWRref }\) \( \newcommand {\multicolumn }[3]{#3}\) \(\require {textcomp}\) \(\newcommand {\toprule }[1][]{\hline }\) \(\let \midrule \toprule \) \(\let \bottomrule \toprule \) \(\def \LWRbooktabscmidruleparen (#1)#2{}\) \(\newcommand {\LWRbooktabscmidrulenoparen }[1]{}\) \(\newcommand {\cmidrule }[1][]{\ifnextchar (\LWRbooktabscmidruleparen \LWRbooktabscmidrulenoparen }\) \(\newcommand {\morecmidrules }{}\) \(\newcommand {\specialrule }[3]{\hline }\) \(\newcommand {\addlinespace }[1][]{}\)

3Implementation

3.1Packages

pgfgantt is modest in terms of dependencies: It only requires the TikZ and pgfcalendar packages.

\RequirePackage{tikz} \usetikzlibrary{% arrows, backgrounds, calc,% patterns, positioning, shapes.geometric% } \RequirePackage{pgfcalendar}
3.2Macros for Key and Error Management

\@gtt@ifstar

\@gtt@ifstar reimplements the 2ε kernel’s \@ifstar macro. This makes it robust to amsgen’s reimplementation of \@ifstar.

\def\@gtt@ifstar#1{\kernel@ifnextchar*{\@firstoftwo{#1}}}

\ganttset

\ganttset changes the current key path to /pgfgantt/ and then executes the keys in its mandatory argument.

\def\ganttset#1{\pgfqkeys{/pgfgantt}{#1}}

\@gtt@keydef

The following auxiliary macros save us some code when we devise keys later on. \@gtt@keydef{⟨key⟩}{⟨initial value⟩} declares the key /pgfgantt/⟨key⟩ and stores its ⟨initial value⟩.

\def\@gtt@keydef#1#2{% \pgfkeyssetvalue{/pgfgantt/#1}{#2}% }

\ganttvalueof

\ganttvalueof{⟨key⟩} retrieves the value stored by a ⟨key⟩. Link type authors should be able to use this macro in their code; thus, it lacks any @s.

\def\ganttvalueof#1{% \pgfkeysvalueof{/pgfgantt/#1}% }

\@gtt@stylekeydef

\@gtt@stylekeydef{⟨key⟩}{⟨initial style⟩} declares a style ⟨key⟩ with an ⟨initial style⟩.

\def\@gtt@stylekeydef#1#2{% \pgfkeys{/pgfgantt/#1/.style={#2}}% }

\@gtt@PackageError

\@gtt@PackageWarning

\@gtt@PackageError{⟨message⟩} and \@gtt@PackageWarning{⟨message⟩} issue a package error or warning ⟨message⟩, respectively.

\def\@gtt@PackageError#1{% \PackageError{pgfgantt}{#1}{}% } \def\@gtt@PackageWarning#1{% \PackageWarning{pgfgantt}{#1}% }
3.3The Horizontal and Vertical Grid

\gtt @currentline

\gtt @lasttitleline

\gtt @currgrid

\gtt @chartwidth

The count register \gtt@currentline holds the current line; it starts from 0 and decreases. \gtt@lasttitleline equals the line of the title element drawn last. \gtt@currgrid is the index of the current grid line drawn. \gtt@chartwidth equals the number of time slots.

\newcount\gtt@currentline \newcount\gtt@lasttitleline \newcount\gtt@currgrid \newcount\gtt@chartwidth

hgrid

hgrid style

\ifgtt @hgrid

\gtt @hgridstyle

hgrid checks whether its value is false and sets the boolean \ifgtt@hgrid accordingly. If the value is true or missing, horizontal grid lines appear dotted.

\@gtt@stylekeydef{hgrid style}{dotted} \newif\ifgtt@hgrid \ganttset{% hgrid/.code={% \def\@tempa{#1}% \def\@tempb{false}% \ifx\@tempa\@tempb% \gtt@hgridfalse% \else% \gtt@hgridtrue% \def\@tempb{true}% \ifx\@tempa\@tempb% \def\gtt@hgridstyle{dotted}% \else% \def\gtt@hgridstyle{#1}% \fi% \fi% },% hgrid/.default=dotted }

\gtt @hgrid@do

The \gtt@hgrid@do macro decomposes the style list for the horizontal grid into its comma-separated items. Each item is analyzed (see below) only if some grid lines are still left to draw. Note the “elegant” quadruple \expandafter construction, which enables tail recursion.

\def\gtt@hgrid@do#1,{% \ifx\relax#1\else \ifnum\gtt@currgrid<\gtt@currentline\else% \gtt@hgrid@analyze#1\relax% \expandafter\expandafter\expandafter\gtt@hgrid@do% \expandafter\fi% \fi% }

\gtt @hgrid@analyze

In the absence of a star as the first token in a style list item, \gtt@hgrid@analyze adds the multiplier 1 to the input stream.

\def\gtt@hgrid@analyze{% \@gtt@ifstar{\gtt@hgrid@draw}{\gtt@hgrid@draw1}% }

\gtt @hgrid@draw

\gtt@hgrid@draw draws as many grid lines as required by the multiplier. It increases \gtt@currgrid after each line drawn and breaks the loop as soon as all grid rules have been drawn.

\def\gtt@hgrid@draw#1#2\relax{% \foreach \i in {1,...,#1} {% \pgfmathsetmacro\y@upper{% \gtt@lasttitleline * \ganttvalueof{y unit title} +% (\gtt@currgrid - \gtt@lasttitleline)% * \ganttvalueof{y unit chart}% }% \draw [#2] (0pt, \y@upper pt) -- (\gtt@chartwidth * \ganttvalueof{x unit}, \y@upper pt);% \global\advance\gtt@currgrid by-1\relax% \ifnum\gtt@currgrid<\gtt@currentline\breakforeach\fi% }% }

vgrid

\ifgtt @vgrid

\gtt @vgridstyle

\gtt @vgrid@do

\gtt @vgrid@analyze

\gtt @vgrid@draw

Analogously, we declare options and macros for printing the vertical grid.

\newif\ifgtt@vgrid \ganttset{% vgrid/.code={% \def\@tempa{#1}% \def\@tempb{false}% \ifx\@tempa\@tempb% \gtt@vgridfalse% \else% \gtt@vgridtrue% \def\@tempb{true}% \ifx\@tempa\@tempb% \def\gtt@vgridstyle{dotted}% \else% \def\gtt@vgridstyle{#1}% \fi% \fi% },% vgrid/.default=dotted } \def\gtt@vgrid@do#1,{% \ifx\relax#1\else% \ifnum\gtt@currgrid>\gtt@chartwidth\else% \gtt@vgrid@analyze#1\relax% \expandafter\expandafter\expandafter\gtt@vgrid@do% \expandafter\fi% \fi% } \def\gtt@vgrid@analyze{% \@gtt@ifstar{\gtt@vgrid@draw}{\gtt@vgrid@draw1}% } \def\gtt@vgrid@draw#1#2\relax{% \foreach \i in {1,...,#1} {% \draw [#2] (\gtt@currgrid * \ganttvalueof{x unit}, \y@upper pt) --% (\gtt@currgrid * \ganttvalueof{x unit}, \y@lower pt);% \global\advance\gtt@currgrid by1\relax% \ifnum\gtt@currgrid>\gtt@chartwidth\breakforeach\fi% }% }
3.4Time Slot Formats

\gtt @smugglecount

\gtt@smugglecount{⟨count⟩} smuggles the local value of a count register over the end of a group.

\def\gtt@smugglecount#1\endgroup{% \edef\@tempa{\the#1}% \expandafter\endgroup\expandafter#1\expandafter=\@tempa% }

\gtt @juliantotimeslot

\gtt@juliantotimeslot{⟨count 1⟩}{⟨count 2⟩} converts the Julian date stored in ⟨count 1⟩ to a time slot and stores the latter in ⟨count 2⟩. This macro is called after the start of Gantt chart. Thus, \gtt@startyear, \gtt@startmonth and \gtt@startjulian (see section 3.5) have already been initialized. Depending on the value of time slot unit, one time slot corresponds to one day, one month or one year.

\newcommand\gtt@juliantotimeslot[2]{% \begingroup% \@tempcnta=#1\relax% \ifgtt@timeslotunit@day% \advance\@tempcnta by-\gtt@startjulian\relax% \advance\@tempcnta by1\relax% \fi% \ifgtt@timeslotunit@month% \pgfcalendarjuliantodate{\@tempcnta}{\@tempa}{\@tempb}{\@tempc}% \@tempcnta=\@tempa\relax% \advance\@tempcnta by-\gtt@startyear\relax% \multiply\@tempcnta by12\relax% \advance\@tempcnta by\@tempb\relax% \advance\@tempcnta by-\gtt@startmonth\relax% \advance\@tempcnta by1\relax% \fi% \ifgtt@timeslotunit@year% \pgfcalendarjuliantodate{\@tempcnta}{\@tempa}{\@tempb}{\@tempc}% \@tempcnta=\@tempa\relax% \advance\@tempcnta by-\gtt@startyear\relax% \advance\@tempcnta by1\relax% \fi% #2=\@tempcnta\relax% \gtt@smugglecount#2% \endgroup% }

\newgantttimeslotformat

\newgantttimeslotformat{⟨name⟩}{⟨code⟩} defines the macro
\gtt@tsstojulian@⟨name⟩{⟨tss⟩}{⟨count⟩}. This macro executes ⟨code⟩ (within a group), which should convert ⟨tss⟩ to a Julian date and store the date in ⟨count⟩.

\newcommand\newgantttimeslotformat[2]{% \expandafter\def\csname gtt@tsstojulian@#1\endcsname##1##2{% \begingroup#2\gtt@smugglecount##2\endgroup% }% }

The predefined time slot formats simple, isodate, isodate-yearmonth and isodate-year are straight forward.

\newgantttimeslotformat{simple}{% #2=#1\relax% \advance#2 by\gtt@tsf@startjulian\relax% \advance#2 by-1\relax% } \newgantttimeslotformat{isodate}{% \pgfcalendardatetojulian{#1}{#2}% } \newgantttimeslotformat{isodate-yearmonth}{% \pgfcalendardatetojulian{#1-01}{#2}% } \newgantttimeslotformat{isodate-year}{% \pgfcalendardatetojulian{#1-01-01}{#2}% }

\gtt @tsf@getdmy

\gtt@tsf@getdmy{⟨date⟩} decomposes a ⟨date⟩ day[sep]month[sep]year (with [sep] representing a period, hyphen or slash) into day, month and year and stores these numbers in \local@day, \local@month and \local@year, respectively.

\newcommand\gtt@tsf@getdmy[1]{% \edef\local@firstarg{#1}% \def\local@decompose##1.##2.##3\relax{% \def\local@day{##1}\def\local@month{##2}\def\local@year{##3}% }% \expandafter\local@decompose\local@firstarg..\relax% \ifx\local@month\@empty% \def\local@decompose##1/##2/##3\relax{% \def\local@day{##1}\def\local@month{##2}\def\local@year{##3}% }% \expandafter\local@decompose\local@firstarg//\relax% \ifx\local@month\@empty% \def\local@decompose##1-##2-##3\relax{% \def\local@day{##1}\def\local@month{##2}\def\local@year{##3}% }% \expandafter\local@decompose\local@firstarg--\relax% \ifx\local@month\@empty% \@gtt@PackageError{Illegal time slot specifier `#1'.}% \else% \def\local@decompose##1--{\def\local@year{##1}}% \expandafter\local@decompose\local@year% \fi% \else% \def\local@decompose##1//{\def\local@year{##1}}% \expandafter\local@decompose\local@year% \fi% \else% \def\local@decompose##1..{\def\local@year{##1}}% \expandafter\local@decompose\local@year% \fi% }

Time slot formats little-endian, big-endian and middle-endian only differ in their call of \pgfcalendardatetojulian. If the year (stored in \local@year or \local@day) lacks a century (e. g., 13 instead of 2013), it is completed according to the value of time slot format/base century.

\newgantttimeslotformat{little-endian}{% \gtt@tsf@getdmy{#1}% \ifnum\local@year<100\relax% \edef\local@year{\gtt@tsf@basecentury\local@year}% \fi% \pgfcalendardatetojulian{\local@year-\local@month-\local@day}{#2}% } \newgantttimeslotformat{big-endian}{% \gtt@tsf@getdmy{#1}% \ifnum\local@day<100\relax% \edef\local@day{\gtt@tsf@basecentury\local@day}% \fi% \pgfcalendardatetojulian{\local@day-\local@month-\local@year}{#2}% } \newgantttimeslotformat{middle-endian}{% \gtt@tsf@getdmy{#1}% \ifnum\local@year<100\relax% \edef\local@year{\gtt@tsf@basecentury\local@year}% \fi% \pgfcalendardatetojulian{\local@year-\local@day-\local@month}{#2}% }

time slot format

\gtt @tsstojulian

The key time slot format=⟨name⟩ checks whether the format ⟨name⟩ exists and then defines the macro \gtt@tsstojulian to be equivalent to
\gtt@tsstojulian@⟨name⟩.

\ganttset{% time slot format/.code={% \@ifundefined{gtt@tsstojulian@#1}{% \@gtt@PackageError{% Time slot format `#1' undefined.% }% }{}% \expandafter\let\expandafter\gtt@tsstojulian% \csname gtt@tsstojulian@#1\endcsname% },% time slot format=simple,%

time slot format/base century

\gtt @tsf@basecentury

time slot format/base century=⟨year⟩ extracts the century from the four-digit ⟨year⟩ (e. g., 20 from 2000) and stores it in \gtt@tsf@basecentury.

time slot format/base century/.code={% \begingroup% \@tempcnta=#1\relax% \divide\@tempcnta by100\relax% \xdef\gtt@tsf@basecentury{\the\@tempcnta}% \endgroup% },% time slot format/base century=2000,%

time slot format/start date

\gtt @tsf@startjulian

time slot format/start date=⟨isodate⟩ stores the Julian date corresponding to ⟨isodate⟩ in \gtt@tsf@startjulian.

time slot format/start date/.code={% \begingroup% \pgfcalendardatetojulian{#1}{\@tempcnta}% \xdef\gtt@tsf@startjulian{\the\@tempcnta}% \endgroup% },% time slot format/start date=2000-01-01% }
3.5The Main Environment

x unit

y unit title

y unit chart

Keys that store the basis vectors of the chart.

\@gtt@keydef{x unit}{.5cm} \@gtt@keydef{y unit title}{1cm} \@gtt@keydef{y unit chart}{1cm}

canvas

expand chart

today

today offset

today rule

today label

today label font

today label node

Keys related to the canvas and the today rule.

\@gtt@stylekeydef{canvas}{shape=rectangle, draw, fill=white} \@gtt@keydef{expand chart}{none} \@gtt@keydef{today}{none} \@gtt@keydef{today offset}{1} \@gtt@stylekeydef{today rule}{dashed, line width=1pt} \@gtt@keydef{today label}{TODAY} \@gtt@keydef{today label font}{\normalfont} \@gtt@stylekeydef{today label node}{% anchor=north, font=\ganttvalueof{today label font}% }

\ifgtt @newlineshortcut

newline shortcut

Boolean key that determines if \\ is equivalent to \ganttnewline.

\newif\ifgtt@newlineshortcut \ganttset{% newline shortcut/.is if=gtt@newlineshortcut,% newline shortcut=true% }

\ifgtt @tikzpicture

\ifgtt @intitle

\gtt @lasttitleslot

\gtt @elementid

\gtt @today@slot

\gtt @startjulian

\gtt @endjulian

\gtt @chartid

The boolean \ifgtt@tikzpicture is true if a Gantt chart appears within a TikZ picture. \ifgtt@intitle is true at the start of a ganttchart environment and set to false as soon as the first non-title element is encountered. \gtt@lasttitleslot corresponds to the \(x\)-coordinate of its right border. \gtt@elementid enumerates the automatic names of chart elements. \gtt@today@slot is the time slot of the today rule. \gtt@startjulian and \gtt@endjulian contain the Julian dates corresponding to the first and last time slot, respectively. \gtt@chartid assigns a consecutive number to each chart.

\newif\ifgtt@tikzpicture \newif\ifgtt@intitle \newcount\gtt@lasttitleslot \newcount\gtt@elementid \newcount\gtt@today@slot \newcount\gtt@startjulian \newcount\gtt@endjulian \newcount\gtt@chartid

\gtt @chartextrasize

Each ganttchart environment writes a \gtt@chartextrasize{⟨chart id⟩}{⟨extra size⟩} macro to the auxililary file. This macro stores its second argument in a macro of the form \@gtt@chart@⟨chart id⟩@extrasize. The ⟨extra size⟩ is the size of the chart’s bounding box less the size of the canvas, calculated as x unit times the number of time slots.

\def\gtt@chartextrasize#1#2{% \global\@namedef{@gtt@chart@#1@extrasize}{#2}% }

ganttchart

At the beginning of a ganttchart environment, the keys in its optional argument are executed. Initialize the macros and counts that contain start dates, end dates, the chart width, …

\newenvironment{ganttchart}[3][]{% \ganttset{#1}% \gtt@tsstojulian{#2}{\gtt@startjulian}% \global\gtt@startjulian=\gtt@startjulian\relax% \gtt@tsstojulian{#3}{\gtt@endjulian}% \global\gtt@endjulian=\gtt@endjulian\relax% \pgfcalendarjuliantodate{\gtt@startjulian}% {\gtt@startyear}{\gtt@startmonth}{\@tempa}% \xdef\gtt@startyear{\gtt@startyear}% \xdef\gtt@startmonth{\gtt@startmonth}% \gtt@juliantotimeslot{\gtt@endjulian}{\gtt@chartwidth} \global\gtt@chartwidth=\gtt@chartwidth\relax%

… the time slot of the today rule, ….

\def\@tempa{none}% \edef\@tempb{\ganttvalueof{today}}% \ifx\@tempa\@tempb\else% \gtt@tsstojulian{\ganttvalueof{today}}{\gtt@today@slot} \gtt@juliantotimeslot{\gtt@today@slot}{\gtt@today@slot}% \fi%

… the current element number, and information for drawing actions.

\global\gtt@elementid=0\relax% \global\gtt@currentline=0\relax% \global\gtt@lasttitleline=0\relax% \global\gtt@lasttitleslot=0\relax%

\gtt @expanded@xunit

If expand chart contains a value different from none, scale the chart so that its \(x\)-extent equals this value. To this end, use the information stored in the auxiliary file. \gtt@expanded@xunit will contain the new value for x unit.

\def\@tempa{none}% \edef\@tempb{\ganttvalueof{expand chart}}% \ifx\@tempa\@tempb\else% \@ifundefined{@gtt@chart@\the\gtt@chartid @extrasize}{% \@gtt@PackageWarning{Gantt chart expansion may have changed. Rerun to get expansion right}% }{% \pgfmathparse{(\ganttvalueof{expand chart}% - \@nameuse{@gtt@chart@\the\gtt@chartid @extrasize})% / \gtt@chartwidth}% \edef\gtt@expanded@xunit{\pgfmathresult pt}% \ganttset{x unit=\gtt@expanded@xunit}% }% \fi%

\\

\ganttalignnewline

If a ganttchart appears outside of a tikzpicture, we implicitly start this environment. “Within a tikzpicture” means that \useasboundingbox is defined. Since we expect a chart to start with at least one title element, \ifgtt@intitle is true. If newline shortcut is true, make the control symbol \\ equivalent to \ganttnewline. In any case, \ganttalignnewline is defined.

\@ifundefined{useasboundingbox}% {\gtt@tikzpicturefalse\begin{tikzpicture}}% {\gtt@tikzpicturetrue}% \gtt@intitletrue% \ifgtt@newlineshortcut% \let\\\ganttnewline% \fi% \let\ganttalignnewline\tikz@align@newline% }{

\y @upper

\y @lower

\y @mid

\y @size

\x @size

After the contents of the environment have been drawn, we add the canvas to the background layer. pgfgantt saves \(x\)- and \(y\)-coordinates in local internal macros called \x@left, \x@right, \x@mid, \x@size, \y@upper, \y@lower, \y@mid and \y@size.

\begin{scope}[on background layer]% \ifgtt@includetitle% \def\y@upper{0}% \else% \pgfmathsetmacro\y@upper{% \gtt@lasttitleline * \ganttvalueof{y unit title}% }% \fi% \pgfmathsetmacro\y@lower{% \gtt@lasttitleline * \ganttvalueof{y unit title}% + (\gtt@currentline - \gtt@lasttitleline - 1)% * \ganttvalueof{y unit chart}% }% \pgfmathsetmacro\y@mid{% (\y@upper + \y@lower) / 2% }% \pgfmathsetmacro\y@size{% abs(\y@lower - \y@upper)% }% \pgfmathsetmacro\x@size{% \gtt@chartwidth * \ganttvalueof{x unit}% }% \node [/pgfgantt/canvas, minimum width=\x@size pt, minimum height=\y@size pt] at (\x@size pt / 2, \y@mid pt) {};%

The contents of the vertical grid style list are evaluated at most \gtt@chartwidth-times, but the loop breaks as soon as all grid lines have been drawn.

\pgfmathsetmacro\y@upper{% \gtt@lasttitleline * \ganttvalueof{y unit title}% }% \ifgtt@vgrid \gtt@currgrid=1\relax% \global\advance\gtt@chartwidth by-1\relax% \foreach \x in {1,...,\gtt@chartwidth} {% \expandafter\gtt@vgrid@do\gtt@vgridstyle,\relax,% \ifnum\gtt@currgrid>\gtt@chartwidth\relax\breakforeach\fi% }% \global\advance\gtt@chartwidth by1\relax% \fi%

Now, we draw the horizontal grid. If we exclude the title from the canvas, we omit the uppermost horizontal grid line since it would coincide with the canvas border.

\ifgtt@hgrid% \gtt@currgrid=\gtt@lasttitleline\relax% \ifgtt@includetitle\else% \advance\gtt@currgrid by-1\relax \fi% \edef\@tempa{\the\gtt@currgrid}% \foreach \t in {\@tempa,...,\gtt@currentline} {% \expandafter\gtt@hgrid@do\gtt@hgridstyle,\relax,% \ifnum\gtt@currgrid<\gtt@currentline\relax\breakforeach\fi% }% \fi%

\x @mid

The last task of ganttchart is to apply the today key if its value differs from none.

\def\@tempa{none}% \edef\@tempb{\ganttvalueof{today}}% \ifx\@tempa\@tempb\else% \pgfmathsetmacro\x@mid{% (\gtt@today@slot - 1 + \ganttvalueof{today offset})% * \ganttvalueof{x unit}% }% \draw [/pgfgantt/today rule] (\x@mid pt, \y@upper pt) -- (\x@mid pt, \y@lower pt) node [/pgfgantt/today label node] {\ganttvalueof{today label}};% \fi% \end{scope}%

Store the \(x\)-extent of the bounding box in \@tempdima. Calculate the size by which the bounding box exceeds the “raw” canvas size. Write this information to the auxiliary file.

\pgfextractx{\@tempdima}{% \pgfpointdiff{\pgfpointanchor{current bounding box}{south west}}% {\pgfpointanchor{current bounding box}{north east}}% }% \pgfmathparse{\@tempdima -\ganttvalueof{x unit} * \gtt@chartwidth}% \protected@write\@auxout{}{% \string\gtt@chartextrasize{\the\gtt@chartid}{\pgfmathresult pt}}%

Increase the chart counter.

\global\advance\gtt@chartid by1\relax%

At the end of a ganttchart, we also close the tikzpicture if we started it implicitly.

\ifgtt@tikzpicture\else\end{tikzpicture}\fi% }
3.6Starting a New Line

\ganttnewline

\local @drawarg

Unless the optional argument of \ganttnewline is empty, this macro adds a horizontal grid rule between the current and the new line. The style of this line, which is stored in \local@drawarg, is either hgrid style or the style specified in the optional argument. Anyway, \ganttnewline decreases \gtt@currentline and, if we are still in the title, \gtt@lasttitleline. Since the new line starts at time slot zero, \gtt@lasttitleslot is reset.

\newcommand\ganttnewline[1][]{% \begingroup% \def\local@drawarg{#1}% \def\@tempa{grid}% \ifx\local@drawarg\@empty\else% \ifx\local@drawarg\@tempa% \def\local@drawarg{/pgfgantt/hgrid style}% \fi% \pgfmathsetmacro\y@upper{% \gtt@lasttitleline * \ganttvalueof{y unit title}% + (\gtt@currentline - \gtt@lasttitleline - 1)% * \ganttvalueof{y unit chart}% } \expandafter\draw\expandafter[\local@drawarg] (0pt, \y@upper pt) -- (\gtt@chartwidth * \ganttvalueof{x unit}, \y@upper pt);% \fi% \global\advance\gtt@currentline by-1\relax% \ifgtt@intitle\global\advance\gtt@lasttitleline by-1\relax\fi% \global\gtt@lasttitleslot=0\relax% \endgroup% }
3.7Vertical rules

vrule offset

vrule

vrule label font

vrule label node

Keys related to the vertical rules.

\@gtt@keydef{vrule offset}{1} \@gtt@stylekeydef{vrule}{dashed, line width=1pt} \@gtt@keydef{vrule label font}{\normalfont} \@gtt@stylekeydef{vrule label node}{% anchor=north, font=\ganttvalueof{vrule label font}% }

\gtt @vrule@slot

A count for storing the vrule time slot.

\newcount\gtt@vrule@slot

\ganttvrule

Calculate the coordinates for the vertical rule and draw it.

\newcommand\ganttvrule[3][]{% \begingroup \ganttset{#1} \gtt@tsstojulian{#3}{\gtt@vrule@slot}% \gtt@juliantotimeslot{\gtt@vrule@slot}{\gtt@vrule@slot}% \pgfmathsetmacro\y@upper{% \gtt@lasttitleline * \ganttvalueof{y unit title}% }% \pgfmathsetmacro\y@lower{% \gtt@lasttitleline * \ganttvalueof{y unit title}% + (\gtt@currentline - \gtt@lasttitleline - 1)% * \ganttvalueof{y unit chart}% }% \pgfmathsetmacro\x@mid{% (\gtt@vrule@slot - 1 + \ganttvalueof{vrule offset})% * \ganttvalueof{x unit}% }% \draw [/pgfgantt/vrule] (\x@mid pt, \y@upper pt) -- (\x@mid pt, \y@lower pt) node [/pgfgantt/vrule label node] {#2};% \endgroup }
3.8Titles

title

title label font

title label node

title label text

\gtt @titlelabeltext

title list options

\gtt @titlelistoptions

title left shift

title right shift

title top shift

title height

include title in canvas

\ifgtt @includetitle

Keys that influence title elements. The parameter token #1 in the value of title label text is replaced by the argument of \gtt@titlelabeltext. Note that \@gtt@keydef cannot define title list options, since \@gtt@titlelistoptions is expanded after a \foreach statement, where \ganttvalueof will not work.

\@gtt@stylekeydef{title}{shape=rectangle, inner sep=0pt, draw, fill=white} \@gtt@keydef{title label font}{\small} \@gtt@stylekeydef{title label node}{% anchor=center, font=\ganttvalueof{title label font}% } \ganttset{% title label text/.code={% \def\gtt@titlelabeltext##1{#1}% },% title label text=\strut#1,% title list options/.code={% \def\gtt@titlelistoptions{[#1]}% },% title list options={var=\x, evaluate=\x}% } \@gtt@keydef{title left shift}{0} \@gtt@keydef{title right shift}{0} \@gtt@keydef{title top shift}{0} \@gtt@keydef{title height}{.6} \newif\ifgtt@includetitle \ganttset{% include title in canvas/.is if=gtt@includetitle,% include title in canvas }

calendar week text

time slot unit

\ifgtt @timeslotunit@day

\ifgtt @timeslotunit@month

\ifgtt @timeslotunit@year

Keys for title calendars.

\@gtt@keydef{calendar week text}{Week~\currentweek} \newif\ifgtt@timeslotunit@day \newif\ifgtt@timeslotunit@month \newif\ifgtt@timeslotunit@year \ganttset{% time slot unit/.is choice, time slot unit/day/.code={% \gtt@timeslotunit@daytrue% \gtt@timeslotunit@monthfalse% \gtt@timeslotunit@yearfalse% },% time slot unit/month/.code={% \gtt@timeslotunit@dayfalse% \gtt@timeslotunit@monthtrue% \gtt@timeslotunit@yearfalse% },% time slot unit/year/.code={% \gtt@timeslotunit@dayfalse% \gtt@timeslotunit@monthfalse% \gtt@timeslotunit@yeartrue% },% time slot unit=day }

\gantttitle

\x @left

\x @right

\gantttitle draws a title element (i. e., a rectangle with a single node at its center). For reasons that will become clear below, the element essentially starts at the \(x\)-coordinate stored in \gtt@lasttitleslot. This count is updated at the end of the macro.

\newcommand\gantttitle[3][]{% \begingroup% \ganttset{#1}% \pgfmathsetmacro\x@left{% (\gtt@lasttitleslot + \ganttvalueof{title left shift})% * \ganttvalueof{x unit}% }% \pgfmathsetmacro\x@right{% (\gtt@lasttitleslot + #3 + \ganttvalueof{title right shift})% * \ganttvalueof{x unit}% }% \pgfmathsetmacro\x@mid{% (\x@left + \x@right) / 2% }% \pgfmathsetmacro\x@size{% \x@right - \x@left% }% \pgfmathsetmacro\y@upper{% (\gtt@currentline - \ganttvalueof{title top shift})% * \ganttvalueof{y unit title}% }% \pgfmathsetmacro\y@lower{% (\gtt@currentline - \ganttvalueof{title top shift}% - \ganttvalueof{title height}) * \ganttvalueof{y unit title}% }% \pgfmathsetmacro\y@mid{% (\y@upper + \y@lower) / 2% }% \pgfmathsetmacro\y@size{% \y@upper - \y@lower% }% \path (\x@mid pt, \y@mid pt) node [/pgfgantt/title, minimum width=\x@size pt, minimum height=\y@size pt] {} node [/pgfgantt/title label node] {\gtt@titlelabeltext{#2}};% \global\advance\gtt@lasttitleslot by#3\relax% \endgroup% }

\gantttitlelist

\gantttitlelist generates title elements by repeatedly calling \gantttitle. Since the latter always starts after the last time slot occupied by the previous element, \gantttitlelist does not have to calculate the respective \(x\)-coordinates explicitly.

\newcommand\gantttitlelist[3][]{% \begingroup% \ganttset{#1}% \expandafter\foreach\gtt@titlelistoptions in {#2} {\gantttitle{\x}{#3}}% \endgroup% }

\ifgtt @titlecalendarstar

\gantttitlecalendar

\gantttitlecalendar *

\gantttitlecalendar checks whether it is invoked in the starred or nonstarred form, sets \ifgtt@titlecalendarstar accordingly and then starts a command relaying chain.

\newif\ifgtt@titlecalendarstar \newcommand\gantttitlecalendar{% \@gtt@ifstar% {\gtt@titlecalendarstartrue\@gantttitlecalendar}% {\gtt@titlecalendarstarfalse\@gantttitlecalendar}% }

\@gantttitlecalendar

The first command in the relaying chain, \@gantttitlecalendar[⟨options⟩], processes the ⟨options⟩. If it was executed by the starred form of \gantttitlecalendar, it calls the second command in the chain. Otherwise, it directly calls the third command in the chain.

\newcommand\@gantttitlecalendar[1][]{ \begingroup% \ganttset{#1}% \ifgtt@titlecalendarstar% \expandafter\@@gantttitlecalendar% \else% \expandafter\@@@gantttitlecalendar\expandafter% {\expandafter\gtt@startjulian\expandafter}\expandafter% {\expandafter\gtt@endjulian\expandafter}% \fi% }

\@@gantttitlecalendar

The second command in the relaying chain,
\@@gantttitlecalendar{⟨start tss⟩}{⟨end tss⟩},
reads two mandatory arguments from the input stream and converts them to Julian dates. Finally, it calls the third command in the chain.

\newcommand\@@gantttitlecalendar[2]{ \gtt@tsstojulian{#1}{\@tempcnta}% \gtt@tsstojulian{#2}{\@tempcntb}% \@@@gantttitlecalendar{\@tempcnta}{\@tempcntb}% }

\@@@gantttitlecalendar

\gtt @calendar@startdate

\gtt @calendar@enddate

The third and last command in the relaying chain, \@@@gantttitlecalendar{⟨start Julian⟩}{⟨end Julian⟩}{⟨calendar lines⟩}, stores the start and end ISO-standard dates of the calendar in \gtt@calendar@startdate and \gtt@calendar@enddate, respectively. Then, it executes the keys in ⟨calendar lines⟩, which reside in path /pgfgantt/calendar.

\newcommand\@@@gantttitlecalendar[3]{% \pgfcalendarjuliantodate{#1}{\@tempa}{\@tempb}{\@tempc}% \edef\gtt@calendar@startdate{\@tempa-\@tempb-\@tempc}% \pgfcalendarjuliantodate{#2}{\@tempa}{\@tempb}{\@tempc}% \edef\gtt@calendar@enddate{\@tempa-\@tempb-\@tempc}% \gtt@calendar@eolfalse% \pgfqkeys{/pgfgantt/calendar}{#3}% \endgroup% }

\ifgtt @calendar@eol

\gtt @calendar@slots

\gtt @calendar@weeknumber

\gtt @calendar@startofweek

Booleans and counts for drawing title calendars: \ifgtt@calendar@eol is true if \ganttcalendar should start a new calendar line. \gtt@calendar@slots is the number of time slots a calendar element will cover. \gtt@calendar@weeknumber is the current week number in a calendar line of type week. \gtt@calendar@startofweek is the Julian date of the Monday in the current week.

\newif\ifgtt@calendar@eol \newcount\gtt@calendar@slots \newcount\gtt@calendar@weeknumber \newcount\gtt@calendar@startofweek

\@gtt@getfourthdigit

\@gtt@getdecade

\@gtt@getfourthdigit returns the fourth digit of a year, while \@gtt@getdecade returns the first three digits of a year.

\def\@gtt@getfourthdigit#1#2#3#4{#4} \def\@gtt@getdecade#1#2#3#4{#1#2#3}

We define a new check for \pgfcalendarifdate as described in the pgfcalendar manual: end of decade=⟨date⟩ returns true if a date marks the end of a decade as defined by ⟨date⟩. For instance, if ⟨date⟩ is 2009-12-31, then the conditional will be true for the dates 1999-12-31, 2009-12-31, 2019-12-31 and so on.

\pgfkeys{% /pgf/calendar/end of decade/.code={ \begingroup \pgfcalendardatetojulian{#1}{\@tempcnta} \pgfcalendarjuliantodate{\@tempcnta}{\@tempa}{\@tempb}{\@tempc} \edef\endofdecade{\expandafter\@gtt@getfourthdigit\@tempa} \edef\querydecade{\expandafter\@gtt@getfourthdigit\pgfcalendarifdateyear} \ifnum\endofdecade=\querydecade\relax% \ifnum\pgfcalendarifdatemonth=\@tempb\relax% \ifnum\pgfcalendarifdateday=\@tempc\relax% \global\pgfcalendarmatchestrue% \fi% \fi% \fi% \endgroup }% }

For each ⟨line type⟩, we define a corresponding key /pgfgantt/calendar/⟨line type⟩. This key performs the necessary calculations and draws one or several \gantttitles. Line type decade draws decades.

\ganttset{% calendar/decade/.code={% \ifgtt@calendar@eol\ganttnewline\fi% \begingroup% \gtt@calendar@slots=1\relax% \ifgtt@timeslotunit@year% \pgfcalendar{}{\gtt@calendar@startdate}{\gtt@calendar@enddate}{% \ifdate{end of decade=2009-12-31}{% \gantttitle{% \expandafter\@gtt@getdecade\pgfcalendarcurrentyear% 0s% }{\the\gtt@calendar@slots}% \gtt@calendar@slots=0\relax% }{ \ifdate{equals=01-01}{% \ifnum\pgfcalendarcurrentjulian>\pgfcalendarbeginjulian\relax% \advance\gtt@calendar@slots by1\relax% \fi }{}% }% \ifdate{equals=\pgfcalendarendiso}{% \ifnum\gtt@calendar@slots=0\relax\else% \gantttitle{% \expandafter\@gtt@getdecade\pgfcalendarcurrentyear% 0s% }{\the\gtt@calendar@slots}% \fi% }{}% }% \fi% \endgroup% \gtt@calendar@eoltrue% },%

Line type year draws years.

calendar/year/.code={% \ifgtt@calendar@eol\ganttnewline\fi% \begingroup% \gtt@calendar@slots=1\relax% \ifgtt@timeslotunit@year% \pgfcalendar{}{\gtt@calendar@startdate}{\gtt@calendar@enddate}{% \ifdate{equals=12-31}{% \gantttitle{\pgfcalendarcurrentyear}{1}% \gtt@calendar@slots=1\relax% }{ \advance\gtt@calendar@slots by1\relax% }% \ifdate{equals=\pgfcalendarendiso}{% \ifnum\gtt@calendar@slots=1\relax\else% \gantttitle{\pgfcalendarcurrentyear}{1}% \fi% }{}% }% \fi% \ifgtt@timeslotunit@month% \pgfcalendar{}{\gtt@calendar@startdate}{\gtt@calendar@enddate}{% \ifdate{equals=12-31}{% \gantttitle{\pgfcalendarcurrentyear}{\the\gtt@calendar@slots}% \gtt@calendar@slots=1\relax% }{% \ifdate{end of month=1}{% \advance\gtt@calendar@slots by1\relax% }{}% }% \ifdate{equals=\pgfcalendarendiso}{% \ifdate{end of month=1}{% \advance\gtt@calendar@slots by-1\relax% }{}% \ifdate{equals=12-31}{}{% \gantttitle{\pgfcalendarcurrentyear}{\the\gtt@calendar@slots}% }% }{}% }% \fi% \ifgtt@timeslotunit@day% \pgfcalendar{}{\gtt@calendar@startdate}{\gtt@calendar@enddate}{% \ifdate{equals=12-31}{% \gantttitle{\pgfcalendarcurrentyear}{\the\gtt@calendar@slots}% \gtt@calendar@slots=1\relax% }{% \advance\gtt@calendar@slots by1\relax% }% \ifdate{equals=\pgfcalendarendiso}{% \ifnum\gtt@calendar@slots=1\relax\else% \advance\gtt@calendar@slots by-1\relax% \gantttitle{\pgfcalendarcurrentyear}{\the\gtt@calendar@slots}% \fi% }{}% }% \fi% \endgroup% \gtt@calendar@eoltrue% },%

Line type month=⟨format⟩ draws months. Internally, a month is represented by a number between 1 (January) and 12 (December). However, when the title element is drawn, this number is fed to the macro \pgfcalendarmonth⟨format⟩ and possibly converted.

calendar/month/.code={% \ifgtt@calendar@eol\ganttnewline\fi% \begingroup% \gtt@calendar@slots=1\relax% \pgfcalendar{}{\gtt@calendar@startdate}{\gtt@calendar@enddate}{% \ifdate{end of month=1}{% \gantttitle{% \csname pgfcalendarmonth#1\endcsname{\pgfcalendarcurrentmonth}% }{% \ifgtt@timeslotunit@month1\fi% \ifgtt@timeslotunit@day\the\gtt@calendar@slots\fi% }% \gtt@calendar@slots=1\relax% }{% \advance\gtt@calendar@slots by1\relax% }% \ifdate{equals=\pgfcalendarendiso}{% \ifnum\gtt@calendar@slots=1\relax\else% \advance\gtt@calendar@slots by-1\relax% \gantttitle{% \csname pgfcalendarmonth#1\endcsname{\pgfcalendarcurrentmonth}% }{% \ifgtt@timeslotunit@month1\fi% \ifgtt@timeslotunit@day\the\gtt@calendar@slots\fi% }% \fi% }{}% }% \endgroup% \gtt@calendar@eoltrue% },%

\startyear

\startmonth

\startday

\currentweek

Line type week=⟨number⟩ draws weeks. The first week receives ⟨number⟩, which is also saved in \currentweek. This key also defines the macros \startyear, \startmonth and \startday, which store the year, month and day of the current week’s Monday. These four macros can be used in the value of calendar week text.

calendar/week/.code={% \ifgtt@calendar@eol\ganttnewline\fi% \begingroup% \gtt@calendar@slots=1\relax% \gtt@calendar@weeknumber=#1\relax% \pgfcalendar{}{\gtt@calendar@startdate}{\gtt@calendar@enddate}{% \ifdate{Sunday}{% \gtt@calendar@startofweek=\pgfcalendarcurrentjulian\relax% \advance\gtt@calendar@startofweek by1\relax% \advance\gtt@calendar@startofweek by-\gtt@calendar@slots\relax% \pgfcalendarjuliantodate{\gtt@calendar@startofweek}% {\startyear}{\startmonth}{\startday}% \def\currentweek{\the\gtt@calendar@weeknumber}% \gantttitle{% \ganttvalueof{calendar week text}% }{% \the\gtt@calendar@slots% }% \gtt@calendar@slots=1\relax% \advance\gtt@calendar@weeknumber by1\relax% }{% \advance\gtt@calendar@slots by1% }% \ifdate{equals=\pgfcalendarendiso}{% \ifnum\gtt@calendar@slots=1\relax\else% \advance\gtt@calendar@slots by-1\relax% \gtt@calendar@startofweek=\pgfcalendarcurrentjulian\relax% \advance\gtt@calendar@startofweek by1\relax% \advance\gtt@calendar@startofweek by-\gtt@calendar@slots\relax% \pgfcalendarjuliantodate{\gtt@calendar@startofweek}% {\startyear}{\startmonth}{\startday}% \def\currentweek{\the\gtt@calendar@weeknumber}% \gantttitle{% \ganttvalueof{calendar week text}% }{% \the\gtt@calendar@slots% }% \fi% }{}% }% \endgroup% \gtt@calendar@eoltrue% },% calendar/week/.default=1,%

Line type weekday=⟨format⟩ draws weekdays. Internally, a weekday is represented by a number between 0 (Monday) and 6 (Sunday). However, when the title element is drawn, this number is fed to the macro \pgfcalendarweekday⟨format⟩ and possibly converted.

calendar/weekday/.code={% \ifgtt@calendar@eol\ganttnewline\fi% \begingroup% \pgfcalendar{}{\gtt@calendar@startdate}{\gtt@calendar@enddate}{% \gantttitle{% \csname pgfcalendarweekday#1\endcsname{\pgfcalendarcurrentweekday}% }{1}% }% \endgroup% \gtt@calendar@eoltrue% },%

Line type day=⟨format⟩ draws days of the month.

calendar/day/.code={% \ifgtt@calendar@eol\ganttnewline\fi% \begingroup% \pgfcalendar{}{\gtt@calendar@startdate}{\gtt@calendar@enddate}{% \gantttitle{\pgfcalendarcurrentday}{1}% }% \endgroup% \gtt@calendar@eoltrue% }% }
3.9Chart Elements

progress

\gtt @progress

progress label text

\gtt @progresslabeltext

name

chart element start border

\ifgtt @ce@startatleftborder

inline

\ifgtt @inline

Keys that apply to all chart elements. The parameter token #1 in the value of progress label text is replaced by the argument of \gtt@progresslabeltext.

\ganttset{% progress/.code={% \def\gtt@progress{#1}% },% progress=none,% progress label text/.code={% \def\gtt@progresslabeltext##1{#1}% },% progress label text={% \pgfmathprintnumber[precision=0, verbatim]{#1}\% complete% }% } \@gtt@keydef{name}{} \newif\ifgtt@ce@startatleftborder \ganttset{% chart element start border/.is choice,% chart element start border/left/.code=\gtt@ce@startatleftbordertrue,%, chart element start border/right/.code=\gtt@ce@startatleftborderfalse,% chart element start border=left% } \newif\ifgtt@inline \ganttset{% inline/.is if=gtt@inline,% inline=false% }

\gtt @lastelement

\gtt @currentelement

\ifgtt @draw@complete

\ifgtt @draw@incomplete

\ifgtt @draw@clip

\gtt @left@slot

\gtt @right@slot

The macros \gtt@lastelement and \gtt@currentelement save the name of the current and last chart element drawn. Thereby, the \ganttlinked... macros can add a link connecting them. \ifgtt@draw@complete, \ifgtt@draw@incomplete and \ifgtt@draw@clip decide whether to draw the complete and incomplete part of a chart element and if these parts are clipped. \gtt@left@slot and \gtt@right@slot store a chart element’s start and end time slot, respectively.

\def\gtt@lastelement{} \def\gtt@currentelement{} \newif\ifgtt@draw@complete \newif\ifgtt@draw@incomplete \newif\ifgtt@draw@clip \newcount\gtt@left@slot \newcount\gtt@right@slot

\gtt @chartelement

\local @timeslotmodifier

\gtt @name

\gtt@chartelement[⟨options⟩]{⟨label⟩}{⟨start tss⟩}{⟨end tss⟩}{⟨type⟩}
is the generic command for drawing chart elements of a certain ⟨type⟩. First, \gtt@chartelement converts ⟨start tss⟩ to \gtt@left@slot and ⟨end tss⟩ to \gtt@right@slot. Then it calculates the usual coordinates. \gtt@name stores the name of the chart element.

\newcommand\gtt@chartelement[5][]{% \begingroup% \ganttset{#1}% \gtt@tsstojulian{#3}{\gtt@left@slot}% \gtt@juliantotimeslot{\gtt@left@slot}{\gtt@left@slot}% \gtt@tsstojulian{#4}{\gtt@right@slot}% \gtt@juliantotimeslot{\gtt@right@slot}{\gtt@right@slot}% \def\local@timeslotmodifier{-1}% \ifgtt@ce@startatleftborder\else% \ifnum\gtt@left@slot=\gtt@right@slot\relax\else% \def\local@timeslotmodifier{0}% \fi% \fi% \pgfmathsetmacro\x@left{% (\gtt@left@slot + \local@timeslotmodifier% + \ganttvalueof{#5 left shift})% * \ganttvalueof{x unit}% }% \pgfmathsetmacro\x@right{% (\gtt@right@slot + \ganttvalueof{#5 right shift})% * \ganttvalueof{x unit}% }% \pgfmathsetmacro\x@mid{% (\x@left + \x@right) / 2% }% \pgfmathsetmacro\x@size{% \x@right - \x@left% }% \pgfmathsetmacro\y@upper{% \gtt@lasttitleline * \ganttvalueof{y unit title} + (\gtt@currentline - \gtt@lasttitleline - \ganttvalueof{#5 top shift}) * \ganttvalueof{y unit chart}% }% \pgfmathsetmacro\y@lower{% \y@upper - \ganttvalueof{#5 height} * \ganttvalueof{y unit chart}% }% \pgfmathsetmacro\y@mid{% (\y@upper + \y@lower) / 2% }% \pgfmathsetmacro\y@size{% \y@upper - \y@lower% }% \edef\gtt@name{\ganttvalueof{name}}% \ifx\gtt@name\@empty\edef\gtt@name{elem\the\gtt@elementid}\fi%

\local @none

Depending on the values of progress and today, we determine the correct value for \gtt@progress. A value between 0 and 100 corresponds to a percentage of completeness. A value of 999 indicates that the chart element has no associated progress.

\def\local@none{none}% \ifx\gtt@progress\local@none% \def\gtt@progress{999}% \else% \def\@tempa{today}% \ifx\gtt@progress\@tempa% \edef\@tempa{\ganttvalueof{today}}% \ifx\@tempa\local@none% \@gtt@PackageWarning{% Value of today is `none'. Ignoring `progress=today'% }% \def\gtt@progress{999}% \else\ifnum\gtt@today@slot>\gtt@right@slot\relax% \def\gtt@progress{100}% \else\ifnum\gtt@today@slot<\gtt@left@slot\relax% \def\gtt@progress{0}% \else% \pgfmathsetmacro\gtt@progress{% (\gtt@today@slot - \gtt@left@slot - \local@timeslotmodifier)% / (\gtt@right@slot - \gtt@left@slot - \local@timeslotmodifier)% * 100% }% \fi\fi\fi% \fi% \fi%

\x @clip@size

Now we determine whether only the complete part of the chart element, only its incomplete one or both are drawn. In the former two cases, we refrain from clipping the (in)complete part.

\gtt@draw@completetrue% \gtt@draw@incompletetrue% \gtt@draw@cliptrue% \ifdim\gtt@progress pt<0.001pt\relax% \gtt@draw@completefalse% \gtt@draw@clipfalse% \else\ifdim\gtt@progress pt>99.999pt\relax% \gtt@draw@incompletefalse% \gtt@draw@clipfalse% \fi\fi% \ifgtt@draw@clip% \pgfmathsetmacro\x@clip@size{% (\gtt@right@slot - \gtt@left@slot - \local@timeslotmodifier)% * \gtt@progress / 100% } \pgfmathsetmacro\x@clip{% (\gtt@left@slot + \local@timeslotmodifier + \x@clip@size% + \ganttvalueof{today offset} - 1) * \ganttvalueof{x unit}% }% \fi%

We draw the chart element within a pgfinterruptboundingbox, since we clip a large area of the canvas in order to avoid removing parts of the chart element border.

\begin{pgfinterruptboundingbox}% \begin{scope}% \ifgtt@draw@clip% \clip (\x@left pt - 10cm, \y@upper pt + 10cm) rectangle (\x@clip pt, \y@lower pt - 10cm);% \fi% \ifgtt@draw@complete% \node [/pgfgantt/#5, minimum width=\x@size pt, minimum height=\y@size pt] (\gtt@name) at (\x@mid pt, \y@mid pt) {};% \fi% \end{scope}% \begin{scope}% \ifgtt@draw@clip% \clip (\x@clip pt, \y@upper pt + 10cm) rectangle (\x@right pt + 10cm, \y@lower pt - 10cm);% \fi% \ifgtt@draw@incomplete% \node [/pgfgantt/#5 incomplete, minimum width=\x@size pt, minimum height=\y@size pt] (\gtt@name) at (\x@mid pt, \y@mid pt) {};% \fi% \end{scope}% \end{pgfinterruptboundingbox}%

If progress differs from none and progress label text differs from \relax, the progress label is drawn.

\ifdim\gtt@progress pt=999pt\relax\else% \expandafter\ifx\gtt@progresslabeltext\relax\relax\else% \node at (\gtt@name.\ganttvalueof{#5 progress label anchor}) [/pgfgantt/#5 progress label node] {\gtt@progresslabeltext{\gtt@progress}};% \fi% \fi%

If ⟨label⟩ is not empty, a label is printed. Its anchor is either at the ⟨type⟩ inline label anchor of the chart element (inline=true) or at the left canvas border halfway between the upper and lower \(y\)-coordinate of the chart element (inline=false).

\def\@tempa{#2}% \ifx\@tempa\@empty\else% \ifgtt@inline% \node at (\gtt@name.\ganttvalueof{#5 inline label anchor}) [/pgfgantt/#5 inline label node] {\csname gtt@#5labeltext\endcsname{#2}};% \else% \node at (0, \y@mid pt) [/pgfgantt/#5 label node] {\csname gtt@#5labeltext\endcsname{#2}};% \fi% \fi%

Since the first bar clearly appears after the last line containing a title element, we set the boolean \ifgtt@intitle to false.

\xdef\gtt@lastelement{\gtt@currentelement}% \xdef\gtt@currentelement{\gtt@name}% \global\advance\gtt@elementid by1\relax% \global\gtt@intitlefalse% \endgroup% }

\newganttchartelement

\newganttchartelement *

\newganttchartelement checks whether it was invoked in the starred or nonstarred form and executes \@newganttchartelement@one or \@newganttchartelement@two, respectively.

\def\newganttchartelement{% \@gtt@ifstar\@newganttchartelement@one\@newganttchartelement@two% }

\@newganttchartelement@one

\@newganttchartelement@two

Both \@newganttchartelement@one{⟨type⟩} and ...two{⟨type⟩} define two macros \gantt⟨type⟩ and \ganttlinked⟨type⟩, which draw a singular chart element or one that is linked to its predecessor. However, the newly defined macros will take three or four mandatory arguments (cf. \ganttmilestone vs. \ganttbar). At the end, we execute \@newganttchartelement@definekeys to process the second mandatory argument of \newganttchartelement.

\newcommand\@newganttchartelement@one[1]{% \expandafter\newcommand\csname gantt#1\endcsname[3][]{% \gtt@chartelement[##1]{##2}{##3}{##3}{#1}% }% \expandafter\newcommand\csname ganttlinked#1\endcsname[3][]{% \begingroup% \ganttset{##1}% \gtt@chartelement{##2}{##3}{##3}{#1}% \ganttlink{\gtt@lastelement}{\gtt@currentelement}% \endgroup% }% \@newganttchartelement@definekeys{#1}% } \newcommand\@newganttchartelement@two[1]{% \expandafter\newcommand\csname gantt#1\endcsname[4][]{% \gtt@chartelement[##1]{##2}{##3}{##4}{#1}% }% \expandafter\newcommand\csname ganttlinked#1\endcsname[4][]{% \begingroup% \ganttset{##1}% \gtt@chartelement{##2}{##3}{##4}{#1}% \ganttlink{\gtt@lastelement}{\gtt@currentelement}% \endgroup% }% \@newganttchartelement@definekeys{#1}% }

\@newganttchartelement@definekeys

\@newganttchartelement@definekeys{⟨type⟩}{⟨key-value list⟩} introduces 14 keys for the newly generated chart element ⟨type⟩.

\newcommand\@newganttchartelement@definekeys[2]{% \@gtt@stylekeydef{#1}{shape=rectangle, inner sep=0pt, draw, fill=white}% \@gtt@stylekeydef{#1 incomplete}{/pgfgantt/#1, fill=black!25}% \@gtt@keydef{#1 label font}{\normalsize}% \@gtt@stylekeydef{#1 label node}{% anchor=east, font=\ganttvalueof{#1 label font}% }% \@gtt@keydef{#1 inline label anchor}{center}% \@gtt@stylekeydef{#1 inline label node}{% anchor=center, font=\ganttvalueof{#1 label font}% }% \@gtt@keydef{#1 progress label anchor}{east}% \@gtt@keydef{#1 progress label font}{\scriptsize}% \@gtt@stylekeydef{#1 progress label node}{% anchor=west, font=\ganttvalueof{#1 progress label font}% }% \@gtt@keydef{#1 left shift}{0}% \@gtt@keydef{#1 right shift}{0}% \@gtt@keydef{#1 top shift}{.3}% \@gtt@keydef{#1 height}{.4}% \ganttset{% #1 label text/.code={% \expandafter\def\csname gtt@#1labeltext\endcsname####1{##1}% },% #1 label text=\strut##1,% #2% }% }

\ganttbar

\ganttlinkedbar

bar

bar incomplete

bar label text

bar label font

bar label node

bar inline label anchor

bar inline label node

bar progress label anchor

bar progress label font

bar progress label node

bar left shift

bar right shift

bar top shift

bar height

Code for the predefined chart element type bar.

\newganttchartelement{bar}{% bar/.style={shape=ganttbar, inner sep=0pt, draw, fill=white},% bar incomplete/.style={/pgfgantt/bar, fill=black!25},% bar label text=\strut#1,% bar label font=\normalsize,% bar label node/.style={% anchor=east, font=\ganttvalueof{bar label font}% },% bar inline label anchor=center,% bar inline label node/.style={% anchor=center, font=\ganttvalueof{bar label font}% },% bar progress label anchor=east,% bar progress label font=\scriptsize,% bar progress label node/.style={% anchor=west, font=\ganttvalueof{bar progress label font}% },% bar left shift=0,% bar right shift=0,% bar top shift=.3,% bar height=.4% }

\ganttgroup

\ganttlinkedgroup

group

group incomplete

group label text

group label font

group label node

group inline label anchor

group inline label node

group progress label anchor

group progress label font

group progress label node

group left shift

group right shift

group top shift

group height

Code for the predefined chart element type group.

\newganttchartelement{group}{% group/.style={shape=ganttgroup, inner sep=0pt, fill=black},% group incomplete/.style={/pgfgantt/group, fill=black!25},% group label text=\strut#1,% group label font=\bfseries,% group label node/.style={% anchor=east, font=\ganttvalueof{group label font}% },% group inline label anchor=center,% group inline label node/.style={% anchor=south, font=\ganttvalueof{group label font}% },% group progress label anchor=east,% group progress label font=\scriptsize,% group progress label node/.style={% anchor=west, font=\ganttvalueof{group progress label font}% },% group left shift=-.1,% group right shift=.1,% group top shift=.4,% group height=.2% }

group right peak tip position

group right peak width

group right peak height

group left peak tip position

group left peak width

group left peak height

group peaks tip position

group peaks width

group peaks height

More keys for the appearance of groups.

\@gtt@keydef{group right peak tip position}{.5} \@gtt@keydef{group right peak width}{.4} \@gtt@keydef{group right peak height}{.1} \@gtt@keydef{group left peak tip position}{.5} \@gtt@keydef{group left peak width}{.4} \@gtt@keydef{group left peak height}{.1} \ganttset{% group peaks tip position/.code={% \ganttset{% group left peak tip position=#1,% group right peak tip position=#1% }% },% group peaks width/.code={% \ganttset{% group left peak width=#1,% group right peak width=#1% }% },% group peaks height/.code={% \ganttset{% group left peak height=#1,% group right peak height=#1% }% }% }

\ganttmilestone

\ganttlinkedmilestone

milestone

milestone incomplete

milestone label text

milestone label font

milestone label node

milestone inline label anchor

milestone inline label node

milestone progress label anchor

milestone progress label font

milestone progress label node

milestone left shift

milestone right shift

milestone top shift

milestone height

Code for the predefined chart element type milestone.

\newganttchartelement*{milestone}{% milestone/.style={% shape=ganttmilestone, inner sep=0pt, draw, fill=black% },% milestone incomplete/.style={/pgfgantt/milestone, fill=black!25},% milestone label text=\strut#1,% milestone label font=\itshape,% milestone label node/.style={% anchor=east, font=\ganttvalueof{milestone label font}% },% milestone inline label anchor=center,% milestone inline label node/.style={% anchor=south, font=\ganttvalueof{milestone label font}% },% milestone progress label anchor=center,% milestone progress label font=\scriptsize,% milestone progress label node/.style={% anchor=west, font=\ganttvalueof{milestone progress label font}% },% milestone left shift=.6,% milestone right shift=.4,% milestone top shift=.3,% milestone height=.4% }
3.10Node Shapes

on top fraction

on bottom fraction

on left fraction

on right fraction

Keys for configuring the additional anchors of the new node shapes.

\@gtt@keydef{on top fraction}{.5} \@gtt@keydef{on bottom fraction}{.5} \@gtt@keydef{on left fraction}{.5} \@gtt@keydef{on right fraction}{.5}

Code for node shape ganttbar. Anchors and background path derive from node shape rectangle. The four additional anchors on top, on bottom, on left and on right are defined.

\pgfdeclareshape{ganttbar}{ \inheritsavedanchors[from=rectangle] \inheritanchor[from=rectangle]{center} \inheritanchor[from=rectangle]{mid} \inheritanchor[from=rectangle]{base} \inheritanchor[from=rectangle]{north} \inheritanchor[from=rectangle]{south} \inheritanchor[from=rectangle]{west} \inheritanchor[from=rectangle]{mid west} \inheritanchor[from=rectangle]{base west} \inheritanchor[from=rectangle]{north west} \inheritanchor[from=rectangle]{south west} \inheritanchor[from=rectangle]{east} \inheritanchor[from=rectangle]{mid east} \inheritanchor[from=rectangle]{base east} \inheritanchor[from=rectangle]{north east} \inheritanchor[from=rectangle]{south east} \inheritanchorborder[from=rectangle] \anchor{on top}{ \southwest \pgf@xa=\pgf@x \northeast \pgf@xb=\pgf@x \advance\pgf@xb by-\pgf@xa \pgf@xb=\ganttvalueof{on top fraction}\pgf@xb \advance\pgf@xa by\pgf@xb \pgf@x=\pgf@xa } \anchor{on bottom}{ \northeast \pgf@xb=\pgf@x \southwest \pgf@xa=\pgf@x \advance\pgf@xb by-\pgf@xa \pgf@xb=\ganttvalueof{on bottom fraction}\pgf@xb \advance\pgf@xa by\pgf@xb \pgf@x=\pgf@xa } \anchor{on left}{ \northeast \pgf@ya=\pgf@y \southwest \pgf@yb=\pgf@y \advance\pgf@yb by-\pgf@ya \pgf@yb=\ganttvalueof{on left fraction}\pgf@yb \advance\pgf@ya by\pgf@yb \pgf@y=\pgf@ya } \anchor{on right}{ \southwest \pgf@yb=\pgf@y \northeast \pgf@ya=\pgf@y \advance\pgf@yb by-\pgf@ya \pgf@yb=\ganttvalueof{on right fraction}\pgf@yb \advance\pgf@ya by\pgf@yb \pgf@y=\pgf@ya } \inheritbackgroundpath[from=rectangle] }

Code for node shape ganttgroup. Anchors derive from node shape ganttbar. The two additional anchors left peak and right peak are defined.

\pgfdeclareshape{ganttgroup}{ \inheritsavedanchors[from=rectangle] \inheritanchor[from=rectangle]{center} \inheritanchor[from=rectangle]{mid} \inheritanchor[from=rectangle]{base} \inheritanchor[from=rectangle]{north} \inheritanchor[from=rectangle]{south} \inheritanchor[from=rectangle]{west} \inheritanchor[from=rectangle]{mid west} \inheritanchor[from=rectangle]{base west} \inheritanchor[from=rectangle]{north west} \inheritanchor[from=rectangle]{south west} \inheritanchor[from=rectangle]{east} \inheritanchor[from=rectangle]{mid east} \inheritanchor[from=rectangle]{base east} \inheritanchor[from=rectangle]{north east} \inheritanchor[from=rectangle]{south east} \inheritanchorborder[from=rectangle] \inheritanchor[from=ganttbar]{on top} \inheritanchor[from=ganttbar]{on bottom} \inheritanchor[from=ganttbar]{on left} \inheritanchor[from=ganttbar]{on right} \anchor{left peak}{ \pgf@process{ \pgfpointadd{ \southwest }{ \pgfpoint% {\pgfkeysvalueof{/pgf/outer xsep}}% {\pgfkeysvalueof{/pgf/outer ysep}} } } \pgfmathsetlength\pgf@x{ \pgf@x + \ganttvalueof{group left peak tip position} * \ganttvalueof{group left peak width} * \ganttvalueof{x unit} } \pgfmathsetlength\pgf@y{ \pgf@y - \ganttvalueof{group left peak height} * \ganttvalueof{y unit chart} } } \anchor{right peak}{ \pgf@process{ \pgfpointadd{ \northeast }{ \pgfpointscale{-1}{ \pgfpoint% {\pgfkeysvalueof{/pgf/outer xsep}}% {\pgfkeysvalueof{/pgf/outer ysep}} } } } \pgf@xa=\pgf@x \pgf@process{ \pgfpointadd{ \southwest }{ \pgfpoint% {\pgfkeysvalueof{/pgf/outer xsep}}% {\pgfkeysvalueof{/pgf/outer ysep}} } } \pgfmathsetlength\pgf@x{ \pgf@xa - \ganttvalueof{group right peak tip position} * \ganttvalueof{group right peak width} * \ganttvalueof{x unit} } \pgfmathsetlength\pgf@y{ \pgf@y - \ganttvalueof{group right peak height} * \ganttvalueof{y unit chart} } } \backgroundpath{ \pgf@process{ \pgfpointadd{ \northeast }{ \pgfpointscale{-1}{ \pgfpoint% {\pgfkeysvalueof{/pgf/outer xsep}}% {\pgfkeysvalueof{/pgf/outer ysep}} } } } \pgf@xb=\pgf@x \pgf@ya=\pgf@y \pgf@process{ \pgfpointadd{ \southwest }{ \pgfpoint% {\pgfkeysvalueof{/pgf/outer xsep}}% {\pgfkeysvalueof{/pgf/outer ysep}} } } \pgf@xa=\pgf@x \pgf@yb=\pgf@y \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}} \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}} \pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}} \pgfmathsetlength\pgf@xc{ \pgf@xb - \ganttvalueof{group right peak tip position} * \ganttvalueof{group right peak width} * \ganttvalueof{x unit} } \pgfmathsetlength\pgf@yc{ \pgf@yb - \ganttvalueof{group right peak height} * \ganttvalueof{y unit chart} } \pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@yc}} \pgfmathsetlength\pgf@xc{ \pgf@xb - \ganttvalueof{group right peak width} * \ganttvalueof{x unit} } \pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@yb}} \pgfmathsetlength\pgf@xc{ \pgf@xa + \ganttvalueof{group left peak width} * \ganttvalueof{x unit} } \pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@yb}} \pgfmathsetlength\pgf@xc{ \pgf@xa + \ganttvalueof{group left peak tip position} * \ganttvalueof{group left peak width} * \ganttvalueof{x unit} } \pgfmathsetlength\pgf@yc{ \pgf@yb - \ganttvalueof{group left peak height} * \ganttvalueof{y unit chart} } \pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@yc}} \pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@yb}} \pgfpathclose } }

Code for node shape ganttmilestone. Anchors and background path derive from node shape diamond. The four additional anchors on top, on bottom, on left and on right are defined.

\pgfdeclareshape{ganttmilestone}{ \inheritsavedanchors[from=diamond] \inheritanchor[from=diamond]{text} \inheritanchor[from=diamond]{center} \inheritanchor[from=diamond]{mid} \inheritanchor[from=diamond]{base} \inheritanchor[from=diamond]{north} \inheritanchor[from=diamond]{south} \inheritanchor[from=diamond]{west} \inheritanchor[from=diamond]{north west} \inheritanchor[from=diamond]{south west} \inheritanchor[from=diamond]{east} \inheritanchor[from=diamond]{north east} \inheritanchor[from=diamond]{south east} \inheritanchorborder[from=diamond] \inheritbackgroundpath[from=diamond] \anchor{on top}{ \pgf@process{\outernortheast} \pgf@xa=2\pgf@x \pgf@x=-\pgf@x \advance\pgf@x by\ganttvalueof{on top fraction}\pgf@xa \pgf@ya=2\pgf@y \pgf@y=0pt \pgfmathparse{ \ganttvalueof{on top fraction} < 0.5 ? \ganttvalueof{on top fraction} : 1 - \ganttvalueof{on top fraction} } \advance\pgf@y by\pgfmathresult\pgf@ya } \anchor{on bottom}{ \pgf@process{\outernortheast} \pgf@xa=2\pgf@x \pgf@x=-\pgf@x \advance\pgf@x by\ganttvalueof{on bottom fraction}\pgf@xa \pgf@ya=-2\pgf@y \pgf@y=0pt \pgfmathparse{ \ganttvalueof{on bottom fraction} < 0.5 ? \ganttvalueof{on bottom fraction} : 1 - \ganttvalueof{on bottom fraction} } \advance\pgf@y by\pgfmathresult\pgf@ya } \anchor{on right}{ \pgf@process{\outernortheast} \pgf@ya=-2\pgf@y \advance\pgf@y by\ganttvalueof{on right fraction}\pgf@ya \pgf@xa=2\pgf@x \pgf@x=0pt \pgfmathparse{ \ganttvalueof{on right fraction} < 0.5 ? \ganttvalueof{on right fraction} : 1 - \ganttvalueof{on right fraction} } \advance\pgf@x by\pgfmathresult\pgf@xa } \anchor{on left}{ \pgf@process{\outernortheast} \pgf@ya=-2\pgf@y \advance\pgf@y by\ganttvalueof{on left fraction}\pgf@ya \pgf@xa=-2\pgf@x \pgf@x=0pt \pgfmathparse{ \ganttvalueof{on left fraction} < 0.5 ? \ganttvalueof{on left fraction} : 1 - \ganttvalueof{on left fraction} } \advance\pgf@x by\pgfmathresult\pgf@xa } }
3.11Links

link

link type

link label

link label font

link label node

Keys for configuring links.

\@gtt@stylekeydef{link}{-latex, rounded corners=1pt} \@gtt@keydef{link type}{auto} \@gtt@keydef{link label}{} \@gtt@keydef{link label font}{\scriptsize\itshape} \@gtt@stylekeydef{link label node}{% anchor=west, font=\ganttvalueof{link label font}% }

\newganttlinktype

\newganttlinktype{⟨type⟩}{⟨code⟩} stores ⟨code⟩ in an internal macro
\@gtt@linktype@⟨type⟩, which is later called by \gtt@drawlink.

\newcommand\newganttlinktype[2]{% \expandafter\def\csname @gtt@linktype@#1\endcsname{#2}% }

\setganttlinklabel

\setganttlinklabel{⟨type⟩}{⟨label⟩} stores a given ⟨label⟩ in an internal macro \@gtt@linktype@⟨type⟩@label, which is later used by \gtt@drawlink.

\newcommand\setganttlinklabel[2]{% \expandafter\def\csname @gtt@linktype@#1@label\endcsname{#2}% }

\newganttlinktypealias

\newganttlinktypealias{⟨new link type⟩}{⟨existing link type⟩} copies both the link code and label of an ⟨existing link type⟩ into the internal macros associated with a ⟨new link type⟩.

\newcommand\newganttlinktypealias[2]{% \expandafter\def\csname @gtt@linktype@#1\endcsname{% \csname @gtt@linktype@#2\endcsname% }% \expandafter\def\csname @gtt@linktype@#1@label\endcsname{% \csname @gtt@linktype@#2@label\endcsname% }% }

link mid

link bulge

link tolerance

We will define three link subtypes for the type auto, which require the following keys:

\@gtt@keydef{link mid}{.5} \@gtt@keydef{link bulge}{.4} \@gtt@keydef{link tolerance}{.6}

(1) r (short for “right”) draws a straight arrow. Note that r and default are alias types.

\newganttlinktype{r}{% \draw [/pgfgantt/link] (\xLeft, \yUpper) -- (\xRight, \yLower) node [pos=.5, /pgfgantt/link label node] {\ganttlinklabel}; } \newganttlinktypealias{default}{r}

(2) rdr (“right-down-right”) is an unlabeled three-part arrow. The value of link mid sets the position of the middle segment.

\newganttlinktype{rdr}{% \draw [/pgfgantt/link] (\xLeft, \yUpper) -- ($(\xLeft, \yUpper)!\ganttvalueof{link mid}! (\xRight, \yUpper)$) -- ($(\xLeft, \yLower)!\ganttvalueof{link mid}! (\xRight, \yLower)$) -- (\xRight, \yLower);% }

(3) rdldr (“right-down-left-down-right”) is an unlabeled five-part arrow, which considers the values of link bulge and link mid.

\newganttlinktype{rdldr}{% \draw [/pgfgantt/link] (\xLeft, \yUpper) -- (\xLeft + \ganttvalueof{link bulge} * \ganttvalueof{x unit}, \yUpper) -- ($(\xLeft + \ganttvalueof{link bulge} * \ganttvalueof{x unit}, \yUpper)!% \ganttvalueof{link mid}!% (\xLeft + \ganttvalueof{link bulge} * \ganttvalueof{x unit}, \yLower)$) -- ($(\xRight - \ganttvalueof{link bulge} * \ganttvalueof{x unit}, \yUpper)!% \ganttvalueof{link mid}!% (\xRight - \ganttvalueof{link bulge} * \ganttvalueof{x unit}, \yLower)$) -- (\xRight - \ganttvalueof{link bulge} * \ganttvalueof{x unit}, \yLower) -- (\xRight, \yLower);% }

Now we may define linke type auto: The first and last coordinate of the link should touch the preceding or following element at the center of its right or left border, respectively. We check if the connected elements lie in the same row or not (i. e., their \(y\)-coordinates differ at most 1 pt). In the latter case, \pgfmathparse yields 0.

\newganttlinktype{auto}{% \pgfmathparse{abs(\yUpper - \yLower) <= 1}% \ifcase\pgfmathresult%

Once again, two possibilities arise: Either the elements to be connected are at least separated by link tolerance time slots, in which case we draw a three-part arrow (i. e., link type rdr). Alternatively, the elements lie in adjacent time slots or even overlap, in which case we draw a five-part arrow (i. e., link type rdldr).

\pgfmathparse{ (\xRight - \xLeft) >= \ganttvalueof{link tolerance} * \ganttvalueof{x unit} }% \ifcase\pgfmathresult% \gtt@drawlink{rdldr}% \else% \gtt@drawlink{rdr}% \fi%

For elements that lie in the same row, we draw a simple arrow (i. e., link type r).

\else% \gtt@drawlink{r}% \fi% }

The dr type is explained in section 2.9.

\newganttlinktype{dr}{% \ganttsetstartanchor{south}% \ganttsetendanchor{west}% \draw [/pgfgantt/link] (\xLeft, \yUpper) -- (\xLeft, \yLower) node [pos=.5, /pgfgantt/link label node] {\ganttlinklabel} -- (\xRight, \yLower);% }

Here is the definition of the four straight link types and their labels.

\newganttlinktype{s-s}{% \ganttsetstartanchor{south west}% \ganttsetendanchor{north west}% \draw [/pgfgantt/link] (\xLeft, \yUpper) -- (\xRight, \yLower) node [pos=.5, /pgfgantt/link label node] {\ganttlinklabel}; } \setganttlinklabel{s-s}{start-to-start} \newganttlinktype{s-f}{% \ganttsetstartanchor{on bottom=0}% \ganttsetendanchor{on top=1}% \draw [/pgfgantt/link] (\xLeft, \yUpper) -- (\xRight, \yLower) node [pos=.5, /pgfgantt/link label node] {\ganttlinklabel}; } \setganttlinklabel{s-f}{start-to-finish} \newganttlinktype{f-s}{% \ganttsetstartanchor{south east}% \ganttsetendanchor{north west}% \draw [/pgfgantt/link] (\xLeft, \yUpper) -- (\xRight, \yLower) node [pos=.5, /pgfgantt/link label node] {\ganttlinklabel}; } \setganttlinklabel{f-s}{finish-to-start} \newganttlinktype{f-f}{% \ganttsetstartanchor{south east}% \ganttsetendanchor{north east}% \draw [/pgfgantt/link] (\xLeft, \yUpper) -- (\xRight, \yLower) node [pos=.5, /pgfgantt/link label node] {\ganttlinklabel}; } \setganttlinklabel{f-f}{finish-to-finish}

\gtt @drawlink

\@gtt@currlinktype

\gtt@drawlink{⟨link type⟩} first checks if the ⟨link type⟩ is defined, falling back to type default if it is unknown. \@gtt@currlinktype stores the link type for future reference.

\newcommand\gtt@drawlink[1]{% \@ifundefined{@gtt@linktype@#1}{% \@gtt@PackageWarning{Link type `#1' unknown, using `default'.}% \def\@gtt@currlinktype{default}% }{% \def\@gtt@currlinktype{#1}% }%

\@gtt@currlabel

\ganttlinklabel

If the link label key contains any value, it locally overrides the label set by \setganttlinklabel. \ganttlinklabel is defined accordingly.

\edef\@gtt@currlabel{\ganttvalueof{link label}}% \ifx\@gtt@currlabel\@empty% \def\ganttlinklabel{% \csname @gtt@linktype@\@gtt@currlinktype @label\endcsname% }% \else% \edef\ganttlinklabel{% \ganttvalueof{link label}% }% \fi%

Finally, we call the internal macro that stores the code for the desired link type.

\csname @gtt@linktype@\@gtt@currlinktype\endcsname% }

\@gtt@link@anchor

We need the following keys for setting the start and end anchor of a link: Whenever a key /pgfgantt/link anchor/⟨anchor⟩ is undefined, pgfgantt stores ⟨anchor⟩ in \@gtt@link@anchor.

\ganttset{% link anchor/.unknown/.code={% \edef\@gtt@link@anchor{\pgfkeyscurrentname}% },% }

\@gtt@linkanchordef

\@gtt@linkanchordef{⟨anchor⟩} deals with the anchors on top etc.: It creates a code key /pgfgantt/link anchor/⟨anchor⟩, which stores its own name in \@gtt@link@anchor and sets the appropriate …fraction key.

\def\@gtt@linkanchordef#1{% \ganttset{% link anchor/#1/.code={% \edef\@gtt@link@anchor{#1}% \ganttset{#1 fraction=##1}% },% link anchor/#1/.default=.5% }% } \@gtt@linkanchordef{on top} \@gtt@linkanchordef{on bottom} \@gtt@linkanchordef{on left} \@gtt@linkanchordef{on right}

\@gtt@setstartanchor

\xLeft

\yUpper

\@gtt@setstartanchor{⟨anchor⟩} recalls the coordinates of the anchor stored in \@gtt@link@anchor from chart element \@gtt@link@startelement. It stores these coordinates in the auxiliary macros \xLeft and \yUpper.

\newcommand\@gtt@setstartanchor[1]{% \pgfqkeys{/pgfgantt/link anchor}{#1}% \pgfpointanchor{\@gtt@link@startelement}{\@gtt@link@anchor}% \edef\xLeft{\the\pgf@x}% \edef\yUpper{\the\pgf@y}% }

\@gtt@setendanchor

\xRight

\yLower

\@gtt@setendanchor{⟨anchor⟩} is similar to the command above. However, it stores the anchor coordinates in the auxiliary macros \xRight and \yLower.

\newcommand\@gtt@setendanchor[1]{% \pgfqkeys{/pgfgantt/link anchor}{#1}% \pgfpointanchor{\@gtt@link@endelement}{\@gtt@link@anchor}% \edef\xRight{\the\pgf@x}% \edef\yLower{\the\pgf@y}% }

\ganttlink

\@gtt@link@startelement

\@gtt@link@endelement

\ganttlink[⟨options⟩]{⟨E1⟩}{⟨E2⟩} executes the ⟨options⟩ and stores the names of the connected elements ⟨E1⟩ and ⟨E2⟩ in \@gtt@link@startelement and \@gtt@link@endelement.

\newcommand\ganttlink[3][]{% \begingroup% \ganttset{#1}% \def\@gtt@link@startelement{#2}% \def\@gtt@link@endelement{#3}%

\ganttsetstartanchor

\ganttsetendanchor

\ganttsetstartanchor and \ganttsetendanchor are only valid in the second argument of \newganttlinktype. Since you may wish to omit one of those commands, we set default anchors for the link.

\let\ganttsetstartanchor\@gtt@setstartanchor% \let\ganttsetendanchor\@gtt@setendanchor% \ganttsetstartanchor{east}% \ganttsetendanchor{west}%

We call \gtt@drawlink with the value of link type.

\gtt@drawlink{\ganttvalueof{link type}}% \endgroup% }