summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Master/texmf-dist/doc/latex/timechart/README.md16
-rw-r--r--Master/texmf-dist/doc/latex/timechart/timechart-doc.pdfbin0 -> 797483 bytes
-rw-r--r--Master/texmf-dist/source/latex/timechart/timechart.dtx3458
-rw-r--r--Master/texmf-dist/source/latex/timechart/timechart.ins38
-rw-r--r--Master/texmf-dist/tex/latex/timechart/timechart.sty1615
-rwxr-xr-xMaster/tlpkg/bin/tlpkg-ctan-check2
-rw-r--r--Master/tlpkg/tlpsrc/collection-pictures.tlpsrc1
-rw-r--r--Master/tlpkg/tlpsrc/timechart.tlpsrc0
8 files changed, 5129 insertions, 1 deletions
diff --git a/Master/texmf-dist/doc/latex/timechart/README.md b/Master/texmf-dist/doc/latex/timechart/README.md
new file mode 100644
index 00000000000..8a4830fa6ad
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/timechart/README.md
@@ -0,0 +1,16 @@
+# `timechart` - A package for drawing chronological charts
+
+## Description
+
+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.
+
+## Author
+
+This package is by Alan J. Cain: a.j.cain (AT) gmail.com
+
+## Licence
+
+Released under the LaTeX Project Public License v1.3c or later: https://www.latex-project.org/lppl.txt
diff --git a/Master/texmf-dist/doc/latex/timechart/timechart-doc.pdf b/Master/texmf-dist/doc/latex/timechart/timechart-doc.pdf
new file mode 100644
index 00000000000..31b778e9de7
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/timechart/timechart-doc.pdf
Binary files differ
diff --git a/Master/texmf-dist/source/latex/timechart/timechart.dtx b/Master/texmf-dist/source/latex/timechart/timechart.dtx
new file mode 100644
index 00000000000..82048a452a8
--- /dev/null
+++ b/Master/texmf-dist/source/latex/timechart/timechart.dtx
@@ -0,0 +1,3458 @@
+% \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.3 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{\jobname.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/no axis}{}{}
+% Do not draw the axis.
+% \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}
+%
+%
+%
+% \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}). 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}
+%
+% \begin{describekey}{/timechart/fade minimum width}{dimension}{0pt}
+% No start or finish range indicator of type \val{fade} will be drawn if it is smaller than \meta{dimension}. Using
+% this key is sometimes necessary because, under certain limited circumstances, a very narrow fading can cause
+% PGF/\TikZ\ to produce a \texttt{dimension too large} error.
+% \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{timechartcomplete} 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}}
+%
+% 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.
+%
+%
+%
+% \subsection{\texorpdfstring{\texttt{dimension too large}}{dimension too large} error}
+%
+% Under certain limited circumstances, a very narrow fading can cause PGF/\TikZ\ to produce a \texttt{dimension too
+% large} error. This error can be triggered by a range of type \val{fade} at the start or end of an interval when the
+% range is small compared to the width of the chart. In this case, the fading is unlikely to be visible, so one can
+% simply set \key{/timechart/fade minimum width} to a suitable small positive value, which will stop the fading from
+% being drawn and so prevent the error.
+%
+%
+%
+% \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}
+%
+%
+%
+% \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-02-15}{0.51}
+ {Typesetting chronological charts}
+% \end{macrocode}
+%
+%
+%
+% \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}{\l_@@_left_nonclip_x,\l_@@_right_nonclip_x}
+% In order to clip `only on one side', define coordinates for specifying the `other side' of the clipping path.
+% \begin{macrocode}
+\pgfmathsetmacro{\l_@@_left_nonclip_x}{-16000pt}
+\pgfmathsetmacro{\l_@@_right_nonclip_x}{16000pt}
+% \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 whole chart.
+% \begin{macrocode}
+ width/.initial=\textwidth,
+ tolerance/.initial=5pt,
+ beyond~length/.initial=5pt,
+ beyond~x~radius/.initial=4pt,
+ ystep/.initial=-10pt,
+ minor~tick~interval/.initial=10,
+ major~tick~interval/.initial=50,
+% \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}
+ no~axis/.code = { \bool_set_false:N\l_@@_axis_bool },
+ axis~line/.style={
+ line~cap=rect,
+ },
+ axis~ysep/.initial=3pt,
+ 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,
+ },
+% \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} },
+ fade~minimum~width/.initial = 0pt,
+% \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_bool}
+% Boolean indicating whether the axis will be drawn. This variable is by default true but can be set false via the
+% \key{/timechart/no axis} PGF key.
+% \begin{macrocode}
+\bool_new:N\l_@@_axis_bool
+\bool_set_true:N\l_@@_axis_bool
+% \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,
+ tolerance/.get=\l_@@_tolerance_pgf,
+ ystep/.get=\l_@@_ystep_pgf,
+ grid~top~ysep/.get=\l_@@_grid_top_ysep_pgf,
+ grid~bottom~ysep/.get=\l_@@_grid_bottom_ysep_pgf,
+ beyond~length/.get=\l_@@_beyond_length_pgf,
+ beyond~x~radius/.get=\l_@@_beyond_x_radius_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} }
+ \bool_if:NTF\l_@@_axis_bool
+ {
+ \@@_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}
+ }
+ {
+ \pgfmathsetlengthmacro{\l_@@_axis_line_width}{0}
+ \pgfmathsetlengthmacro{\l_@@_major_tick_line_width}{0}
+ \pgfmathsetlengthmacro{\l_@@_minor_tick_line_width}{0}
+ }
+% \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)}
+ \pgfmathsetmacro{\l_@@_start_tolerance_x}{
+ \l_@@_start_x-(\l_@@_tolerance_pgf)
+ }
+ \pgfmathsetmacro{\l_@@_finish_tolerance_x}{
+ \l_@@_finish_x+(\l_@@_tolerance_pgf)
+ }
+ \pgfmathsetmacro{\l_@@_start_beyond_x}{
+ \l_@@_start_x-(\l_@@_beyond_length_pgf)
+ }
+ \pgfmathsetmacro{\l_@@_finish_beyond_x}{
+ \l_@@_finish_x+(\l_@@_beyond_length_pgf)
+ }
+% \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:
+ \pgfmathsetmacro{\l_@@_axis_y}
+ {
+ \l_@@_content_top_y
+ + \l_@@_grid_top_ysep_pgf
+ + \pgfkeysvalueof{/timechart/axis~ysep}
+ }
+ }
+ {
+ \@@_nogrid_bounding_box_set:
+ \pgfmathsetmacro{\l_@@_axis_y}
+ {
+ \l_@@_content_top_y
+ +\pgfkeysvalueof{/timechart/axis~ysep}
+ }
+ }
+ \bool_if:NT{\l_@@_axis_bool}
+ { \@@_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}.
+% \begin{macrocode}
+\cs_new:Npn\@@_grid_draw:
+ {
+ \pgfmathsetmacro{\l_@@_grid_bottom_y}{
+ \l_@@_content_bottom_y-\l_@@_grid_bottom_ysep_pgf
+ }
+ \pgfmathsetmacro{\l_@@_grid_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_@@_grid_top_y} }
+ \pgfpathlineto{ \pgfpoint{0}{\l_@@_grid_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_@@_grid_bottom_y} }
+ { \pgfpoint{\l_@@_finish_x}{\l_@@_grid_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, assuming that the \(y\) coordinate has been
+% calculated and stored in \cs{l_@@_axis_y}.
+% \begin{macrocode}
+\cs_new:Npn\@@_axis_draw:
+ {
+ \group_begin:
+ \pgfkeys{
+ /timechart/minor~tick~length/.get=\@@_minor_tick_length_pgf,
+ /timechart/major~tick~length/.get=\@@_major_tick_length_pgf,
+ }
+% \end{macrocode}
+% Shift to the \(y\) coordinate of the axis line.
+% \begin{macrocode}
+ \pgftransformshift{ \pgfpoint{0}{\l_@@_axis_y} }
+% \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{\@@_start_major_tick_year}
+ {
+ \l_@@_start_year
+ -Mod(
+ \l_@@_start_year,
+ \l_@@_major_tick_interval_year
+ )
+ }
+ \pgfmathsetmacro{\@@_start_major_tick_year}
+ {
+ ifthenelse(
+ \@@_start_major_tick_year<\l_@@_start_year,
+ \@@_start_major_tick_year
+ +\l_@@_major_tick_interval_year,
+ \@@_start_major_tick_year
+ )
+ }
+ \pgfmathsetmacro{\@@_finish_major_tick_year}
+ {
+ \l_@@_finish_year
+ -Mod(
+ \l_@@_finish_year,
+ \l_@@_major_tick_interval_year
+ )
+ }
+% \end{macrocode}
+% Loop over years and draw the appropriate 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_@@_major_tick_interval_year)==0 }
+ \bool_if:NTF\l_@@_tmpa_bool
+ { \@@_axis_draw_labelled_major_tick:NN\x\year }
+ { \@@_axis_draw_minor_tick:N\x }
+ }
+ \@@_draw_axis_line
+% \end{macrocode}
+% Define the axis node.
+% \begin{macrocode}
+ \pgfextracty{\l_@@_tmpa_dim}
+ { \pgfpointanchor{current~bounding~box}{north} }
+ \@@_make_rectangle_node:nnnn
+ { \pgfpoint{\l_@@_start_x}{0} }
+ { \pgfpoint{\l_@@_finish_x}{\l_@@_tmpa_dim} }
+ { axis }
+ { \c_false_bool }
+ \group_end:
+ }
+% \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}{\@@_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 }
+ {
+ \@@_pgfmathsetbool:nn{\l_@@_tmpb_bool}
+ { #2==\@@_start_major_tick_year }
+ \@@_pgfmathsetbool:nn{\l_@@_tmpc_bool}
+ { #2==\@@_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 }
+ { mid~west }
+ { 0 }
+ { \@@_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}{\@@_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]
+ \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}
+ \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 }
+ { base~west }
+ { -.5mm }
+ { 5.5mm }
+ \@@_axis_draw_year_label:nnnnnn
+ { 0 }
+ { 1 }
+ { \c_true_bool }
+ { north~west }
+ { .5mm }
+ { 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 }
+ \@@_hsmash_pgfnode:nnnnn
+ {rectangle}
+ {#4}
+ {\@@_make_year:n{\absyear}}
+ {}
+ {}
+ }
+ { \pgfnode{rectangle}{#4}{\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_in_tolerance_bounds_x:nT}%
+% Check if \(x\) coordinate \param{1} is within the specified tolerance of the bounds of the chart; if so, execute
+% \param{2}.
+% \begin{macrocode}
+\cs_new:Npn\@@_if_x_in_tolerance_bounds:nT #1#2
+ {
+ \@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}{
+ and(
+ #1>=\l_@@_start_tolerance_x,
+ #1<=\l_@@_finish_tolerance_x
+ )
+ }
+ \bool_if:NT\l_@@_tmpa_bool{#2}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_if_x_range_intersect_tolerance_bounds_x:nnT}%
+% Check if the range between \(x\) coordinates \param{1} and \param{2} intersects the range of the bounds of the chart
+% plus the specified tolerance; if so, execute \param{3}.
+% \begin{macrocode}
+\cs_new:Npn\@@_if_x_range_intersect_tolerance_bounds:nnT #1#2#3
+ {
+ \@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}{
+ or(
+ or(
+ and(
+ #2>=\l_@@_start_tolerance_x,
+ #2<=\l_@@_finish_tolerance_x
+ ),
+ and(
+ #1>=\l_@@_start_tolerance_x,
+ #1<=\l_@@_finish_tolerance_x
+ )
+ ),
+ and(
+ #1<\l_@@_start_tolerance_x,
+ #2>\l_@@_finish_tolerance_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_@@_startmin_circa_bool,
+% \l_@@_startmax_circa_bool,
+% \l_@@_finish_is_range_bool,
+% \l_@@_finishmin_circa_bool,
+% \l_@@_finishmax_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_@@_startmin_circa_bool
+\bool_new:N\l_@@_startmax_circa_bool
+\bool_new:N\l_@@_finish_is_range_bool
+\bool_new:N\l_@@_finishmin_circa_bool
+\bool_new:N\l_@@_finishmax_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.
+% \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 }
+ {
+ \group_begin:
+% \end{macrocode}
+% Parse the start and finish dates or date ranges.
+% \begin{macrocode}
+ \@@_parse_date_or_daterange:NNNNNn
+ \l_@@_start_is_range_bool
+ \l_@@_startmin_circa_bool\l_@@_startmin_year
+ \l_@@_startmax_circa_bool\l_@@_startmax_year
+ {#2}
+ \@@_parse_date_or_daterange:NNNNNn
+ \l_@@_finish_is_range_bool
+ \l_@@_finishmin_circa_bool\l_@@_finishmin_year
+ \l_@@_finishmax_circa_bool\l_@@_finishmax_year
+ {#3}
+% \end{macrocode}
+% Check the results of parsing and only proceed if they are valid.
+% \begin{macrocode}
+ \@@_pgfmathsetbool:nn{\l_tmpa_bool}{
+ and(
+ \l_@@_startmin_year <= \l_@@_startmax_year,
+ and(
+ \l_@@_startmax_year <= \l_@@_finishmin_year,
+ \l_@@_finishmin_year <= \l_@@_finishmax_year
+ )
+ )
+ }
+ \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}
+%
+% \begin{macro}{\@@_interval_checked:nn}
+% Draw an interval using the parsed and checked years or year ranges.
+% \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.
+% \begin{macrocode}
+ \bool_if:NTF\l_@@_startmin_circa_bool
+ {
+ \pgfmathsetmacro{\l_@@_start_extreme_x}
+ { yeartox(\l_@@_startmin_year
+ - \l_@@_circa_uncertainty_year) }
+ }
+ {
+ \pgfmathsetmacro{\l_@@_start_extreme_x}
+ { yeartox(\l_@@_startmin_year) }
+ }
+ \bool_if:NTF\l_@@_finishmax_circa_bool
+ {
+ \pgfmathsetmacro{\l_@@_finish_extreme_x}
+ { yeartox(\l_@@_finishmax_year
+ + \l_@@_circa_uncertainty_year) }
+ }
+ {
+ \pgfmathsetmacro{\l_@@_finish_extreme_x}
+ { yeartox(\l_@@_finishmax_year) }
+ }
+% \end{macrocode}
+% Draw the interval if some part of it is visible.
+% \begin{macrocode}
+ \@@_if_x_range_intersect_tolerance_bounds:nnT
+ {\l_@@_start_extreme_x}{\l_@@_finish_extreme_x}
+ { \@@_draw_visible_interval:nn{#1}{#2} }
+ }
+% \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}{
+ 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}
+% Do the remaining calculations.
+% \begin{macrocode}
+ \pgfmathsetlengthmacro{\l_@@_bar_half_thickness_pgf}
+ {.5*\l_@@_bar_thickness_pgf}
+ \cs_set:Npn\l_@@_label_text{#2}
+ \bool_if:NTF\l_@@_startmax_circa_bool
+ {
+ \pgfmathsetmacro{\l_@@_start_definite_x}
+ { yeartox(\l_@@_startmax_year
+ + \l_@@_circa_uncertainty_year) }
+ }
+ {
+ \pgfmathsetmacro{\l_@@_start_definite_x}
+ { yeartox(\l_@@_startmax_year) }
+ }
+ \bool_if:NTF\l_@@_finishmin_circa_bool
+ {
+ \pgfmathsetmacro{\l_@@_finish_definite_x}
+ { yeartox(\l_@@_finishmin_year
+ - \l_@@_circa_uncertainty_year) }
+ }
+ {
+ \pgfmathsetmacro{\l_@@_finish_definite_x}
+ { yeartox(\l_@@_finishmin_year) }
+ }
+% \end{macrocode}
+% It is possible that circa indicators have made \cs{l_@@_start_definite_x} greater than \cs{l_@@_finish_definite_x}.
+% Check for this; if so, set them both to their average.
+% \begin{macrocode}
+ \@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}
+ {
+ \l_@@_start_definite_x > \l_@@_finish_definite_x
+ }
+ \bool_if:NT\l_@@_tmpa_bool
+ {
+ \pgfmathsetmacro{\l_@@_start_definite_x}
+ {
+ .5*(
+ \l_@@_start_definite_x
+ + \l_@@_finish_definite_x
+ )
+ }
+ \pgfmathsetmacro{\l_@@_finish_definite_x}
+ { \l_@@_start_definite_x }
+ }
+% \end{macrocode}
+% Calculate whether it is necessary to make an adjustment to ensure that the minimum width requirement is satisfied,
+% and store in \cs{l_@@_tmpa_bool}.
+% \begin{macrocode}
+ \@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}
+ {
+ (\l_@@_finish_extreme_x-\l_@@_start_extreme_x)
+ < \l_@@_minimum_width_pgf
+ }
+% \end{macrocode}
+% Calculate whether it is necessary to make an adjustment to prevent a rendering glitch when there are two fadings and
+% a zero-width (or very small) definite part, and store in \cs{l_@@_tmpb_bool}. Note the quick test for both ranges
+% being fadings.
+% \begin{macrocode}
+ \int_if_zero:nTF
+ {
+ \l_@@_start_range_type_int
+ + \l_@@_finish_range_type_int
+ }
+ {
+ \@@_pgfmathsetbool:nn{\l_@@_tmpb_bool}
+ {
+ (
+ \l_@@_finish_definite_x
+ - \l_@@_start_definite_x
+ )
+ < \l_@@_minimum_width_pgf
+ }
+ }
+ { \bool_set_false:N\l_@@_tmpb_bool }
+% \end{macrocode}
+% Make the adjustment if necessary.
+% \begin{macrocode}
+ \bool_if:nT{
+ \l_@@_tmpa_bool || \l_@@_tmpb_bool
+ }{
+ \pgfmathsetmacro{\l_@@_width_adjust}
+ { .5*\l_@@_minimum_width_pgf }
+ \pgfmathsetmacro{\l_@@_start_definite_x}
+ { \l_@@_start_definite_x-\l_@@_width_adjust }
+ \pgfmathsetmacro{\l_@@_finish_definite_x}
+ { \l_@@_finish_definite_x+\l_@@_width_adjust }
+ \pgfmathsetmacro{\l_@@_start_extreme_x}
+ {
+ min(
+ \l_@@_start_extreme_x,
+ \l_@@_start_definite_x
+ )
+ }
+ \pgfmathsetmacro{\l_@@_finish_extreme_x}
+ {
+ max(
+ \l_@@_finish_extreme_x,
+ \l_@@_finish_definite_x
+ )
+ }
+ }
+ \pgfmathsetmacro{\l_@@_start_solid_x}
+ { \l_@@_start_definite_x }
+ \pgfmathsetmacro{\l_@@_finish_solid_x}
+ { \l_@@_finish_definite_x }
+% \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 necessary clipping if the interval extends beyond the specified tolerance from the chart, then process
+% the ranges, then draw the solid part of the bar, then do the labelling, then define the node for the bar. Note that
+% ranges wth the `slant' style function by adding a new clipping path and extending the solid part, so that there is
+% only \emph{one} solid rectangle drawn.
+% \begin{macrocode}
+ \@@_interval_beyond_clip:
+ \int_case:nn {\l_@@_start_range_type_int}
+ {
+ {0}{ \@@_interval_start_range_fade: }
+ {1}{ \@@_interval_start_range_slant: }
+ }
+ \int_case:nn {\l_@@_finish_range_type_int}
+ {
+ {0}{ \@@_interval_finish_range_fade: }
+ {1}{ \@@_interval_finish_range_slant: }
+ }
+ \@@_interval_draw_solid:
+ \@@_interval_mark:
+ \@@_interval_define_bar_node:
+ \endpgfscope
+ \@@_interval_label:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsubsection{Clipping}
+%
+% \begin{macro}{\@@_interval_beyond_clip:}
+% If the interval bar extends beyond the specified tolerance from the chart, clip it appropriately. To avoid repeated
+% computation, use \cs{l_@@_tmpa_bool} and \cs{l_@@_tmpb_bool} to store whether it is necessary to clip on the left
+% and right (respectively). If both are false, there is no need for any clipping.
+% \begin{macrocode}
+\cs_new:Npn\@@_interval_beyond_clip:
+ {
+ \@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}
+ {\l_@@_start_extreme_x<=\l_@@_start_tolerance_x}
+ \@@_pgfmathsetbool:nn{\l_@@_tmpb_bool}
+ {\l_@@_finish_extreme_x>=\l_@@_finish_tolerance_x}
+ \bool_if:nT{ \l_@@_tmpa_bool || \l_@@_tmpb_bool }
+ { \@@_interval_beyond_clip_aux: }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_interval_beyond_clip_aux:}
+% This macro does the actual clipping. The clipping path starts at the north-east and proceeds clockwise.
+% \begin{macrocode}
+\cs_new:Npn\@@_interval_beyond_clip_aux:
+ {
+ \pgfinterruptboundingbox
+ \bool_if:NTF\l_@@_tmpb_bool
+ {
+ \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_@@_beyond_x_radius_pgf
+ ~and~\l_@@_bar_half_thickness_pgf}
+ \pgfpathlineto{
+ \pgfpoint
+ {\l_@@_finish_beyond_x}
+ {-\l_@@_bar_thickness_pgf}
+ }
+ }
+ {
+ \pgfpathmoveto{
+ \pgfpoint
+ {\l_@@_right_nonclip_x}
+ {\l_@@_bar_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l_@@_right_nonclip_x}
+ {-\l_@@_bar_thickness_pgf}
+ }
+ }
+ \bool_if:NTF\l_@@_tmpa_bool
+ {
+ \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_@@_beyond_x_radius_pgf
+ ~and~\l_@@_bar_half_thickness_pgf}
+ \pgfpathlineto{
+ \pgfpoint
+ {\l_@@_start_beyond_x}
+ {\l_@@_bar_thickness_pgf}
+ }
+ }
+ {
+ \pgfpathlineto{
+ \pgfpoint
+ {\l_@@_left_nonclip_x}
+ {-\l_@@_bar_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l_@@_left_nonclip_x}
+ {\l_@@_bar_thickness_pgf}
+ }
+ }
+ \pgfpathclose
+ \pgfusepath{clip}
+ \endpgfinterruptboundingbox
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsubsection{Fading in/out}
+%
+% Set up the PGF `in' fading.
+% \begin{macrocode}
+\pgfdeclarehorizontalshading{@@_fade_in_shading}{4bp}{
+ color(0bp)=(transparent!100);
+ color(1bp)=(transparent!100);
+ color(3bp)=(transparent!0);
+ color(4bp)=(transparent!0)
+}
+\pgfdeclarefading
+ {@@_fade_in}
+ {\pgfuseshading{@@_fade_in_shading}}
+% \end{macrocode}
+%
+% \begin{macro}{\@@_interval_start_range_fade:}
+% Draw fading to indicate a start range. Because some PDF renderers may otherwise leave a gap between the fade and
+% solid part, compute \cs{l_@@_fade_extra_pgf} and draw this amount of overlap with the solid part. Because of the
+% definition of the `in' fading, \cs{l_@@_fade_extra_pgf} must not exceed half of the fade width. And the overlap
+% should not exceed the actual length of the solid part.
+% \begin{macrocode}
+\cs_new:Npn\@@_interval_start_range_fade:
+ {
+ \pgfmathsetlengthmacro{\l_@@_fade_width_pgf}
+ { \l_@@_start_solid_x-\l_@@_start_extreme_x }
+ \@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}
+ { \l_@@_fade_width_pgf
+ > \pgfkeysvalueof{/timechart/fade~minimum~width} }
+ \bool_if:NT \l_@@_tmpa_bool
+ {
+ \@@_if_x_range_intersect_tolerance_bounds:nnT
+ {\l_@@_start_extreme_x}{\l_@@_start_solid_x}
+ {
+ \pgfmathsetmacro{\l_@@_fade_extra_pgf}
+ {
+ min(
+ .49*\l_@@_fade_width_pgf,
+ \l_@@_finish_solid_x-\l_@@_start_solid_x
+ )
+ }
+ \pgfscope
+ \pgfpathrectanglecorners{
+ \pgfpoint
+ {\l_@@_start_extreme_x}
+ {-\l_@@_bar_half_thickness_pgf}
+ }{
+ \pgfpoint
+ {\l_@@_start_solid_x+\l_@@_fade_extra_pgf}
+ {\l_@@_bar_half_thickness_pgf}
+ }
+ \pgfgettransform{\@@_transform_current}
+ \pgfsetfading{@@_fade_in}{
+ \pgfsettransform{\@@_transform_current}
+ \pgftransformshift{
+ \pgfpoint
+ {
+ .5*\l_@@_start_extreme_x
+ +.5*\l_@@_start_solid_x
+ }
+ {0}
+ }
+ \pgftransformxscale{
+ (\l_@@_start_solid_x-\l_@@_start_extreme_x)
+ /2bp
+ }
+ \pgftransformyscale{\l_@@_bar_thickness_pgf/4bp}
+ }
+ \pgfsetfillcolor{\l_@@_bar_color}
+ \pgfusepath{fill}
+ \endpgfscope
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% Set up the PGF `out' fading.
+% \begin{macrocode}
+\pgfdeclarehorizontalshading{@@_fade_out_shading}{4bp}{
+ color(0bp)=(transparent!0);
+ color(1bp)=(transparent!0);
+ color(3bp)=(transparent!100);
+ color(4bp)=(transparent!100)
+}
+\pgfdeclarefading
+ {@@_fade_out}
+ {\pgfuseshading{@@_fade_out_shading}}
+% \end{macrocode}
+%
+% \begin{macro}{\@@_interval_finish_range_fade:}
+% Draw fading to indicate a finish range. As in \cs{@@_interval_start_range_fade:}, a small overlap is computed.
+% \begin{macrocode}
+\cs_new:Npn\@@_interval_finish_range_fade:
+ {
+ \pgfmathsetlengthmacro{\l_@@_fade_width_pgf}
+ { \l_@@_finish_extreme_x-\l_@@_finish_solid_x }
+ \@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}
+ { \l_@@_fade_width_pgf
+ > \pgfkeysvalueof{/timechart/fade~minimum~width} }
+ \bool_if:NT \l_@@_tmpa_bool
+ {
+ \@@_if_x_range_intersect_tolerance_bounds:nnT
+ {\l_@@_finish_solid_x}{\l_@@_finish_extreme_x}
+ {
+ \pgfmathsetmacro{\l_@@_fade_extra_pgf}
+ {
+ min(
+ .49*\l_@@_fade_width_pgf,
+ \l_@@_finish_solid_x-\l_@@_start_solid_x
+ )
+ }
+ \pgfscope
+ \pgfpathrectanglecorners{
+ \pgfpoint
+ {\l_@@_finish_solid_x-\l_@@_fade_extra_pgf}
+ {-\l_@@_bar_half_thickness_pgf}
+ }{
+ \pgfpoint
+ {\l_@@_finish_extreme_x}
+ {\l_@@_bar_half_thickness_pgf}
+ }
+ \pgfgettransform{\@@_transform_current}
+ \pgfsetfading{@@_fade_out}{
+ \pgfsettransform{\@@_transform_current}
+ \pgftransformshift{
+ \pgfpoint{
+ .5*\l_@@_finish_solid_x
+ +.5*\l_@@_finish_extreme_x
+ }
+ {0}
+ }
+ \pgftransformxscale{
+ (\l_@@_finish_extreme_x-\l_@@_finish_solid_x)
+ /2bp
+ }
+ \pgftransformyscale{\l_@@_bar_thickness_pgf/4bp}
+ }
+ \pgfsetfillcolor{\l_@@_bar_color}
+ \pgfusepath{fill}
+ \endpgfscope
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsubsection{Slant in/out}
+%
+% \begin{macro}{\@@_interval_start_range_slant:}
+% Clip and modify \cs{l_@@_start_solid_x} to draw a slanting shape to indicate the start range.
+% \begin{macrocode}
+\cs_new:Npn\@@_interval_start_range_slant:
+ {
+ \@@_if_equal:nnF
+ {\l_@@_start_extreme_x}{\l_@@_start_solid_x}
+ {
+ \@@_if_x_range_intersect_tolerance_bounds:nnT
+ {\l_@@_start_extreme_x}{\l_@@_start_solid_x}
+ {
+ \pgfinterruptboundingbox
+ \pgfpathmoveto{
+ \pgfpoint
+ {\l_@@_start_extreme_x}
+ {-\l_@@_bar_half_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l_@@_start_solid_x}
+ {\l_@@_bar_half_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l_@@_start_solid_x}
+ {\l_@@_bar_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l_@@_right_nonclip_x}
+ {\l_@@_bar_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l_@@_right_nonclip_x}
+ {-\l_@@_bar_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l_@@_start_extreme_x}
+ {-\l_@@_bar_thickness_pgf}
+ }
+ \pgfpathclose
+ \pgfusepath{clip}
+ \endpgfinterruptboundingbox
+ \pgfmathsetmacro{\l_@@_start_solid_x}
+ {\l_@@_start_extreme_x}
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_interval_finish_range_slant:}
+% Clip and modify \cs{l_@@_finish_solid_x} to draw a slanting shape to indicate the finish range.
+% \begin{macrocode}
+\cs_new:Npn\@@_interval_finish_range_slant:
+ {
+ \@@_if_equal:nnF
+ {\l_@@_finish_solid_x}{\l_@@_finish_extreme_x}
+ {
+ \@@_if_x_range_intersect_tolerance_bounds:nnT
+ {\l_@@_finish_solid_x}{\l_@@_finish_extreme_x}
+ {
+ \pgfinterruptboundingbox
+ \pgfpathmoveto{
+ \pgfpoint
+ {\l_@@_finish_solid_x}
+ {-\l_@@_bar_half_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l_@@_finish_extreme_x}
+ {\l_@@_bar_half_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l_@@_finish_extreme_x}
+ {\l_@@_bar_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l_@@_left_nonclip_x}
+ {\l_@@_bar_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l_@@_left_nonclip_x}
+ {-\l_@@_bar_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l_@@_finish_solid_x}
+ {-\l_@@_bar_thickness_pgf}
+ }
+ \pgfpathclose
+ \pgfusepath{clip}
+ \endpgfinterruptboundingbox
+ \pgfmathsetmacro{\l_@@_finish_solid_x}
+ {\l_@@_finish_extreme_x}
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsubsection{Solid bar}
+%
+% \begin{macro}{\@@_interval_draw_solid:}
+% Draw the solid part of an interval.
+% \begin{macrocode}
+\cs_new:Npn\@@_interval_draw_solid:
+ {
+ \@@_if_x_range_intersect_tolerance_bounds:nnT
+ {\l_@@_start_solid_x}
+ {\l_@@_finish_solid_x}
+ {
+ \pgfpathrectanglecorners{
+ \pgfpoint
+ {\l_@@_start_solid_x}
+ {-\l_@@_bar_half_thickness_pgf}
+ }{
+ \pgfpoint
+ {\l_@@_finish_solid_x}
+ {\l_@@_bar_half_thickness_pgf}
+ }
+ \pgfsetfillcolor{\l_@@_bar_color}
+ \pgfusepath{fill}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsubsection{Marks}
+%
+% \begin{macrocode}
+\msg_new:nnn{timechart}{interval_mark_outside}
+ { Attempt~to~mark~outside~interval~at~date~#1 }
+% \end{macrocode}
+%
+% \begin{macro}{\@@_interval_mark:}
+% Draw marks on an interval.
+% \begin{macrocode}
+\cs_new:Npn\@@_interval_mark:
+ {
+ \pgfscope
+ \pgfsetstrokecolor{\l_@@_mark_color}
+ \foreach \year in \l_@@_mark_text
+ {
+ \pgfmathsetmacro{\l_@@_mark_x}{yeartox(\year)}
+ \@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}
+ {
+ or (
+ \l_@@_mark_x < \l_@@_start_extreme_x,
+ \l_@@_mark_x > \l_@@_finish_extreme_x
+ )
+ }
+ \bool_if:NT\l_@@_tmpa_bool
+ { \msg_error:nne{timechart}{interval_mark_outside}{\year} }
+ \pgfpathmoveto{
+ \pgfpoint
+ {\l_@@_mark_x}
+ {-\l_@@_bar_half_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l_@@_mark_x}
+ {\l_@@_bar_half_thickness_pgf}
+ }
+ \pgfusepath{draw}
+ }
+ \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_@@_start_extreme_x}
+ {-\l_@@_bar_half_thickness_pgf}
+ }{
+ \pgfpoint
+ {\l_@@_finish_extreme_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_@@_start_extreme_x}
+ {
+ \group_begin:
+ \pgftransformshift{
+ \pgfpoint
+ {\l_@@_start_extreme_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_@@_finish_extreme_x}
+ {
+ \group_begin:
+ \pgftransformshift{
+ \pgfpoint
+ {\l_@@_finish_extreme_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_@@_start_definite_x,\l_@@_start_x)
+ + .5*min(\l_@@_finish_definite_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_@@_start_extreme_x}
+ {-\l_@@_bar_half_thickness_pgf}
+ }{
+ \pgfpoint
+ {\l_@@_finish_extreme_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)}
+ \@@_if_x_in_tolerance_bounds:nT{\l_@@_text_x}
+ {
+% \end{macrocode}
+% Process keys supplied locally and retrieve needed keys.
+% \begin{macrocode}
+ \pgfqkeys{/timechart}{
+ #1,
+ 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_@@_start_solid_x}{0}
+ \pgfmathsetlengthmacro{\l_@@_finish_solid_x}
+ {\l_@@_legenditem_width_pgf}
+ \@@_interval_draw_solid:
+ }
+ }
+% \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_@@_start_extreme_x}{0}
+ \pgfmathsetlengthmacro{\l_@@_start_solid_x}
+ {\pgfkeysvalueof{/timechart/legend~item~range~width}}
+ \pgfmathsetlengthmacro{\l_@@_finish_solid_x}
+ {\l_@@_legenditem_width_pgf}
+ \int_case:nn {\l_@@_start_range_type_int}
+ {
+ {0}{ \@@_interval_start_range_fade: }
+ {1}{ \@@_interval_start_range_slant: }
+ }
+ \@@_interval_draw_solid:
+ }
+ }
+\NewDocumentCommand{\timechartlegendfinishrange}{ O{} }
+ {
+ \@@_legend_aux:nn{#1}{
+ \pgfmathsetlengthmacro{\l_@@_start_solid_x}{0}
+ \pgfmathsetlengthmacro{\l_@@_finish_solid_x}
+ {
+ \l_@@_legenditem_width_pgf
+ -\pgfkeysvalueof{/timechart/legend~item~range~width}
+ }
+ \pgfmathsetlengthmacro{\l_@@_finish_extreme_x}
+ {\l_@@_legenditem_width_pgf}
+ \int_case:nn {\l_@@_finish_range_type_int}
+ {
+ {0}{ \@@_interval_finish_range_fade: }
+ {1}{ \@@_interval_finish_range_slant: }
+ }
+ \@@_interval_draw_solid:
+ }
+ }
+% \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
+ {
+ \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/.get=\l_@@_beyond_length_pgf,
+ legend~item~width/.get=\l_@@_legenditem_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_@@_beyond_length_pgf}
+ \pgfmathsetlengthmacro{\l_@@_finish_beyond_x}
+ {\l_@@_finish_x+\l_@@_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}
+ #2
+% \end{macrocode}
+% Make sure that the legend has the required bounding box.
+% \begin{macrocode}
+ \pgfresetboundingbox
+ \pgfmoveto{
+ \pgfpoint{0}{-\l_@@_bar_half_thickness_pgf}
+ }
+ \pgfmoveto{
+ \pgfpoint
+ {\l_@@_legenditem_width_pgf}
+ {\l_@@_bar_half_thickness_pgf}
+ }
+ \endtikzpicture%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/timechart/timechart.ins b/Master/texmf-dist/source/latex/timechart/timechart.ins
new file mode 100644
index 00000000000..e4a9c32bed5
--- /dev/null
+++ b/Master/texmf-dist/source/latex/timechart/timechart.ins
@@ -0,0 +1,38 @@
+%%
+%% 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.3 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.
+%%
+\input l3docstrip.tex
+\askforoverwritefalse
+\nopostamble
+
+\preamble
+
+This is a generated file.
+
+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.3 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.
+
+\endpreamble
+
+\generate{\file{timechart.sty}{\from{timechart.dtx}{package}}}
+
+\endbatchfile
diff --git a/Master/texmf-dist/tex/latex/timechart/timechart.sty b/Master/texmf-dist/tex/latex/timechart/timechart.sty
new file mode 100644
index 00000000000..47ab006e982
--- /dev/null
+++ b/Master/texmf-dist/tex/latex/timechart/timechart.sty
@@ -0,0 +1,1615 @@
+%%
+%% This is file `timechart.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% timechart.dtx (with options: `package')
+%%
+%% This is a generated file.
+%%
+%% 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.3 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.
+%%
+\NeedsTeXFormat{LaTeX2e}[2020-02-02]
+\ProvidesExplPackage{timechart}{2025-02-15}{0.51}
+ {Typesetting chronological charts}
+\RequirePackage{tikz}
+\bool_new:N\l__timechart_tmpa_bool
+\bool_new:N\l__timechart_tmpb_bool
+\bool_new:N\l__timechart_tmpc_bool
+\bool_new:N\l__timechart_tmpd_bool
+\cs_set_eq:NN\l__timechart_tmpa_dim\l_tmpa_dim
+\cs_set_eq:NN\l__timechart_tmpb_dim\l_tmpb_dim
+\dim_new:N\l__timechart_tmpc_dim
+\dim_new:N\l__timechart_tmpd_dim
+\cs_new:Npn\__timechart_make_ref:NN #1#2
+ {
+ \str_if_empty:NTF #1
+ { #2 }
+ { \hyperref[#1]{#2} }
+ }
+\cs_new:Npn\__timechart_pgfmathsetbool:nn #1#2
+ {
+ \pgfmathsetmacro{#1}{ifthenelse(#2,"\c_true_bool","\c_false_bool")}
+ }
+\cs_new:Npn\__timechart_if_equal:nnF #1#2#3
+ {
+ \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}{#1==#2}
+ \bool_if:NF\l__timechart_tmpa_bool{#3}
+ }
+\cs_new:Npn\__timechart_pgfextractxy:nnn #1#2#3
+ {
+ \pgf@process{#3}
+ #1=\pgf@x\relax
+ #2=\pgf@y\relax
+ }
+\cs_new:Npn\__timechart_hsmash_pgfnode:nnnnn #1#2#3#4#5
+ {
+ \pgfinterruptboundingbox
+ \pgfnode{#1}{#2}{#3}{#4}{#5}
+ \pgfcoordinate
+ {__timechart_tmpa_coord}
+ {\pgfpointanchor{current~bounding~box}{south}}
+ \pgfcoordinate
+ {__timechart_tmpb_coord}
+ {\pgfpointanchor{current~bounding~box}{north}}
+ \endpgfinterruptboundingbox
+ \pgfextractx
+ {\l__timechart_tmpa_dim}
+ {\pgfpointanchor{__timechart_tmpa_coord}{center}}
+ \pgfextractx
+ {\l__timechart_tmpb_dim}
+ {\pgfpointanchor{__timechart_tmpb_coord}{center}}
+ \pgfpathmoveto{\pgfpoint{\l__timechart_tmpa_dim}{0}}
+ \pgfpathmoveto{\pgfpoint{\l__timechart_tmpb_dim}{0}}
+ \pgfusepath{discard}
+ }
+\cs_new:Npn\__timechart_make_rectangle_node:nnnn #1#2#3#4
+ {
+ \group_begin:
+ \__timechart_pgfextractxy:nnn
+ {\l__timechart_tmpa_dim}{\l__timechart_tmpb_dim}{#1}
+ \__timechart_pgfextractxy:nnn
+ {\l__timechart_tmpc_dim}{\l__timechart_tmpd_dim}{#2}
+ \pgftransformshift{#1}
+ \pgfset{
+ minimum~width=\l__timechart_tmpc_dim-\l__timechart_tmpa_dim,
+ minimum~height=\l__timechart_tmpd_dim-\l__timechart_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:
+ }
+\pgfmathsetmacro{\l__timechart_left_nonclip_x}{-16000pt}
+\pgfmathsetmacro{\l__timechart_right_nonclip_x}{16000pt}
+\cs_new:Npn\__timechart_set_style_line_width:nn #1#2
+ {
+ \begingroup
+ \tikzset{#2}
+ \pgfmathsetlengthmacro{#1}{\pgflinewidth}
+ \pgfmathsmuggle #1
+ \endgroup
+ }
+\pgfkeys{
+ /timechart/.cd,
+ width/.initial=\textwidth,
+ tolerance/.initial=5pt,
+ beyond~length/.initial=5pt,
+ beyond~x~radius/.initial=4pt,
+ ystep/.initial=-10pt,
+ minor~tick~interval/.initial=10,
+ major~tick~interval/.initial=50,
+ no~grid/.code = { \bool_set_false:N\l__timechart_grid_bool },
+ grid~top~ysep/.initial={3pt},
+ grid~bottom~ysep/.initial={3pt},
+ grid/.style={},
+ no~axis/.code = { \bool_set_false:N\l__timechart_axis_bool },
+ axis~line/.style={
+ line~cap=rect,
+ },
+ axis~ysep/.initial=3pt,
+ 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,
+ },
+ no~autostep/.code = { \bool_set_false:Nz\l__timechart_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__timechart_label_pos_int{0} },
+ interval~label~pos/center/.code
+ = { \int_set:Nn\l__timechart_label_pos_int{1} },
+ interval~label~pos/right/.code
+ = { \int_set:Nn\l__timechart_label_pos_int{2} },
+ interval~label~node~name/.initial = {label~node},
+ start~range/.is~choice,
+ start~range/fade/.code
+ = { \int_set:Nn\l__timechart_start_range_type_int{0} },
+ start~range/slant/.code
+ = { \int_set:Nn\l__timechart_start_range_type_int{1} },
+ finish~range/.is~choice,
+ finish~range/fade/.code
+ = { \int_set:Nn\l__timechart_finish_range_type_int{0} },
+ finish~range/slant/.code
+ = { \int_set:Nn\l__timechart_finish_range_type_int{1} },
+ fade~minimum~width/.initial = 0pt,
+ text~node~name/.initial = {text~node},
+ text/.style={},
+ text~baseline/.initial=-3pt,
+ text~pos/.is~choice,
+ text~pos/left/.code = { \int_set:Nn\l__timechart_text_pos_int{0} },
+ text~pos/center/.code = { \int_set:Nn\l__timechart_text_pos_int{1} },
+ text~pos/right/.code = { \int_set:Nn\l__timechart_text_pos_int{2} },
+ legend~item~width/.initial=9mm,
+ legend~item~range~width/.initial=3mm,
+ left/.code = {
+ \int_set:Nn\l__timechart_label_pos_int{0}
+ \int_set:Nn\l__timechart_text_pos_int{0}
+ },
+ center/.code = {
+ \int_set:Nn\l__timechart_label_pos_int{1}
+ \int_set:Nn\l__timechart_text_pos_int{1}
+ },
+ right/.code = {
+ \int_set:Nn\l__timechart_label_pos_int{2}
+ \int_set:Nn\l__timechart_text_pos_int{2}
+ },
+}
+\bool_new:N\l__timechart_grid_bool
+\bool_set_true:N\l__timechart_grid_bool
+\bool_new:N\l__timechart_axis_bool
+\bool_set_true:N\l__timechart_axis_bool
+\bool_new:N\l__timechart_autostep_bool
+\bool_set_true:N\l__timechart_autostep_bool
+\int_new:N \l__timechart_label_pos_int
+\int_new:N \l__timechart_text_pos_int
+\int_new:N \l__timechart_start_range_type_int
+\int_new:N \l__timechart_finish_range_type_int
+\NewDocumentEnvironment{timechart}{ O{} m m }
+ { \__timechart_main_begin:nnn{#1}{#2}{#3} }
+ { \__timechart_main_end: }
+\cs_new:Npn \__timechart_main_begin:nnn #1#2#3
+ {
+ \pgfkeys{
+ /timechart/.cd,
+ #1,
+ width/.get=\l__timechart_width_pgf,
+ tolerance/.get=\l__timechart_tolerance_pgf,
+ ystep/.get=\l__timechart_ystep_pgf,
+ grid~top~ysep/.get=\l__timechart_grid_top_ysep_pgf,
+ grid~bottom~ysep/.get=\l__timechart_grid_bottom_ysep_pgf,
+ beyond~length/.get=\l__timechart_beyond_length_pgf,
+ beyond~x~radius/.get=\l__timechart_beyond_x_radius_pgf,
+ minor~tick~interval/.get=\l__timechart_minor_tick_interval_year,
+ major~tick~interval/.get=\l__timechart_major_tick_interval_year,
+ }
+ \tikzpicture
+ \pgfdeclarelayer{grid}
+ \pgfdeclarelayer{labelbg}
+ \pgfsetlayers{grid,labelbg,main}
+ \bool_if:NTF\l__timechart_grid_bool
+ {
+ \__timechart_set_style_line_width:nn
+ {\l__timechart_grid_line_width}
+ {/timechart/grid}
+ }
+ { \pgfmathsetlengthmacro{\l__timechart_grid_line_width}{0} }
+ \bool_if:NTF\l__timechart_axis_bool
+ {
+ \__timechart_set_style_line_width:nn
+ {\l__timechart_axis_line_width}
+ {/timechart/axis~line}
+ \__timechart_set_style_line_width:nn
+ {\l__timechart_major_tick_line_width}
+ {/timechart/major~tick}
+ \__timechart_set_style_line_width:nn
+ {\l__timechart_minor_tick_line_width}
+ {/timechart/minor~tick}
+ }
+ {
+ \pgfmathsetlengthmacro{\l__timechart_axis_line_width}{0}
+ \pgfmathsetlengthmacro{\l__timechart_major_tick_line_width}{0}
+ \pgfmathsetlengthmacro{\l__timechart_minor_tick_line_width}{0}
+ }
+ \__timechart_parse_date:NNn\l_tmpa_bool\l__timechart_start_year{#2}
+ \__timechart_parse_date:NNn\l_tmpa_bool\l__timechart_finish_year{#3}
+ \pgfmathsetmacro{\l__timechart_start_year}
+ {floor(\l__timechart_start_year)}
+ \pgfmathsetmacro{\l__timechart_finish_year}
+ {floor(\l__timechart_finish_year)}
+ \pgfmathsetmacro{\l__timechart_x}
+ {
+ (
+ \l__timechart_width_pgf
+ - max(
+ \l__timechart_grid_line_width,
+ \l__timechart_axis_line_width,
+ \l__timechart_major_tick_line_width,
+ \l__timechart_minor_tick_line_width
+ )
+ )/(\l__timechart_finish_year-\l__timechart_start_year)
+ }
+ \pgfkeys{
+ /pgf/declare~function={
+ yeartox(\n)=\l__timechart_x*(\n-\l__timechart_start_year);
+ },
+ }
+ \pgfmathsetmacro{\l__timechart_start_x}
+ {yeartox(\l__timechart_start_year)}
+ \pgfmathsetmacro{\l__timechart_finish_x}
+ {yeartox(\l__timechart_finish_year)}
+ \pgfmathsetmacro{\l__timechart_start_tolerance_x}{
+ \l__timechart_start_x-(\l__timechart_tolerance_pgf)
+ }
+ \pgfmathsetmacro{\l__timechart_finish_tolerance_x}{
+ \l__timechart_finish_x+(\l__timechart_tolerance_pgf)
+ }
+ \pgfmathsetmacro{\l__timechart_start_beyond_x}{
+ \l__timechart_start_x-(\l__timechart_beyond_length_pgf)
+ }
+ \pgfmathsetmacro{\l__timechart_finish_beyond_x}{
+ \l__timechart_finish_x+(\l__timechart_beyond_length_pgf)
+ }
+ \pgfmathsetmacro{\l__timechart_current_y}{0}
+ \pgfmathsetmacro{\l__timechart_saved_y}{0}
+ \pgfmathsetmacro{\l__timechart_auto_reset_minimum_y}{-16000pt}
+ \pgfmathsetmacro{\l__timechart_auto_reset_maximum_y}{16000pt}
+ \pgfmathsetmacro{\l__timechart_start_plus_year}{
+ \l__timechart_start_year+\l__timechart_minor_tick_interval_year
+ }
+ \pgfmathsetmacro{\l__timechart_start_plusplus_year}{
+ \l__timechart_start_year+(2*\l__timechart_minor_tick_interval_year)
+ }
+ \pgfmathsetmacro{\l__timechart_end_minus_year}{
+ \l__timechart_finish_year-\l__timechart_minor_tick_interval_year
+ }
+ \group_begin:
+ \cs_set_eq:NN\timechartinterval\__timechart_interval_user:Ommm
+ \cs_set_eq:NN\timecharttext\__timechart_text_user:Omm
+ \cs_set_eq:NN\timechartspace\__timechart_space_user:O
+ \cs_set_eq:NN\timechartsety\__timechart_set_y_user:m
+ \cs_set_eq:NN\timechartsavey\__timechart_save_y_user:
+ \cs_set_eq:NN\timechartresety\__timechart_reset_y_user:
+ \cs_set_eq:NN\timechartsetyminimumautoreset
+ \__timechart_set_y_minimum_auto_reset_user:m
+ \cs_set_eq:NN\timechartsetymaximumautoreset
+ \__timechart_set_y_maximum_auto_reset_user:m
+ \cs_set_eq:NN\timechartstepy\__timechart_step_y_user:O
+ \cs_set_eq:NN\timechartfinish\__timechart_main_end_user:
+ }
+\cs_new:Npn\__timechart_main_end:
+ {
+ \cs_if_eq:NNT\timechartfinish\__timechart_main_end_user:
+ { \__timechart_main_end_user: }
+ \endtikzpicture
+ }
+\cs_new:Npn\__timechart_main_end_user:
+ {
+ \pgfextracty{\l__timechart_tmpa_dim}
+ { \pgfpointanchor{current~bounding~box}{south} }
+ \pgfextracty{\l__timechart_tmpb_dim}
+ { \pgfpointanchor{current~bounding~box}{north} }
+ \pgfresetboundingbox
+ \dim_compare:nNnTF{\l__timechart_tmpa_dim}>{\l__timechart_tmpb_dim}
+ {
+ \pgfmathsetmacro{\l__timechart_content_bottom_y}{0pt}
+ \pgfmathsetmacro{\l__timechart_content_top_y}{0pt}
+ }
+ {
+ \pgfmathsetmacro{\l__timechart_content_bottom_y}
+ {\l__timechart_tmpa_dim}
+ \pgfmathsetmacro{\l__timechart_content_top_y}
+ {\l__timechart_tmpb_dim}
+ }
+ \bool_if:NTF{\l__timechart_grid_bool}
+ {
+ \__timechart_grid_draw:
+ \pgfmathsetmacro{\l__timechart_axis_y}
+ {
+ \l__timechart_content_top_y
+ + \l__timechart_grid_top_ysep_pgf
+ + \pgfkeysvalueof{/timechart/axis~ysep}
+ }
+ }
+ {
+ \__timechart_nogrid_bounding_box_set:
+ \pgfmathsetmacro{\l__timechart_axis_y}
+ {
+ \l__timechart_content_top_y
+ +\pgfkeysvalueof{/timechart/axis~ysep}
+ }
+ }
+ \bool_if:NT{\l__timechart_axis_bool}
+ { \__timechart_axis_draw: }
+ \group_end:
+ }
+\cs_new:Npn\__timechart_grid_draw:
+ {
+ \pgfmathsetmacro{\l__timechart_grid_bottom_y}{
+ \l__timechart_content_bottom_y-\l__timechart_grid_bottom_ysep_pgf
+ }
+ \pgfmathsetmacro{\l__timechart_grid_top_y}{
+ \l__timechart_content_top_y+\l__timechart_grid_top_ysep_pgf
+ }
+ \pgfonlayer{ grid }
+ \scope[/timechart/grid]
+ \foreach \year in {
+ \l__timechart_start_plus_year,
+ \l__timechart_start_plusplus_year,
+ ...,
+ \l__timechart_end_minus_year
+ } {
+ \group_begin:
+ \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}
+ { Mod(\year,\l__timechart_major_tick_interval_year)==0 }
+ \bool_if:NT\l__timechart_tmpa_bool
+ {
+ \pgftransformshift{ \pgfpoint{yeartox(\year)}{0} }
+ \pgfpathmoveto{ \pgfpoint{0}{\l__timechart_grid_top_y} }
+ \pgfpathlineto{ \pgfpoint{0}{\l__timechart_grid_bottom_y} }
+ \pgfusepath{ draw }
+ }
+ \group_end:
+ }
+ \__timechart_make_rectangle_node:nnnn
+ { \pgfpoint{\l__timechart_start_x}{\l__timechart_grid_bottom_y} }
+ { \pgfpoint{\l__timechart_finish_x}{\l__timechart_grid_top_y} }
+ { grid }
+ { \c_true_bool }
+ \endscope
+ \endpgfonlayer
+ }
+\cs_new:Npn\__timechart_axis_draw:
+ {
+ \group_begin:
+ \pgfkeys{
+ /timechart/minor~tick~length/.get=\__timechart_minor_tick_length_pgf,
+ /timechart/major~tick~length/.get=\__timechart_major_tick_length_pgf,
+ }
+ \pgftransformshift{ \pgfpoint{0}{\l__timechart_axis_y} }
+ \pgfmathsetmacro{\__timechart_start_major_tick_year}
+ {
+ \l__timechart_start_year
+ -Mod(
+ \l__timechart_start_year,
+ \l__timechart_major_tick_interval_year
+ )
+ }
+ \pgfmathsetmacro{\__timechart_start_major_tick_year}
+ {
+ ifthenelse(
+ \__timechart_start_major_tick_year<\l__timechart_start_year,
+ \__timechart_start_major_tick_year
+ +\l__timechart_major_tick_interval_year,
+ \__timechart_start_major_tick_year
+ )
+ }
+ \pgfmathsetmacro{\__timechart_finish_major_tick_year}
+ {
+ \l__timechart_finish_year
+ -Mod(
+ \l__timechart_finish_year,
+ \l__timechart_major_tick_interval_year
+ )
+ }
+ \foreach \year in {
+ \l__timechart_start_year,
+ \l__timechart_start_plus_year,
+ ...,
+ \l__timechart_finish_year
+ } {
+ \pgfmathsetmacro{\x}{yeartox(\year)}
+ \__timechart_pgfmathsetbool:nn
+ {\l__timechart_tmpa_bool}
+ { Mod(\year,\l__timechart_major_tick_interval_year)==0 }
+ \bool_if:NTF\l__timechart_tmpa_bool
+ { \__timechart_axis_draw_labelled_major_tick:NN\x\year }
+ { \__timechart_axis_draw_minor_tick:N\x }
+ }
+ \__timechart_draw_axis_line
+ \pgfextracty{\l__timechart_tmpa_dim}
+ { \pgfpointanchor{current~bounding~box}{north} }
+ \__timechart_make_rectangle_node:nnnn
+ { \pgfpoint{\l__timechart_start_x}{0} }
+ { \pgfpoint{\l__timechart_finish_x}{\l__timechart_tmpa_dim} }
+ { axis }
+ { \c_false_bool }
+ \group_end:
+ }
+\cs_new:Npn\__timechart_axis_draw_minor_tick:N #1
+ {
+ \scope[/timechart/minor~tick]
+ \pgfpathmoveto{ \pgfpoint{#1}{0} }
+ \pgfpathlineto{ \pgfpoint{#1}{\__timechart_minor_tick_length_pgf} }
+ \pgfusepath{draw}
+ \endscope
+ }
+\cs_new:Npn\__timechart_axis_draw_labelled_major_tick:NN #1#2
+ {
+ \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}{#2==0}
+ \bool_if:NTF \l__timechart_tmpa_bool
+ { \__timechart_axis_draw_zero_tick:N #1 }
+ {
+ \__timechart_pgfmathsetbool:nn{\l__timechart_tmpb_bool}
+ { #2==\__timechart_start_major_tick_year }
+ \__timechart_pgfmathsetbool:nn{\l__timechart_tmpc_bool}
+ { #2==\__timechart_finish_major_tick_year }
+ \bool_set:Nn\l__timechart_tmpd_bool
+ { \l__timechart_tmpb_bool || \l__timechart_tmpc_bool }
+ \__timechart_axis_draw_major_tick:N #1
+ \__timechart_axis_draw_year_label:nnnnnn
+ { #1 }
+ { #2 }
+ { \l__timechart_tmpd_bool }
+ { mid~west }
+ { 0 }
+ { \__timechart_major_tick_length_pgf+1mm }
+ }
+ }
+\cs_new:Npn\__timechart_axis_draw_major_tick:N #1
+ {
+ \scope[/timechart/major~tick]
+ \pgfpathmoveto{ \pgfpoint{#1}{0} }
+ \pgfpathlineto{ \pgfpoint{#1}{\__timechart_major_tick_length_pgf} }
+ \pgfusepath{draw}
+ \endscope
+ }
+\cs_new:Npn\__timechart_axis_draw_zero_tick:N #1
+ {
+ \group_begin:
+ \pgftransformshift{ \pgfpoint{#1}{0} }
+ \pgfmathsetmacro{\a}{5}
+ \pgfmathsetlengthmacro{\r}{1mm}
+ \pgfmathsetlengthmacro{\t}{\r*(cos(\a)-cos(90-\a))/(1-cos(90-\a))}
+ \scope[/timechart/major~tick,line~join=miter]
+ \pgfpathmoveto{\pgfpointorigin}
+ \pgfpathlineto{\pgfpoint{0}{\__timechart_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}{\__timechart_major_tick_length_pgf-1pt}}
+ \pgfusepath{draw}
+ \endscope
+ \__timechart_axis_draw_year_label:nnnnnn
+ { 0 }
+ { -1 }
+ { \c_true_bool }
+ { base~west }
+ { -.5mm }
+ { 5.5mm }
+ \__timechart_axis_draw_year_label:nnnnnn
+ { 0 }
+ { 1 }
+ { \c_true_bool }
+ { north~west }
+ { .5mm }
+ { 5.5mm }
+ \group_end:
+ }
+\cs_new:Npn\__timechart_draw_axis_line
+ {
+ \scope[/timechart/axis~line]
+ \pgfpathmoveto{ \pgfpoint{\l__timechart_start_x}{0} }
+ \pgfpathlineto{ \pgfpoint{\l__timechart_finish_x}{0} }
+ \pgfusepath{draw}
+ \endscope
+ }
+\cs_new:Npn\__timechart_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
+ {
+ \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}{#2<0}
+ \bool_if:NTF\l__timechart_tmpa_bool
+ { \cs_set_eq:NN\__timechart_make_year:n\timechartmakebeforeyear }
+ { \cs_set_eq:NN\__timechart_make_year:n\timechartmakeafteryear }
+ \__timechart_hsmash_pgfnode:nnnnn
+ {rectangle}
+ {#4}
+ {\__timechart_make_year:n{\absyear}}
+ {}
+ {}
+ }
+ { \pgfnode{rectangle}{#4}{\absyear}{}{} }
+ \endscope
+ \group_end:
+ }
+\cs_new:Npn\timechartmakebeforeyear #1
+ {
+ #1\nobreakspace\textsc{bce}
+ }
+\cs_new:Npn\timechartmakeafteryear #1
+ {
+ #1\nobreakspace\textsc{ce}
+ }
+\cs_new:Npn\__timechart_nogrid_bounding_box_set:
+ {
+ \pgfpathmoveto
+ { \pgfpoint{\l__timechart_start_x}{\l__timechart_content_bottom_y} }
+ \pgfpathmoveto
+ { \pgfpoint{\l__timechart_finish_x}{\l__timechart_content_top_y} }
+ \pgfusepath{discard}
+ }
+\cs_new:Npn\__timechart_set_y_user:m #1
+ {
+ \pgfmathsetmacro{\l__timechart_current_y}{#1}
+ }
+\cs_new:Npn\__timechart_save_y_user:
+ {
+ \pgfmathsetmacro{\l__timechart_saved_y}{\l__timechart_current_y}
+ }
+\cs_new:Npn\__timechart_reset_y_user:
+ {
+ \pgfmathsetmacro{\l__timechart_current_y}{\l__timechart_saved_y}
+ }
+\cs_new:Npn\__timechart_set_y_minimum_auto_reset_user:m #1
+ {
+ \pgfmathsetmacro{\l__timechart_auto_reset_minimum_y}{#1}
+ }
+\cs_new:Npn\__timechart_set_y_maximum_auto_reset_user:m #1
+ {
+ \pgfmathsetmacro{\l__timechart_auto_reset_maximum_y}{#1}
+ }
+\NewDocumentCommand{\__timechart_step_y_user:O}{ O{1} }
+ {
+ \pgfmathsetmacro{\l__timechart_current_y}
+ {\l__timechart_current_y+#1*\l__timechart_ystep_pgf}
+ \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}
+ {
+ or(
+ \l__timechart_current_y<\l__timechart_auto_reset_minimum_y,
+ \l__timechart_current_y>\l__timechart_auto_reset_maximum_y
+ )
+ }
+ \bool_if:nT{\l__timechart_tmpa_bool}
+ { \pgfmathsetmacro{\l__timechart_current_y}{\l__timechart_saved_y)} }
+ }
+\cs_new:Npn\__timechart_if_x_in_bounds:nT #1#2
+ {
+ \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}{
+ and(
+ #1>=\l__timechart_start_x,
+ #1<=\l__timechart_finish_x
+ )
+ }
+ \bool_if:NT\l__timechart_tmpa_bool
+ {#2}
+ }
+
+\cs_new:Npn\__timechart_if_x_in_tolerance_bounds:nT #1#2
+ {
+ \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}{
+ and(
+ #1>=\l__timechart_start_tolerance_x,
+ #1<=\l__timechart_finish_tolerance_x
+ )
+ }
+ \bool_if:NT\l__timechart_tmpa_bool{#2}
+ }
+\cs_new:Npn\__timechart_if_x_range_intersect_tolerance_bounds:nnT #1#2#3
+ {
+ \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}{
+ or(
+ or(
+ and(
+ #2>=\l__timechart_start_tolerance_x,
+ #2<=\l__timechart_finish_tolerance_x
+ ),
+ and(
+ #1>=\l__timechart_start_tolerance_x,
+ #1<=\l__timechart_finish_tolerance_x
+ )
+ ),
+ and(
+ #1<\l__timechart_start_tolerance_x,
+ #2>\l__timechart_finish_tolerance_x
+ )
+ )
+ }
+ \bool_if:NT\l__timechart_tmpa_bool
+ {#3}
+ }
+\cs_new:Npn\__timechart_parse_date_or_daterange:NNNNNn #1#2#3#4#5#6
+{
+ \bool_set:Nn #1 {\__timechart_is_nondaterange_p:w #6/\q_stop}
+ \bool_set_inverse:N #1
+ \bool_if:nTF #1
+ { \__timechart_parse_range:w #2#3#4#5\q_mark #6\q_stop }
+ {
+ \__timechart_parse_date:NNn #2#3{#6}
+ \bool_set_eq:NN #4#2
+ \pgfmathsetmacro{#5}{#3}
+ }
+}
+\cs_new:Npn\__timechart_is_nondaterange_p:w #1/#2\q_stop
+{
+ \tl_if_empty_p:n{#2}
+}
+\cs_new:Npn\__timechart_parse_range:w #1#2#3#4\q_mark #5/#6\q_stop
+{
+ \__timechart_parse_date:NNn #1#2{#5}
+ \__timechart_parse_date:NNn #3#4{#6}
+}
+\cs_new:Npn\__timechart_parse_date:NNn #1#2#3
+{
+ \bool_set:Nn #1 { \__timechart_is_circa_p:w #3c\q_stop }
+ \bool_if:NTF #1
+ { \__timechart_parse_circa_date:w #2\q_mark #3\q_stop }
+ { \__timechart_parse_noncirca_date:Nn #2{#3} }
+}
+\cs_new:Npn\__timechart_is_circa_p:w #1c#2\q_stop
+{
+ \tl_if_empty_p:n{#1}
+}
+\cs_new:Npn\__timechart_parse_circa_date:w #1\q_mark c#2\q_stop
+{
+ \__timechart_parse_noncirca_date:Nn #1{#2}
+}
+\cs_new:Npn\__timechart_parse_noncirca_date:Nn #1#2
+{
+ \bool_if:nTF { \__timechart_is_before_p:w #2-\q_stop }
+ { \__timechart_parse_before_date:w #1\q_mark #2\q_stop }
+ { \__timechart_parse_signed_date:w #1\q_mark #2-0-0\q_stop }
+}
+\cs_new:Npn\__timechart_is_before_p:w #1-#2\q_stop
+{
+ \tl_if_empty_p:n{#1}
+}
+\cs_new:Npn\__timechart_parse_before_date:w #1\q_mark-#2\q_stop
+{
+ \__timechart_parse_signed_date:w #1-\q_mark #2-0-0\q_stop
+}
+\cs_new:cpn{c__timechart_year_days_pgf}{365}
+\cs_new:cpn{c__timechart_month_days_1_pgf}{31}
+\cs_new:cpn{c__timechart_month_days_2_pgf}{28}
+\cs_new:cpn{c__timechart_month_days_3_pgf}{31}
+\cs_new:cpn{c__timechart_month_days_4_pgf}{30}
+\cs_new:cpn{c__timechart_month_days_5_pgf}{31}
+\cs_new:cpn{c__timechart_month_days_6_pgf}{30}
+\cs_new:cpn{c__timechart_month_days_7_pgf}{31}
+\cs_new:cpn{c__timechart_month_days_8_pgf}{31}
+\cs_new:cpn{c__timechart_month_days_9_pgf}{30}
+\cs_new:cpn{c__timechart_month_days_10_pgf}{31}
+\cs_new:cpn{c__timechart_month_days_11_pgf}{30}
+\cs_new:cpn{c__timechart_month_days_12_pgf}{31}
+\cs_new:cpn{c__timechart_cumulative_days_1_pgf}{0}
+\cs_new:cpn{c__timechart_cumulative_days_2_pgf}{31}
+\cs_new:cpn{c__timechart_cumulative_days_3_pgf}{59}
+\cs_new:cpn{c__timechart_cumulative_days_4_pgf}{90}
+\cs_new:cpn{c__timechart_cumulative_days_5_pgf}{120}
+\cs_new:cpn{c__timechart_cumulative_days_6_pgf}{151}
+\cs_new:cpn{c__timechart_cumulative_days_7_pgf}{181}
+\cs_new:cpn{c__timechart_cumulative_days_8_pgf}{212}
+\cs_new:cpn{c__timechart_cumulative_days_9_pgf}{243}
+\cs_new:cpn{c__timechart_cumulative_days_10_pgf}{273}
+\cs_new:cpn{c__timechart_cumulative_days_11_pgf}{304}
+\cs_new:cpn{c__timechart_cumulative_days_12_pgf}{334}
+\cs_new:Npn\__timechart_parse_signed_date:w #1#2\q_mark #3-#4-#5\q_stop
+{
+ \pgfmathtruncatemacro{\__timechart_parsed_year_pgf}{#2#3}
+ \pgfmathtruncatemacro{\__timechart_parsed_month_pgf}{#4}
+ \pgfmathtruncatemacro{\__timechart_parsed_day_pgf}{#5}
+ \__timechart_pgfmathsetbool:nn{\l_tmpa_bool}{
+ or(
+ \__timechart_parsed_month_pgf < 1,
+ \__timechart_parsed_month_pgf > 12,
+ )
+ }
+ \bool_if:NTF\l_tmpa_bool
+ {
+ \pgfmathsetmacro{#1}{#2#3}
+ }
+ {
+ \cs_set_eq:NN\l__timechart_year_days_pgf\c__timechart_year_days_pgf
+ \cs_set_eq:Nc\l__timechart_month_days_pgf
+ { c__timechart_month_days_\__timechart_parsed_month_pgf _pgf }
+ \cs_set_eq:Nc\l__timechart_cumulative_days_pgf
+ { c__timechart_cumulative_days_\__timechart_parsed_month_pgf _pgf }
+ \__timechart_pgfmathsetbool:nn{\l_tmpa_bool}{
+ or(
+ Mod(\__timechart_parsed_year_pgf,400) == 0,
+ and(
+ Mod(\__timechart_parsed_year_pgf,4) == 0,
+ Mod(\__timechart_parsed_year_pgf,100) != 0
+ )
+ )
+ }
+ \bool_if:NT\l_tmpa_bool
+ {
+ \pgfmathsetmacro{\l__timechart_year_days_pgf}
+ { \l__timechart_year_days_pgf+1 }
+ \__timechart_pgfmathsetbool:nn{\l_tmpb_bool}
+ { \__timechart_parsed_month == 1 }
+ \bool_if:NF\l_tmpb_bool
+ {
+ \__timechart_pgfmathsetbool:nn{\l_tmpb_bool}
+ { \__timechart_parsed_month == 2 }
+ \bool_if:NF\l_tmpb_bool
+ {
+ \pgfmathsetmacro{\l__timechart_month_days_pgf}
+ { \l__timechart_month_days_pgf + 1 }
+ }
+ {
+ \pgfmathsetmacro{\l__timechart_cumulative_days_pgf}
+ { \l__timechart_cumulative_days_pgf + 1 }
+ }
+ }
+ }
+ \__timechart_pgfmathsetbool:nn{\l_tmpa_bool}{
+ or(
+ \__timechart_parsed_day_pgf < 1,
+ \__timechart_parsed_day_pgf > \l__timechart_month_days_pgf,
+ )
+ }
+ \bool_if:NTF\l_tmpa_bool
+ {
+ \pgfmathsetmacro{#1}
+ {
+ #2#3
+ + \l__timechart_cumulative_days_pgf/\l__timechart_year_days_pgf
+ }
+ }
+ {
+ \pgfmathsetmacro{#1}
+ {
+ #2#3
+ + (
+ \l__timechart_cumulative_days_pgf
+ + \__timechart_parsed_day_pgf
+ )/\l__timechart_year_days_pgf
+ }
+ }
+ }
+}
+\bool_new:N\l__timechart_start_is_range_bool
+\bool_new:N\l__timechart_startmin_circa_bool
+\bool_new:N\l__timechart_startmax_circa_bool
+\bool_new:N\l__timechart_finish_is_range_bool
+\bool_new:N\l__timechart_finishmin_circa_bool
+\bool_new:N\l__timechart_finishmax_circa_bool
+\msg_new:nnn{timechart}{interval_dates_invalid}
+ { Invalid~interval~dates:~#1~to~#2 }
+\NewDocumentCommand{\__timechart_interval_user:Ommm}{ O{} m m m }
+ {
+ \group_begin:
+ \__timechart_parse_date_or_daterange:NNNNNn
+ \l__timechart_start_is_range_bool
+ \l__timechart_startmin_circa_bool\l__timechart_startmin_year
+ \l__timechart_startmax_circa_bool\l__timechart_startmax_year
+ {#2}
+ \__timechart_parse_date_or_daterange:NNNNNn
+ \l__timechart_finish_is_range_bool
+ \l__timechart_finishmin_circa_bool\l__timechart_finishmin_year
+ \l__timechart_finishmax_circa_bool\l__timechart_finishmax_year
+ {#3}
+ \__timechart_pgfmathsetbool:nn{\l_tmpa_bool}{
+ and(
+ \l__timechart_startmin_year <= \l__timechart_startmax_year,
+ and(
+ \l__timechart_startmax_year <= \l__timechart_finishmin_year,
+ \l__timechart_finishmin_year <= \l__timechart_finishmax_year
+ )
+ )
+ }
+ \bool_if:NTF\l_tmpa_bool
+ {
+ \__timechart_interval_checked:nn{#1}{#4}
+ \group_end:
+ \bool_if:NT\l__timechart_autostep_bool
+ { \__timechart_step_y_user:O }
+ }
+ {
+ \msg_error:nnnn{timechart}{interval_dates_invalid}{#2}{#3}
+ \group_end:
+ }
+ }
+\cs_new:Npn \__timechart_interval_checked:nn #1#2
+ {
+ \pgfqkeys{/timechart}{
+ #1,
+ circa~uncertainty/.get=\l__timechart_circa_uncertainty_year
+ }
+ \bool_if:NTF\l__timechart_startmin_circa_bool
+ {
+ \pgfmathsetmacro{\l__timechart_start_extreme_x}
+ { yeartox(\l__timechart_startmin_year
+ - \l__timechart_circa_uncertainty_year) }
+ }
+ {
+ \pgfmathsetmacro{\l__timechart_start_extreme_x}
+ { yeartox(\l__timechart_startmin_year) }
+ }
+ \bool_if:NTF\l__timechart_finishmax_circa_bool
+ {
+ \pgfmathsetmacro{\l__timechart_finish_extreme_x}
+ { yeartox(\l__timechart_finishmax_year
+ + \l__timechart_circa_uncertainty_year) }
+ }
+ {
+ \pgfmathsetmacro{\l__timechart_finish_extreme_x}
+ { yeartox(\l__timechart_finishmax_year) }
+ }
+ \__timechart_if_x_range_intersect_tolerance_bounds:nnT
+ {\l__timechart_start_extreme_x}{\l__timechart_finish_extreme_x}
+ { \__timechart_draw_visible_interval:nn{#1}{#2} }
+ }
+\cs_new:Npn\__timechart_draw_visible_interval:nn #1#2
+ {
+ \pgfqkeys{/timechart}{
+ ref/.get=\l__timechart_ref_text,
+ mark/.get=\l__timechart_mark_text,
+ interval~minimum~width/.get=\l__timechart_minimum_width_pgf,
+ interval~bar~color/.get=\l__timechart_bar_color,
+ interval~bar~thickness/.get=\l__timechart_bar_thickness_pgf,
+ interval~mark~color/.get=\l__timechart_mark_color,
+ interval~label~baseline/.get=\l__timechart_text_baseline_pgf,
+ interval~label~node~name/.get=\l__timechart_interval_label_node_name,
+ }
+ \pgfmathsetlengthmacro{\l__timechart_bar_half_thickness_pgf}
+ {.5*\l__timechart_bar_thickness_pgf}
+ \cs_set:Npn\l__timechart_label_text{#2}
+ \bool_if:NTF\l__timechart_startmax_circa_bool
+ {
+ \pgfmathsetmacro{\l__timechart_start_definite_x}
+ { yeartox(\l__timechart_startmax_year
+ + \l__timechart_circa_uncertainty_year) }
+ }
+ {
+ \pgfmathsetmacro{\l__timechart_start_definite_x}
+ { yeartox(\l__timechart_startmax_year) }
+ }
+ \bool_if:NTF\l__timechart_finishmin_circa_bool
+ {
+ \pgfmathsetmacro{\l__timechart_finish_definite_x}
+ { yeartox(\l__timechart_finishmin_year
+ - \l__timechart_circa_uncertainty_year) }
+ }
+ {
+ \pgfmathsetmacro{\l__timechart_finish_definite_x}
+ { yeartox(\l__timechart_finishmin_year) }
+ }
+ \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}
+ {
+ \l__timechart_start_definite_x > \l__timechart_finish_definite_x
+ }
+ \bool_if:NT\l__timechart_tmpa_bool
+ {
+ \pgfmathsetmacro{\l__timechart_start_definite_x}
+ {
+ .5*(
+ \l__timechart_start_definite_x
+ + \l__timechart_finish_definite_x
+ )
+ }
+ \pgfmathsetmacro{\l__timechart_finish_definite_x}
+ { \l__timechart_start_definite_x }
+ }
+ \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}
+ {
+ (\l__timechart_finish_extreme_x-\l__timechart_start_extreme_x)
+ < \l__timechart_minimum_width_pgf
+ }
+ \int_if_zero:nTF
+ {
+ \l__timechart_start_range_type_int
+ + \l__timechart_finish_range_type_int
+ }
+ {
+ \__timechart_pgfmathsetbool:nn{\l__timechart_tmpb_bool}
+ {
+ (
+ \l__timechart_finish_definite_x
+ - \l__timechart_start_definite_x
+ )
+ < \l__timechart_minimum_width_pgf
+ }
+ }
+ { \bool_set_false:N\l__timechart_tmpb_bool }
+ \bool_if:nT{
+ \l__timechart_tmpa_bool || \l__timechart_tmpb_bool
+ }{
+ \pgfmathsetmacro{\l__timechart_width_adjust}
+ { .5*\l__timechart_minimum_width_pgf }
+ \pgfmathsetmacro{\l__timechart_start_definite_x}
+ { \l__timechart_start_definite_x-\l__timechart_width_adjust }
+ \pgfmathsetmacro{\l__timechart_finish_definite_x}
+ { \l__timechart_finish_definite_x+\l__timechart_width_adjust }
+ \pgfmathsetmacro{\l__timechart_start_extreme_x}
+ {
+ min(
+ \l__timechart_start_extreme_x,
+ \l__timechart_start_definite_x
+ )
+ }
+ \pgfmathsetmacro{\l__timechart_finish_extreme_x}
+ {
+ max(
+ \l__timechart_finish_extreme_x,
+ \l__timechart_finish_definite_x
+ )
+ }
+ }
+ \pgfmathsetmacro{\l__timechart_start_solid_x}
+ { \l__timechart_start_definite_x }
+ \pgfmathsetmacro{\l__timechart_finish_solid_x}
+ { \l__timechart_finish_definite_x }
+ \pgftransformshift{ \pgfpoint{0}{\l__timechart_current_y} }
+ \pgfscope
+ \__timechart_interval_beyond_clip:
+ \int_case:nn {\l__timechart_start_range_type_int}
+ {
+ {0}{ \__timechart_interval_start_range_fade: }
+ {1}{ \__timechart_interval_start_range_slant: }
+ }
+ \int_case:nn {\l__timechart_finish_range_type_int}
+ {
+ {0}{ \__timechart_interval_finish_range_fade: }
+ {1}{ \__timechart_interval_finish_range_slant: }
+ }
+ \__timechart_interval_draw_solid:
+ \__timechart_interval_mark:
+ \__timechart_interval_define_bar_node:
+ \endpgfscope
+ \__timechart_interval_label:
+ }
+\cs_new:Npn\__timechart_interval_beyond_clip:
+ {
+ \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}
+ {\l__timechart_start_extreme_x<=\l__timechart_start_tolerance_x}
+ \__timechart_pgfmathsetbool:nn{\l__timechart_tmpb_bool}
+ {\l__timechart_finish_extreme_x>=\l__timechart_finish_tolerance_x}
+ \bool_if:nT{ \l__timechart_tmpa_bool || \l__timechart_tmpb_bool }
+ { \__timechart_interval_beyond_clip_aux: }
+ }
+\cs_new:Npn\__timechart_interval_beyond_clip_aux:
+ {
+ \pgfinterruptboundingbox
+ \bool_if:NTF\l__timechart_tmpb_bool
+ {
+ \pgfpathmoveto{
+ \pgfpoint
+ {\l__timechart_finish_beyond_x}
+ {\l__timechart_bar_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l__timechart_finish_beyond_x}
+ {\l__timechart_bar_half_thickness_pgf}
+ }
+ \pgfpatharc
+ {90}
+ {270}
+ {\l__timechart_beyond_x_radius_pgf
+ ~and~\l__timechart_bar_half_thickness_pgf}
+ \pgfpathlineto{
+ \pgfpoint
+ {\l__timechart_finish_beyond_x}
+ {-\l__timechart_bar_thickness_pgf}
+ }
+ }
+ {
+ \pgfpathmoveto{
+ \pgfpoint
+ {\l__timechart_right_nonclip_x}
+ {\l__timechart_bar_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l__timechart_right_nonclip_x}
+ {-\l__timechart_bar_thickness_pgf}
+ }
+ }
+ \bool_if:NTF\l__timechart_tmpa_bool
+ {
+ \pgfpathlineto{
+ \pgfpoint
+ {\l__timechart_start_beyond_x}
+ {-\l__timechart_bar_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l__timechart_start_beyond_x}
+ {-\l__timechart_bar_half_thickness_pgf}
+ }
+ \pgfpatharc
+ {-90}
+ {90}
+ {\l__timechart_beyond_x_radius_pgf
+ ~and~\l__timechart_bar_half_thickness_pgf}
+ \pgfpathlineto{
+ \pgfpoint
+ {\l__timechart_start_beyond_x}
+ {\l__timechart_bar_thickness_pgf}
+ }
+ }
+ {
+ \pgfpathlineto{
+ \pgfpoint
+ {\l__timechart_left_nonclip_x}
+ {-\l__timechart_bar_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l__timechart_left_nonclip_x}
+ {\l__timechart_bar_thickness_pgf}
+ }
+ }
+ \pgfpathclose
+ \pgfusepath{clip}
+ \endpgfinterruptboundingbox
+ }
+\pgfdeclarehorizontalshading{__timechart_fade_in_shading}{4bp}{
+ color(0bp)=(transparent!100);
+ color(1bp)=(transparent!100);
+ color(3bp)=(transparent!0);
+ color(4bp)=(transparent!0)
+}
+\pgfdeclarefading
+ {__timechart_fade_in}
+ {\pgfuseshading{__timechart_fade_in_shading}}
+\cs_new:Npn\__timechart_interval_start_range_fade:
+ {
+ \pgfmathsetlengthmacro{\l__timechart_fade_width_pgf}
+ { \l__timechart_start_solid_x-\l__timechart_start_extreme_x }
+ \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}
+ { \l__timechart_fade_width_pgf
+ > \pgfkeysvalueof{/timechart/fade~minimum~width} }
+ \bool_if:NT \l__timechart_tmpa_bool
+ {
+ \__timechart_if_x_range_intersect_tolerance_bounds:nnT
+ {\l__timechart_start_extreme_x}{\l__timechart_start_solid_x}
+ {
+ \pgfmathsetmacro{\l__timechart_fade_extra_pgf}
+ {
+ min(
+ .49*\l__timechart_fade_width_pgf,
+ \l__timechart_finish_solid_x-\l__timechart_start_solid_x
+ )
+ }
+ \pgfscope
+ \pgfpathrectanglecorners{
+ \pgfpoint
+ {\l__timechart_start_extreme_x}
+ {-\l__timechart_bar_half_thickness_pgf}
+ }{
+ \pgfpoint
+ {\l__timechart_start_solid_x+\l__timechart_fade_extra_pgf}
+ {\l__timechart_bar_half_thickness_pgf}
+ }
+ \pgfgettransform{\__timechart_transform_current}
+ \pgfsetfading{__timechart_fade_in}{
+ \pgfsettransform{\__timechart_transform_current}
+ \pgftransformshift{
+ \pgfpoint
+ {
+ .5*\l__timechart_start_extreme_x
+ +.5*\l__timechart_start_solid_x
+ }
+ {0}
+ }
+ \pgftransformxscale{
+ (\l__timechart_start_solid_x-\l__timechart_start_extreme_x)
+ /2bp
+ }
+ \pgftransformyscale{\l__timechart_bar_thickness_pgf/4bp}
+ }
+ \pgfsetfillcolor{\l__timechart_bar_color}
+ \pgfusepath{fill}
+ \endpgfscope
+ }
+ }
+ }
+\pgfdeclarehorizontalshading{__timechart_fade_out_shading}{4bp}{
+ color(0bp)=(transparent!0);
+ color(1bp)=(transparent!0);
+ color(3bp)=(transparent!100);
+ color(4bp)=(transparent!100)
+}
+\pgfdeclarefading
+ {__timechart_fade_out}
+ {\pgfuseshading{__timechart_fade_out_shading}}
+\cs_new:Npn\__timechart_interval_finish_range_fade:
+ {
+ \pgfmathsetlengthmacro{\l__timechart_fade_width_pgf}
+ { \l__timechart_finish_extreme_x-\l__timechart_finish_solid_x }
+ \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}
+ { \l__timechart_fade_width_pgf
+ > \pgfkeysvalueof{/timechart/fade~minimum~width} }
+ \bool_if:NT \l__timechart_tmpa_bool
+ {
+ \__timechart_if_x_range_intersect_tolerance_bounds:nnT
+ {\l__timechart_finish_solid_x}{\l__timechart_finish_extreme_x}
+ {
+ \pgfmathsetmacro{\l__timechart_fade_extra_pgf}
+ {
+ min(
+ .49*\l__timechart_fade_width_pgf,
+ \l__timechart_finish_solid_x-\l__timechart_start_solid_x
+ )
+ }
+ \pgfscope
+ \pgfpathrectanglecorners{
+ \pgfpoint
+ {\l__timechart_finish_solid_x-\l__timechart_fade_extra_pgf}
+ {-\l__timechart_bar_half_thickness_pgf}
+ }{
+ \pgfpoint
+ {\l__timechart_finish_extreme_x}
+ {\l__timechart_bar_half_thickness_pgf}
+ }
+ \pgfgettransform{\__timechart_transform_current}
+ \pgfsetfading{__timechart_fade_out}{
+ \pgfsettransform{\__timechart_transform_current}
+ \pgftransformshift{
+ \pgfpoint{
+ .5*\l__timechart_finish_solid_x
+ +.5*\l__timechart_finish_extreme_x
+ }
+ {0}
+ }
+ \pgftransformxscale{
+ (\l__timechart_finish_extreme_x-\l__timechart_finish_solid_x)
+ /2bp
+ }
+ \pgftransformyscale{\l__timechart_bar_thickness_pgf/4bp}
+ }
+ \pgfsetfillcolor{\l__timechart_bar_color}
+ \pgfusepath{fill}
+ \endpgfscope
+ }
+ }
+ }
+\cs_new:Npn\__timechart_interval_start_range_slant:
+ {
+ \__timechart_if_equal:nnF
+ {\l__timechart_start_extreme_x}{\l__timechart_start_solid_x}
+ {
+ \__timechart_if_x_range_intersect_tolerance_bounds:nnT
+ {\l__timechart_start_extreme_x}{\l__timechart_start_solid_x}
+ {
+ \pgfinterruptboundingbox
+ \pgfpathmoveto{
+ \pgfpoint
+ {\l__timechart_start_extreme_x}
+ {-\l__timechart_bar_half_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l__timechart_start_solid_x}
+ {\l__timechart_bar_half_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l__timechart_start_solid_x}
+ {\l__timechart_bar_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l__timechart_right_nonclip_x}
+ {\l__timechart_bar_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l__timechart_right_nonclip_x}
+ {-\l__timechart_bar_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l__timechart_start_extreme_x}
+ {-\l__timechart_bar_thickness_pgf}
+ }
+ \pgfpathclose
+ \pgfusepath{clip}
+ \endpgfinterruptboundingbox
+ \pgfmathsetmacro{\l__timechart_start_solid_x}
+ {\l__timechart_start_extreme_x}
+ }
+ }
+ }
+\cs_new:Npn\__timechart_interval_finish_range_slant:
+ {
+ \__timechart_if_equal:nnF
+ {\l__timechart_finish_solid_x}{\l__timechart_finish_extreme_x}
+ {
+ \__timechart_if_x_range_intersect_tolerance_bounds:nnT
+ {\l__timechart_finish_solid_x}{\l__timechart_finish_extreme_x}
+ {
+ \pgfinterruptboundingbox
+ \pgfpathmoveto{
+ \pgfpoint
+ {\l__timechart_finish_solid_x}
+ {-\l__timechart_bar_half_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l__timechart_finish_extreme_x}
+ {\l__timechart_bar_half_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l__timechart_finish_extreme_x}
+ {\l__timechart_bar_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l__timechart_left_nonclip_x}
+ {\l__timechart_bar_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l__timechart_left_nonclip_x}
+ {-\l__timechart_bar_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l__timechart_finish_solid_x}
+ {-\l__timechart_bar_thickness_pgf}
+ }
+ \pgfpathclose
+ \pgfusepath{clip}
+ \endpgfinterruptboundingbox
+ \pgfmathsetmacro{\l__timechart_finish_solid_x}
+ {\l__timechart_finish_extreme_x}
+ }
+ }
+ }
+\cs_new:Npn\__timechart_interval_draw_solid:
+ {
+ \__timechart_if_x_range_intersect_tolerance_bounds:nnT
+ {\l__timechart_start_solid_x}
+ {\l__timechart_finish_solid_x}
+ {
+ \pgfpathrectanglecorners{
+ \pgfpoint
+ {\l__timechart_start_solid_x}
+ {-\l__timechart_bar_half_thickness_pgf}
+ }{
+ \pgfpoint
+ {\l__timechart_finish_solid_x}
+ {\l__timechart_bar_half_thickness_pgf}
+ }
+ \pgfsetfillcolor{\l__timechart_bar_color}
+ \pgfusepath{fill}
+ }
+ }
+\msg_new:nnn{timechart}{interval_mark_outside}
+ { Attempt~to~mark~outside~interval~at~date~#1 }
+\cs_new:Npn\__timechart_interval_mark:
+ {
+ \pgfscope
+ \pgfsetstrokecolor{\l__timechart_mark_color}
+ \foreach \year in \l__timechart_mark_text
+ {
+ \pgfmathsetmacro{\l__timechart_mark_x}{yeartox(\year)}
+ \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}
+ {
+ or (
+ \l__timechart_mark_x < \l__timechart_start_extreme_x,
+ \l__timechart_mark_x > \l__timechart_finish_extreme_x
+ )
+ }
+ \bool_if:NT\l__timechart_tmpa_bool
+ { \msg_error:nne{timechart}{interval_mark_outside}{\year} }
+ \pgfpathmoveto{
+ \pgfpoint
+ {\l__timechart_mark_x}
+ {-\l__timechart_bar_half_thickness_pgf}
+ }
+ \pgfpathlineto{
+ \pgfpoint
+ {\l__timechart_mark_x}
+ {\l__timechart_bar_half_thickness_pgf}
+ }
+ \pgfusepath{draw}
+ }
+ \endpgfscope
+ }
+\cs_new:Npn\__timechart_interval_define_bar_node:
+ {
+ \__timechart_make_rectangle_node:nnnn
+ {
+ \pgfpoint
+ {\l__timechart_start_extreme_x}
+ {-\l__timechart_bar_half_thickness_pgf}
+ }{
+ \pgfpoint
+ {\l__timechart_finish_extreme_x}
+ {\l__timechart_bar_half_thickness_pgf}
+ }
+ {\pgfkeysvalueof{/timechart/interval~bar~node~name}}
+ {\c_false_bool}
+ }
+\cs_new:Npn\__timechart_interval_label:
+ {
+ \str_if_empty:NF \l__timechart_label_text
+ {
+ \pgfinterruptboundingbox
+ \int_case:nn {\l__timechart_label_pos_int}
+ {
+ {0}{ \__timechart_interval_label_left: }
+ {1}{ \__timechart_interval_label_center: }
+ {2}{ \__timechart_interval_label_right: }
+ }
+ \endpgfinterruptboundingbox
+ }
+ }
+\cs_new:Npn\__timechart_interval_label_left:
+ {
+ \__timechart_if_x_in_bounds:nT{\l__timechart_start_extreme_x}
+ {
+ \group_begin:
+ \pgftransformshift{
+ \pgfpoint
+ {\l__timechart_start_extreme_x}
+ {\l__timechart_text_baseline_pgf}
+ }
+ \node[/timechart/interval~label,anchor=base~east]
+ (\l__timechart_interval_label_node_name)
+ at (0,0)
+ {
+ \__timechart_make_ref:NN
+ \l__timechart_ref_text
+ \l__timechart_label_text
+ };
+ \group_end:
+ }
+ }
+\cs_new:Npn\__timechart_interval_label_right:
+ {
+ \__timechart_if_x_in_bounds:nT{\l__timechart_finish_extreme_x}
+ {
+ \group_begin:
+ \pgftransformshift{
+ \pgfpoint
+ {\l__timechart_finish_extreme_x}
+ {\l__timechart_text_baseline_pgf}
+ }
+ \node[/timechart/interval~label,anchor=base~west]
+ (\l__timechart_interval_label_node_name)
+ at (0,0)
+ {
+ \__timechart_make_ref:NN
+ \l__timechart_ref_text
+ \l__timechart_label_text
+ };
+ \group_end:
+ }
+ }
+\cs_new:Npn\__timechart_interval_label_center:
+ {
+ \pgfmathsetlengthmacro{\l__timechart_label_anchor_x}
+ {
+ .5*max(\l__timechart_start_definite_x,\l__timechart_start_x)
+ + .5*min(\l__timechart_finish_definite_x,\l__timechart_finish_x)
+ }
+ \group_begin:
+ \pgftransformshift{
+ \pgfpoint
+ {\l__timechart_label_anchor_x}
+ {\l__timechart_text_baseline_pgf}
+ }
+ \pgfonlayer{labelbg}
+ \node[
+ /timechart/interval~label~centered~background,
+ anchor=base
+ ]
+ at (0,0)
+ { \l__timechart_label_text };
+ \endpgfonlayer
+ \group_end:
+ \pgfscope
+ \pgfpathrectanglecorners{
+ \pgfpoint
+ {\l__timechart_start_extreme_x}
+ {-\l__timechart_bar_half_thickness_pgf}
+ }{
+ \pgfpoint
+ {\l__timechart_finish_extreme_x}
+ {\l__timechart_bar_half_thickness_pgf}
+ }
+ \pgfusepath{clip}
+ \group_begin:
+ \pgftransformshift{
+ \pgfpoint
+ {\l__timechart_label_anchor_x}
+ {\l__timechart_text_baseline_pgf}
+ }
+ \node[
+ /timechart/interval~label~centered,
+ anchor=base
+ ]
+ (\l__timechart_interval_label_node_name)
+ at (0,0)
+ {
+ \__timechart_make_ref:NN
+ \l__timechart_ref_text
+ \l__timechart_label_text
+ };
+ \group_end:
+ \endpgfscope
+ }
+\NewDocumentCommand{\__timechart_text_user:Omm}{ O{} m m }
+ {
+ \str_if_empty:nF{#3}{
+ \group_begin:
+ \pgfmathsetmacro{\l__timechart_text_x}{yeartox(#2)}
+ \__timechart_if_x_in_tolerance_bounds:nT{\l__timechart_text_x}
+ {
+ \pgfqkeys{/timechart}{
+ #1,
+ ref/.get=\l__timechart_ref_text,
+ text~node~name/.get=\l__timechart_node_name_text,
+ text~baseline/.get=\l__timechart_text_baseline_pgf,
+ }
+ \pgftransformshift{
+ \pgfpoint{0}{\l__timechart_current_y}
+ }
+ \pgfinterruptboundingbox
+ \group_begin:
+ \pgftransformshift{
+ \pgfpoint{\l__timechart_text_x}{\l__timechart_text_baseline_pgf}
+ }
+ \cs_set:Npn\l__timechart_text{#3}
+ \int_case:nn {\l__timechart_text_pos_int}
+ {
+ {0}{ \cs_set:Npn\l__timechart_node_anchor_text{base~east} }
+ {1}{ \cs_set:Npn\l__timechart_node_anchor_text{base} }
+ {2}{ \cs_set:Npn\l__timechart_node_anchor_text{base~west} }
+ }
+ \node[/timechart/text,anchor=\l__timechart_node_anchor_text]
+ (\l__timechart_node_name_text)
+ at (0,0)
+ {
+ \__timechart_make_ref:NN
+ \l__timechart_ref_text
+ \l__timechart_text
+ };
+ \group_end:
+ \endpgfinterruptboundingbox
+ }
+ \group_end:
+ }
+ \__timechart_space_user:O[#1]
+ }
+\NewDocumentCommand{\__timechart_space_user:O}{ O{} }
+ {
+ \group_begin:
+
+ \pgfqkeys{/timechart}{
+ #1,
+ interval~bar~thickness/.get=\l__timechart_bar_thickness_pgf,
+ }
+ \pgfmathsetlengthmacro{\l__timechart_bar_half_thickness_pgf}
+ { .5*\l__timechart_bar_thickness_pgf }
+ \pgftransformshift{
+ \pgfpoint{0}{\l__timechart_current_y}
+ }
+ \pgfpathmoveto{
+ \pgfpoint{0}{-\l__timechart_bar_half_thickness_pgf}
+ }
+ \pgfpathmoveto{
+ \pgfpoint{0}{\l__timechart_bar_half_thickness_pgf}
+ }
+ \pgfusepath{discard}
+ \group_end:
+ \bool_if:NT\l__timechart_autostep_bool{
+ \__timechart_step_y_user:O
+ }
+ }
+\NewDocumentCommand{\timechartlegenditem}{ O{} }
+ {
+ \__timechart_legend_aux:nn{#1}{
+ \pgfmathsetlengthmacro{\l__timechart_start_solid_x}{0}
+ \pgfmathsetlengthmacro{\l__timechart_finish_solid_x}
+ {\l__timechart_legenditem_width_pgf}
+ \__timechart_interval_draw_solid:
+ }
+ }
+\NewDocumentCommand{\timechartlegendstartrange}{ O{} }
+ {
+ \__timechart_legend_aux:nn{#1}{
+ \pgfmathsetlengthmacro{\l__timechart_start_extreme_x}{0}
+ \pgfmathsetlengthmacro{\l__timechart_start_solid_x}
+ {\pgfkeysvalueof{/timechart/legend~item~range~width}}
+ \pgfmathsetlengthmacro{\l__timechart_finish_solid_x}
+ {\l__timechart_legenditem_width_pgf}
+ \int_case:nn {\l__timechart_start_range_type_int}
+ {
+ {0}{ \__timechart_interval_start_range_fade: }
+ {1}{ \__timechart_interval_start_range_slant: }
+ }
+ \__timechart_interval_draw_solid:
+ }
+ }
+\NewDocumentCommand{\timechartlegendfinishrange}{ O{} }
+ {
+ \__timechart_legend_aux:nn{#1}{
+ \pgfmathsetlengthmacro{\l__timechart_start_solid_x}{0}
+ \pgfmathsetlengthmacro{\l__timechart_finish_solid_x}
+ {
+ \l__timechart_legenditem_width_pgf
+ -\pgfkeysvalueof{/timechart/legend~item~range~width}
+ }
+ \pgfmathsetlengthmacro{\l__timechart_finish_extreme_x}
+ {\l__timechart_legenditem_width_pgf}
+ \int_case:nn {\l__timechart_finish_range_type_int}
+ {
+ {0}{ \__timechart_interval_finish_range_fade: }
+ {1}{ \__timechart_interval_finish_range_slant: }
+ }
+ \__timechart_interval_draw_solid:
+ }
+ }
+\cs_new:Npn\__timechart_legend_aux:nn #1#2
+ {
+ \tikzpicture
+ \pgfkeys{
+ /timechart/.cd,
+ #1,
+ interval~bar~thickness/.get=\l__timechart_bar_thickness_pgf,
+ interval~bar~color/.get=\l__timechart_bar_color,
+ interval~minimum~width/.get=\l__timechart_minimum_width_pgf,
+ beyond~length/.get=\l__timechart_beyond_length_pgf,
+ legend~item~width/.get=\l__timechart_legenditem_width_pgf,
+ }
+ \pgfmathsetlengthmacro{\l__timechart_bar_half_thickness_pgf}
+ {.5*\l__timechart_bar_thickness_pgf}
+ \pgfmathsetmacro{\l__timechart_start_x}{0}
+ \pgfmathsetmacro{\l__timechart_finish_x}
+ {\l__timechart_legenditem_width_pgf}
+ \pgfmathsetlengthmacro{\l__timechart_start_beyond_x}
+ {\l__timechart_start_x-\l__timechart_beyond_length_pgf}
+ \pgfmathsetlengthmacro{\l__timechart_finish_beyond_x}
+ {\l__timechart_finish_x+\l__timechart_beyond_length_pgf}
+ \pgfmathsetmacro{\l__timechart_current_y}{0}
+ \pgfmathsetmacro{\l__timechart_start_tolerance_x}
+ {\l__timechart_start_x-10mm}
+ \pgfmathsetmacro{\l__timechart_finish_tolerance_x}
+ {\l__timechart_finish_x+10mm}
+ #2
+ \pgfresetboundingbox
+ \pgfmoveto{
+ \pgfpoint{0}{-\l__timechart_bar_half_thickness_pgf}
+ }
+ \pgfmoveto{
+ \pgfpoint
+ {\l__timechart_legenditem_width_pgf}
+ {\l__timechart_bar_half_thickness_pgf}
+ }
+ \endtikzpicture%
+ }
diff --git a/Master/tlpkg/bin/tlpkg-ctan-check b/Master/tlpkg/bin/tlpkg-ctan-check
index 323561b7801..e6a15e38bea 100755
--- a/Master/tlpkg/bin/tlpkg-ctan-check
+++ b/Master/tlpkg/bin/tlpkg-ctan-check
@@ -878,7 +878,7 @@ my @TLP_working = qw(
tikzpackets tikzpagenodes tikzpeople tikzpfeile tikzpingus tikzposter
tikzquads tikzquests tikzscale tikzsymbols
tikztosvg tikzviolinplots tile-graphic tilings
- timbreicmc timeop times timetable timing-diagrams
+ timbreicmc timechart timeop times timetable timing-diagrams
tinos tipa tipa-de tipauni tipfr
tiscreen titlecaps titlefoot titlepages titlepic titleref titlesec titling
tkz-base tkz-berge tkz-bernoulli tkz-doc tkz-elements tkz-euclide
diff --git a/Master/tlpkg/tlpsrc/collection-pictures.tlpsrc b/Master/tlpkg/tlpsrc/collection-pictures.tlpsrc
index 2d0e057812e..abe6c620ee4 100644
--- a/Master/tlpkg/tlpsrc/collection-pictures.tlpsrc
+++ b/Master/tlpkg/tlpsrc/collection-pictures.tlpsrc
@@ -240,6 +240,7 @@ depend tikztosvg
depend tikzviolinplots
depend tile-graphic
depend tilings
+depend timechart
depend timing-diagrams
depend tipfr
depend tkz-base
diff --git a/Master/tlpkg/tlpsrc/timechart.tlpsrc b/Master/tlpkg/tlpsrc/timechart.tlpsrc
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Master/tlpkg/tlpsrc/timechart.tlpsrc