% \iffalse meta-comment
%
% Copyright (C) 2025 Alan J. Cain
%
% This file may be distributed and/or modified under the conditions of the LaTeX Project Public Licence, either version
% 1.3c of this licence or (at your option) any later version. The latest version of this licence is in:
%
%
http://www.latex-project.org/lppl.txt
%
% and version 1.3c or later is part of all distributions of LaTeX version 2008-05-04 or later.
%
% \fi
%
% \iffalse
%<*driver>
\PassOptionsToPackage{inline}{enumitem}
\documentclass{l3doc}
% Make space for larger numbers in contents
\makeatletter
\ExplSyntaxOn
\cs_gset:Npn \l@subsection { \@dottedtocline{2}{2.5em}{2.8em} }
\cs_gset:Npn \l@subsubsection { \@dottedtocline{3}{5.3em}{4em} }
\ExplSyntaxOff
\makeatother
% Link formatting
\usepackage{xcolor}
\definecolor{linkcolor}{rgb}{0.0,0.4,0.7}
\colorlet{citecolor}{linkcolor}
\colorlet{urlcolor}{linkcolor}
\hypersetup{
linkcolor=linkcolor,%
citecolor=citecolor,%
urlcolor=urlcolor,%
}
\newcommand*\fullref[2]{%
\hyperref[#2]{#1\penalty 200\ \ref*{#2}}%
}
% Use siunitx for typesetting dimensions
\usepackage{siunitx}
\sisetup{
mode=match,
}
\DeclareSIUnit\point{pt}
% Listings and grammars
\usepackage{listings}
\lstset{
language=[LaTeX]TeX,
basicstyle=\small\ttfamily,
basewidth=0.5em,
numbers=left,
numberstyle=\scriptsize\sffamily,
}
\usepackage{simplebnf}
% Macros for describing keys
\newlist{optionlist}{description}{1}
\setlist[optionlist]{
leftmargin=3em,
style=unboxed,
labelsep=1em,
font=\descriptionitemcolon,
nosep,
}
\newcommand*{\descriptionitemcolon}[1]{\kern 1em #1:}
\newcommand*\key[1]{\texttt{#1}}
\newcommand*\val[1]{\texttt{#1}}
\newcommand*\keyval[2]{\texttt{#1=#2}}
\usepackage{xcolor}
\definecolor{keycolor}{rgb}{0.8,0.0,0.0}
\definecolor{keyvaluecolor}{rgb}{0.0,0.65,0.0}
\ExplSyntaxOn
\NewDocumentEnvironment{describekey}{ m m m }{
\group_begin:
\group_begin:
\noindent{\textcolor{keycolor}{\texttt{#1}}}
\str_if_empty:nF{#2}
{
\skip_set:Nn{\parfillskip}{0pt}
\str_case:nnF{#2}
{
{style}
{
\hfil
(style,~initially~#3)
}
}
{
\textcolor{keyvaluecolor}{\texttt{=}\meta{#2}}
\str_if_empty:nF{#3}
{
\hfil
(default\nobreakspace\texttt{#3})
}
}
}
\par
\group_end:
\nobreak
\skip_add:Nn{\leftskip}{\parindent}
\noindent\ignorespaces
}{
\par
\group_end:
}
\ExplSyntaxOff
\newcommand*\mcode[1]{\texttt{#1}}
\newcommand*\param[1]{\texttt{\##1}}
% Other macros
\newcommand*\TikZ{\texorpdfstring{Ti\textit{k}Z}{TikZ}}
\newcommand*\ISO{\textsc{iso}}
% Timechart
\usepackage{timechart}
\input{timechart-example1-setup.tex}
\begin{document}
\DocInput{timechart.dtx}
\end{document}
%</driver>
% \fi
%
%
%
% \GetFileInfo{timechart.sty}
%
%
%
% \title{^^A
% \pkg{timechart} ^^A
% --- A package for drawing chronological charts^^A
% \thanks{This file describes \fileversion, last revised \filedate.}^^A
% }
%
% \author{^^A
% Alan J. Cain^^A
% }
%
% \date{Released \filedate}
%
% \maketitle
%
%
%
% \begin{abstract}
% This package provides for the easy creation of chronological charts which show visually the relative historical
% positions of people and events. Each event or period can be specified by a single line of \LaTeX\ code comprising
% (possibly uncertain) start and finish dates and a label, and the package takes care of indicating the uncertainties
% and whether intervals extend beyond the specified bounds of the chart.
% \end{abstract}
%
%
%
% \tableofcontents
%
%
%
% \begin{documentation}
%
% \setcounter{secnumdepth}{2}
%
%
% \section{Introduction}
%
% The \pkg{timechart} package provides a system for the easy creation of chronological charts --- of the type pioneered
% by Joseph Priestley (1733--1804) in his `Chart of Biography' and more famously in his `New Chart of
% History'\footnote{\textsc{url}:~\url{
https://commons.wikimedia.org/wiki/File:A_New_Chart_of_History_color.jpg}} ---
% which can show visually the relative historical positions of people and events. An example of what \pkg{timechart} can
% be used to produce is shown in \fullref{Figure}{fig:example1} on page~\pageref{fig:example1}.
%
% \begin{figure}[p]
% \centering
% \input{timechart-example1-timechart.tex}
% \caption{Timechart showing the lifetimes of Roman emperors from \timechartmakebeforeyear{50} to
% \timechartmakeafteryear{500}. Marks on each lifetime indicate the beginning (and, where relevant, the end) of that
% emperor's reign. Colours generally indicate dynasties, with shades of green indicating periods when the imperial
% power shifted between many short-reigning emperors.}
% \label{fig:example1}
% \end{figure}
%
% Essentially (and this was a design requirement), \emph{only one line} of \LaTeX\ code is required for each interval
% (which, in the case of \fullref{Figure}{fig:example1}, are mostly lifetimes). The \pkg{timechart} package takes care
% of indicating ranges of possible dates by suitable fading from or to transparency. It also handles indicators to show
% that intervals continue outside the specified scope of the chart.
%
% \pkg{timechart} was developed from, and replaced, a set of macros used to create the chronological charts in the
% author's book \textit{Form \& Number: A History of Mathematical Beauty}, which is available on the Internet Archive
% under a Creative Commons licence.\footnote{\textsc{url}:
% \url{
https://archive.org/details/cain_formandnumber_ebook_large}}
%
%
%
% \paragraph*{Licence.} \noindent\pkg{timechart} is released under the \LaTeX\ Project Public Licence v1.3c or
% later.\footnote{\textsc{url}: \url{
https://www.latex-project.org/lppl.txt}}
%
%
%
% \paragraph*{Acknowledgements.} The author thanks Tânia Paulista for reading and commenting on an earlier draft of the
% documentation.
%
%
%
% \section{Requirements}
%
% \pkg{timechart} requires PGF/\TikZ\ and a \LaTeX\ kernel with \pkg{expl3} support (any kernel version since 2020-02-02
% should suffice).
%
%
%
% \section{Installation}
%
% To install manually, run \texttt{tex timechart.ins} and copy the file \file{timechart.sty} to somewhere \LaTeX\ can
% find it.
%
%
%
% \section{Getting started}
%
% The \pkg{timechart} package is loaded as usual via \cs{usepackage}\texttt{\{timechart\}}. There are no package
% options.
%
% The small example in \fullref{Section}{sec:example} illustrates the basic principles of \pkg{timechart}.
% \fullref{Section}{sec:full-example} shows the full code used to produce the large example in \fullref{Figure}{fig:example1}.
%
%
%
%
%
% \section{Example}
% \label{sec:example}
%
% This section illustrates how to create the small chart shown in \fullref{Figure}{fig:example2-v2} on
% page~\pageref{fig:example2-v2}.
%
% The basic environment is \env{timechart}, which includes the specification of the start and finish years. The start
% year \timechartmakebeforeyear{50} is specified as \mcode{-50}, the finish year \timechartmakeafteryear{75} as
% \mcode{75}. Each interval in the chart is specified using the \cs{timechartinterval} command, which takes three
% mandatory parameters: a start year, a finish year, and a label. The following code produces the flawed preliminary
% version shown in \fullref{Figure}{fig:example2-v1}.
%
% \lstinputlisting{timechart-example2-v1.tex}
%
% \begin{figure}[ht]
% \centering
% \input{timechart-example2-v1.tex}
% \medskip
% \caption{Flawed preliminary version of a chart showing the lifetimes of Roman emperors of the Julio-Claudian
% dynasty. (The final version is shown in \fullref{Figure}{fig:example2-v2}.)}
% \label{fig:example2-v1}
% \end{figure}
%
% This first attempt result illustrates some of the principles of \pkg{timechart}. Each interval has been placed on its
% own line. More precisely, the \(y\) coordinate of the first interval is \(0\) and each use of \cs{timechartinterval}
% increments the `current \(y\) coordinate' by a specified amount. (Various commands are available to set the \(y\)
% coordinate manually or to reset it automatically when it passes certain bounds; see
% \fullref{Subsection}{subsec:positioning}.) Horizontally, the chart starts and finishes at the specified years. The topmost
% interval, indicating Augustus' life, has been truncated with an indicator that it begins before the specified start
% year of the chart. Vertically, the chart has been sized to fit around the specified intervals.
%
% But this version is hardly satisfactory, for many reasons. The chart finishes between two minor ticks on the axis,
% because the intervals between major and minor ticks default respectively to 10 years and 50 years. The black intervals
% and text do not contrast well with the black axis and grid. The serif font is perhaps not best suited to label the
% intervals. And the label `Augustus' has been lost, since labels are by default placed on the left of intervals. To
% rectify these problems, some changes are necessary, all of which can be made using key-value syntax in an optional
% parameter to the \env{timechart} environment or the \cs{timechartinterval} command:
% \begin{enumerate}
% \item Set the intervals between major and minor ticks to 5 years and 25 years respectively, by setting
% \keyval{minor tick interval}{5} and \keyval{major tick interval}{25}.
% \item Change the colour of the grid to light grey by appending \keyval{draw}{lightgray} to the \key{grid} style
% \item Change the colour of the axis to grey by appending \keyval{draw}{gray} to the \key{axis line}, \key{minor
% tick}, and \key{major tick} styles.
% \item Change the font used for interval labels to small san-serif by appending \keyval{node
% font}{\cs{sffamily}\cs{small}} to the \key{interval label} style
% \item Change the colour of the intervals by defining a style \key{julioclaudian} that sets \keyval{interval bar
% color}{red!80!black} and applying it to each interval via its optional argument. (While \key{interval bar
% color} could be set locally for each interval, it is better to define a style that corresponds to the
% semantic meaning of the colour: in this case, a single dynasty.)
% \item Use the \key{right} key to place some labels on the right
% \end{enumerate}
%
% The result is the following code, which produces \fullref{Figure}{fig:example2-v2}.
%
% \lstinputlisting{timechart-example2-v2.tex}
%
% \begin{figure}[ht]
% \centering
% \input{timechart-example2-v2.tex}
% \caption{Chart showing the lifetimes of Roman emperors of the Julio-Claudian dynasty.}
% \label{fig:example2-v2}
% \end{figure}
%
%
%
% \section{Configuration}
%
% All \pkg{timechart} configuration, global or local, is via PGF keys, so some familiarity with their use is beneficial;
% see the PGF/\TikZ\ manual.
%
% Configuration keys for \pkg{timechart} are contained in \key{/timechart/} in the PGF keys hierarchy. The
% \meta{options} passed to the \env{timechart} environment or any of the commands \cs{timechartinterval},
% \cs{timecharttext}, or \cs{timechartspace} are processed within \key{/timechart/} (since \key{/timechart/.cd} is
% executed before keys are processed).
%
% The user may wish to define PGF styles for different kinds of interval within a chart. For example, one could
% define styles \key{science} and \key{art} that set a particular colour for the interval, and write
% \cs{timechartinterval}\key{[science]}\marg{birth}\marg{death}\marg{name} or
% \cs{timechartinterval}\key{[art]}\marg{birth}\marg{death}\marg{name} to distinguish visually the lifetimes of
% various scientists and artists.
%
%
%
% \section{Specifying dates and date ranges}
% \label{sec:dates-and-ranges}
%
% Using \pkg{timechart} requires specification of dates and date ranges for the start and finish of each interval, both
% of which may be uncertain.
%
% The basic specification of a date uses \ISO~8601 format \mcode{YYYY-MM-DD}. This format specifies a date with
% day-level precision; use \mcode{YYYY-MM} and \mcode{YYYY} for month- and year-level precision. If the date is prefixed
% by \mcode{-}, it is treated as the corresponding date before the epoch. (This is a difference with \ISO~8601, in which
% \texttt{0} represents \timechartmakebeforeyear{1}, \texttt{-1} represents \timechartmakebeforeyear{2}, and so on.) So
% (assuming that one is using \textsc{bce}/\textsc{ce}) one uses \mcode{-100} to indicate \timechartmakebeforeyear{100}
% and \mcode{100} to indicate \timechartmakeafteryear{100}. (The era indicators `\textsc{bce}' and `\textsc{ce}' appear
% on the axis. Alternative era indicators --- or a different epoch --- can be specified; see
% \fullref{Section}{sec:era-indicators}.)
%
% A date can be prefixed with a \mcode{c} to indicate `circa', such as \mcode{c-100} for `circa
% \timechartmakebeforeyear{100}' and \mcode{c100} for `circa \timechartmakeafteryear{100}'. When an interval is drawn in
% a chart, `circa' will be indicated by automatically creating (or extending) a range according to the value of the key
% \key{circa uncertainty} (see \fullref{Subsection}{subsec:intervals}).
%
% A date range comprises two dates (each with or without \mcode{c}) separated by a slash \mcode{/}, with the first date
% being earlier (or equal to) the second date. (The slash indicates a range of dates per \ISO~8601.) A date
% range can be used to indicate a broader uncertainty than the default `circa', or to indicate a definite range within
% which an interval starts or ends.
%
% \begin{description}
% \item[Examples of correctly formatted dates and date ranges:] \mcode{-50}, \mcode{100}, \mcode{c-50},
% \mcode{c100}, \mcode{-50/100}, \mcode{c-50 / +100}, \mcode{-50/c100}, \mcode{c-50/c100}, \mcode{-585-05-28},
% \mcode{1947-12-01}, \mcode{1989-11}.
%
% \item[Examples of incorrectly formatted date and date ranges:] \mcode{100?}, \mcode{100CE}, \mcode{100BCE},
% \mcode{-50-100}, \mcode{100/-50}.
% \end{description}
%
% \noindent That is, the syntax for dates and date ranges is per the following (not-quite-formal) grammar:
%
% \smallskip
%
% \begin{bnf}
% \meta{cdate-or-crange} ::= \meta{cdate}
% | \meta{crange} ;;
% \meta{cdate} ::= \meta{date}
% | \mcode{c}\meta{date} ;;
% \meta{date} ::= \meta{pdate}
% | \mcode{-}\meta{pdate} ;;
% \meta{pdate} ::= \meta{year}\mcode{-}\meta{month}\mcode{-}\meta{day}
% | \meta{year}\mcode{-}\meta{month}
% | \meta{year} ;;
% \meta{crange} ::= \meta{\(\text{date}_1\)}\mcode{/}\meta{\(\text{date}_2\)}
% | \mcode{c}\meta{\(\text{date}_1\)}\mcode{/}\meta{\(\text{date}_2\)}
% | \meta{\(\text{date}_1\)}\mcode{/}\mcode{c}\meta{\(\text{date}_2\)}
% | \mcode{c}\meta{\(\text{date}_1\)}\mcode{/}\mcode{c}\meta{\(\text{date}_2\)} ~~~(with \(\text{date}_1 \leq \text{date}_2\)) ;;
% \end{bnf}
%
% \smallskip
%
% \noindent The bounds of the \env{timechart} environment (see \fullref{Section}{sec:timechart-env}) must satisfy
% \meta{cdate} in this grammar (although only the \meta{year} is used); the start and finish dates of an
% \cs{timechartinterval} command (see \fullref{Subsection}{subsec:intervals}) must satisfy \meta{cdate-or-crange}; the
% parameter of an \cs{timecharttext} command (see \fullref{Subsection}{subsec:text}) must satisfy \meta{date}.
%
% \medskip
% \noindent \textit{Note.} For performance reasons, the date parser does only limited error-checking. Months outside the
% range from \mcode{01} to \mcode{12} or days outside the range of the specified month will be ignored. Otherwise
% malformed dates or date ranges may produce obscure error messages or unexpected results.
%
%
%
% \section{\env{timechart} environment}
% \label{sec:timechart-env}
%
% \begin{function}{timechart}
% \begin{syntax}
% \cs{begin}\texttt{\{}\env{timechart}\texttt{\}}\oarg{options}\marg{start}\marg{finish}
% \meta{content}
% \cs{end}\texttt{\{}\env{timechart}\texttt{\}}
% \end{syntax}
% This is the main environment for creating a chronological chart. The mandatory arguments \meta{start} and
% \meta{finish} specify the first and last years of the chart. These can be dates with circa indicators (that is, they
% satisfy \meta{cdate} in the grammar in \fullref{Section}{sec:dates-and-ranges}), but the circa specifier has no
% effect and only the `year' part of the date is used. The optional argument \meta{options} supplies PGF keys that
% apply to the entire chart.
%
% The \meta{content} comprises commands like \cs{timechartinterval}, \cs{timecharttext}, \cs{timechartspace},
% commands for positioning, as described in \fullref{Section}{sec:within}, and the user's own \TikZ\ code.
% \end{function}
%
%
%
% \subsection{General configuration of the \env{timechart} environment}
%
% \begin{describekey}{/timechart/width}{dimension}{\cs{textwidth}}
% The width of the chart. This refers to the width of the grid and axis of the chart, not
% including intervals that pass beyond the specified limits of the chart, or axis labels that protrude beyond the
% width of the axis itself.
% \end{describekey}
%
%
% \begin{describekey}{/timechart/tolerance}{dimension}{5pt}
% The length by which an interval is allowed to pass beyond the limits of the chart before it `counts' as doing so
% and the appropriate indicator is drawn.
% \end{describekey}
%
%
% \begin{describekey}{/timechart/beyond length}{dimension}{5pt}
% The length of the indicator that an interval passes beyond the limits of the chart.
% \end{describekey}
%
% \begin{describekey}{/timechart/beyond x radius}{dimension}{4pt}
% The horizontal radius of the concave part of the indicator that an interval passes beyond the limits of the chart.
% (The vertical radius will be half the thickness of the bar.)
% \end{describekey}
%
% \begin{describekey}{/timechart/ystep}{dimension}{-10pt}
% The default length (positive or negative) by which the current \(y\) coordinate is automatically adjusted after each
% interval, text, or space is placed.
% \end{describekey}
%
% \begin{describekey}{/timechart/minor tick interval}{number}{10}
% The number of years (which must be positive) between each minor tick on the axis.
% \end{describekey}
%
% \begin{describekey}{/timechart/major tick interval}{number}{50}
% The number of years (which must be positive) between each major tick on the axis and each vertical line in the grid.
% \end{describekey}
%
%
%
% \subsection{Grid configuration}
%
% \begin{describekey}{/timechart/no grid}{}{}
% Do not draw the grid.
% \end{describekey}
%
% \begin{describekey}{/timechart/grid top ysep}{dimension}{3pt}
% Distance between the top of the grid and the topmost interval or space.
% \end{describekey}
%
% \begin{describekey}{/timechart/grid bottom ysep}{dimension}{3pt}
% Distance between the bottom of the grid and the bottommost interval or space.
% \end{describekey}
%
% \begin{describekey}{/timechart/grid}{style}{empty}
% Style for drawing the grid.
% \end{describekey}
%
%
%
% \subsection{Axis configuration}
%
% \begin{describekey}{/timechart/axis}{position}{above}
% Where and whether to draw the axis. \meta{position} may be \val{above}, \val{below}, or
% \val{none}.
% \end{describekey}
%
% \begin{describekey}{/timechart/no axis}{}{}
% Do not draw the axis. Equivalent to \keyval{/timechart/axis}{none}.
% \end{describekey}
%
% \begin{describekey}{/timechart/axis line}{style}{\keyval{line cap}{rect}}
% Style for drawing the axis line.
% \end{describekey}
%
% \begin{describekey}{/timechart/minor tick}{style}{empty}
% Style for drawing minor ticks.
% \end{describekey}
%
% \begin{describekey}{/timechart/minor tick length}{dimension}{1.5mm}
% Length of minor ticks.
% \end{describekey}
%
% \begin{describekey}{/timechart/major tick}{style}{empty}
% Style for drawing major ticks.
% \end{describekey}
%
% \begin{describekey}{/timechart/major tick length}{dimension}{3mm}
% Length of major ticks.
% \end{describekey}
%
% \begin{describekey}{/timechart/major tick label}{style}{as described below}
% Style for labels on the major ticks on the axis. The intial style essentially sets \keyval{inner sep}{0},
% \keyval{outer sep}{0}, \keyval{anchor}{mid west}, \keyval{rotate}{90}.
% \end{describekey}
%
% \begin{describekey}{/timechart/major tick eras}{locations}{outer}
% Which major tick labels have era indicators. \meta{locations} may be \val{none}, \val{all}, or \val{outer} (which
% means that only the first and last labels have era indicators). This option does not affect the epoch marker (see
% \fullref{Subsection}{subsec:year-zero}).
% \end{describekey}
%
%
%
% \section{Within the \env{timechart} environment}
% \label{sec:within}
%
%
%
% \subsection{Intervals}
% \label{subsec:intervals}
%
% \begin{function}{\timechartinterval}
% \begin{syntax}
% \cs{timechartinterval}\oarg{options}\marg{start}\marg{finish}\marg{label}
% \end{syntax}
% This command creates an interval in the chart at the current \(y\) coordinate between the specified \meta{start} and
% \meta{finish}, with the given \meta{label}. These arguments are mandatory. Each of \meta{start} and \meta{finish}
% can be either a year or a range of years, possibly with circa markers. That is, each must satisfy
% \meta{cyear-or-crange} in the grammar in \fullref{Section}{sec:dates-and-ranges}.
%
% The optional argument \meta{options} specifies PGF keys within \key{/timechart/} that are applied locally to the
% interval.
%
% The current \(y\) coordinate will be adjusted according to \key{/timechart/ystep} unless \key{/timechart/no
% autostep} has been set.
% \end{function}
%
%
%
% \subsubsection{Interval configuration}
%
% \begin{describekey}{/timechart/no autostep}{}{}
% Do not automatically alter the current \(y\) coordinate by the amount specified in \key{/timechart/ystep}.
% \end{describekey}
%
% \begin{describekey}{/timechart/ref}{label}{none}
% Make the interval label a hyperlink to the position labelled by \meta{label}.
% \end{describekey}
%
% \begin{describekey}{/timechart/mark}{comma-separated list of years}{empty}
% Draw marks in the interval at the years contained in the list. Each entry in the list must be a definite year (that
% is, must satisfy \meta{year} in the grammar in \fullref{Section}{sec:dates-and-ranges}), must lie in the definite
% part of the interval (not in the start or finish ranges) and cannot lie beyond the bounds of the chart on a side
% where there interval exceeds tolerance. The colour of marks can be specified using \key{/timechart/interval mark
% color}. \key{/timechart/marks} is a synonym for this key.
% \end{describekey}
%
% \begin{describekey}{/timechart/circa uncertainty}{number}{3}
% Treat a circa indicator \mcode{c} as indicating an uncertainity of \(\pm\meta{number}\).
% \end{describekey}
%
% \begin{describekey}{/timechart/interval minimum width}{dimension}{1pt}
% Ensure that any interval has a width of at least \meta{dimension}. This is useful to ensure that a single event is
% visible in the chart.
%
% If an interval is specified with start and finish ranges, and with \keyval{start range}{fade} and \keyval{finish
% range}{fade}, then the `certain' portion of the interval will also have width at least \meta{dimension}. (This
% restriction prevents a common rendering error where start and finish fadings around a `certain' interval of length
% \(0\) would not quite meet.)
% \end{describekey}
%
% \begin{describekey}{/timechart/interval bar color}{color}{black}
% Fill the interval bar with \meta{color}.
% \end{describekey}
%
% \begin{describekey}{/timechart/interval bar thickness}{dimension}{8pt}
% Set the vertical thickness of the interval bar to \meta{dimension}.
% \end{describekey}
%
% \begin{describekey}{/timechart/interval bar node name}{string}{bar node}
% Set the name of the node containing the interval bar to \meta{string}.
% \end{describekey}
%
% \begin{describekey}{/timechart/interval mark color}{color}{gray}
% Draw marks using \meta{color}.
% \end{describekey}
%
% \begin{describekey}{/timechart/interval label}{style}{empty}
% Style to apply to an interval label.
% \end{describekey}
%
% \begin{describekey}{/timechart/interval label centered}{style}{as below}
% Style to apply to an interval label placed centrally. Initially, this style executes the style
% \key{/timechart/interval label} and sets \keyval{text}{white}. The reason for a separate style for centred labels is
% that often a contrasting colour will be required. For instance, labels positioned to the left and right may be
% black, but if the bar is black, a centred label should be a light colour.
% \end{describekey}
%
% \begin{describekey}{/timechart/interval label centered background}{style}{as below}
% Style to apply to the `background' interval label placed centrally. Initially, this style executes
% \key{/timechart/interval label}. The `background' interval label is simply the usual label and is placed in the same
% location, but on a layer behind the bar and, unlike the label itself, is not clipped. The reason for this style is
% that if the bar is narrow, part of the label text (such as ascenders and/or descenders) may naturally extend beyond
% the bar itself and it may be useful that thse should appear in a different colour.
% \end{describekey}
%
% \begin{describekey}{/timechart/interval label baseline}{dimension}{-3pt}
% Position the baseline of the interval label \meta{dimension} below the current \(y\) coordinate (which is the
% midpoint of the interval bar).
% \end{describekey}
%
% \begin{describekey}{/timechart/interval label pos}{position}{left}
% Specify where to place the label relative to the interval bar: \meta{position} may be \val{left}, \val{center}, or
% \val{right}. The position \val{center} places the label at the midpoint of \emph{the visible segment of the solid
% part} of the interval bar (that is, not including fading at the start or finish of the bar, and not including part
% of the bart that would extend beyond the bounds of the chart). Further, a centred label is clipped to the size of
% the bar and a unclipped `background' copy of it is drawn behind the bar, so that the portion appearing `on' and
% `outside' the bar can have different styles. (See the keys \key{/timechart/interval label centered} and
% \key{/timechart/interval label centered background}.)
% \end{describekey}
%
% \begin{describekey}{/timechart/interval label node name}{string}{label node}
% Set the name of the node containing the interval label to \meta{string}.
% \end{describekey}
%
% \begin{describekey}{/timechart/start range}{range-type}{fade}
% Type of indication of the range where an interval may start. \meta{range-type} can be \val{fade}, which produces an
% indicator like \timechartlegendstartrange[legend item width=8mm], or \val{slant}, which produces
% \timechartlegendstartrange[legend item width=8mm,start range=slant].
% \end{describekey}
%
% \begin{describekey}{/timechart/finish range}{range-type}{fade}
% Type of indication of the range where an interval may finish. \meta{range-type} can be \val{fade}, which produces an
% indicator like \timechartlegendfinishrange[legend item width=8mm], or \val{slant}, which produces
% \timechartlegendfinishrange[legend item width=8mm,finish range=slant].
% \end{describekey}
%
%
%
% \subsection{Text}
% \label{subsec:text}
%
% \begin{function}{\timecharttext}
% \begin{syntax}
% \cs{timecharttext}\oarg{options}\marg{year}\marg{text}
% \end{syntax}
% Place \meta{text} in the time chart at the current \(y\) coordinate and at the horizontal position of \meta{year},
% which must be a definite year (that is, must satsify \meta{year} in the grammar in
% \fullref{Section}{sec:dates-and-ranges}).
%
% The optional argument \meta{options} specifies PGF keys within \key{/timechart/} that are applied locally.
%
% The current \(y\) coordinate will be adjusted according to \key{/timechart/ystep} unless \key{/timechart/no
% autostep} has been set.
% \end{function}
%
%
%
% \subsubsection{Text configuration}
%
% \begin{describekey}{/timechart/text node name}{string}{text node}
% Set the name of the node containing the text to \meta{string}.
% \end{describekey}
%
% \begin{describekey}{/timechart/text}{style}{empty}
% Style to apply to the text.
% \end{describekey}
%
% \begin{describekey}{/timechart/text baseline}{dimension}{-3pt}
% Position the baseline of the text \meta{dimension} below the current \(y\) coordinate.
% \end{describekey}
%
% \begin{describekey}{/timechart/text pos}{position}{left}
% Specify where to place the label relative to the given \meta{year}: \meta{position} may be \val{left}, \val{center},
% or \val{right}.
% \end{describekey}
%
%
%
% \subsection{Space}
%
% \begin{function}{\timechartspace}
% \begin{syntax}
% \cs{timechartspace}\oarg{options}
% \end{syntax}
% Create a space in the time chart at the current \(y\) coordinate, with the same effect on vertical spacing as an
% interval. More precisely, the current \(y\) coordinate will be adjusted according to \key{/timechart/ystep} unless
% \key{/timechart/no autostep} has been set.
%
% The optional argument \meta{options} specifies PGF keys within \key{/timechart/} that are applied locally.
% \end{function}
%
%
%
% \subsection{Positioning}
% \label{subsec:positioning}
%
% The commands \cs{timechartinterval}, \cs{timecharttext}, and \cs{timechartspace} all act at the current \(y\)
% coordinate and change its value according to \key{/timechart/ystep} (unless \key{/timechart/no autostep} is used).
% There are several functions to set the current \(y\) coordinate and to have it reset automatically.
%
% \begin{function}{\timechartsety}
% \begin{syntax}
% \cs{timechartsety}\marg{dimension}
% \end{syntax}
% Set the current \(y\) coordinate to \meta{dimension}.
% \end{function}
%
% \begin{function}{\timechartsavey}
% \begin{syntax}
% \cs{timechartsavey}
% \end{syntax}
% Save the current \(y\) coordinate. If \cs{timechartresety} is used, the \(y\) coordinate resets to the last saved
% \(y\) coordinate. If the current \(y\) coordinate exceeds the minimum or maximum set by
% \cs{timechartsetyminimumautoreset} and \cs{timechartsetymaximumautoreset}, it will be reset to the last saved \(y\)
% coordinate.
% \end{function}
%
% \begin{function}{\timechartresety}
% \begin{syntax}
% \cs{timechartresety}
% \end{syntax}
% Reset the \(y\) coordinate to the last coordinate saved using \cs{timechartsavey}, or to \(0\) if there has been no
% use of \cs{timechartsavey} within the current \env{timechart} environment.
% \end{function}
%
% \begin{function}{\timechartsetyminimumautoreset, \timechartsetymaximumautoreset}
% \begin{syntax}
% \cs{timechartsetyminimumautoreset}\marg{min-coordinate}
% \cs{timechartsetymaximumautoreset}\marg{max-coordinate}
% \end{syntax}
% Set \(y\) coordinates that automatically trigger \cs{timechartresety} if the current \(y\) coordinate goes below
% \meta{min-coordinate} or above \meta{max-coordinate}.
% \end{function}
%
% \begin{function}{\timechartstepy}
% \begin{syntax}
% \cs{timechartstepy}\oarg{count}
% \end{syntax}
% Manually step the current \(y\) coordinate by \meta{count} times the value of \key{/timechart/ystep}. The default
% value of \meta{count} is 1. (The \key{/timechart/no autostep} does not affect \cs{timechartstepy}.)
% \end{function}
%
%
%
% \subsection{Completion}
%
% \begin{function}{\timechartfinish}
% Signal that the chart is complete and that the grid and axis should be drawn (unless the keys \key{/timechart/no
% grid} and/or \key{/timechart/no axis} have been used). It is not necessary to use this command: if it is not given,
% the grid and axis will be drawn at the end of the \env{timechart} environment. But after this command, the \TikZ\
% nodes \texttt{grid} and \texttt{axis} are available, containing (respectively) the grid and the axis. These can be
% used in for further \TikZ\ drawing.
%
% Note that after \cs{timechartfinish}, none of the various \cs{timechart}\ldots\ commands are available inside that
% \env{timechart} environment.
% \end{function}
%
%
%
% \subsection{Shortcut keys}
%
% \begin{describekey}{/timechart/left}{}{}
% Equivalent to setting \key{/timechart/interval label pos} and \key{/timechart/text pos} to \val{left}.
% \end{describekey}
%
% \begin{describekey}{/timechart/center}{}{}
% Equivalent to setting \key{/timechart/interval label pos} and \key{/timechart/text pos} to \val{center}.
% \end{describekey}
%
% \begin{describekey}{/timechart/right}{}{}
% Equivalent to setting \key{/timechart/interval label pos} and \key{/timechart/text pos}{right} to \val{right}.
% \end{describekey}
%
%
%
% \section{Era indicators}
% \label{sec:era-indicators}
%
% \begin{function}{\timechartmakebeforeyear,\timechartmakeafteryear}
% \begin{syntax}
% \cs{timechartmakebeforeyear}\marg{number}
% \cs{timechartmakeafteryear}\marg{number}
% \end{syntax}
% Typeset \meta{number} (which should be a positive whole number) as a year before or after the epoch. By default,
% \cs{timechartmakebeforeyear}\marg{number} produces \timechartmakebeforeyear{\meta{number}} and
% \cs{timechartmakeafteryear}\marg{number} produces \timechartmakeafteryear{\meta{number}}.
%
% These commands are used for axis labels and can be re-defined by the user. For example, if \textsc{bc}/\textsc{ad}
% is preferred to \textsc{bce}/\textsc{ce}, the user can define
% \iffalse
%<*example>
% \fi
\begin{lstlisting}
\renewcommand*{\timechartmakebeforeyear}[1]{#1~\textsc{bc}}
\renewcommand*{\timechartmakeafteryear}[1]{\textsc{ad}~#1}
\end{lstlisting}
% \iffalse
%</example>
% \fi
% Similarly, if \textsc{ah}/\textsc{bh} is preferred, the user can define
% \iffalse
%<*example>
% \fi
\begin{lstlisting}
\renewcommand*{\timechartmakebeforeyear}[1]{#1~\textsc{bh}}
\renewcommand*{\timechartmakeafteryear}[1]{\textsc{ah}~#1}
\end{lstlisting}
% \iffalse
%</example>
% \fi
% \end{function}
%
%
%
% \section{Legend}
% \label{sec:keys}
%
% \pkg{timechart} supplies a number of auxiliary macros for creating a legend to explain, for example the significance
% of different colours of intervals. For example, \fullref{Figure}{fig:example1-legend} shows a suitable legend for
% \fullref{Figure}{fig:example1}.
%
% \begin{figure}[t]
% \centering
% \input{timechart-example1-legend.tex}
% \caption{Example legend for the timechart shown in \fullref{Figure}{fig:example1}.}
% \label{fig:example1-legend}
% \end{figure}
%
% The \cs{timechartlength}\ldots\ macros are \emph{not} meant to be used inside a \env{timechart} environment, but in
% locations such as running text or a \env{tabular} environment.
%
% \begin{function}{\timechartlegenditem}
% \begin{syntax}
% \cs{timechartlegenditem}\oarg{options}
% \end{syntax}
% Draw a bar suitable for use in a legend. \meta{options} specifies PGF keys that are applied within
% \key{/timechart}. The same PGF keys that affect interval bars affect the drawn bar, as do the keys listed below.
% \end{function}
%
% \begin{function}{\timechartlegendstartrange, \timechartlegendfinishrange}
% \begin{syntax}
% \cs{timechartlegendstartrange}\oarg{options}
% \cs{timechartlegendfinishrange}\oarg{options}
% \end{syntax}
% Draw a bar suitable for use in a legend, with a start or finish range. \meta{options} specifies PGF keys that are
% applied within \key{/timechart/}. The same PGF keys that affect interval bars affect the drawn bar, as do the
% keys listed below.
% \end{function}
%
% \begin{describekey}{/timechart/legend item width}{dimension}{9mm}
% When using macros \cs{timechartlegenditem}, \cs{timechartlegendstartrange}, or \cs{timechartlegendfinishrange}, draw
% a bar of total width \meta{dimension}.
% \end{describekey}
%
% \begin{describekey}{/timechart/legend item range width}{dimension}{3mm}
% When using \cs{timechartlegendstartrange} or \cs{timechartlegendfinishrange}, draw a bar with a range of width
% \meta{dimension}.
% \end{describekey}
%
%
%
% \section{Usage notes}
%
% \subsection{Additional \TikZ\ code}
%
% The \env{timechart} environment is a \env{tikzpicture}. The user can add any \TikZ\ code before, between, or after
% content created using the \cs{timechart}\ldots\ commands. Each use of \cs{timechartinterval} defines two nodes. One,
% by default named \val{bar node}, contains the interval bar; the other, by default named \val{label node}, contains the
% interval label. Similarly, text added using \cs{timecharttext} is contained in a node, by default named \val{text
% node}. (The default names are re-used, but can be changed using the keys \key{/timechart/interval bar node name},
% \key{/timechart/interval label node name}, and \key{/timechart/text node name}.) The user can use these nodes to
% position extra content.
%
% If the \cs{timechartfinish} command is used (after which the \cs{timechart}\ldots\ commands are no longer available
% within the \env{timechart} environment) the nodes \mcode{grid} and \mcode{axis}, which contain the grid and the axis,
% are also available.
%
%
%
% \subsection{\texorpdfstring{`year zero'}{year zero}}
% \label{subsec:year-zero}
%
% Although calendars typically do not admit a `year zero' (for instance, \timechartmakebeforeyear{1} is immediately
% followed by \timechartmakeafteryear{1}, with no intervening `year zero'), \pkg{timechart} does allow \val{0} for the
% \meta{start} or \meta{finish} of the \env{timechart} environment or as the \meta{start} or \meta{finish} of
% \cs{timechartinterval} or the \meta{year} of \cs{timecharttext}. But `year zero' is indicated on the axis by a special
% epoch marker showing the last year before and first year after the epoch.
%
%
%
% \section{Feature requests and bug reports}
%
% The development code and issue tracker are hosted at Codeberg: \url{
https://codeberg.org/ajcain/timechart}
%
%
%
% \section{Appendix: full example source}
% \label{sec:full-example}
%
% This section contains the necessary source code to produce the example timechart and legend shown in
% \fullref{Figures}{fig:example1} and \ref{fig:example1-legend} on pages \pageref{fig:example1} and
% \pageref{fig:example1-legend}.
%
%
%
% \subsection{Setup source}
%
% \lstinputlisting{timechart-example1-setup.tex}
%
%
%
% \subsection{Timechart source}
%
% \lstinputlisting[breaklines=true]{timechart-example1-timechart.tex}
%
%
%
% \subsection{Legend source}
%
% \lstinputlisting{timechart-example1-legend.tex}
%
%
%
% \end{documentation}
%
%
%
% \iffalse
%<*example1-setup>
\pgfkeys{
/timechart/.cd,
julioclaudian/.style={
interval bar color=red!70!black,
interval mark color=red!70!black!50!white
},
fouremperors/.style={
interval bar color=green!65!black,
interval mark color=green!65!black!50!white
},
flavian/.style={
interval bar color=yellow!85!black,
interval mark color=yellow!85!black!50!white
},
nervaantonine/.style={
interval bar color=blue!80!black,
interval mark color=blue!80!black!50!white
},
fiveemperors/.style={
interval bar color=green!50!black,
interval mark color=green!50!black!50!white
},
severan/.style={
interval bar color=orange!80!black,
interval mark color=orange!80!black!50!white
},
thirdcentury/.style={
interval bar color=green!35!black,
interval mark color=green!35!black!50!white
},
tetrarchy/.style={
interval bar color=purple!70!black,
interval mark color=purple!70!black!50!white
},
constantinian/.style={
interval bar color=blue!65!white,
interval mark color=blue!65!white!50!white
},
valentinianic/.style={
interval bar color=orange!60!black,
interval mark color=orange!60!black!50!white
},
theodosian/.style={
interval bar color=cyan,
interval mark color=cyan!50!white
},
theodosian-east/.style={
interval bar color=cyan!80!black,
interval mark color=cyan!80!black!50!white
},
theodosian-west/.style={
interval bar color=cyan!80!white,
interval mark color=cyan!80!white!50!white
},
leonid/.style={
interval bar color=purple!40!white,
interval mark color=purple!40!white!50!white
},
justinian/.style={
interval bar color=orange!60!white,
interval mark color=orange!60!white!50!white
},
lastwest/.style={
interval bar color=green!25!black,
interval mark color=green!25!black!50!white
},
}
%</example1-setup>
%<*example1-timechart>
\begin{timechart}[
axis line/.append style={ draw=gray, line width=.5pt },
grid/.append style={ draw=lightgray!50!white, line width=.5pt },
minor tick/.append style={ draw=gray },
major tick/.append style={ line width=.5pt, draw=gray },
major tick label/.append style={ node font=\small },
interval label/.style={ node font=\sffamily\footnotesize },
text/.style={ node font=\sffamily\small\itshape, },
ystep=-3.25mm,
]{-50}{500}
\pgfmathsetmacro{\mainlinecount}{46}
\timechartsetyminimumautoreset{-3.25mm*\mainlinecount+1mm}
\timechartinterval[interval bar color=gray,right,mark=-45]{-100}{-44}{Julius Caesar}
\timechartinterval[julioclaudian,right,mark=-27]{-63}{-14}{Augustus}
\timechartinterval[julioclaudian,right,mark=14]{-42}{37}{Tiberius}
\timechartinterval[julioclaudian,right,mark=37]{12}{41}{Caligula}
\timechartinterval[julioclaudian,right,mark=41]{-10}{54}{Claudius}
\timechartinterval[julioclaudian,right,mark=54]{37}{68}{Nero}
\timechartinterval[fouremperors,mark=68]{-3}{69}{Galba}
\timechartinterval[fouremperors,mark=69]{32}{69}{Otho}
\timechartinterval[fouremperors,mark=69]{15}{69}{Vitellius}
\timechartinterval[flavian,mark=69]{9}{79}{Vespasian}
\timechartinterval[flavian,mark=79]{39}{81}{Titus}
\timechartinterval[flavian,mark=81]{51}{96}{Domitian}
\timechartinterval[nervaantonine,mark=96]{30}{98}{Nerva}
\timechartinterval[nervaantonine,mark=98]{53}{117}{Trajan}
\timechartinterval[nervaantonine,mark=117]{76}{138}{Hadrian}
\timechartinterval[nervaantonine,mark=138]{86}{161}{Antoninus Pius}
\timechartinterval[nervaantonine,mark=161]{121}{180}{Marcus Aurelius}
\timechartinterval[nervaantonine,mark=161]{130}{169}{Lucius Verus}
\timechartinterval[nervaantonine,mark=180]{161}{192}{Commodus}
\timechartinterval[fiveemperors,mark=193]{126}{193}{Pertinax}
\timechartinterval[fiveemperors,mark=193]{133}{193}{Didius Julianus}
\timechartinterval[severan,mark=193]{145}{211}{Septimus Severus}
\timechartinterval[severan,mark=211]{188}{217}{Caracalla}
\timechartinterval[severan,mark=211]{189}{211}{Geta}
\timechartinterval[severan,mark=217]{c165}{218}{Macrinus}
\timechartinterval[severan,mark=218]{203/204}{222}{Elagabalus}
\timechartinterval[severan,mark=222]{208}{235}{Severus Alexander}
\timechartinterval[thirdcentury,mark=235]{c172/c180}{238}{Maximinus I}
\timechartinterval[thirdcentury,mark=238]{c158}{238}{Gordian I}
\timechartinterval[thirdcentury,mark=238]{192}{238}{Gordian II}
\timechartinterval[thirdcentury,mark=238]{164}{238}{Pupienus}
\timechartinterval[thirdcentury,mark=238]{c164}{238}{Balbinus}
\timechartinterval[thirdcentury,mark=238]{225}{244}{Gordian III}
\timechartinterval[thirdcentury,mark=244]{c204}{249}{Philip I}
\timechartinterval[thirdcentury,mark=249]{c190/200}{251}{Decius}
\timechartinterval[thirdcentury,mark=251]{c206}{253}{Trebonianus Gallus}
\timechartinterval[thirdcentury,mark=253]{c207}{253}{Aemilianus}
\timechartinterval[thirdcentury,mark=253]{c200}{262}{Valerian}
\timechartinterval[thirdcentury,mark=253]{218}{268}{Gallienus}
\timechartinterval[thirdcentury,mark=268]{214}{270}{Claudius II}
\timechartinterval[thirdcentury,mark=270]{230/250}{270}{Quintillus}
\timechartinterval[thirdcentury,mark=270]{214}{275}{Aurelian}
\timechartinterval[thirdcentury,mark=275]{c200}{276}{Tacitus}
\timechartinterval[thirdcentury,mark=276]{226/256}{276}{Florianus}
\timechartinterval[thirdcentury,mark=276]{232}{282}{Probus}
\timechartinterval[thirdcentury,mark=282]{c224}{283}{Carus}
\timechartinterval[thirdcentury,mark=283]{c250}{285}{Carinus}
\timechartinterval[thirdcentury,mark=283]{c253}{284}{Numerian}
\timechartinterval[tetrarchy,mark=284]{242/245}{311/312}{Diocletian}
\timechartinterval[tetrarchy,mark=286]{c250}{310}{Maximian}
\timechartinterval[tetrarchy,mark=305]{c258}{311}{Galerius}
\timechartinterval[tetrarchy,mark=305]{c250}{306}{Constantius I}
\timechartinterval[tetrarchy,mark=306]{257/287}{307}{Severus II}
\timechartinterval[tetrarchy,marks={308,324}]{c265}{325}{Licinius}
\timechartinterval[tetrarchy,mark=310]{c270}{313}{Maximinus II}
\timechartinterval[tetrarchy,mark=316]{267/297}{317}{Valerius Valens}
\timechartinterval[tetrarchy,mark=324]{275/305}{325}{Martinian}
\timechartinterval[constantinian,mark=306]{272/273}{337}{Constantine I}
\timechartinterval[constantinian,mark=337]{316}{340}{Constantine II}
\timechartinterval[constantinian,mark=337]{322/323}{350}{Constans I}
\timechartinterval[constantinian,mark=337]{317}{361}{Constantius II}
\timechartinterval[constantinian,mark=361]{331}{363}{Julian}
\timechartinterval[constantinian,mark=363]{330/331}{364}{Jovian}
\timechartinterval[valentinianic,mark=364]{321}{375}{Valentinian I}
\timechartinterval[valentinianic,mark=364]{c328}{378}{Valens}
\timechartinterval[valentinianic,mark=375]{359}{383}{Gratian}
\timechartinterval[valentinianic,mark=388]{371}{392}{Valentinian II}
\timechartinterval[theodosian,mark=379]{346/347}{395}{Theodosius I}
\timecharttext[center]{395}{Eastern}
\timechartinterval[theodosian-east,mark=395]{377}{408}{Arcadius}
\timechartinterval[theodosian-east,mark=408]{401}{450}{Theodosius II}
\timechartinterval[theodosian-east,mark=450]{391/392}{457}{Marcian}
\timechartinterval[leonid,mark=457]{400/401}{474}{Leo I}
\timechartinterval[leonid,mark=474]{467}{474}{Leo II}
\timechartinterval[leonid,mark={474,475,476}]{425}{491}{Zeno}
\timechartinterval[leonid,mark=475]{426/456}{476/477}{Basilicus}
\timechartinterval[leonid,mark=491]{430/431}{518}{Anastasius I}
\timechartinterval[justinian,mark=518]{450}{527}{Justin I}
\timechartinterval[justinian,mark=527]{482}{565}{Justinian I}
\timecharttext[center]{395}{Western}
\timechartinterval[theodosian-west,mark=395]{384}{423}{Honorius}
\timechartinterval[theodosian-west,mark=421]{371/401}{421}{Constantius III}
\timechartinterval[theodosian-west,mark=425]{419}{455}{Valentian III}
\timechartinterval[lastwest,mark=455]{405/435}{455}{Petronius Maximus}
\timechartinterval[lastwest,mark=455]{406/436}{456/457}{Avitius}
\timechartinterval[lastwest,mark=457]{411/441}{461}{Majorian}
\timechartinterval[lastwest,mark=461]{415/445}{465}{Libius Severus}
\timechartinterval[lastwest,mark=467]{422/452}{472}{Anthemius}
\timechartinterval[lastwest,mark=472]{422/452}{472}{Olybrius}
\timechartinterval[lastwest,mark={473,474}]{443/473}{474/504}{Glycerius}
\timechartinterval[lastwest,mark={474,465}]{430/460}{480}{Julius Nepos}
\timechartinterval[lastwest,mark={475,476}]{c465}{507/527}{Romulus}
\timechartsetyminimumautoreset{-\maxdimen}
\timechartsety{(-\mainlinecount-1)*3.25mm}
\timechartinterval[
center,
interval bar color=darkgray,
interval text/.append style={ text=white },
interval bar thickness=6.5mm
]{-509}{-27}{}
\timechartstepy[-1]
\timechartinterval[
center,
interval bar color=black,
interval text/.append style={ node font=\sffamily\normalsize,text=white },
interval bar thickness=6.5mm
]{-27}{395}{Roman Empire}
\timechartstepy[-1.5]
\timechartinterval[
center,
interval bar color=lightgray,
interval bar thickness=3.25mm
]{395}{1453}{Eastern}
\timechartinterval[
center,
interval bar color=gray,
interval bar thickness=3.25mm
]{395}{476}{Western}
\end{timechart}
%</example1-timechart>
%<*example1-legend>
\begin{tabular}{rl}
\timechartlegenditem[julioclaudian] & Julio-Claudian dynasty \\
\timechartlegenditem[fouremperors] & Year of four emperors \\
\timechartlegenditem[flavian] & Flavian dynasty \\
\timechartlegenditem[nervaantonine] & Nerva-Antonine dynasty \\
\timechartlegenditem[fiveemperors] & Year of five emperors \\
\timechartlegenditem[severan] & Severan dynasty \\
\timechartlegenditem[thirdcentury] & Crisis of the third century \\
\timechartlegenditem[tetrarchy] & Tetrarchy \\
\timechartlegenditem[constantinian] & Constantinian dynasty \\
\timechartlegenditem[valentinianic] & Valentinianic dynasty \\
\timechartlegenditem[theodosian] & Theodosian dynasty \\
\timechartlegenditem[theodosian-east] & --- in the east \\
\timechartlegenditem[theodosian-west] & --- in the west \\
\timechartlegenditem[leonid] & Leonid dynasty \\
\timechartlegenditem[justinian] & Justinian dynasty \\
\timechartlegenditem[lastwest] & Last emperors in the west \\
\end{tabular}
%</example1-legend>
%<*example2-v1>
\begin{timechart}{-50}{75}
\timechartinterval{-63}{-14}{Augustus}
\timechartinterval{-42}{37}{Tiberius}
\timechartinterval{12}{41}{Caligula}
\timechartinterval{-10}{54}{Claudius}
\timechartinterval{37}{68}{Nero}
\end{timechart}
%</example2-v1>
%<*example2-v2>
\begin{timechart}[
minor tick interval=5,
major tick interval=25,
grid/.append style={ draw=lightgray },
axis line/.append style={ draw=gray },
minor tick/.append style={ draw=gray },
major tick/.append style={ draw=gray },
interval label/.append style={ node font=\sffamily\small },
julioclaudian/.style={ interval bar color=red!80!black },
]{-50}{75}
\timechartinterval[right,julioclaudian]{-63}{-14}{Augustus}
\timechartinterval[right,julioclaudian]{-42}{37}{Tiberius}
\timechartinterval[julioclaudian]{12}{41}{Caligula}
\timechartinterval[julioclaudian]{-10}{54}{Claudius}
\timechartinterval[julioclaudian]{37}{68}{Nero}
\end{timechart}
%</example2-v2>
% \fi
%
%
%
% \begin{implementation}
%
% \setcounter{secnumdepth}{7}
%
%
%
% \section{Implementation}
%
% \begin{macrocode}
%<*package>
%<@@=timechart>
% \end{macrocode}
%
%
%
% \subsection{Coding standard}
%
% This package makes extensive use of \pkg{pgfmath} computations. The usual \pkg{expl3} standard of ending variables
% with a type indicator (\texttt{\_bool}, \texttt{\_int}, etc.) is therefore adapted as follows:
% \begin{itemize}
% \item[\texttt{\_year}] Stores a year, which could in principle be fractional.
% \item[\texttt{\_pgf}] Stores a length calculated by \pkg{pgfmath}. (Unlike \texttt{\_dim}, there is no underlying
% dimension register.)
% \item[\texttt{\_x}] Stores a raw \(x\) coordinate (not in \TikZ's XY-coordinate system).
% \item[\texttt{\_y}] Stores a raw \(y\) coordinate (not in \TikZ's XY-coordinate system).
% \item[\texttt{\_text}] Stores text (not an \pkg{expl3} string).
% \end{itemize}
%
%
%
% \subsection{Initial set-up}
%
% Package identification/version information.
% \begin{macrocode}
\NeedsTeXFormat{LaTeX2e}[2020-02-02]
\ProvidesExplPackage{timechart}{2025-10-17}{0.56.1}
{Typesetting chronological charts}
% \end{macrocode}
%
%
%
% \subsection{Debugging macro}
%
% \begin{macro}{\@@_debug:n,\@@_debug_real:n}
% Macro to output (many) debugging messages.
% \begin{macrocode}
\cs_new:Npn \@@_debug_real:n #1
{
\typeout{timechart:~#1}
}
\cs_set_eq:NN\@@_debug:n\use_none:n
% \end{macrocode}
% \end{macro}
%
%
%
% \subsection{Load TikZ}
%
% \begin{macrocode}
\RequirePackage{tikz}
% \end{macrocode}
% In the remainder of the package, only a limited subset of \TikZ\ is used, and PGF code is preferred. For PGF keys, it
% is necessary to use \texttt{\textasciitilde} in place of a space.
%
%
%
% \subsection{Scratch variables}
%
% \begin{macro}{\l_@@_tmpa_bool,\l_@@_tmpb_bool,\l_@@_tmpc_bool,\l_@@_tmpd_bool}
% Scratch boolean variables.
% \begin{macrocode}
\bool_new:N\l_@@_tmpa_bool
\bool_new:N\l_@@_tmpb_bool
\bool_new:N\l_@@_tmpc_bool
\bool_new:N\l_@@_tmpd_bool
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\l_@@_tmpa_dim,\l_@@_tmpb_dim,\l_@@_tmpc_dim,\l_@@_tmpd_dim}
% Scratch dimension variables, reusing \cs{l_tmpa_dim} and \cs{l_tmpb_dim} with uniform names.
% \begin{macrocode}
\cs_set_eq:NN\l_@@_tmpa_dim\l_tmpa_dim
\cs_set_eq:NN\l_@@_tmpb_dim\l_tmpb_dim
\dim_new:N\l_@@_tmpc_dim
\dim_new:N\l_@@_tmpd_dim
% \end{macrocode}
% \end{macro}
%
%
%
% \subsection{Generic auxiliary functions}
%
% \begin{macro}{\@@_make_ref:NN}
% Make hyperreference from text, if the supplied target is non-empty.
% \begin{arguments}
% \item Reference for hyperlink target, or empty.
% \item Text.
% \end{arguments}
% \begin{macrocode}
\cs_new:Npn\@@_make_ref:NN #1#2
{
\str_if_empty:NTF #1
{ #2 }
{ \hyperref[#1]{#2} }
}
% \end{macrocode}
% \end{macro}
%
%
%
% \subsection{PGF auxiliary functions}
%
% \begin{macro}{@@_pgfmathsetbool:nn}
% Set an \pkg{expl3} boolean variable to the outcome of a \pkg{pgfmath} comparison. This macro is simply a wrapper
% around \cs{pgfmathsetmacro} using \mcode{ifthenelse} and returning the boolean literal true or false.
% \begin{macrocode}
\cs_new:Npn\@@_pgfmathsetbool:nn #1#2
{
\pgfmathsetmacro{#1}{ifthenelse(#2,"\c_true_bool","\c_false_bool")}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_if_equal:nnF}%
% Use \pkg{pgfmath} to check whether \param{1} and \param{2} are equal. If not, execute \param{3}.
% \begin{macrocode}
\cs_new:Npn\@@_if_equal:nnF #1#2#3
{
\@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}{#1==#2}
\bool_if:NF\l_@@_tmpa_bool{#3}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_pgfextractxy:nnn}
% Extract coordinates of \param{3} (a PGF point) to dimension variables \param{1} and \param{2}. This macro simply
% combines the functionality of \cs{pgfextractx} and \cs{pgfextracty}.
% \begin{macrocode}
\cs_new:Npn\@@_pgfextractxy:nnn #1#2#3
{
\pgf@process{#3}
#1=\pgf@x\relax
#2=\pgf@y\relax
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_hsmash_pgfnode:nnnnn}
% Do the same as \cs{pgfnode} but only update the bounding box `vertically'.
% \begin{macrocode}
\cs_new:Npn\@@_hsmash_pgfnode:nnnnn #1#2#3#4#5
{
\pgfinterruptboundingbox
\pgfnode{#1}{#2}{#3}{#4}{#5}
\pgfcoordinate
{@@_tmpa_coord}
{\pgfpointanchor{current~bounding~box}{south}}
\pgfcoordinate
{@@_tmpb_coord}
{\pgfpointanchor{current~bounding~box}{north}}
\endpgfinterruptboundingbox
\pgfextractx
{\l_@@_tmpa_dim}
{\pgfpointanchor{@@_tmpa_coord}{center}}
\pgfextractx
{\l_@@_tmpb_dim}
{\pgfpointanchor{@@_tmpb_coord}{center}}
\pgfpathmoveto{\pgfpoint{\l_@@_tmpa_dim}{0}}
\pgfpathmoveto{\pgfpoint{\l_@@_tmpb_dim}{0}}
\pgfusepath{discard}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_make_rectangle_node:nnnn}
% Make a node with south west corner \param{1}, north east corner \param{2}, and name \param{3}. \param{1} and
% \param{2} should be given as PGF points. \param{4} is a boolean literal indicating whether the path should be
% stroked.
% \begin{macrocode}
\cs_new:Npn\@@_make_rectangle_node:nnnn #1#2#3#4
{
\group_begin:
\@@_pgfextractxy:nnn
{\l_@@_tmpa_dim}{\l_@@_tmpb_dim}{#1}
\@@_pgfextractxy:nnn
{\l_@@_tmpc_dim}{\l_@@_tmpd_dim}{#2}
\pgftransformshift{#1}
\pgfset{
minimum~width=\l_@@_tmpc_dim-\l_@@_tmpa_dim,
minimum~height=\l_@@_tmpd_dim-\l_@@_tmpb_dim,
inner~sep=0,
outer~sep=0,
}
\bool_if:NTF #4
{ \pgfnode{rectangle}{south~west}{}{#3}{\pgfusepath{draw}} }
{ \pgfnode{rectangle}{south~west}{}{#3}{\pgfusepath{discard}} }
\group_end:
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_set_style_line_width:nn}
% Set macro \param{1} to be the line width set by the PGF style \param{2}. Note that \cs{begingroup} and \cs{endgroup}
% are used here because of the definition of \cs{pgfmathsmuggle}.
% \begin{macrocode}
\cs_new:Npn\@@_set_style_line_width:nn #1#2
{
\begingroup
\tikzset{#2}
\pgfmathsetlengthmacro{#1}{\pgflinewidth}
\pgfmathsmuggle #1
\endgroup
}
% \end{macrocode}
% \end{macro}
%
%
%
% \subsection{PGF keys}
%
% All PGF keys for this package are under \key{/timechart/}.
% \begin{macrocode}
\pgfkeys{
/timechart/.cd,
% \end{macrocode}
% Keys applicable to debugging.
% \begin{macrocode}
debug/.code = {
\cs_set_eq:NN\@@_debug:n\@@_debug_real:n
},
no~debug/.code = {
\cs_set_eq:NN\@@_debug:n\use_none:n
},
% \end{macrocode}
% Keys applicable to whole chart.
% \begin{macrocode}
width/.initial=\textwidth,
ystep/.initial=-10pt,
minor~tick~interval/.initial=10,
major~tick~interval/.initial=50,
tolerance~start/.initial=5pt,
tolerance~finish/.initial=5pt,
beyond~length~start/.initial=5pt,
beyond~length~finish/.initial=5pt,
beyond~x~radius~start/.initial=4pt,
beyond~x~radius~finish/.initial=4pt,
% \end{macrocode}
% Shortcuts for tolerance and `beyond' indicators.
% \begin{macrocode}
tolerance/.code = {
\pgfkeyssetvalue{/timechart/tolerance~start}{#1}
\pgfkeyssetvalue{/timechart/tolerance~finish}{#1}
},
beyond~length/.code = {
\pgfkeyssetvalue{/timechart/beyond~length~start}{#1}
\pgfkeyssetvalue{/timechart/beyond~length~finish}{#1}
},
beyond~x~radius/.code = {
\pgfkeyssetvalue{/timechart/beyond~x~radius~start}{#1}
\pgfkeyssetvalue{/timechart/beyond~x~radius~finish}{#1}
},
% \end{macrocode}
% Keys applicable to the grid.
% \begin{macrocode}
no~grid/.code = { \bool_set_false:N\l_@@_grid_bool },
grid~top~ysep/.initial={3pt},
grid~bottom~ysep/.initial={3pt},
grid/.style={},
% \end{macrocode}
% Keys applicable to the axis.
% \begin{macrocode}
axis~line/.style={
line~cap=rect,
},
axis~ysep/.initial=3pt,
axis/.is~choice,
axis/none/.code
= { \int_set:Nn\l_@@_axis_int{0} },
axis/above/.code
= { \int_set:Nn\l_@@_axis_int{1} },
axis/below/.code
= { \int_set:Nn\l_@@_axis_int{2} },
no~axis/.code = { \int_set:Nn\l_@@_axis_int{0} },
minor~tick/.style={},
minor~tick~length/.initial=1.5mm,
major~tick/.style={},
major~tick~length/.initial=3mm,
major~tick~label/.style={
inner~sep=0,
outer~sep=0,
anchor=mid~west,
rotate=90,
},
major~tick~eras/.is~choice,
major~tick~eras/none/.code
= { \int_set:Nn\l_@@_major_tick_eras_int{0} },
major~tick~eras/all/.code
= { \int_set:Nn\l_@@_major_tick_eras_int{1} },
major~tick~eras/outer/.code
= { \int_set:Nn\l_@@_major_tick_eras_int{2} },
% \end{macrocode}
% Keys applicable to intervals, texts, spaces, and legends.
% \begin{macrocode}
no~autostep/.code = { \bool_set_false:Nz\l_@@_autostep_bool },
ref/.initial={},
mark/.initial={},
marks/.forward~to=/timechart/mark,
circa~uncertainty/.initial=3,
interval~minimum~width/.initial=1pt,
interval~bar~color/.initial=black,
interval~bar~thickness/.initial=8pt,
interval~bar~node~name/.initial = {bar~node},
interval~mark~color/.initial=gray,
interval~label/.style={},
interval~label~centered/.style={/timechart/interval~label,text=white},
interval~label~centered~background/.style={/timechart/interval~label},
interval~label~baseline/.initial=-3pt,
interval~label~pos/.is~choice,
interval~label~pos/left/.code
= { \int_set:Nn\l_@@_label_pos_int{0} },
interval~label~pos/center/.code
= { \int_set:Nn\l_@@_label_pos_int{1} },
interval~label~pos/right/.code
= { \int_set:Nn\l_@@_label_pos_int{2} },
interval~label~node~name/.initial = {label~node},
start~range/.is~choice,
start~range/fade/.code
= { \int_set:Nn\l_@@_start_range_type_int{0} },
start~range/slant/.code
= { \int_set:Nn\l_@@_start_range_type_int{1} },
finish~range/.is~choice,
finish~range/fade/.code
= { \int_set:Nn\l_@@_finish_range_type_int{0} },
finish~range/slant/.code
= { \int_set:Nn\l_@@_finish_range_type_int{1} },
% \end{macrocode}
% Keys applicable only to texts.
% \begin{macrocode}
text~node~name/.initial = {text~node},
text/.style={},
text~baseline/.initial=-3pt,
text~pos/.is~choice,
text~pos/left/.code = { \int_set:Nn\l_@@_text_pos_int{0} },
text~pos/center/.code = { \int_set:Nn\l_@@_text_pos_int{1} },
text~pos/right/.code = { \int_set:Nn\l_@@_text_pos_int{2} },
% \end{macrocode}
% Keys applicable only to legends.
% \begin{macrocode}
legend~item~width/.initial=9mm,
legend~item~range~width/.initial=3mm,
% \end{macrocode}
% Shortcuts for positioning.
% \begin{macrocode}
left/.code = {
\int_set:Nn\l_@@_label_pos_int{0}
\int_set:Nn\l_@@_text_pos_int{0}
},
center/.code = {
\int_set:Nn\l_@@_label_pos_int{1}
\int_set:Nn\l_@@_text_pos_int{1}
},
right/.code = {
\int_set:Nn\l_@@_label_pos_int{2}
\int_set:Nn\l_@@_text_pos_int{2}
},
}
% \end{macrocode}
%
% \begin{macro}{\l_@@_grid_bool}
% Boolean indicating whether the grid will be drawn. This variable is by default true but can be set false via the
% \key{/timechart/no grid} PGF key.
% \begin{macrocode}
\bool_new:N\l_@@_grid_bool
\bool_set_true:N\l_@@_grid_bool
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\l_@@_axis_int}
% An integer indicating whether and where the axis will be drawn. This is set via the \key{/timechart/axis} PGF
% key.
% \begin{macrocode}
\int_new:N\l_@@_axis_int
\int_set:Nn\l_@@_axis_int{1}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\l_@@_major_tick_eras_int}
% An integer indicating which major ticks will have era indicators. This is set via the \key{/timechart/major tick
% era} PGF key.
% \begin{macrocode}
\int_new:N\l_@@_major_tick_eras_int
\int_set:Nn\l_@@_major_tick_eras_int{2}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\l_@@_autostep_bool}
% Boolean indicating whether to automatically step the \(y\) coordinate after an interval, text, or space. This
% variable is by default true but can be set false via the \key{/timechart/no autostep} PGF key.
% \begin{macrocode}
\bool_new:N\l_@@_autostep_bool
\bool_set_true:N\l_@@_autostep_bool
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\l_@@_label_pos_int}
% An integer to hold the interval label position. This is set via the \key{/timechart/interval label pos} PGF key.
% \begin{macrocode}
\int_new:N \l_@@_label_pos_int
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\l_@@_text_pos_int}
% An integer to hold the text position. This is set via the \key{/timechart/text pos} PGF key.
% \begin{macrocode}
\int_new:N \l_@@_text_pos_int
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\l_@@_start_range_type_int,\l_@@_finish_range_type_int}
% Integers to hold the type of the start/end ranges. These are set via the \key{/timechart/start range} and
% \key{/timechart/finish range} PGF keys.
% \begin{macrocode}
\int_new:N \l_@@_start_range_type_int
\int_new:N \l_@@_finish_range_type_int
% \end{macrocode}
% \end{macro}
%
%
%
% \subsection{Main environment}
%
% \begin{macro}{timechart}
% The main environment.
% \begin{arguments}
% \item PGF keys to apply.
% \item Start year.
% \item End year.
% \end{arguments}
% \begin{macrocode}
\NewDocumentEnvironment{timechart}{ O{} m m }
{ \@@_main_begin:nnn{#1}{#2}{#3} }
{ \@@_main_end: }
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_main_begin:nnn}
% This command uses values specified by PGF keys to make some necessary calculations to begin the chart.
% \begin{macrocode}
\cs_new:Npn \@@_main_begin:nnn #1#2#3
{
% \end{macrocode}
% Process the supplied PGF keys and retrieve values that affect the chart as a whole.
% \begin{macrocode}
\pgfkeys{
/timechart/.cd,
#1,
width/.get=\l_@@_width_pgf,
ystep/.get=\l_@@_ystep_pgf,
grid~top~ysep/.get=\l_@@_grid_top_ysep_pgf,
grid~bottom~ysep/.get=\l_@@_grid_bottom_ysep_pgf,
minor~tick~interval/.get=\l_@@_minor_tick_interval_year,
major~tick~interval/.get=\l_@@_major_tick_interval_year,
}
% \end{macrocode}
% Start the \TikZ\ picture and set up the necessary layers.
% \begin{macrocode}
\tikzpicture
\pgfdeclarelayer{grid}
\pgfdeclarelayer{labelbg}
\pgfsetlayers{grid,labelbg,main}
% \end{macrocode}
% Store the line width of the grid and axis, treating them as \qty{0}{\point} if they are disabled.
% \begin{macrocode}
\bool_if:NTF\l_@@_grid_bool
{
\@@_set_style_line_width:nn
{\l_@@_grid_line_width}
{/timechart/grid}
}
{ \pgfmathsetlengthmacro{\l_@@_grid_line_width}{0} }
\int_if_zero:nTF{ \l_@@_axis_int }
{
\pgfmathsetlengthmacro{\l_@@_axis_line_width}{0}
\pgfmathsetlengthmacro{\l_@@_major_tick_line_width}{0}
\pgfmathsetlengthmacro{\l_@@_minor_tick_line_width}{0}
}
{
\@@_set_style_line_width:nn
{\l_@@_axis_line_width}
{/timechart/axis~line}
\@@_set_style_line_width:nn
{\l_@@_major_tick_line_width}
{/timechart/major~tick}
\@@_set_style_line_width:nn
{\l_@@_minor_tick_line_width}
{/timechart/minor~tick}
}
% \end{macrocode}
% Store the start and finish years (ignoring circa, month, day), and then set up the conversion from years to \(x\)
% coordinates. \cs{l_@@_x} is the \(x\)-distance corresponding to one year, and \mcode{yeartox} is the \pkg{pgfmath}
% function that does the conversion.
% \begin{macrocode}
\@@_parse_date:NNn\l_tmpa_bool\l_@@_start_year{#2}
\@@_parse_date:NNn\l_tmpa_bool\l_@@_finish_year{#3}
\pgfmathsetmacro{\l_@@_start_year}
{floor(\l_@@_start_year)}
\pgfmathsetmacro{\l_@@_finish_year}
{floor(\l_@@_finish_year)}
\pgfmathsetmacro{\l_@@_x}
{
(
\l_@@_width_pgf
- max(
\l_@@_grid_line_width,
\l_@@_axis_line_width,
\l_@@_major_tick_line_width,
\l_@@_minor_tick_line_width
)
)/(\l_@@_finish_year-\l_@@_start_year)
}
\pgfkeys{
/pgf/declare~function={
yeartox(\n)=\l_@@_x*(\n-\l_@@_start_year);
},
}
% \end{macrocode}
% Calculate the start and finish \(x\) coordinates.
% \begin{macrocode}
\pgfmathsetmacro{\l_@@_start_x}
{yeartox(\l_@@_start_year)}
\pgfmathsetmacro{\l_@@_finish_x}
{yeartox(\l_@@_finish_year)}
% \end{macrocode}
% Set up tracking of current \(y\) coordinate.
% \begin{macrocode}
\pgfmathsetmacro{\l_@@_current_y}{0}
\pgfmathsetmacro{\l_@@_saved_y}{0}
\pgfmathsetmacro{\l_@@_auto_reset_minimum_y}{-16000pt}
\pgfmathsetmacro{\l_@@_auto_reset_maximum_y}{16000pt}
% \end{macrocode}
% Calculate some years used in loops.
% \begin{macrocode}
\pgfmathsetmacro{\l_@@_start_plus_year}{
\l_@@_start_year+\l_@@_minor_tick_interval_year
}
\pgfmathsetmacro{\l_@@_start_plusplus_year}{
\l_@@_start_year+(2*\l_@@_minor_tick_interval_year)
}
\pgfmathsetmacro{\l_@@_end_minus_year}{
\l_@@_finish_year-\l_@@_minor_tick_interval_year
}
% \end{macrocode}
% Begin a group and make available the user commands \cs{timechart}\ldots. (The group will be ended by
% \cs{@@_main_end_user:}.)
% \begin{macrocode}
\group_begin:
\cs_set_eq:NN\timechartinterval\@@_interval_user:Ommm
\cs_set_eq:NN\timecharttext\@@_text_user:Omm
\cs_set_eq:NN\timechartspace\@@_space_user:O
\cs_set_eq:NN\timechartsety\@@_set_y_user:m
\cs_set_eq:NN\timechartsavey\@@_save_y_user:
\cs_set_eq:NN\timechartresety\@@_reset_y_user:
\cs_set_eq:NN\timechartsetyminimumautoreset
\@@_set_y_minimum_auto_reset_user:m
\cs_set_eq:NN\timechartsetymaximumautoreset
\@@_set_y_maximum_auto_reset_user:m
\cs_set_eq:NN\timechartstepy\@@_step_y_user:O
\cs_set_eq:NN\timechartfinish\@@_main_end_user:
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_main_end:}
% Make sure the chart is complete and end the \TikZ\ picture. \cs{@@_main_end_user:} ends the group begun by
% \cs{@@_main_begin:nnn}, so whether the user has \emph{not} called it (as \cs{timechartfinish}) is equivalent to it
% being equal to \cs{timechartfinish}.
% \begin{macrocode}
\cs_new:Npn\@@_main_end:
{
\cs_if_eq:NNT\timechartfinish\@@_main_end_user:
{ \@@_main_end_user: }
\endtikzpicture
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_main_end_user:}
% End the group begun by \cs{@@_main_begin:nnn}, draw the axis and grid, and set the bounding box. This macro is made
% available as \cs{timechartfinish} inside the \env{timechart} environment.
% \begin{macrocode}
\cs_new:Npn\@@_main_end_user:
{
% \end{macrocode}
% The aim here is to set the bounding box (1) to fit horizontally the axis \emph{not} including labels and the grid
% and (2) to fit vertically the axis including labels and the grid . All the `horizonatal' data is already known, and
% the `vertical' data is determined by the \emph{current} bounding box. So extract the `vertical' data and then reset
% the bounding box.
% \begin{macrocode}
\pgfextracty{\l_@@_tmpa_dim}
{ \pgfpointanchor{current~bounding~box}{south} }
\pgfextracty{\l_@@_tmpb_dim}
{ \pgfpointanchor{current~bounding~box}{north} }
\pgfresetboundingbox
% \end{macrocode}
% If the timechart is empty, then the extracted \(y\) coordinates of `north' and `south' anchors of the bounding box
% will be \qty{-16000}{\point} and \qty{16000}{\point} respectively. Test for this and treat them as both having \(y\)
% coordinate \qty{0}{\point} in this case.
% \begin{macrocode}
\dim_compare:nNnTF{\l_@@_tmpa_dim}>{\l_@@_tmpb_dim}
{
\pgfmathsetmacro{\l_@@_content_bottom_y}{0pt}
\pgfmathsetmacro{\l_@@_content_top_y}{0pt}
}
{
\pgfmathsetmacro{\l_@@_content_bottom_y}
{\l_@@_tmpa_dim}
\pgfmathsetmacro{\l_@@_content_top_y}
{\l_@@_tmpb_dim}
}
% \end{macrocode}
% Now draw the grid and axis if necessary and set the bounding box if not.
% \begin{macrocode}
\bool_if:NTF{\l_@@_grid_bool}
{ \@@_grid_draw: }
{ \@@_nogrid_bounding_box_set: }
\@@_axis_draw:
% \end{macrocode}
% Finally, end the group begun by \cs{@@_main_begin:nnn}.
% \begin{macrocode}
\group_end:
}
% \end{macrocode}
% \end{macro}
%
%
%
% \subsection{Grid drawing}
%
% \begin{macro}{\@@_grid_draw:}
% Draw the grid of the chart, assuming that the \(y\) coordinates of the top and bottom of the content have been
% calculated and stored in \cs{l_@@_content_top_y} and \cs{l_@@_content_bottom_y}. These variable will be updated to
% the grid top and bottom.
% \begin{macrocode}
\cs_new:Npn\@@_grid_draw:
{
\pgfmathsetmacro{\l_@@_content_bottom_y}{
\l_@@_content_bottom_y-\l_@@_grid_bottom_ysep_pgf
}
\pgfmathsetmacro{\l_@@_content_top_y}{
\l_@@_content_top_y+\l_@@_grid_top_ysep_pgf
}
\pgfonlayer{ grid }
\scope[/timechart/grid]
\foreach \year in {
\l_@@_start_plus_year,
\l_@@_start_plusplus_year,
...,
\l_@@_end_minus_year
} {
\group_begin:
% \end{macrocode}
% Only draw gridlines at major ticks.
% \begin{macrocode}
\@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}
{ Mod(\year,\l_@@_major_tick_interval_year)==0 }
\bool_if:NT\l_@@_tmpa_bool
{
\pgftransformshift{ \pgfpoint{yeartox(\year)}{0} }
\pgfpathmoveto{ \pgfpoint{0}{\l_@@_content_top_y} }
\pgfpathlineto{ \pgfpoint{0}{\l_@@_content_bottom_y} }
\pgfusepath{ draw }
}
\group_end:
}
% \end{macrocode}
% Define and draw the grid node.
% \begin{macrocode}
\@@_make_rectangle_node:nnnn
{ \pgfpoint{\l_@@_start_x}{\l_@@_content_bottom_y} }
{ \pgfpoint{\l_@@_finish_x}{\l_@@_content_top_y} }
{ grid }
{ \c_true_bool }
\endscope
\endpgfonlayer
}
% \end{macrocode}
% \end{macro}
%
%
%
% \subsection{Axis drawing}
%
% \begin{macro}{\@@_axis_draw:}
% Draw the axis, with large/small ticks and labels on appropriate years.
% \begin{macrocode}
\cs_new:Npn\@@_axis_draw:
{
\group_begin:
\int_case:nn{ \l_@@_axis_int }
{
{0}
{ \prg_do_nothing: }
{1}
{
\pgftransformshift{
\pgfpoint{0}{
\l_@@_content_top_y
+\pgfkeysvalueof{/timechart/axis~ysep}
}
}
\pgfmathsetmacro{\l_@@_tick_orientation_pgf}{1}
\cs_set:Npn\l_@@_tick_label_anchor_text
{ mid~west }
\cs_set:Npn\l_@@_zero_tick_before_label_anchor_text
{ base~west }
\cs_set:Npn\l_@@_zero_tick_after_label_anchor_text
{ north~west }
\@@_axis_draw_aux:
}
{2}
{
\pgftransformshift{
\pgfpoint{0}{
\l_@@_content_bottom_y
-\pgfkeysvalueof{/timechart/axis~ysep}
}
}
\pgfmathsetmacro{\l_@@_tick_orientation_pgf}{-1}
\cs_set:Npn\l_@@_tick_label_anchor_text
{ mid~east }
\cs_set:Npn\l_@@_zero_tick_before_label_anchor_text
{ base~east }
\cs_set:Npn\l_@@_zero_tick_after_label_anchor_text
{ north~east }
\@@_axis_draw_aux:
}
}
\group_end:
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_axis_draw_aux:}
% Draw the axis, with large/small ticks and labels on appropriate years, assuming that the \(y\) coordinate has been
% calculated and stored in \cs{l_@@_axis_y}.
% \begin{macrocode}
\cs_new:Npn\@@_axis_draw_aux:
{
\pgfkeys{
/timechart/minor~tick~length/.get=\@@_minor_tick_length_pgf,
/timechart/major~tick~length/.get=\@@_major_tick_length_pgf,
}
% \end{macrocode}
% Work out the first and last years which will have a major tick (since these are marked with the era).
% \begin{macrocode}
\pgfmathsetmacro{\l_@@_start_major_tick_year}
{
\l_@@_start_year
-Mod(
\l_@@_start_year,
\l_@@_major_tick_interval_year
)
}
\pgfmathsetmacro{\l_@@_start_major_tick_year}
{
ifthenelse(
\l_@@_start_major_tick_year<\l_@@_start_year,
\l_@@_start_major_tick_year
+\l_@@_major_tick_interval_year,
\l_@@_start_major_tick_year
)
}
\pgfmathsetmacro{\l_@@_start_plus_major_tick_year}
{
\l_@@_start_major_tick_year
+\l_@@_major_tick_interval_year
}
\pgfmathsetmacro{\l_@@_finish_major_tick_year}
{
\l_@@_finish_year
-Mod(
\l_@@_finish_year,
\l_@@_major_tick_interval_year
)
}
% \end{macrocode}
% Loop over years and draw the minor ticks.
% \begin{macrocode}
\foreach \year in {
\l_@@_start_year,
\l_@@_start_plus_year,
...,
\l_@@_finish_year
} {
\pgfmathsetmacro{\x}{yeartox(\year)}
\@@_pgfmathsetbool:nn
{\l_@@_tmpa_bool}
{
Mod(
\year-\l_@@_start_major_tick_year,
\l_@@_major_tick_interval_year
)==0
}
\bool_if:NF\l_@@_tmpa_bool
{ \@@_axis_draw_minor_tick:N\x }
}
% \end{macrocode}
% Loop over years and draw the major ticks.
% \begin{macrocode}
\foreach \year in {
\l_@@_start_major_tick_year,
\l_@@_start_plus_major_tick_year,
...,
\l_@@_finish_major_tick_year
} {
\pgfmathsetmacro{\x}{yeartox(\year)}
\@@_axis_draw_labelled_major_tick:NN\x\year
}
% \end{macrocode}
% Define the axis line and define the axis node.
% \begin{macrocode}
\@@_draw_axis_line
\int_case:nn{\l_@@_axis_int}
{
{1}
{
\pgfextracty{\l_@@_tmpa_dim}
{ \pgfpointanchor{current~bounding~box}{north} }
\pgfmathsetmacro{\l_@@_axis_top_y}{\l_@@_tmpa_dim}
\pgfmathsetmacro{\l_@@_axis_bottom_y}{0}
}
{2}
{
\pgfextracty{\l_@@_tmpa_dim}
{ \pgfpointanchor{current~bounding~box}{south} }
\pgfmathsetmacro{\l_@@_axis_top_y}{0}
\pgfmathsetmacro{\l_@@_axis_bottom_y}{\l_@@_tmpa_dim}
}
}
\@@_make_rectangle_node:nnnn
{ \pgfpoint{\l_@@_start_x}{\l_@@_axis_bottom_y} }
{ \pgfpoint{\l_@@_finish_x}{\l_@@_axis_top_y} }
{ axis }
{ \c_false_bool }
}
% \end{macrocode}
% \end{macro}
%
% All the remaining axis-related macros (which begin \cs{@@_axis_draw_}) assume that a transformation has been applied
% so that the axis line is at \(y=0\).
%
% \begin{macro}{\@@_axis_draw_minor_tick:N}
% Draw an unlabelled tick at \(x\) coordinate \param{1}.
% \begin{macrocode}
\cs_new:Npn\@@_axis_draw_minor_tick:N #1
{
\scope[/timechart/minor~tick]
\pgfpathmoveto{ \pgfpoint{#1}{0} }
\pgfpathlineto{
\pgfpoint{#1}{
\l_@@_tick_orientation_pgf
*\@@_minor_tick_length_pgf
}
}
\pgfusepath{draw}
\endscope
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_axis_draw_labelled_major_tick:NN}
% Draw a labelled major tick at \(x\) coordinate \param{1}, with label for year \param{2}, using the special epoch
% marker if the year is 0, and showing the era if and only if the year is for the first or last major tick. This macro
% assumes that \cs{@@_start_major_tick_year} and \cs{@@_finish_major_tick_year} have been calculated.
% \begin{macrocode}
\cs_new:Npn\@@_axis_draw_labelled_major_tick:NN #1#2
{
\@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}{#2==0}
\bool_if:NTF \l_@@_tmpa_bool
{ \@@_axis_draw_zero_tick:N #1 }
{
\int_case:nn { \l_@@_major_tick_eras_int }
{
{0}{ \bool_set_false:N\l_@@_tmpd_bool }
{1}{ \bool_set_true:N\l_@@_tmpd_bool }
{2}
{
\@@_pgfmathsetbool:nn{\l_@@_tmpb_bool}
{ #2==\l_@@_start_major_tick_year }
\@@_pgfmathsetbool:nn{\l_@@_tmpc_bool}
{ #2==\l_@@_finish_major_tick_year }
\bool_set:Nn\l_@@_tmpd_bool
{ \l_@@_tmpb_bool || \l_@@_tmpc_bool }
}
}
\@@_axis_draw_major_tick:N #1
\@@_axis_draw_year_label:nnnnnn
{ #1 }
{ #2 }
{ \l_@@_tmpd_bool }
{ \l_@@_tick_label_anchor_text }
{ 0 }
{
\l_@@_tick_orientation_pgf
*(\@@_major_tick_length_pgf+1mm)
}
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_axis_draw_major_tick:N}
% Draw a major tick at \(x\) coordinate \param{1}.
% \begin{macrocode}
\cs_new:Npn\@@_axis_draw_major_tick:N #1
{
\scope[/timechart/major~tick]
\pgfpathmoveto{ \pgfpoint{#1}{0} }
\pgfpathlineto{
\pgfpoint{#1}{
\l_@@_tick_orientation_pgf
*\@@_major_tick_length_pgf
}
}
\pgfusepath{draw}
\endscope
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_axis_draw_zero_tick:N}
% Draw a special (labelled) tick for year zero at \(x=\param{1}\).
% \begin{macrocode}
\cs_new:Npn\@@_axis_draw_zero_tick:N #1
{
\group_begin:
\pgftransformshift{ \pgfpoint{#1}{0} }
% \end{macrocode}
% The mark is a cross made up of four arcs and the miter joins between them. The parameter \cs{r} is the arc radius.
% The parameter \cs{a} is how many degrees should be trimmed from the start/end of a quarter-circle to form each arc.
% Thus the length of the miter is dependent on \cs{a}.
% \begin{macrocode}
\pgfmathsetmacro{\a}{5}
\pgfmathsetlengthmacro{\r}{1mm}
\pgfmathsetlengthmacro{\t}{\r*(cos(\a)-cos(90-\a))/(1-cos(90-\a))}
% \end{macrocode}
% The drawing process is: move to the start of the tick, draw the tick, draw the four arcs, then draw a small part of
% the tick again. The last step is not mathematically necessary for a smooth join, but ensures that the join
% \emph{appears} smooth.
% \begin{macrocode}
\scope[/timechart/major~tick,line~join=miter]
\group_begin:
\pgftransformyscale{\l_@@_tick_orientation_pgf}
\pgfpathmoveto{\pgfpointorigin}
\pgfpathlineto{\pgfpoint{0}{\@@_major_tick_length_pgf}}
\pgfpatharc{0}{90-\a}{\t~and~\r}
\pgfpatharc{270+\a}{360-\a}{\r}
\pgfpatharc{180+\a}{270-\a}{\r}
\pgfpatharc{90+\a}{180-\a}{\t~and~\r}
\pgfpathlineto{\pgfpoint{0}{\@@_major_tick_length_pgf-1pt}}
\pgfusepath{draw}
\group_end:
\endscope
% \end{macrocode}
% There is no year 0, so label the zero mark with the 1 before and 1 after the epoch.
% \begin{macrocode}
\@@_axis_draw_year_label:nnnnnn
{ 0 }
{ -1 }
{ \c_true_bool }
{ \l_@@_zero_tick_before_label_anchor_text }
{ -.5mm }
{ \l_@@_tick_orientation_pgf*5.5mm }
\@@_axis_draw_year_label:nnnnnn
{ 0 }
{ 1 }
{ \c_true_bool }
{ \l_@@_zero_tick_after_label_anchor_text }
{ .5mm }
{ \l_@@_tick_orientation_pgf*5.5mm }
\group_end:
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_axis_draw_line}
% Draw the axis line itself.
% \begin{macrocode}
\cs_new:Npn\@@_draw_axis_line
{
\scope[/timechart/axis~line]
\pgfpathmoveto{ \pgfpoint{\l_@@_start_x}{0} }
\pgfpathlineto{ \pgfpoint{\l_@@_finish_x}{0} }
\pgfusepath{draw}
\endscope
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_axis_draw_year_label:nnnnnn}
% Draw a year label.
% \begin{arguments}
% \item \(x\) coordinate.
% \item Year for label.
% \item Boolean literal indicating whether the era should be shown.
% \item Anchor for node.
% \item \(x\) offset (dimension).
% \item \(y\) offset (dimension).
% \end{arguments}
% \begin{macrocode}
\cs_new:Npn\@@_axis_draw_year_label:nnnnnn #1#2#3#4#5#6
{
\group_begin:
\pgftransformshift{ \pgfpoint{#1+#5}{#6} }
\pgfmathtruncatemacro{\absyear}{ abs(#2) }
\scope[/timechart/major~tick~label]
\bool_if:NTF #3
{
\@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}{#2<0}
\bool_if:NTF\l_@@_tmpa_bool
{ \cs_set_eq:NN\@@_make_year:n\timechartmakebeforeyear }
{ \cs_set_eq:NN\@@_make_year:n\timechartmakeafteryear }
}
{ \cs_set_eq:NN\@@_make_year:n\use:n }
\@@_hsmash_pgfnode:nnnnn
{rectangle}
{#4}
{\@@_make_year:n{\absyear}}
{}
{}
\endscope
\group_end:
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\timechartmakebeforeyear,\timechartmakeafteryear}
% User-redefineable macros to format a year as before or after the epoch.
% \begin{macrocode}
\cs_new:Npn\timechartmakebeforeyear #1
{
#1\nobreakspace\textsc{bce}
}
\cs_new:Npn\timechartmakeafteryear #1
{
#1\nobreakspace\textsc{ce}
}
% \end{macrocode}
% \end{macro}
%
%
%
% \subsection{Bounding box}
%
% \begin{macro}{\@@_nogrid_bounding_box_set:}
% Set the bounding box when no grid is being drawn.
% \begin{macrocode}
\cs_new:Npn\@@_nogrid_bounding_box_set:
{
\pgfpathmoveto
{ \pgfpoint{\l_@@_start_x}{\l_@@_content_bottom_y} }
\pgfpathmoveto
{ \pgfpoint{\l_@@_finish_x}{\l_@@_content_top_y} }
\pgfusepath{discard}
}
% \end{macrocode}
% \end{macro}
%
%
%
% \subsection{Positioning}
%
% \begin{macro}{\@@_set_y_user:m}
% Set current \(y\) coordinate to \param{1}. This macro will be made available as \cs{timechartsety} in the
% \env{timechart} environment.
% \begin{macrocode}
\cs_new:Npn\@@_set_y_user:m #1
{
\pgfmathsetmacro{\l_@@_current_y}{#1}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_save_y_user:}
% Save the current \(y\) coordinate. This macro will be made available as \cs{timechartsavey} in the
% \env{timechart} environment.
% \begin{macrocode}
\cs_new:Npn\@@_save_y_user:
{
\pgfmathsetmacro{\l_@@_saved_y}{\l_@@_current_y}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_reset_y_user:}
% Set the current \(y\) coordinate to the last saved coordinate. This macro will be made available as
% \cs{timechartsresety} in the \env{timechart} environment.
% \begin{macrocode}
\cs_new:Npn\@@_reset_y_user:
{
\pgfmathsetmacro{\l_@@_current_y}{\l_@@_saved_y}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_set_y_minimum_auto_reset_user:m}
% Set a \(y\) coordinate below which \cs{@@_step_y_user:} will automatically reset the currrent \(y\) coordinate to
% the last saved \(y\) coordinate. This macro will be made available as \cs{timechartssetyminimumautoreset} in the
% \env{timechart} environment.
% \begin{macrocode}
\cs_new:Npn\@@_set_y_minimum_auto_reset_user:m #1
{
\pgfmathsetmacro{\l_@@_auto_reset_minimum_y}{#1}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_set_y_maximum_auto_reset_user:m}
% Set a \(y\) coordinate above which \cs{@@_step_y_user:} will automatically reset the currrent \(y\) coordinate to
% the last saved \(y\) coordinate. This macro will be made available as \cs{timechartssetymaximumautoreset} in the
% \env{timechart} environment.
% \begin{macrocode}
\cs_new:Npn\@@_set_y_maximum_auto_reset_user:m #1
{
\pgfmathsetmacro{\l_@@_auto_reset_maximum_y}{#1}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_step_y_user:O}
% Increment the current \(y\) coordinate by \param{1} times the length specified in \key{/timechart/ystep}. This
% macro will be made available as \cs{timechartstepy} in the \env{timechart} environment.
% \begin{macrocode}
\NewDocumentCommand{\@@_step_y_user:O}{ O{1} }
{
\pgfmathsetmacro{\l_@@_current_y}
{\l_@@_current_y+#1*\l_@@_ystep_pgf}
\@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}
{
or(
\l_@@_current_y<\l_@@_auto_reset_minimum_y,
\l_@@_current_y>\l_@@_auto_reset_maximum_y
)
}
\bool_if:nT{\l_@@_tmpa_bool}
{ \pgfmathsetmacro{\l_@@_current_y}{\l_@@_saved_y)} }
}
% \end{macrocode}
% \end{macro}
%
%
%
% \subsection{Bounds checking}
%
% \begin{macro}{\@@_if_x_in_bounds:nT}%
% Check if \(x\) coordinate \param{1} is (strictly) within the bounds of the chart; if so, execute \param{2}.
% \begin{macrocode}
\cs_new:Npn\@@_if_x_in_bounds:nT #1#2
{
\@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}{
and(
#1>=\l_@@_start_x,
#1<=\l_@@_finish_x
)
}
\bool_if:NT\l_@@_tmpa_bool
{#2}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_if_x_range_intersect_bounds_x:nnT}%
% Check if the range between \(x\) coordinates \param{1} and \param{2} intersects the range of the bounds of the
% chart; if so, execute \param{3}.
% \begin{macrocode}
\cs_new:Npn\@@_if_x_range_intersect_bounds:nnT #1#2#3
{
\@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}{
or(
or(
and(
#2>=\l_@@_start_x,
#2<=\l_@@_finish_x
),
and(
#1>=\l_@@_start_x,
#1<=\l_@@_finish_x
)
),
and(
#1<\l_@@_start_x,
#2>\l_@@_finish_x
)
)
}
\bool_if:NT\l_@@_tmpa_bool
{#3}
}
% \end{macrocode}
% \end{macro}
%
%
%
% \subsection{Date and date range parsing}
%
% \begin{macro}{\@@_parse_date_or_daterange:NNNNNn}
% Parse the text in \param{6}, which should represent a date or date range, into parameters \param{1}--\param{5}.
% \begin{arguments}
% \item range indicator boolean variable.
% \item minimum circa indicator boolean variable.
% \item minimum variable.
% \item maximum circa indicator boolean variable.
% \item maximum variable.
% \item text to parse.
% \end{arguments}
% \begin{macrocode}
\cs_new:Npn\@@_parse_date_or_daterange:NNNNNn #1#2#3#4#5#6
{
\bool_set:Nn #1 {\@@_is_nondaterange_p:w #6/\q_stop}
\bool_set_inverse:N #1
\bool_if:nTF #1
{ \@@_parse_range:w #2#3#4#5\q_mark #6\q_stop }
{
\@@_parse_date:NNn #2#3{#6}
\bool_set_eq:NN #4#2
\pgfmathsetmacro{#5}{#3}
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_is_nondaterange_p:w}
% To be called in the form \cs{@@_is_nondaterange_p:w}\meta{text}\texttt{/}\cs{q_stop}. Return boolean true if and
% only if \meta{text} (known to be either a date or date range) contains a range marker.
% \begin{macrocode}
\cs_new:Npn\@@_is_nondaterange_p:w #1/#2\q_stop
{
\tl_if_empty_p:n{#2}
}
% \end{macrocode}
% \end{macro}
% \begin{macro}{\@@_parse_range:w}
% To be called in the form
% \cs{@@_parse_range:w}\meta{cmin}\meta{min}\meta{cmax}\meta{max}\cs{q_mark}\meta{text}\cs{q_stop}. Parse \meta{text}
% (known to represent a date range) into minimum circa indicator boolean variable \meta{cmin}, minimum variable
% \meta{min}, maximum circa indicator boolean variable \meta{cmax}, maximum variable \meta{max}.
% \begin{macrocode}
\cs_new:Npn\@@_parse_range:w #1#2#3#4\q_mark #5/#6\q_stop
{
\_@@_parse_date:NNn #1#2{#5}
\_@@_parse_date:NNn #3#4{#6}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_parse_date:NNn}
% Parse text (known to represent a date) into the supplied variables. Parameters \param{1} and \param{2} are the
% variables for (respectively) circa indicator boolean and date, and \param{3} is the text to be parsed:
% \begin{arguments}
% \item circa indicator boolean variable.
% \item date variable.
% \item text to parse.
% \end{arguments}
% \begin{macrocode}
\cs_new:Npn\@@_parse_date:NNn #1#2#3
{
\bool_set:Nn #1 { \@@_is_circa_p:w #3c\q_stop }
\bool_if:NTF #1
{ \@@_parse_circa_date:w #2\q_mark #3\q_stop }
{ \@@_parse_noncirca_date:Nn #2{#3} }
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_is_circa_p:w}
% To be called in the form \cs{@@_is_circa_p:w}\meta{text}\texttt{c}\cs{q_stop}. Return boolean true if and only if
% \meta{text} (known to be either a date or a date with a circa indicator) has a circa indicator.
% \begin{macrocode}
\cs_new:Npn\@@_is_circa_p:w #1c#2\q_stop
{
\tl_if_empty_p:n{#1}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_parse_circa_date:w}
% To be called in the form \cs{@@_parse_circa_date:w}\meta{var}\cs{q_mark}\meta{text}\cs{q_stop}. Parse \meta{text}
% (known to represent a circa date) into the supplied variable. \param{1} is the variable for the date and \param{2}
% is the text to be parsed.
% \begin{macrocode}
\cs_new:Npn\@@_parse_circa_date:w #1\q_mark c#2\q_stop
{
\@@_parse_noncirca_date:Nn #1{#2}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_parse_noncirca_date:w}
% To be called in the form \cs{@@_parse_noncirca_date:w}\meta{var}\cs{q_mark}\meta{text}\break\cs{q_stop}. Parse
% \meta{text} (known to represent a non-circa date) into the supplied variable. \param{1} is the variable for the date
% and \param{2} is the text to be parsed.
% \begin{macrocode}
\cs_new:Npn\@@_parse_noncirca_date:Nn #1#2
{
\bool_if:nTF { \@@_is_before_p:w #2-\q_stop }
{ \@@_parse_before_date:w #1\q_mark #2\q_stop }
{ \@@_parse_signed_date:w #1\q_mark #2-0-0\q_stop }
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_is_before_p:w}
% To be called in the form \cs{@@_is_before_p:w}\meta{text}\texttt{-}\cs{q_stop}. Return boolean true if and only if
% \meta{text} (known to be a date without a circa indicator) begins with a \texttt{-}.
% \begin{macrocode}
\cs_new:Npn\@@_is_before_p:w #1-#2\q_stop
{
\tl_if_empty_p:n{#1}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_parse_before_date:w}
% To be called in the form \cs{@@_parse_before_date:w}\meta{var}\cs{q_mark}\meta{text}\cs{q_stop}. Parse \meta{text}
% (known to represent a date with a leading \texttt{-}) into the supplied variable. \param{1} is the variable for the
% date and \param{2} is the text to be parsed.
% \begin{macrocode}
\cs_new:Npn\@@_parse_before_date:w #1\q_mark-#2\q_stop
{
\@@_parse_signed_date:w #1-\q_mark #2-0-0\q_stop
}
% \end{macrocode}
% \end{macro}
%
% Now comes that actual parsing of an ISO-format date \texttt{YYYY-MM-DD}. The following macros serve as lookup tables
% for the number of days in the \(n\)-th month and the number of days in the year up to the start of the \(n\)-th month.
% \begin{macrocode}
\cs_new:cpn{c_@@_year_days_pgf}{365}
\cs_new:cpn{c_@@_month_days_1_pgf}{31}
\cs_new:cpn{c_@@_month_days_2_pgf}{28}
\cs_new:cpn{c_@@_month_days_3_pgf}{31}
\cs_new:cpn{c_@@_month_days_4_pgf}{30}
\cs_new:cpn{c_@@_month_days_5_pgf}{31}
\cs_new:cpn{c_@@_month_days_6_pgf}{30}
\cs_new:cpn{c_@@_month_days_7_pgf}{31}
\cs_new:cpn{c_@@_month_days_8_pgf}{31}
\cs_new:cpn{c_@@_month_days_9_pgf}{30}
\cs_new:cpn{c_@@_month_days_10_pgf}{31}
\cs_new:cpn{c_@@_month_days_11_pgf}{30}
\cs_new:cpn{c_@@_month_days_12_pgf}{31}
\cs_new:cpn{c_@@_cumulative_days_1_pgf}{0}
\cs_new:cpn{c_@@_cumulative_days_2_pgf}{31}
\cs_new:cpn{c_@@_cumulative_days_3_pgf}{59}
\cs_new:cpn{c_@@_cumulative_days_4_pgf}{90}
\cs_new:cpn{c_@@_cumulative_days_5_pgf}{120}
\cs_new:cpn{c_@@_cumulative_days_6_pgf}{151}
\cs_new:cpn{c_@@_cumulative_days_7_pgf}{181}
\cs_new:cpn{c_@@_cumulative_days_8_pgf}{212}
\cs_new:cpn{c_@@_cumulative_days_9_pgf}{243}
\cs_new:cpn{c_@@_cumulative_days_10_pgf}{273}
\cs_new:cpn{c_@@_cumulative_days_11_pgf}{304}
\cs_new:cpn{c_@@_cumulative_days_12_pgf}{334}
% \end{macrocode}
%
% \begin{macro}{\@@_parse_signed_date:w}
% To be called in the form \cs{@@_parse_positive_date:w}\meta{var}\meta{sign}\cs{q_mark}\break
% \meta{text}\texttt{-0-0}\cs{q_stop}. Parse \meta{text} (known to represent a non-circa date) into the supplied
% variable. \param{1} is the variable for the date and \param{2} is possibly \texttt{-}.
%
% There is a trick in the parsing:
% \begin{enumerate}
% \item If \meta{text} has the form \meta{year}\texttt{-}\meta{month}\texttt{-}\meta{day}, then parameters
% \param{3}, \param{4}, and \param{5} will be, respectively, \meta{year}, \meta{month}, and
% \meta{day}\texttt{-0-0}. Thus \param{5} will be evaulated by \pkg{pgfmath} to \meta{day}.
% \item If \meta{text} has the form \meta{year}\texttt{-}\meta{month}, then parameters \param{3}, \param{4}, and
% \param{5} will be, respectively, \meta{year}, \meta{month}, and \texttt{0-0}. Thus \param{5} will be
% evaulated by \pkg{pgfmath} to \(0\).
% \item If \meta{text} is simply \meta{year}, then parameters \param{3}, \param{4}, and \param{5} will be,
% respectively, \meta{year}, \texttt{0}, and \texttt{0}.
% \end{enumerate}
% \begin{macrocode}
\cs_new:Npn\@@_parse_signed_date:w #1#2\q_mark #3-#4-#5\q_stop
{
\pgfmathtruncatemacro{\@@_parsed_year_pgf}{#2#3}
\pgfmathtruncatemacro{\@@_parsed_month_pgf}{#4}
\pgfmathtruncatemacro{\@@_parsed_day_pgf}{#5}
\@@_pgfmathsetbool:nn{\l_tmpa_bool}{
or(
\@@_parsed_month_pgf < 1,
\@@_parsed_month_pgf > 12,
)
}
\bool_if:NTF\l_tmpa_bool
{
% \end{macrocode}
% \textit{Case: no valid month is given.} Use only the year.
% \begin{macrocode}
\pgfmathsetmacro{#1}{#2#3}
}
{
% \end{macrocode}
% \textit{Case: a valid month is given.} Get the number of days in the year, in the month, and in the year up to the
% month. Then check if the year is a leap year and, if so, make the appropriate adjustments.
% \begin{macrocode}
\cs_set_eq:NN\l_@@_year_days_pgf\c_@@_year_days_pgf
\cs_set_eq:Nc\l_@@_month_days_pgf
{ c_@@_month_days_\@@_parsed_month_pgf _pgf }
\cs_set_eq:Nc\l_@@_cumulative_days_pgf
{ c_@@_cumulative_days_\@@_parsed_month_pgf _pgf }
\@@_pgfmathsetbool:nn{\l_tmpa_bool}{
or(
Mod(\@@_parsed_year_pgf,400) == 0,
and(
Mod(\@@_parsed_year_pgf,4) == 0,
Mod(\@@_parsed_year_pgf,100) != 0
)
)
}
\bool_if:NT\l_tmpa_bool
{
\pgfmathsetmacro{\l_@@_year_days_pgf}
{ \l_@@_year_days_pgf+1 }
\@@_pgfmathsetbool:nn{\l_tmpb_bool}
{ \@@_parsed_month == 1 }
\bool_if:NF\l_tmpb_bool
{
\@@_pgfmathsetbool:nn{\l_tmpb_bool}
{ \@@_parsed_month == 2 }
\bool_if:NF\l_tmpb_bool
{
\pgfmathsetmacro{\l_@@_month_days_pgf}
{ \l_@@_month_days_pgf + 1 }
}
{
\pgfmathsetmacro{\l_@@_cumulative_days_pgf}
{ \l_@@_cumulative_days_pgf + 1 }
}
}
}
\@@_pgfmathsetbool:nn{\l_tmpa_bool}{
or(
\@@_parsed_day_pgf < 1,
\@@_parsed_day_pgf > \l_@@_month_days_pgf,
)
}
\bool_if:NTF\l_tmpa_bool
{
% \end{macrocode}
% \textit{Sub-case: no valid day is given.} Use only the year and month.
% \begin{macrocode}
\pgfmathsetmacro{#1}
{
#2#3
+ \l_@@_cumulative_days_pgf/\l_@@_year_days_pgf
}
}
{
% \end{macrocode}
% \textit{Sub-case: a valid day is given.} Use the year, month, and day.
% \begin{macrocode}
\pgfmathsetmacro{#1}
{
#2#3
+ (
\l_@@_cumulative_days_pgf
+ \@@_parsed_day_pgf
)/\l_@@_year_days_pgf
}
}
}
}
% \end{macrocode}
% \end{macro}
%
%
%
% \subsection{Interval drawing}
%
% \subsubsection{Preliminaries}
%
% \begin{macro}{
% \l_@@_start_is_range_bool,
% \l_@@_interval_start_min_circa_bool,
% \l_@@_interval_start_max_circa_bool,
% \l_@@_finish_is_range_bool,
% \l_@@_interval_finish_min_circa_bool,
% \l_@@_interval_finish_max_circa_bool,
% }
% These boolean variables will be used to hold parsed data for the start and finish of an interval: whether it is a
% range, whether the beginning of that range is qualified by `circa', and whether the end of that range is qualified
% by `circa'.
% \begin{macrocode}
\bool_new:N\l_@@_start_is_range_bool
\bool_new:N\l_@@_interval_start_min_circa_bool
\bool_new:N\l_@@_interval_start_max_circa_bool
\bool_new:N\l_@@_finish_is_range_bool
\bool_new:N\l_@@_interval_finish_min_circa_bool
\bool_new:N\l_@@_interval_finish_max_circa_bool
% \end{macrocode}
% \end{macro}
%
%
%
% \subsubsection{Error message definition}
%
% \begin{macrocode}
\msg_new:nnn{timechart}{interval_dates_invalid}
{ Invalid~interval~dates:~#1~to~#2 }
% \end{macrocode}
%
%
%
% \subsubsection{Main macros}
%
% \begin{macro}{\@@_interval_user:Ommm}
% Draw an interval. This macro will be made available as \cs{timechartinterval} inside the \env{timechart}
% environment. It is simply a wrapper around the internal \cs{@@_interval:nnnn} macro.
% \begin{arguments}
% \item PGF keys under \key{/timechart/} to apply.
% \item Start year.
% \item Finish year.
% \item Label.
% \end{arguments}
% \begin{macrocode}
\NewDocumentCommand{\@@_interval_user:Ommm}{ O{} m m m }
{
\@@_interval:nnnn{#1}{#2}{#3}{#4}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_interval:nnnn}
% Internal macro for drawing an interval.
% \begin{macrocode}
\cs_new:Npn \@@_interval:nnnn #1#2#3#4
{
\@@_debug:n{
************************************************************
}
\@@_debug:n{Interval~#2~to~#3~"#4"}
% \end{macrocode}
% Open an group and parse the start and finish dates or date ranges.
% \begin{macrocode}
\group_begin:
\@@_parse_date_or_daterange:NNNNNn
\l_@@_start_is_range_bool
\l_@@_interval_start_min_circa_bool
\l_@@_interval_start_min_year
\l_@@_interval_start_max_circa_bool
\l_@@_interval_start_max_year
{#2}
\@@_parse_date_or_daterange:NNNNNn
\l_@@_finish_is_range_bool
\l_@@_interval_finish_min_circa_bool
\l_@@_interval_finish_min_year
\l_@@_interval_finish_max_circa_bool
\l_@@_interval_finish_max_year
{#3}
% \end{macrocode}
% Check the results of parsing.
% \begin{macrocode}
\@@_pgfmathsetbool:nn{\l_tmpa_bool}{
and(
\l_@@_interval_start_min_year
<= \l_@@_interval_start_max_year,
and(
\l_@@_interval_start_max_year
<= \l_@@_interval_finish_min_year,
\l_@@_interval_finish_min_year
<= \l_@@_interval_finish_max_year
)
)
}
% \end{macrocode}
% Proceed if and only if the results of parsing are valid, otherwise output an error message. In both cases, close the
% group and, in the former case, step the \(y\) coordinate if appropriate.
% \begin{macrocode}
\bool_if:NTF\l_tmpa_bool
{
\@@_interval_checked:nn{#1}{#4}
\group_end:
\bool_if:NT\l_@@_autostep_bool
{ \@@_step_y_user:O }
}
{
\msg_error:nnnn{timechart}{interval_dates_invalid}{#2}{#3}
\group_end:
}
}
% \end{macrocode}
% \end{macro}
%
% In \cs{@@_interval_user_aux:nnnn}, the start and finish dates were parsed and it has been checked that they satisfy
% \begin{align*}
% &\cs{l_@@_interval_start_min_year} \\
% &\qquad\leq \cs{l_@@_interval_start_max_year} \\
% &\qquad\qquad\leq \cs{l_@@_interval_finish_min_year} \\
% &\qquad\qquad\qquad\leq \cs{l_@@_interval_finish_max_year}.
% \end{align*}
% In the code that follows, horizontal coordinates \cs[no-index]{l_@@_interval_..._x} will be computed from
% \cs[no-index]{l_@@_interval_..._year}. Subsequently, only the former variables will be used.
%
%
%
%
% \begin{macro}{\@@_interval_checked:nn}
% Draw an interval using the parsed and checked start and finish dates
% \begin{arguments}
% \item PGF keys under \key{/timechart/} to apply.
% \item Label.
% \end{arguments}
% \begin{macrocode}
\cs_new:Npn \@@_interval_checked:nn #1#2
{
% \end{macrocode}
% Process keys supplied locally and retrieve the only value needed at this stage.
% \begin{macrocode}
\pgfqkeys{/timechart}{
#1,
circa~uncertainty/.get=\l_@@_circa_uncertainty_year
}
% \end{macrocode}
% Do the minimum amount of calculation necessary to check whether any part of interval is visible. This means
% calculating \cs{l_@@_interval_start_min_x} and \cs{l_@@_interval_finish_max_x} (including taking into account any
% `circa').
% \begin{macrocode}
\bool_if:NTF\l_@@_interval_start_min_circa_bool
{
\pgfmathsetmacro{\l_@@_interval_start_min_x}
{ yeartox(\l_@@_interval_start_min_year
- \l_@@_circa_uncertainty_year) }
}
{
\pgfmathsetmacro{\l_@@_interval_start_min_x}
{ yeartox(\l_@@_interval_start_min_year) }
}
\bool_if:NTF\l_@@_interval_finish_max_circa_bool
{
\pgfmathsetmacro{\l_@@_interval_finish_max_x}
{ yeartox(\l_@@_interval_finish_max_year
+ \l_@@_circa_uncertainty_year) }
}
{
\pgfmathsetmacro{\l_@@_interval_finish_max_x}
{ yeartox(\l_@@_interval_finish_max_year) }
}
% \end{macrocode}
% Proceed if some part of the interval is visible.
% \begin{macrocode}
\@@_if_x_range_intersect_bounds:nnT
{\l_@@_interval_start_min_x}
{\l_@@_interval_finish_max_x}
{ \@@_draw_visible_interval:nn{#1}{#2} }
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_start_beyond_bool,\@@_finish_beyond_bool}
% Boolean variables to indicate whether the interval extends beyond the chart at the start or the finish more than the
% specified tolerance.
% \begin{macrocode}
\bool_new:N\l_@@_interval_start_beyond_bool
\bool_new:N\l_@@_interval_finish_beyond_bool
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{@@_draw_visible_interval:nn}
% Draw an interval of which some part is known to be visible.
% \begin{arguments}
% \item PGF keys
% \item Label
% \end{arguments}
% \begin{macrocode}
\cs_new:Npn\@@_draw_visible_interval:nn #1#2
{
% \end{macrocode}
% Retrieve PGF key values.
% \begin{macrocode}
\pgfqkeys{/timechart}{
tolerance~start/.get=\l_@@_start_tolerance_pgf,
tolerance~finish/.get=\l_@@_finish_tolerance_pgf,
beyond~length~start/.get=\l_@@_start_beyond_length_pgf,
beyond~length~finish/.get=\l_@@_finish_beyond_length_pgf,
beyond~x~radius~start/.get=\l_@@_start_beyond_x_radius_pgf,
beyond~x~radius~finish/.get=\l_@@_finish_beyond_x_radius_pgf,
ref/.get=\l_@@_ref_text,
mark/.get=\l_@@_mark_text,
interval~minimum~width/.get=\l_@@_minimum_width_pgf,
interval~bar~color/.get=\l_@@_bar_color,
interval~bar~thickness/.get=\l_@@_bar_thickness_pgf,
interval~mark~color/.get=\l_@@_mark_color,
interval~label~baseline/.get=\l_@@_text_baseline_pgf,
interval~label~node~name/.get=\l_@@_interval_label_node_name,
}
% \end{macrocode}
% Calculate the start and finish tolerance and beyond indicator \(x\) coordinates.
% \begin{macrocode}
\pgfmathsetmacro{\l_@@_start_tolerance_x}{
\l_@@_start_x-(\l_@@_start_tolerance_pgf)
}
\pgfmathsetmacro{\l_@@_finish_tolerance_x}{
\l_@@_finish_x+(\l_@@_finish_tolerance_pgf)
}
\pgfmathsetmacro{\l_@@_start_beyond_x}{
\l_@@_start_x-(\l_@@_start_beyond_length_pgf)
}
\pgfmathsetmacro{\l_@@_finish_beyond_x}{
\l_@@_finish_x+(\l_@@_finish_beyond_length_pgf)
}
% \end{macrocode}
% Do the remaining calculations: calculate \cs{l_@@_interval_start_max_x} and \cs{l_@@_interval_finish_min_x}
% (including taking into account any `circa').
% \begin{macrocode}
\pgfmathsetlengthmacro{\l_@@_bar_half_thickness_pgf}
{.5*\l_@@_bar_thickness_pgf}
\cs_set:Npn\l_@@_label_text{#2}
\bool_if:NTF\l_@@_interval_start_max_circa_bool
{
\pgfmathsetmacro{\l_@@_interval_start_max_x}
{ yeartox(\l_@@_interval_start_max_year
+ \l_@@_circa_uncertainty_year) }
}
{
\pgfmathsetmacro{\l_@@_interval_start_max_x}
{ yeartox(\l_@@_interval_start_max_year) }
}
\bool_if:NTF\l_@@_interval_finish_min_circa_bool
{
\pgfmathsetmacro{\l_@@_interval_finish_min_x}
{ yeartox(\l_@@_interval_finish_min_year
- \l_@@_circa_uncertainty_year) }
}
{
\pgfmathsetmacro{\l_@@_interval_finish_min_x}
{ yeartox(\l_@@_interval_finish_min_year) }
}
% \end{macrocode}
% It is possible that circa indicators have made \cs{l_@@_start_max_x} greater than \cs{l_@@_finish_min_x}.
% Check for this; if so, set them both to their average.
% \begin{macrocode}
\@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}
{
\l_@@_interval_start_max_x
> \l_@@_interval_finish_min_x
}
\bool_if:NT\l_@@_tmpa_bool
{
\pgfmathsetmacro{\l_@@_interval_start_max_x}
{
.5*(
\l_@@_interval_start_max_x
+ \l_@@_interval_finish_min_x
)
}
\pgfmathsetmacro{\l_@@_interval_finish_min_x}
{ \l_@@_interval_start_max_x }
}
% \end{macrocode}
% Check whether the minimum width requirement is satisfied; if not, make an adjustment.
% \begin{macrocode}
\@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}
{
(\l_@@_interval_finish_max_x
-\l_@@_interval_start_min_x)
> \l_@@_minimum_width_pgf
}
\bool_if:NF \l_@@_tmpa_bool
{
\pgfmathsetmacro{\l_@@_width_adjust}
{ .5*\l_@@_minimum_width_pgf }
\pgfmathsetmacro{\l_@@_interval_start_max_x}
{ \l_@@_interval_start_max_x-\l_@@_width_adjust }
\pgfmathsetmacro{\l_@@_interval_finish_min_x}
{ \l_@@_interval_finish_min_x+\l_@@_width_adjust }
\pgfmathsetmacro{\l_@@_interval_start_min_x}
{
min(
\l_@@_interval_start_min_x,
\l_@@_interval_start_max_x
)
}
\pgfmathsetmacro{\l_@@_interval_finish_max_x}
{
max(
\l_@@_interval_finish_max_x,
\l_@@_interval_finish_min_x
)
}
}
\@@_debug:n{Calculated+adjusted~x~coords:}
\@@_debug:n{~
\l_@@_interval_start_min_x/\l_@@_interval_start_max_x~
to~
\l_@@_interval_finish_min_x/\l_@@_interval_finish_max_x
}
% \end{macrocode}
% At this point, the \(x\)-coordinates of the interval have been established. First, decide whether the interval
% exceeds the chart by more than the tolerance at the start and the finish. If so, set the appropriate clipping path
% (this may be changed again later).
% \begin{macrocode}
\@@_pgfmathsetbool:nn{\l_@@_interval_start_beyond_bool}
{\l_@@_interval_start_min_x<=\l_@@_start_tolerance_x}
\bool_if:NT\l_@@_interval_start_beyond_bool
{
\cs_set_eq:NN
\@@_interval_start_clip_path:
\@@_interval_start_clip_path_beyond:
}
\@@_pgfmathsetbool:nn{\l_@@_interval_finish_beyond_bool}
{\l_@@_interval_finish_max_x>=\l_@@_finish_tolerance_x}
\bool_if:NT\l_@@_interval_finish_beyond_bool
{
\cs_set_eq:NN
\@@_interval_finish_clip_path:
\@@_interval_finish_clip_path_beyond:
}
% \end{macrocode}
% Compute how the interval will be drawn. There are three components:
% \begin{itemize}
% \item the \emph{startrange}, comprising the part between \cs{l_@@_interval_start_min_x} to
% \cs{l_@@_interval_start_max_x};
% \item the definite part: \cs{l_@@_interval_start_max_x} to \cs{l_@@_interval_finish_min_x};
% \item the \emph{finishrange}: \cs{l_@@_interval_finish_min_x} to \cs{l_@@_interval_finish_max_x}.
% \end{itemize}
% It is necessary to decide which of these will be drawn. The logic is complicated because any part may lie outside
% the timechart or be involved in the beyond indicator. Further, clipping is used for a `slant' startrange or
% finishrange and for beyond indicators.
%
% First of all, consider the definite part. Depending on where this is located, it may be unnecessary to compute or
% draw the startrange or finishrange, so some of the following macros may be set to do nothing.
% \begin{macrocode}
\@@_interval_definite_compute:
\@@_interval_startrange_compute:
\@@_interval_finishrange_compute:
% \end{macrocode}
% All the data needed to draw the interval are now ready. Shift to the correct vertical coordinate and open a scope for
% drawing.
% \begin{macrocode}
\pgftransformshift{ \pgfpoint{0}{\l_@@_current_y} }
\pgfscope
% \end{macrocode}
% First, do the computed clipping, for a slant startrange and/or a slant finishrange, or beyond indicators. Then draw
% the startrange, finish range, and then the `solid' part, which may be only the definite part or may include a slant
% startrange or a slant finishrange. Finally, define the node for the bar, then do the labelling.
% \begin{macrocode}
\@@_interval_clip:
\@@_interval_startrange_draw:
\@@_interval_finishrange_draw:
\@@_interval_solid_draw:
\@@_interval_mark:
\@@_interval_define_bar_node:
\endpgfscope
\@@_interval_label:
}
% \end{macrocode}
% \end{macro}
%
%
%
% \subsubsection{Computation}
%
% These macros determine precisely what is to be drawn. The aim is to minimize the number of drawing commands by
% avoiding drawing where areas that would be clipped.
%
%
%
% \paragraph{Definite part of the interval}
%
% \begin{macro}{\@@_interval_definite_compute:}
% Compute whether and where to draw the definite part of the interval. Two auxiliary macros,
% \cs{@@_interval_definite_compute_ii:} and \cs{@@_interval_definite_compute_ii:} are used, simply to avoid deep
% nesting of code.
%
% First, check whether the entire definite part of the interval is located to the left of the start of the chart and
% that the interval does exceed the start tolerance. In this case, the only thing that might be drawn to appear to the
% left of the start will be the excess indicator drawn as part of the finish range, so there is no need to draw the
% definite part or do anything for the start range.
% \begin{macrocode}
\cs_new:Npn\@@_interval_definite_compute:
{
\@@_debug:n{Computing:~definite~part}
\@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}
{ \l_@@_interval_finish_min_x < \l_@@_start_x }
\bool_if:nTF{
\l_@@_tmpa_bool && \l_@@_interval_start_beyond_bool
}
{
\cs_set_eq:NN
\@@_interval_solid_draw:\prg_do_nothing:
\cs_set_eq:NN
\@@_interval_startrange_compute:\prg_do_nothing:
\cs_set_eq:NN
\@@_interval_startrange_draw:\prg_do_nothing:
}
{
\@@_interval_definite_compute_ii:
}
}
% \end{macrocode}
% Second, check whether the entire definite part of the interval is located to the right of the finish of the chart
% and that the interval does exceed the finish tolerance. In this case, the only thing that might be drawn to appear
% to the right of the finish will be the excess indicator drawn as part of the start range, so there is no need to
% draw the definite part or do anything for the finish range.
% \begin{macrocode}
\cs_new:Npn\@@_interval_definite_compute_ii:
{
\@@_debug:n{~(Stage~II)}
\@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}
{ \l_@@_interval_start_max_x > \l_@@_finish_x }
\bool_if:nTF{
\l_@@_tmpa_bool && \l_@@_interval_finish_beyond_bool
}
{
\cs_set_eq:NN
\@@_interval_solid_draw:\prg_do_nothing:
\cs_set_eq:NN
\@@_interval_finishrange_compute:\prg_do_nothing:
\cs_set_eq:NN
\@@_interval_finishrange_draw:\prg_do_nothing:
}
{
\@@_interval_definite_compute_iii:
}
}
% \end{macrocode}
% At this point, some part of the definite part of the interval has to be drawn.
% \begin{macrocode}
\cs_new:Npn\@@_interval_definite_compute_iii:
{
\@@_debug:n{~(Stage~III)}
% \end{macrocode}
% If the start of the definite part of the interval is at or to the left of the start of the chart and the interval
% exceeds the start tolerance, set the start of the solid part to the position of the start excess indicator. In this
% case, nothing needs to be done for the start range. Otherwise, set the start of the solid part to the start of the
% definite part.
% \begin{macrocode}
\@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}
{ \l_@@_interval_start_max_x <= \l_@@_start_x }
\bool_if:nTF{
\l_@@_tmpa_bool && \l_@@_interval_start_beyond_bool
}
{
\cs_set_eq:NN
\l_@@_interval_solid_start_x\l_@@_start_beyond_x
\cs_set_eq:NN
\@@_interval_startrange_compute:\prg_do_nothing:
\cs_set_eq:NN
\@@_interval_startrange_draw:\prg_do_nothing:
}
{
\cs_set_eq:NN
\l_@@_interval_solid_start_x
\l_@@_interval_start_max_x
}
% \end{macrocode}
% If the finish of the definite part of the interval is at or to the right of the finish of the chart and the interval
% exceeds the finish tolerance, set the finsih of the solid part to the position of the finish excess indicator. In
% this case, nothing needs to be done for the start range. Otherwise, set the start of the solid part to the start of
% the definite part.
% \begin{macrocode}
\@@_pgfmathsetbool:nn{\l_@@_tmpb_bool}
{ \l_@@_interval_finish_min_x >= \l_@@_finish_x }
\bool_if:nTF{
\l_@@_tmpb_bool && \l_@@_interval_finish_beyond_bool
}
{
\cs_set_eq:NN
\l_@@_interval_solid_finish_x\l_@@_finish_beyond_x
\cs_set_eq:NN
\@@_interval_finishrange_compute:\prg_do_nothing:
\cs_set_eq:NN
\@@_interval_finishrange_draw:\prg_do_nothing:
}
{
\cs_set_eq:NN
\l_@@_interval_solid_finish_x
\l_@@_interval_finish_min_x
}
}
% \end{macrocode}
% \end{macro}
%
%
%
% \paragraph{Startrange}
%
% \begin{macro}{\@@_interval_startrange_compute:}
% Compute how to draw the startrange of an interval. This macro will only be called if it is necessary to draw some
% part of the startrange.
% \begin{macrocode}
\cs_new:Npn\@@_interval_startrange_compute:
{
\@@_debug:n{Computing:~startrange}
\@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}
{
\l_@@_interval_start_min_x
== \l_@@_interval_start_max_x
}
\bool_if:NTF\l_@@_tmpa_bool
{
\cs_set_eq:NN\@@_interval_startrange_draw:\prg_do_nothing:
}
{
\@@_interval_startrange_compute_ii:
}
}
% \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_interval_startrange_compute_ii:}
% Compute how to draw the startrange of an interval. This macro will only be called if the start range is non-empty.
% \begin{macrocode}
\bool_new:N\l_@@_interval_startrange_finish_beyond_bool
\cs_new:Npn\@@_interval_startrange_compute_ii:
{
\@@_debug:n{~(Stage~II)}
% \end{macrocode}
% First, if the interval extends beyond the start tolerance then (since some part of the startrange) is visible, the
% start excess indicator forms part of the range. In this case, the drawn range starts at the start of the timechart and the
% start excess indicator mirrors this `level' of the range. Otherwise the drawn range starts at the extreme start of the
% interval at `level' \(0\) and a start excess indicator is not drawn.
% \begin{macrocode}
\bool_if:NTF\l_@@_interval_start_beyond_bool
{
\cs_set_eq:NN
\l_@@_interval_startrange_start_x\l_@@_start_x
\pgfmathsetmacro{\l_@@_interval_startrange_start_level_pgf}
{
(\l_@@_interval_startrange_start_x
-\l_@@_interval_start_min_x)
/
(\l_@@_interval_start_max_x
-\l_@@_interval_start_min_x)
}
}
{
\cs_set_eq:NN
\l_@@_interval_startrange_start_x
\l_@@_interval_start_min_x
\pgfmathsetmacro
{\l_@@_interval_startrange_start_level_pgf}{0}
}
% \end{macrocode}
% Second, if the interval extends beyond the finish tolerance and the start of the definite part of the interval is to
% the right of the finish of the timechart, the finish excess indicator forms part of the range. In this case, the
% drawn range finishes at the finish of the timechart and the excess indicator mirrors this `level' of the range.
% Otherwise the drawn range finishes at the extreme finish of the interval at `level' \(0\) and a finish excess
% indicator is not drawn.
% \begin{macrocode}
\@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}
{ \l_@@_interval_start_max_x > \l_@@_finish_x }
\bool_set:Nn\l_@@_interval_startrange_finish_beyond_bool
{
\l_@@_tmpa_bool
&& \l_@@_interval_finish_beyond_bool
}
\bool_if:NTF\l_@@_interval_startrange_finish_beyond_bool
{
\cs_set_eq:NN
\l_@@_interval_startrange_finish_x
\l_@@_finish_x
\pgfmathsetmacro{\l_@@_interval_startrange_finish_level_pgf}
{
(\l_@@_interval_startrange_finish_x
-\l_@@_interval_start_min_x)
/
(\l_@@_interval_start_max_x
-\l_@@_interval_start_min_x)
}
}
{
\cs_set_eq:NN
\l_@@_interval_startrange_finish_x
\l_@@_interval_start_max_x
\pgfmathsetmacro
{\l_@@_interval_startrange_finish_level_pgf}{1}
}
\int_case:nn {\l_@@_start_range_type_int}
{
{0}{
\cs_set_eq:NN
\@@_interval_startrange_draw:
\@@_interval_startrange_draw_pseudofade:
}
{1}{
\@@_interval_startrange_slant_compute:
}
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_interval_startrange_slant_compute:}
% Compute the clipping and drawing necessary for a slant startrange.
% \begin{macrocode}
\cs_new:Npn \@@_interval_startrange_slant_compute:
{
\@@_debug:n{~(Startrange~slant)}
\bool_if:NTF\l_@@_interval_start_beyond_bool
{
\bool_if:NTF\l_@@_interval_startrange_finish_beyond_bool
{
\cs_set_eq:NN
\@@_interval_both_clip_path:
\@@_interval_startrange_clip_path_beyond_both:
}
{
\cs_set_eq:NN
\@@_interval_start_clip_path:
\@@_interval_startrange_clip_path_beyond_start:
}
}
{
\bool_if:NTF\l_@@_interval_startrange_finish_beyond_bool
{
\cs_set_eq:NN
\@@_interval_both_clip_path:
\@@_interval_startrange_clip_path_beyond_finish:
}
{
\cs_set_eq:NN
\@@_interval_start_clip_path:
\@@_interval_startrange_clip_path_start:
}
}
\cs_if_eq:NNTF\@@_interval_solid_draw:\prg_do_nothing:
{
\cs_set_eq:NN
\@@_interval_startrange_draw:
\@@_interval_startfinishrange_draw_slant:
}
{
\cs_set_eq:NN
\l_@@_interval_solid_start_x
\l_@@_start_beyond_x
\cs_set_eq:NN
\@@_interval_startrange_draw:
\prg_do_nothing:
}
}
% \end{macrocode}
% \end{macro}
%
%
%
% \paragraph{Finishrange}
%
% \begin{macro}{\@@_interval_finishrange_compute:}
% Compute how to draw the finishrange of an interval. This macro will only be called if it is necessary to draw some
% part of the finishrange.
% \begin{macrocode}
\cs_new:Npn\@@_interval_finishrange_compute:
{
\@@_debug:n{Computing:~finishrange}
\@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}
{
\l_@@_interval_finish_max_x
== \l_@@_interval_finish_min_x
}
\bool_if:NTF\l_@@_tmpa_bool
{
\cs_set_eq:NN\@@_interval_finishrange_draw:\prg_do_nothing:
}
{
\@@_interval_finishrange_compute_ii:
}
}
% \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_interval_finishrange_compute_ii:}
% Compute how to draw the finishrange of an interval. This macro will only be called if the finishrange is non-empty.
% \begin{macrocode}
\bool_new:N\l_@@_interval_finishrange_start_beyond_bool
\cs_new:Npn\@@_interval_finishrange_compute_ii:
{
\@@_debug:n{~(Stage~II)}
% \end{macrocode}
% First, if the interval extends beyond the finish tolerance then (since some part of the finishrange) is visible, the
% finish excess indicator forms part of the range. In this case, the drawn range finishs at the finish of the
% timechart and the finish excess indicator mirrors this `level' of the range. Otherwise the drawn range finishs at
% the extreme finish of the interval at `level' \(0\) and a finish excess indicator is not drawn.
% \begin{macrocode}
\bool_if:NTF\l_@@_interval_finish_beyond_bool
{
\cs_set_eq:NN
\l_@@_interval_finishrange_finish_x
\l_@@_finish_x
\pgfmathsetmacro{\l_@@_interval_finishrange_finish_level_pgf}
{
(\l_@@_interval_finishrange_finish_x
-\l_@@_interval_finish_max_x)
/
(\l_@@_interval_finish_min_x
-\l_@@_interval_finish_max_x)
}
}
{
\cs_set_eq:NN
\l_@@_interval_finishrange_finish_x
\l_@@_interval_finish_max_x
\pgfmathsetmacro
{\l_@@_interval_finishrange_finish_level_pgf}{0}
}
% \end{macrocode}
% Second, if the interval extends beyond the start tolerance and the finish of the definite part of the interval is to
% the left of the start of the timechart, the start excess indicator forms part of the range. In this case, the
% drawn range starts at the start of the timechart and the excess indicator mirrors this `level' of the range.
% Otherwise the drawn range starts at the extreme start of the interval at `level' \(0\) and a start excess
% indicator is not drawn.
% \begin{macrocode}
\@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}
{ \l_@@_interval_finish_min_x < \l_@@_start_x }
\bool_set:Nn\l_@@_interval_finishrange_start_beyond_bool
{
\l_@@_tmpa_bool
&& \l_@@_interval_start_beyond_bool
}
\bool_if:NTF\l_@@_interval_finishrange_start_beyond_bool
{
\cs_set_eq:NN
\l_@@_interval_finishrange_start_x
\l_@@_start_x
\pgfmathsetmacro{\l_@@_interval_finishrange_start_level_pgf}
{
(\l_@@_interval_finishrange_start_x
-\l_@@_interval_finish_max_x)
/
(\l_@@_interval_finish_min_x
-\l_@@_interval_finish_max_x)
}
}
{
\cs_set_eq:NN
\l_@@_interval_finishrange_start_x
\l_@@_interval_finish_min_x
\pgfmathsetmacro
{\l_@@_interval_finishrange_start_level_pgf}{1}
}
\int_case:nn {\l_@@_finish_range_type_int}
{
{0}{
\cs_set_eq:NN
\@@_interval_finishrange_draw:
\@@_interval_finishrange_draw_pseudofade:
}
{1}{
\@@_interval_finishrange_slant_compute:
}
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_interval_finishrange_slant_compute:}
% Compute the clipping and drawing necessary for a slant finishrange.
% \begin{macrocode}
\cs_new:Npn \@@_interval_finishrange_slant_compute:
{
\@@_debug:n{~(Finishrange~slant)}
\bool_if:NTF\l_@@_interval_finish_beyond_bool
{
\bool_if:NTF\l_@@_interval_finishrange_start_beyond_bool
{
\cs_set_eq:NN
\@@_interval_both_clip_path:
\@@_interval_finishrange_clip_path_beyond_both:
}
{
\cs_set_eq:NN
\@@_interval_finish_clip_path:
\@@_interval_finishrange_clip_path_beyond_finish:
}
}
{
\bool_if:NTF\l_@@_interval_finishrange_start_beyond_bool
{
\cs_set_eq:NN
\@@_interval_both_clip_path:
\@@_interval_finishrange_clip_path_beyond_start:
}
{
\cs_set_eq:NN
\@@_interval_finish_clip_path:
\@@_interval_finishrange_clip_path_finish:
}
}
\cs_if_eq:NNTF\@@_interval_solid_draw:\prg_do_nothing:
{
\cs_set_eq:NN
\@@_interval_finishrange_draw:
\@@_interval_startfinishrange_draw_slant:
}
{
\cs_set_eq:NN
\l_@@_interval_solid_finish_x
\l_@@_finish_beyond_x
\cs_set_eq:NN
\@@_interval_finishrange_draw:
\prg_do_nothing:
}
}
% \end{macrocode}
% \end{macro}
%
%
%
% \subsubsection{Drawing}
%
%
%
% \paragraph{Solid}
%
% \begin{macro}{\@@_interval_solid_draw:}
% Draw the solid part of an interval.
% \begin{macrocode}
\cs_new:Npn\@@_interval_solid_draw:
{
\@@_debug:n{
Drawing:~solid~\l_@@_interval_solid_start_x~
to~\l_@@_interval_solid_finish_x
}
\pgfpathrectanglecorners{
\pgfpoint
{\l_@@_interval_solid_start_x}
{-\l_@@_bar_half_thickness_pgf}
}{
\pgfpoint
{\l_@@_interval_solid_finish_x}
{\l_@@_bar_half_thickness_pgf}
}
\pgfsetfillcolor{\l_@@_bar_color}
\pgfusepath{fill}
}
% \end{macrocode}
% \end{macro}
%
%
%
% \paragraph{Start/finish range pseudofade}
%
% \begin{macro}{\@@_interval_startrange_draw_pseudofade:}
% Draw a fading startrange and beyond indicators
% \begin{macrocode}
\cs_new:Npn\@@_interval_startrange_draw_pseudofade:
{
\@@_debug:n{Drawing:~startrange,~pseudofade}
\@@_debug:n{~
\l_@@_interval_startrange_start_x~
(\l_@@_interval_startrange_start_level_pgf)~
to~\l_@@_interval_startrange_finish_x~
(\l_@@_interval_startrange_finish_level_pgf)
}
\@@_interval_draw_pseudofade:nnnnn
{\l_@@_interval_startrange_start_x}
{\l_@@_interval_startrange_finish_x}
{\l_@@_bar_color}
{\l_@@_interval_startrange_start_level_pgf}
{\l_@@_interval_startrange_finish_level_pgf}
\bool_if:NT\l_@@_interval_start_beyond_bool
{ \@@_interval_startrange_start_beyond_draw_fade: }
\bool_if:NT\l_@@_interval_startrange_finish_beyond_bool
{ \@@_interval_startrange_finish_beyond_draw_fade: }
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_interval_startrange_start_beyond_draw_fade:}
% Draw a `faded' beyond indicator for a startrange that extends beyond the timechart start.
% \begin{macrocode}
\cs_new:Npn\@@_interval_startrange_start_beyond_draw_fade:
{
\@@_debug:n{Drawing:~startrange,~pseudofade~beyond~start}
\@@_debug:n{~
\l_@@_start_beyond_x~to~\l_@@_start_x
}
\pgfscope
\pgfpathrectanglecorners{
\pgfpoint
{\l_@@_start_beyond_x}
{-\l_@@_bar_half_thickness_pgf}
}{
\pgfpoint
{\l_@@_start_x}
{\l_@@_bar_half_thickness_pgf}
}
\pgfsetfillcolor{\l_@@_bar_color}
\pgfsetfillopacity
{\l_@@_interval_startrange_start_level_pgf}
\pgfusepath{fill}
\endpgfscope
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_interval_startrange_finish_beyond_draw_fade:}
% Draw a `faded' beyond indicator for a startrange that extends beyond the timechart finish.
% \begin{macrocode}
\cs_new:Npn\@@_interval_startrange_finish_beyond_draw_fade:
{
\@@_debug:n{Drawing:~startrange,~pseudofade~beyond~finish}
\@@_debug:n{~
\l_@@_finish_beyond_x~to~\l_@@_finish_x
}
\pgfscope
\pgfpathrectanglecorners{
\pgfpoint
{\l_@@_finish_x}
{-\l_@@_bar_half_thickness_pgf}
}{
\pgfpoint
{\l_@@_finish_beyond_x}
{\l_@@_bar_half_thickness_pgf}
}
\pgfsetfillcolor{\l_@@_bar_color}
\pgfsetfillopacity
{\l_@@_interval_startrange_finish_level_pgf}
\pgfusepath{fill}
\endpgfscope
}
% \end{macrocode}
% \end{macro}
%
%
%
% \begin{macro}{\@@_interval_finishrange_draw_pseudofade:}
% Draw a fading startrange and excess indicators
% \begin{macrocode}
\cs_new:Npn\@@_interval_finishrange_draw_pseudofade:
{
\@@_debug:n{Drawing:~finishrange,~pseudofade}
\@@_debug:n{~
\l_@@_interval_finishrange_start_x~
(\l_@@_interval_finishrange_start_level_pgf)~
to~\l_@@_interval_finishrange_finish_x~
(\l_@@_interval_finishrange_finish_level_pgf)
}
\@@_interval_draw_pseudofade:nnnnn
{\l_@@_interval_finishrange_start_x}
{\l_@@_interval_finishrange_finish_x}
{\l_@@_bar_color}
{\l_@@_interval_finishrange_start_level_pgf}
{\l_@@_interval_finishrange_finish_level_pgf}
\bool_if:NT\l_@@_interval_finish_beyond_bool
{ \@@_interval_finishrange_finish_beyond_draw_fade: }
\bool_if:NT\l_@@_interval_finishrange_start_beyond_bool
{ \@@_interval_finishrange_start_beyond_draw_fade: }
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_interval_finishrange_finish_beyond_draw_fade:}
% Draw a `faded' beyond indicator for a finishrange that extends beyond the timechart finish.
% \begin{macrocode}
\cs_new:Npn\@@_interval_finishrange_finish_beyond_draw_fade:
{
\@@_debug:n{Drawing:~finishrange,~pseudofade~beyond~finish}
\@@_debug:n{~
\l_@@_finish_beyond_x~to~\l_@@_finish_x
}
\pgfscope
\pgfpathrectanglecorners{
\pgfpoint
{\l_@@_finish_beyond_x}
{-\l_@@_bar_half_thickness_pgf}
}{
\pgfpoint
{\l_@@_finish_x}
{\l_@@_bar_half_thickness_pgf}
}
\pgfsetfillcolor{\l_@@_bar_color}
\pgfsetfillopacity
{\l_@@_interval_finishrange_finish_level_pgf}
\pgfusepath{fill}
\endpgfscope
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_interval_finishrange_start_beyond_draw_fade:}
% Draw a `faded' beyond indicator for a finishrange that extends beyond the timechart start.
% \begin{macrocode}
\cs_new:Npn\@@_interval_finishrange_start_beyond_draw_fade:
{
\@@_debug:n{Drawing:~finishrange,~pseudofade~beyond~start}
\@@_debug:n{~
\l_@@_start_beyond_x~to~\l_@@_start_x
}
\pgfscope
\pgfpathrectanglecorners{
\pgfpoint
{\l_@@_start_x}
{-\l_@@_bar_half_thickness_pgf}
}{
\pgfpoint
{\l_@@_start_beyond_x}
{\l_@@_bar_half_thickness_pgf}
}
\pgfsetfillcolor{\l_@@_bar_color}
\pgfsetfillopacity
{\l_@@_interval_finishrange_start_level_pgf}
\pgfusepath{fill}
\endpgfscope
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_interval_draw_pseudofade:nnnnn}
% Draw an imitation fading from \param{1} to \param {2} with color \param{3}, starting with opacity \param{4} and
% ending with opacity \param{5}.
% \begin{macrocode}
\pgfmathsetmacro{\l_@@_fadestep_pgf}{1}
\cs_new:Npn\@@_interval_draw_pseudofade:nnnnn #1#2#3#4#5
{
\@@_debug:n{Pseudofade:~#1~to~#2,~color~#3,~opacity~#4~to~#5}
\group_begin:
\pgfmathsetmacro{\start}{#1}
\pgfmathsetmacro{\stop}{#2}
\pgfmathsetmacro{\fadestep}
{(\stop-\start)/(floor((\stop-\start)/\l_@@_fadestep_pgf)+1)}
\pgfmathsetmacro{\startnext}{\start+\fadestep}
\pgfmathsetmacro{\stopprev}{\stop-\fadestep}
\pgfmathsetmacro{\denominator}{abs(\stop-\start)+\fadestep}
\foreach \xa in {\start,\startnext,...,\stopprev} {
\pgfmathsetlengthmacro{\o}
{((\stop-\xa)*#4+(\xa-\start+\fadestep)*#5)/\denominator}
\pgfscope
\pgfpathrectanglecorners{
\pgfpoint{\xa}{-\l_@@_bar_half_thickness_pgf}
}{
\pgfpoint{\xa+\fadestep}{\l_@@_bar_half_thickness_pgf}
}
\pgfsetfillcolor{#3}
\pgfsetfillopacity{\o}
\pgfusepath{fill}
\endpgfscope
}
\group_end:
}
% \end{macrocode}
% \end{macro}
%
%
%
% \paragraph{Start/finish range slant}
%
% \begin{macro}{\@@_interval_startfinishrange_draw_slant:}
% Draw an already-clipped slanted start/finishrange and beyond indicators. This macro will only be called when there
% is no `solid' part to drawn (for otherwise the solid part is extended to fill the start/finishrange), and so the
% only thing to draw is the start/finishrange. Hence the macro can simply fill everything
% \begin{macrocode}
\cs_new:Npn\@@_interval_startfinishrange_draw_slant:
{
\pgfpathrectanglecorners{
\pgfpoint
{\l_@@_start_beyond_x}
{-\l_@@_bar_half_thickness_pgf}
}{
\pgfpoint
{\l_@@_finish_beyond_x}
{\l_@@_bar_half_thickness_pgf}
}
\pgfsetfillcolor{\l_@@_bar_color}
\pgfusepath{fill}
}
% \end{macrocode}
% \end{macro}
%
%
%
% \subsubsection{Clipping}
%
%
%
% \paragraph{Start/finish no-clipping paths}
%
% \begin{macro}{\c_@@_left_far_x,\c_@@_right_far_x}
% No-clipping paths actually use the following \(x\)-coordinates, which are large in the positive and negative
% direction.
% \begin{macrocode}
\pgfmathsetmacro{\c_@@_left_far_x}{-16000pt}
\pgfmathsetmacro{\c_@@_right_far_x}{16000pt}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_interval_start_clip_path_none:}
% No clip path for start.
% \begin{macrocode}
\cs_new:Npn\@@_interval_start_clip_path_none:
{
\@@_debug:n{~Start~clip~path:~none}
\pgfpathlineto{
\pgfpoint
{\c_@@_left_far_x}
{-\l_@@_bar_thickness_pgf}
}
\pgfpathlineto{
\pgfpoint
{\c_@@_left_far_x}
{\l_@@_bar_thickness_pgf}
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_interval_finish_clip_path_none:}
% No clip path for finish.
% \begin{macrocode}
\cs_new:Npn\@@_interval_finish_clip_path_none:
{
\@@_debug:n{~Finish~clip~path:~none}
\pgfpathmoveto{
\pgfpoint
{\c_@@_right_far_x}
{\l_@@_bar_thickness_pgf}
}
\pgfpathlineto{
\pgfpoint
{\c_@@_right_far_x}
{-\l_@@_bar_thickness_pgf}
}
}
% \end{macrocode}
% \end{macro}
%
%
%
% \paragraph{Start/finish beyond indicator clipping paths}
%
% \begin{macro}{\@@_interval_start_clip_path_beyond:}
% Clip path for start beyond indicator.
% \begin{macrocode}
\cs_new:Npn\@@_interval_start_clip_path_beyond:
{
\@@_debug:n{~Start~clip~path:~beyond}
\pgfpathlineto{
\pgfpoint
{\l_@@_start_beyond_x}
{-\l_@@_bar_thickness_pgf}
}
\pgfpathlineto{
\pgfpoint
{\l_@@_start_beyond_x}
{-\l_@@_bar_half_thickness_pgf}
}
\pgfpatharc
{-90}
{90}
{\l_@@_start_beyond_x_radius_pgf
~and~\l_@@_bar_half_thickness_pgf}
\pgfpathlineto{
\pgfpoint
{\l_@@_start_beyond_x}
{\l_@@_bar_thickness_pgf}
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_interval_finish_clip_path_beyond:}
% Clip path for finish beyond indicator.
% \begin{macrocode}
\cs_new:Npn\@@_interval_finish_clip_path_beyond:
{
\@@_debug:n{~Finish~clip~path:~beyond}
\pgfpathmoveto{
\pgfpoint
{\l_@@_finish_beyond_x}
{\l_@@_bar_thickness_pgf}
}
\pgfpathlineto{
\pgfpoint
{\l_@@_finish_beyond_x}
{\l_@@_bar_half_thickness_pgf}
}
\pgfpatharc
{90}
{270}
{\l_@@_finish_beyond_x_radius_pgf
~and~\l_@@_bar_half_thickness_pgf}
\pgfpathlineto{
\pgfpoint
{\l_@@_finish_beyond_x}
{-\l_@@_bar_thickness_pgf}
}
}
% \end{macrocode}
% \end{macro}
%
%
%
% \paragraph{Startrange/finishrange clipping paths}
%
% \begin{macro}{\@@_interval_startrange_clip_path_start:}
% Clip path for startrange.
% \begin{macrocode}
\cs_new:Npn\@@_interval_startrange_clip_path_start:
{
\@@_debug:n{~Start~clip~path:~startrange}
\pgfpathlineto{
\pgfpoint
{\l_@@_interval_startrange_start_x}
{-\l_@@_bar_thickness_pgf}
}
\pgfpathlineto{
\pgfpoint
{\l_@@_interval_startrange_start_x}
{-\l_@@_bar_half_thickness_pgf}
}
\pgfpathlineto{
\pgfpoint
{\l_@@_interval_startrange_finish_x}
{\l_@@_bar_half_thickness_pgf}
}
\pgfpathlineto{
\pgfpoint
{\l_@@_interval_startrange_finish_x}
{\l_@@_bar_thickness_pgf}
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_interval_finishrange_clip_path_finish:}
% Clip path for finishrange.
% \begin{macrocode}
\cs_new:Npn\@@_interval_finishrange_clip_path_finish:
{
\@@_debug:n{~Finish~clip~path:~finishrange}
\pgfpathmoveto{
\pgfpoint
{\l_@@_interval_finishrange_finish_x}
{\l_@@_bar_thickness_pgf}
}
\pgfpathlineto{
\pgfpoint
{\l_@@_interval_finishrange_finish_x}
{\l_@@_bar_half_thickness_pgf}
}
\pgfpathlineto{
\pgfpoint
{\l_@@_interval_finishrange_start_x}
{-\l_@@_bar_half_thickness_pgf}
}
\pgfpathlineto{
\pgfpoint
{\l_@@_interval_finishrange_start_x}
{-\l_@@_bar_thickness_pgf}
}
}
% \end{macrocode}
% \end{macro}
%
%
%
% \paragraph{Startrange/finishrange clipping paths with `same side' beyond indicator}
%
% \begin{macro}{\@@_interval_startrange_clip_path_beyond_start:}
% Clip path for startrange with start beyond indicator.
% \begin{macrocode}
\cs_new:Npn \@@_interval_startrange_clip_path_beyond_start:
{
\@@_debug:n{~Start~clip~path:~startrange,~beyond~start}
\pgfmathsetmacro{\l_@@_tmpa_pgf}{
\l_@@_bar_thickness_pgf
*\l_@@_interval_startrange_start_level_pgf
}
\pgfmathsetmacro{\l_@@_tmpb_pgf}{
.5*\l_@@_tmpa_pgf
}
\pgfpathlineto{
\pgfpoint
{\l_@@_start_beyond_x}
{-\l_@@_bar_thickness_pgf}
}
\pgfpathlineto{
\pgfpoint
{\l_@@_start_beyond_x}
{-\l_@@_bar_half_thickness_pgf}
}
\pgfpatharc
{-90}
{90}
{\l_@@_start_beyond_x_radius_pgf
~and~\l_@@_tmpb_pgf}
\pgfpathlineto{
\pgfpointadd{
\pgfpoint
{\l_@@_start_x}
{-\l_@@_bar_half_thickness_pgf}
}{
\pgfpoint{0}{\l_@@_tmpa_pgf}
}
}
\pgfpathlineto{
\pgfpoint
{\l_@@_interval_start_max_x}
{\l_@@_bar_half_thickness_pgf}
}
\pgfpathlineto{
\pgfpoint
{\l_@@_interval_start_max_x}
{\l_@@_bar_thickness_pgf}
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_interval_finishrange_clip_path_beyond_finish:}
% Clip path for finishrange with finish beyond indicator.
% \begin{macrocode}
\cs_new:Npn\@@_interval_finishrange_clip_path_beyond_finish:
{
\@@_debug:n{~Finish~clip~path:~finishrange,~beyond~finish}
\pgfmathsetmacro{\l_@@_tmpa_pgf}{
\l_@@_bar_thickness_pgf
*\l_@@_interval_finishrange_finish_level_pgf
}
\pgfmathsetmacro{\l_@@_tmpb_pgf}{
.5*\l_@@_tmpa_pgf
}
\pgfpathmoveto{
\pgfpoint
{\l_@@_finish_beyond_x}
{\l_@@_bar_thickness_pgf}
}
\pgfpathlineto{
\pgfpoint
{\l_@@_finish_beyond_x}
{\l_@@_bar_half_thickness_pgf}
}
\pgfpatharc
{90}
{270}
{\l_@@_finish_beyond_x_radius_pgf
~and~\l_@@_tmpb_pgf}
\pgfpathlineto{
\pgfpointadd{
\pgfpoint
{\l_@@_finish_x}
{\l_@@_bar_half_thickness_pgf}
}{
\pgfpoint{0}{-\l_@@_tmpa_pgf}
}
}
\pgfpathlineto{
\pgfpoint
{\l_@@_interval_finish_min_x}
{-\l_@@_bar_half_thickness_pgf}
}
\pgfpathlineto{
\pgfpoint
{\l_@@_interval_finish_min_x}
{-\l_@@_bar_thickness_pgf}
}
}
% \end{macrocode}
% \end{macro}
%
%
%
% \paragraph{Startrange/finishrange clipping paths with `opposite side' beyond indicator}
%
% \begin{macro}{\@@_interval_startrange_clip_path_beyond_finish:}
% Clip path for startrange with finish beyond indicator. This macro should only be executed as
% \cs{@@_interval_both_clip_path:} and specifies a complete path.
% \begin{macrocode}
\cs_new:Npn\@@_interval_startrange_clip_path_beyond_finish:
{
\@@_debug:n{~Two-sided~clip~path:~startrange,~beyond~finish}
\pgfmathsetmacro{\l_@@_tmpc_pgf}{
\l_@@_bar_thickness_pgf
*\l_@@_interval_startrange_finish_level_pgf
}
\pgfmathsetmacro{\l_@@_tmpd_pgf}{
.5*\l_@@_tmpc_pgf
}
\pgfpathmoveto{
\pgfpointadd{
\pgfpoint
{\l_@@_finish_beyond_x}
{-\l_@@_bar_half_thickness_pgf}
}{
\pgfpoint{0}{\l_@@_tmpc_pgf}
}
}
\pgfpatharc
{90}
{270}
{\l_@@_start_beyond_x_radius_pgf
~and~\l_@@_tmpd_pgf}
\pgfpathlineto{
\pgfpoint
{\l_@@_finish_beyond_x}
{-\l_@@_bar_thickness_pgf}
}
\pgfpathlineto{
\pgfpoint
{\l_@@_interval_start_min_x}
{-\l_@@_bar_thickness_pgf}
}
\pgfpathlineto{
\pgfpoint
{\l_@@_interval_start_min_x}
{-\l_@@_bar_half_thickness_pgf}
}
\pgfpathlineto{
\pgfpointadd{
\pgfpoint
{\l_@@_finish_x}
{-\l_@@_bar_half_thickness_pgf}
}{
\pgfpoint{0}{\l_@@_tmpc_pgf}
}
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_interval_finishrange_clip_path_beyond_start:}
% Clip path for finishrange with start beyond indicator. This macro should only be executed as
% \cs{@@_interval_both_clip_path:} and specifies a complete path.
% \begin{macrocode}
\cs_new:Npn\@@_interval_finishrange_clip_path_beyond_start:
{
\@@_debug:n{~Two-sided~clip~path:~finishrange,~beyond~start}
\pgfmathsetmacro{\l_@@_tmpc_pgf}{
\l_@@_bar_thickness_pgf
*\l_@@_interval_finishrange_start_level_pgf
}
\pgfmathsetmacro{\l_@@_tmpd_pgf}{
.5*\l_@@_tmpc_pgf
}
\pgfpathmoveto{
\pgfpointadd{
\pgfpoint
{\l_@@_start_beyond_x}
{\l_@@_bar_half_thickness_pgf}
}{
\pgfpoint{0}{-\l_@@_tmpc_pgf}
}
}
\pgfpatharc
{-90}
{90}
{\l_@@_start_beyond_x_radius_pgf
~and~\l_@@_tmpd_pgf}
\pgfpathlineto{
\pgfpoint
{\l_@@_start_beyond_x}
{\l_@@_bar_thickness_pgf}
}
\pgfpathlineto{
\pgfpoint
{\l_@@_interval_finish_max_x}
{\l_@@_bar_thickness_pgf}
}
\pgfpathlineto{
\pgfpoint
{\l_@@_interval_finish_max_x}
{\l_@@_bar_half_thickness_pgf}
}
\pgfpathlineto{
\pgfpointadd{
\pgfpoint
{\l_@@_start_x}
{\l_@@_bar_half_thickness_pgf}
}{
\pgfpoint{0}{-\l_@@_tmpc_pgf}
}
}
}
% \end{macrocode}
% \end{macro}
%
%
%
% \paragraph{Startrange/finishrange clipping paths with `both sides' beyond indicator}
%
% \begin{macro}{\@@_interval_startrange_clip_path_beyond_both:}
% Clip path for startrange with start and finish beyond indicators. This macro should only be executed as
% \cs{@@_interval_both_clip_path:} and specifies a complete path.
% \begin{macrocode}
\cs_new:Npn\@@_interval_startrange_clip_path_beyond_both:
{
\@@_debug:n{~Two-sided~clip~path:~startrange,~beyond~both}
\pgfmathsetmacro{\l_@@_tmpa_pgf}{
\l_@@_bar_thickness_pgf
*\l_@@_interval_startrange_start_level_pgf
}
\pgfmathsetmacro{\l_@@_tmpb_pgf}{
.5*\l_@@_tmpa_pgf
}
\pgfmathsetmacro{\l_@@_tmpc_pgf}{
\l_@@_bar_thickness_pgf
*\l_@@_interval_startrange_finish_level_pgf
}
\pgfmathsetmacro{\l_@@_tmpd_pgf}{
.5*\l_@@_tmpc_pgf
}
\pgfpathmoveto{
\pgfpointadd{
\pgfpoint
{\l_@@_finish_beyond_x}
{-\l_@@_bar_half_thickness_pgf}
}{
\pgfpoint{0}{\l_@@_tmpc_pgf}
}
}
\pgfpatharc
{90}
{270}
{\l_@@_finish_beyond_x_radius_pgf
~and~\l_@@_tmpd_pgf}
\pgfpathlineto{
\pgfpoint
{\l_@@_finish_beyond_x}
{-\l_@@_bar_thickness_pgf}
}
\pgfpathlineto{
\pgfpoint
{\l_@@_start_beyond_x}
{-\l_@@_bar_thickness_pgf}
}
\pgfpathlineto{
\pgfpoint
{\l_@@_start_beyond_x}
{-\l_@@_bar_half_thickness_pgf}
}
\pgfpatharc
{-90}
{90}
{\l_@@_start_beyond_x_radius_pgf
~and~\l_@@_tmpb_pgf}
\pgfpathlineto{
\pgfpointadd{
\pgfpoint
{\l_@@_start_x}
{-\l_@@_bar_half_thickness_pgf}
}{
\pgfpoint{0}{\l_@@_tmpa_pgf}
}
}
\pgfpathlineto{
\pgfpointadd{
\pgfpoint
{\l_@@_finish_x}
{-\l_@@_bar_half_thickness_pgf}
}{
\pgfpoint{0}{\l_@@_tmpc_pgf}
}
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_interval_finishrange_clip_path_beyond_both:}
% Clip path for finishrange with start and finish beyond indicators. This macro should only be executed as
% \cs{@@_interval_both_clip_path:} and specifies a complete path.
% \begin{macrocode}
\cs_new:Npn\@@_interval_finishrange_clip_path_beyond_both:
{
\@@_debug:n{~Two-sided~clip~path:~finishrange,~beyond~both}
\pgfmathsetmacro{\l_@@_tmpa_pgf}{
\l_@@_bar_thickness_pgf
*\l_@@_interval_finishrange_finish_level_pgf
}
\pgfmathsetmacro{\l_@@_tmpb_pgf}{
.5*\l_@@_tmpa_pgf
}
\pgfmathsetmacro{\l_@@_tmpc_pgf}{
\l_@@_bar_thickness_pgf
*\l_@@_interval_finishrange_start_level_pgf
}
\pgfmathsetmacro{\l_@@_tmpd_pgf}{
.5*\l_@@_tmpc_pgf
}
\pgfpathmoveto{
\pgfpointadd{
\pgfpoint
{\l_@@_start_beyond_x}
{\l_@@_bar_half_thickness_pgf}
}{
\pgfpoint{0}{-\l_@@_tmpc_pgf}
}
}
\pgfpatharc
{-90}
{90}
{\l_@@_start_beyond_x_radius_pgf
~and~\l_@@_tmpd_pgf}
\pgfpathlineto{
\pgfpoint
{\l_@@_start_beyond_x}
{\l_@@_bar_thickness_pgf}
}
\pgfpathlineto{
\pgfpoint
{\l_@@_finish_beyond_x}
{\l_@@_bar_thickness_pgf}
}
\pgfpathlineto{
\pgfpoint
{\l_@@_finish_beyond_x}
{\l_@@_bar_half_thickness_pgf}
}
\pgfpatharc
{90}
{270}
{\l_@@_finish_beyond_x_radius_pgf
~and~\l_@@_tmpb_pgf}
\pgfpathlineto{
\pgfpointadd{
\pgfpoint
{\l_@@_finish_x}
{\l_@@_bar_half_thickness_pgf}
}{
\pgfpoint{0}{-\l_@@_tmpa_pgf}
}
}
\pgfpathlineto{
\pgfpointadd{
\pgfpoint
{\l_@@_start_x}
{\l_@@_bar_half_thickness_pgf}
}{
\pgfpoint{0}{-\l_@@_tmpc_pgf}
}
}
}
% \end{macrocode}
% \end{macro}
%
%
%
% \paragraph{Core clipping macros}
%
% \begin{macro}{\@@_interval_clip:}
% Clip the interval. The internal macro \cs{@@_interval_both_clip_path:} may be redefined from its default.
% \begin{macrocode}
\cs_new:Npn\@@_interval_clip:
{
\@@_debug:n{Clipping:}
\pgfinterruptboundingbox
\@@_interval_both_clip_path:
\pgfpathclose
\pgfusepath{clip}
\endpgfinterruptboundingbox
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_interval_both_clip_path:}
% Specify a clipping path for the interval. If either of the macros \cs{@@_interval_start_clip_path:} is
% \cs{@@_interval_finish_clip_path:} is defined, it is used, otherwise the respective defaults are used.
% \begin{macrocode}
\cs_new:Npn\@@_interval_both_clip_path:
{
\cs_if_exist_use:NF\@@_interval_finish_clip_path:
{ \@@_interval_finish_clip_path_none: }
\cs_if_exist_use:NF\@@_interval_start_clip_path:
{ \@@_interval_start_clip_path_none: }
}
% \end{macrocode}
% \end{macro}
%
%
%
% \subsubsection{Marks}
%
% \begin{macrocode}
\msg_new:nnn{timechart}{interval_mark_outside}
{ Ignoring~mark~outside~interval~definite~part~at~date~#1 }
% \end{macrocode}
%
% \begin{macro}{\@@_interval_mark:}
% Draw marks on an interval.
% \begin{macrocode}
\cs_new:Npn\@@_interval_mark:
{
\pgfscope
\bool_if:NTF\l_@@_interval_start_beyond_bool
{
\pgfmathsetmacro{\l_@@_interval_mark_min_x}
{ max(\l_@@_interval_start_max_x,\l_@@_start_x) }
}
{
\cs_set_eq:NN\l_@@_interval_mark_min_x\l_@@_interval_start_max_x
}
\bool_if:NTF\l_@@_interval_finish_beyond_bool
{
\pgfmathsetmacro{\l_@@_interval_mark_max_x}
{ min(\l_@@_interval_finish_min_x,\l_@@_finish_x) }
}
{
\cs_set_eq:NN\l_@@_interval_mark_max_x\l_@@_interval_finish_min_x
}
\pgfsetstrokecolor{\l_@@_mark_color}
\foreach \year in \l_@@_mark_text
{
\pgfmathsetmacro{\l_@@_mark_x}{yeartox(\year)}
\@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}
{
and (
\l_@@_mark_x >= \l_@@_interval_mark_min_x,
\l_@@_mark_x <= \l_@@_interval_mark_max_x
)
}
\bool_if:NTF\l_@@_tmpa_bool
{
\pgfpathmoveto{
\pgfpoint
{\l_@@_mark_x}
{-\l_@@_bar_half_thickness_pgf}
}
\pgfpathlineto{
\pgfpoint
{\l_@@_mark_x}
{\l_@@_bar_half_thickness_pgf}
}
\pgfusepath{draw}
}
{ \msg_warning:nne{timechart}{interval_mark_outside}{\year} }
}
\endpgfscope
}
% \end{macrocode}
% \end{macro}
%
%
%
% \subsubsection{Bar node}
%
% \begin{macro}{\@@_interval_define_bar_node:}
% Define a node with into which the bar fits exactly.
% \begin{macrocode}
\cs_new:Npn\@@_interval_define_bar_node:
{
\@@_make_rectangle_node:nnnn
{
\pgfpoint
{\l_@@_interval_start_min_x}
{-\l_@@_bar_half_thickness_pgf}
}{
\pgfpoint
{\l_@@_interval_finish_max_x}
{\l_@@_bar_half_thickness_pgf}
}
{\pgfkeysvalueof{/timechart/interval~bar~node~name}}
{\c_false_bool}
}
% \end{macrocode}
% \end{macro}
%
%
%
% \subsubsection{Label}
%
% \begin{macro}{\@@_interval_label:}
% Place the label for the item.
% \begin{macrocode}
\cs_new:Npn\@@_interval_label:
{
\str_if_empty:NF \l_@@_label_text
{
\pgfinterruptboundingbox
\int_case:nn {\l_@@_label_pos_int}
{
{0}{ \@@_interval_label_left: }
{1}{ \@@_interval_label_center: }
{2}{ \@@_interval_label_right: }
}
\endpgfinterruptboundingbox
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_interval_label_left:}
% Place the label on the left of the interval.
% \begin{macrocode}
\cs_new:Npn\@@_interval_label_left:
{
\@@_if_x_in_bounds:nT{\l_@@_interval_start_min_x}
{
\group_begin:
\pgftransformshift{
\pgfpoint
{\l_@@_interval_start_min_x}
{\l_@@_text_baseline_pgf}
}
\node[/timechart/interval~label,anchor=base~east]
(\l_@@_interval_label_node_name)
at (0,0)
{
\@@_make_ref:NN
\l_@@_ref_text
\l_@@_label_text
};
\group_end:
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_interval_label_right:}
% Place the label on the right of the interval.
% \begin{macrocode}
\cs_new:Npn\@@_interval_label_right:
{
\@@_if_x_in_bounds:nT{\l_@@_interval_finish_max_x}
{
\group_begin:
\pgftransformshift{
\pgfpoint
{\l_@@_interval_finish_max_x}
{\l_@@_text_baseline_pgf}
}
\node[/timechart/interval~label,anchor=base~west]
(\l_@@_interval_label_node_name)
at (0,0)
{
\@@_make_ref:NN
\l_@@_ref_text
\l_@@_label_text
};
\group_end:
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_interval_label_center:}
% Place the label at the center of the interval.
% \begin{macrocode}
\cs_new:Npn\@@_interval_label_center:
{
\pgfmathsetlengthmacro{\l_@@_label_anchor_x}
{
.5*max(\l_@@_interval_start_max_x,\l_@@_start_x)
+ .5*min(\l_@@_interval_finish_min_x,\l_@@_finish_x)
}
% \end{macrocode}
% First draw the `background label' on the layer below the bar.
% \begin{macrocode}
\group_begin:
\pgftransformshift{
\pgfpoint
{\l_@@_label_anchor_x}
{\l_@@_text_baseline_pgf}
}
\pgfonlayer{labelbg}
\node[
/timechart/interval~label~centered~background,
anchor=base
]
at (0,0)
{ \l_@@_label_text };
\endpgfonlayer
\group_end:
% \end{macrocode}
% Then draw the label on top of the bar, clipping it to the bar outline.
% \begin{macrocode}
\pgfscope
\pgfpathrectanglecorners{
\pgfpoint
{\l_@@_interval_start_min_x}
{-\l_@@_bar_half_thickness_pgf}
}{
\pgfpoint
{\l_@@_interval_finish_max_x}
{\l_@@_bar_half_thickness_pgf}
}
\pgfusepath{clip}
\group_begin:
\pgftransformshift{
\pgfpoint
{\l_@@_label_anchor_x}
{\l_@@_text_baseline_pgf}
}
\node[
/timechart/interval~label~centered,
anchor=base
]
(\l_@@_interval_label_node_name)
at (0,0)
{
\@@_make_ref:NN
\l_@@_ref_text
\l_@@_label_text
};
\group_end:
\endpgfscope
}
% \end{macrocode}
% \end{macro}
%
%
%
% \subsection{Text}
%
% \begin{macro}{\@@_text_user:Omm}
% Place text. This macro will be made available as \cs{timecharttext} inside the \env{timechart} environment.
% \begin{arguments}
% \item PGF keys under \key{/timechart/} to apply.
% \item Year at which to place text.
% \item Text.
% \end{arguments}
% \begin{macrocode}
\NewDocumentCommand{\@@_text_user:Omm}{ O{} m m }
{
\str_if_empty:nF{#3}{
\group_begin:
\pgfmathsetmacro{\l_@@_text_x}{yeartox(#2)}
% \end{macrocode}
% Process keys supplied locally and retrieve initially needed keys.
% \begin{macrocode}
\pgfqkeys{/timechart}{
#1,
tolerance~start/.get=\l_@@_start_tolerance_pgf,
tolerance~finish/.get=\l_@@_finish_tolerance_pgf,
}
\@@_if_x_in_bounds:nT{\l_@@_text_x}
{
% \end{macrocode}
% Retrieve other needed keys.
% \begin{macrocode}
\pgfqkeys{/timechart}{
ref/.get=\l_@@_ref_text,
text~node~name/.get=\l_@@_node_name_text,
text~baseline/.get=\l_@@_text_baseline_pgf,
}
% \end{macrocode}
% Shift to the correct vertical coordinate and place the text.
% \begin{macrocode}
\pgftransformshift{
\pgfpoint{0}{\l_@@_current_y}
}
\pgfinterruptboundingbox
\group_begin:
\pgftransformshift{
\pgfpoint{\l_@@_text_x}{\l_@@_text_baseline_pgf}
}
\cs_set:Npn\l_@@_text{#3}
\int_case:nn {\l_@@_text_pos_int}
{
{0}{ \cs_set:Npn\l_@@_node_anchor_text{base~east} }
{1}{ \cs_set:Npn\l_@@_node_anchor_text{base} }
{2}{ \cs_set:Npn\l_@@_node_anchor_text{base~west} }
}
\node[/timechart/text,anchor=\l_@@_node_anchor_text]
(\l_@@_node_name_text)
at (0,0)
{
\@@_make_ref:NN
\l_@@_ref_text
\l_@@_text
};
\group_end:
\endpgfinterruptboundingbox
}
\group_end:
}
% \end{macrocode}
% Since the text itself does not affect the bounding box, create a space (which will handle the automatic step).
% \begin{macrocode}
\@@_space_user:O[#1]
}
% \end{macrocode}
% \end{macro}
%
%
%
% \subsection{Space}
%
% \begin{macro}{\@@_space_user:O}
% Create a vertical space as if there were an interval at the current coordinate. This macro will be made available as
% \cs{timechartspace} inside the \env{timechart} environment.
% \begin{macrocode}
\NewDocumentCommand{\@@_space_user:O}{ O{} }
{
\group_begin:
% \end{macrocode}
% Process keys supplied locally and retreive the one needed value.
% \begin{macrocode}
\pgfqkeys{/timechart}{
#1,
interval~bar~thickness/.get=\l_@@_bar_thickness_pgf,
}
\pgfmathsetlengthmacro{\l_@@_bar_half_thickness_pgf}
{ .5*\l_@@_bar_thickness_pgf }
% \end{macrocode}
% Shift to the correct vertical coordinate and create the space.
% \begin{macrocode}
\pgftransformshift{
\pgfpoint{0}{\l_@@_current_y}
}
\pgfpathmoveto{
\pgfpoint{0}{-\l_@@_bar_half_thickness_pgf}
}
\pgfpathmoveto{
\pgfpoint{0}{\l_@@_bar_half_thickness_pgf}
}
\pgfusepath{discard}
\group_end:
\bool_if:NT\l_@@_autostep_bool{
\@@_step_y_user:O
}
}
% \end{macrocode}
% \end{macro}
%
%
%
% \subsection{Legends}
%
% \begin{macro}{\timechartlegenditem}
% Draw a bar suitable for use in a legend, applying style in \param{1}.
% \begin{macrocode}
\NewDocumentCommand{\timechartlegenditem}{ O{} }
{
\@@_legend_aux:nn{#1}{
\pgfmathsetlengthmacro{\l_@@_interval_solid_start_x}{0}
\pgfmathsetlengthmacro{\l_@@_interval_solid_finish_x}
{\l_@@_legenditem_width_pgf}
\@@_interval_solid_draw:
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\timechartlegendstartrange,\timechartlegendfinishrange}
% Draw a bar with start/finish range, suitable for use in a legend, applying style in \param{1}.
% \begin{macrocode}
\NewDocumentCommand{\timechartlegendstartrange}{ O{} }
{
\@@_legend_aux:nn{#1}{
\pgfmathsetlengthmacro
{\l_@@_interval_startrange_start_x}{0}
\pgfmathsetlengthmacro{\l_@@_interval_startrange_finish_x}
{\l_@@_legenditem_range_width_pgf}
\pgfmathsetlengthmacro
{\l_@@_interval_startrange_start_level_pgf}{0}
\pgfmathsetlengthmacro
{\l_@@_interval_startrange_finish_level_pgf}{1}
\pgfmathsetlengthmacro{\l_@@_interval_solid_finish_x}
{\l_@@_legenditem_width_pgf}
\int_case:nn {\l_@@_start_range_type_int}
{
{0}{
\pgfmathsetlengthmacro{\l_@@_interval_solid_start_x}
{\l_@@_legenditem_range_width_pgf}
\@@_interval_startrange_draw_pseudofade:
}
{1}{
\pgfmathsetlengthmacro{\l_@@_interval_solid_start_x}
{\l_@@_interval_startrange_start_x}
\pgfinterruptboundingbox
\@@_interval_finish_clip_path_none:
\@@_interval_startrange_clip_path_start:
\pgfpathclose
\pgfusepath{clip}
\endpgfinterruptboundingbox
}
}
\@@_interval_solid_draw:
}
}
\NewDocumentCommand{\timechartlegendfinishrange}{ O{} }
{
\@@_legend_aux:nn{#1}{
\pgfmathsetlengthmacro{\l_@@_interval_finishrange_start_x}
{
\l_@@_legenditem_width_pgf
-\l_@@_legenditem_range_width_pgf
}
\pgfmathsetlengthmacro{\l_@@_interval_finishrange_finish_x}
{\l_@@_legenditem_width_pgf}
\pgfmathsetlengthmacro
{\l_@@_interval_finishrange_start_level_pgf}{1}
\pgfmathsetlengthmacro
{\l_@@_interval_finishrange_finish_level_pgf}{0}
\pgfmathsetlengthmacro
{\l_@@_interval_solid_start_x}{0}
\pgfmathsetlengthmacro{\l_@@_interval_finish_max_x}
{\l_@@_legenditem_width_pgf}
\int_case:nn {\l_@@_finish_range_type_int}
{
{0}{
\pgfmathsetlengthmacro{\l_@@_interval_solid_finish_x}
{
\l_@@_legenditem_width_pgf
-\l_@@_legenditem_range_width_pgf
}
\@@_interval_finishrange_draw_pseudofade:
}
{1}{
\pgfmathsetlengthmacro{\l_@@_interval_solid_finish_x}
{\l_@@_interval_finishrange_finish_x}
\pgfinterruptboundingbox
\@@_interval_finishrange_clip_path_finish:
\@@_interval_start_clip_path_none:
\pgfpathclose
\pgfusepath{clip}
\endpgfinterruptboundingbox
}
}
\@@_interval_solid_draw:
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_legend_aux:nn}
% Auxiliary command for legend items. Draw a \TikZ\ picture, applying PGF keys \param{1} under \key{/timechart/}
% and using \TikZ\ code \param{2}.
% \begin{macrocode}
\cs_new:Npn\@@_legend_aux:nn #1#2
{
\@@_debug:n{Legend~auxiliary}
\tikzpicture
% \end{macrocode}
% Process supplied PGF keys and retrieve only those necessary.
% \begin{macrocode}
\pgfkeys{
/timechart/.cd,
#1,
interval~bar~thickness/.get=\l_@@_bar_thickness_pgf,
interval~bar~color/.get=\l_@@_bar_color,
interval~minimum~width/.get=\l_@@_minimum_width_pgf,
beyond~length~start/.get=\l_@@_start_beyond_length_pgf,
beyond~length~finish/.get=\l_@@_finish_beyond_length_pgf,
legend~item~width/.get=\l_@@_legenditem_width_pgf,
legend~item~range~width/.get=\l_@@_legenditem_range_width_pgf,
}
\pgfmathsetlengthmacro{\l_@@_bar_half_thickness_pgf}
{.5*\l_@@_bar_thickness_pgf}
\pgfmathsetmacro{\l_@@_start_x}{0}
\pgfmathsetmacro{\l_@@_finish_x}
{\l_@@_legenditem_width_pgf}
\pgfmathsetlengthmacro{\l_@@_start_beyond_x}
{\l_@@_start_x-\l_@@_start_beyond_length_pgf}
\pgfmathsetlengthmacro{\l_@@_finish_beyond_x}
{\l_@@_finish_x+\l_@@_finish_beyond_length_pgf}
\pgfmathsetmacro{\l_@@_current_y}{0}
% \end{macrocode}
% Ensure that the legend is `visible' from the perspective of the drawing macros.
% \begin{macrocode}
\pgfmathsetmacro{\l_@@_start_tolerance_x}
{\l_@@_start_x-10mm}
\pgfmathsetmacro{\l_@@_finish_tolerance_x}
{\l_@@_finish_x+10mm}
\pgfscope
#2
\endpgfscope
\endtikzpicture%
}
% \end{macrocode}
% \end{macro}
%
%
%
% \begin{macrocode}
%</package>
% \end{macrocode}
%
% \end{implementation}
%
% \PrintIndex
%
%
%
% \iffalse
%<*metadriver>
\input{timechart.dtx}
%</metadriver>
% \fi