我想向pgfgantt
包中添加一个命令,该命令在指定日期绘制垂直线(例如今天的线)。以下是我想要得到的(绿线):
因此我查看了pgfgantt.sty
今天的线是如何绘制的,并将这段代码添加到pgfgantt.sty
文件中:
\newcommand\drawverticalline[1]{%
\begingroup%
\begin{pgfinterruptboundingbox}%
\begin{scope}
\gtt@tsstojulian{#2}{\gtt@today@slot}
\gtt@juliantotimeslot{\gtt@today@slot}{\gtt@today@slot}%
\pgfmathsetmacro\x@mid{%
(\gtt@today@slot - 1 + \ganttvalueof{today offset})%
* \ganttvalueof{x unit}%
}%
\draw [/pgfgantt/today rule]
(\x@mid pt, \y@upper pt) -- (\x@mid pt, \y@lower pt)
node [/pgfgantt/today label node] {\ganttvalueof{today label}};%
\end{scope}
\end{pgfinterruptboundingbox}%
\endgroup%
}
现在通常我可以使用这样的命令:\drawverticalline{2014-05-07}
但是当我执行此操作时出现此错误:
! Package PGF Math Error: Unknown function `pt' (in 'pt').
错误来自此代码:
\pgfmathsetmacro\x@mid{%
(\gtt@today@slot - 1 + \ganttvalueof{today offset})%
* \ganttvalueof{x unit}%
}%
它上面没有pt
。所以我决定注释掉它并\x@mid
用常量 (5) 替换它,但现在我得到了这个错误:
! Undefined control sequence.
为什么我会收到此错误?该命令已定义!
pgfgantt
以下是绘制今天线的代码:
\def\@tempa{none}%
\edef\@tempb{\ganttvalueof{today}}%
\ifx\@tempa\@tempb\else%
\pgfmathsetmacro\x@mid{%
(\gtt@today@slot - 1 + \ganttvalueof{today offset})%
* \ganttvalueof{x unit}%
}%
\draw [/pgfgantt/today rule]
(\x@mid pt, \y@upper pt) -- (\x@mid pt, \y@lower pt)
node [/pgfgantt/today label node] {\ganttvalueof{today label}};%
\fi%
平均能量损失
\documentclass{article}
\usepackage[frenchb]{babel}
\usepackage{pgfgantt}
\usetikzlibrary{shadows}
\begin{document}
\begin{tikzpicture} % optional
\begin{ganttchart}[x unit=1.8mm,
y unit chart=0.87cm,
time slot format=isodate,
vgrid=*{5}{dotted},
]
{2014-04-14}{2014-07-11}
\gantttitlecalendar{month=name} \\
\ganttbar[progress=100]{title1}{2014-04-14}{2014-04-15} \\
\ganttbar[progress=100]{title2}{2014-04-15}{2014-04-17} \\
\drawverticalline{2014-05-07}
\end{ganttchart}
\end{tikzpicture}
\end{document}
答案1
更新答案
多年后,为了回应 tdgunes 对这个答案的评论,我联系了该软件包的作者,询问这个问题,我很高兴地说,他从 2018 年 1 月 11 日发布到 CTAN 的 v5.0 版本开始,将这个功能添加到了软件包中!
本节中的代码展示了如何使用包中实现的功能。我还在下面保留了原始答案,因为我觉得它在解释必要时修改分布式包的最佳实践方面很有价值。
软件包作者添加了一个\ganttvrule
宏,使用方式如下:
\ganttvrule[<options>]{<label-text>}{<time-slot-spec>}
可选参数可以包含样式选项。可用选项在包装手册。
此宏仍必须使用后甘特图的所有行均已定义。
\documentclass{standalone}
\usepackage{pgfgantt}
\begin{document}
\begin{tikzpicture}
\begin{ganttchart}[
time slot format=isodate,
vgrid=*{5}{dotted},
today={2014-04-14},
]{2014-04-14}{2014-05-11}
\gantttitlecalendar{month=name} \\
\ganttbar[progress=100]{title1}{2014-04-14}{2014-04-15} \\
%\ganttvrule{Fail!}{2014-04-24} % must be placed at the end of the ganttchart environment
\ganttbar[progress=100]{title2}{2014-04-15}{2014-04-17} \\
\ganttbar[progress=50]{testing}{2014-04-17}{2014-04-18}
\ganttvrule{Test 1}{2014-05-07}
\ganttvrule{Test 2}{2014-04-30}
\ganttvrule{Test 3}{2014-05-10}
\ganttvrule{Success}{2014-04-24} % works at the very end
\ganttset{vrule/.append style={blue}} % change the style
\ganttvrule{Blue!}{2014-04-28} % check for changed style
\ganttvrule[vrule/.append style={red, ultra thick}]{Red!}{2014-05-03} % alternate styling method
\end{ganttchart}
\end{tikzpicture}
\end{document}
原始答案(已被pgfgantt
v5.0 取代,发布于 2018-01-11)
正如评论中多次提到的那样,直接修改由某些包管理系统(无论是tlmgr
、MikTeX 包管理器,还是任何其他系统上的包管理器,[RPM、、pacman
等npm
])控制的任何文件是一种非常糟糕的想法.™ 除了许可问题之外,即使包管理器没有感到困惑,任何修改将要更新后会丢失,使用这些修改的文档将要被打破。
正确的做法是使用您自己的本地自定义扩展包。我在这里说明了一种方法:
- 创建您自己的包
pgfgantt-custom
(pgfgantt-custom.sty
),加载 TeX 发行版的当前pgfgantt
包并从那里添加/修改命令。 - 将此文件放在
texmf-local
LaTeX 可以找到的位置*。
* 参考我应该将自己的.sty
文件放在哪里才能使它们可供我的所有.tex
文件使用?了解每个主要 TeX 发行版的此过程的完整细节。
因此,请pgfgantt-custom.sty
使用以下内容进行创建:
\ProvidesPackage{pgfgantt-custom}[2015/01/10 My local customizations to the pgfgantt package] % name, date, and description of the package
\RequirePackage{pgfgantt} % load the package we're modifying
% some new keys for the style of our "anyday" marker lines
\@gtt@keydef{anyday}{none}
\@gtt@keydef{anyday offset}{1}
\@gtt@stylekeydef{anyday rule}{dashed, line width=1pt}
\@gtt@keydef{anyday label font}{\normalfont}
\@gtt@stylekeydef{anyday label node}{%
anchor=north, font=\ganttvalueof{anyday label font}%
}
\newcount\gtt@anyday@slot
\newcommand\drawverticalline[2]{%
\gtt@tsstojulian{#1}{\gtt@anyday@slot}%
\gtt@juliantotimeslot{\gtt@anyday@slot}{\gtt@anyday@slot}%
\pgfmathsetmacro\y@upper{%
\gtt@lasttitleline * \ganttvalueof{y unit title}%
}%
\pgfmathsetmacro\y@lower{%
\gtt@lasttitleline * \ganttvalueof{y unit title}%
+ (\gtt@currentline - \gtt@lasttitleline - 1)%
* \ganttvalueof{y unit chart}%
}%
\pgfmathsetmacro\x@mid{%
(\gtt@anyday@slot - 1 + \ganttvalueof{anyday offset})%
* \ganttvalueof{x unit}%
}%
\draw [/pgfgantt/anyday rule]
(\x@mid pt, \y@upper pt) -- (\x@mid pt, \y@lower pt)
node [/pgfgantt/anyday label node] {#2};%
}
代码细目如下:
\@gtt@keydef
/\@gtt@stylekeydef
命令:
我创建了一些类似于今日标记样式选项的键,因此如果需要,可以独立于今日标记样式进行更改。默认值与今日标记样式相同。
\newcount\gtt@anyday@slot
这定义了计数器,其中根据pgfgantt
内部宏来操作标记的日期以处理不同的日期格式。
现在,主要事件:\drawverticalline
接受 2 个参数;第一个是标记的日期,第二个是标记文本(可能为空)。
定义的前两行只是以与 相同的方式处理日期today
。现在到了您遇到麻烦的部分。您无法访问\y@upper
、\y@lower
和 ,\x@mid
因为它们是在单独的范围内定义的。所以我们必须在这个新命令的范围内重新定义它们。
这样做的副作用是,我们不知道甘特图中是否还有更多行需要绘制(标记today
由 内部最后绘制pgfgantt
),并且无法将命令推迟到环境末尾。因此,必须在环境末尾(绘制完所有 s 之后)ganttchart
使用我们的新宏。\drawverticalline
ganttchart
\ganttbar
剩下的就是绘制标记,用适当的样式键替换,节点文本作为#2
第二个参数。
使用示例
\documentclass{standalone}
\usepackage{pgfgantt-custom}
\begin{document}
\begin{tikzpicture}
\begin{ganttchart}[
time slot format=isodate,
vgrid=*{5}{dotted},
today={2014-04-14},
]{2014-04-14}{2014-05-11}
\gantttitlecalendar{month=name} \\
\ganttbar[progress=100]{title1}{2014-04-14}{2014-04-15} \\
%\drawverticalline{2014-04-24}{Fail} must be placed at the end of the ganttchart environment
\ganttbar[progress=100]{title2}{2014-04-15}{2014-04-17} \\
\ganttbar[progress=50]{testing}{2014-04-17}{2014-04-18}
\drawverticalline{2014-05-07}{Test 1}
\drawverticalline{2014-04-30}{Test 2}
\drawverticalline{2014-05-10}{Test 3}
\drawverticalline{2014-04-24}{Success} % works at the very end
\ganttset{anyday rule/.append style={blue}} % change the style
\drawverticalline{2014-04-28}{Blue!} % check for changed style
\end{ganttchart}
\end{tikzpicture}
\end{document}
输出:
您可以取消注释该\drawverticalline{2014-04-24}{Fail}
行以查看当我们尚不知道甘特图中的总行数时会发生什么。