令人困惑的代码

令人困惑的代码

我对一些绝地大师代码感到困惑。这个令人印象深刻的日历代码应该很容易掌握。我可以通过反复试验来操作它,但我想进入下一个层次并理解它。显然,LaTeX3 / expl3 代码很长,可能太多了,无法用一个答案来处理,但对以下问题和对齐中使用的 pgf 代码的解释将是一个可以接受的答案。

以下是哪些:

  • \pgfmathsetlength{\pgf@ya}{\tikz@lib@cal@yshift}

  • \pgfmathsetlength\pgf@xa{\tikz@lib@cal@xshift}

为什么使用这个代码来代替节点的最小高度和最小宽度:

  • \pgfkeys{/tikz/day xshift=\cellwidth+2mm+2mm} % Set width of days
  • \pgfkeys{/tikz/day yshift=\cellheight+2mm+2mm} % Set height of days

为什么会有:

  • \pgfkeys{/tikz/inner sep = 0pt}

然而,日代码节点包含inner sep=1mm且添加\pgfkeys{/tikz/outer sep = 0pt}没有影响。

日历上方的垂直间距由什么定义?如果我有多行日期标签(日期名称有多种语言)怎么办?如何确保月份名称和日历不重叠?

令人困惑的代码

我添加了注释,所以如果它们不正确,你会知道原因。这两个代码块似乎让魔法发生了:

%% Adapted from https://tex.stackexchange.com/a/10199/4771
\makeatletter%
\tikzoption{day headings}{\tikzstyle{day heading}=[#1]}
\tikzstyle{day heading}=[]
\tikzstyle{day letter headings}=[
    execute before day scope={ \ifdate{day of month=1}{%
      \pgfmathsetlength{\pgf@ya}{\tikz@lib@cal@yshift}% 
      \pgfmathsetlength\pgf@xa{\tikz@lib@cal@xshift}%tikz@lib@cal@width effectively a multiple of day xshift
      \pgftransformyshift{-\pgf@ya}
      \foreach \d/\l in {0/Mantig,1/Dienstig,2/Mittwoch,3/Pfingstig,% Translate weekday names (start of week: Monday)
                         4/Freitig,5/Samstig,6/Sunntig} {
        \pgf@xa=\d\pgf@xa%
        \pgftransformxshift{\pgf@xa-\cellwidth/2}% Spread weekdays horizontally across calendar
        \pgftransformyshift{\pgf@ya}% Drop other weeks vertically so that first week is on first line.
        \node[above=-0.5ex,day heading]{\l};%
      }
    }{}%
  }%
]
\makeatother%

或者

\makeatletter
\tikzstyle{month label above centered}=[% Formatting of Month Name Location on Page
  execute before day scope={%
    \ifdate{day of month=1}{% Alignment of first day
      {
        \pgfmathsetlength{\pgf@xa}{\tikz@lib@cal@xshift}% Grab total width
        \pgf@xb=\tikz@lib@cal@width\pgf@xa% Set @xb to total width 
        \advance\pgf@xb by-\pgf@xa% Subtract full width from xb?
        \pgf@xb=.5\pgf@xb% Get half of xb?
        \pgftransformxshift{\pgf@xb}% 
        \pgftransformxshift{-\cellwidth/2}%
        \pgfmathsetlength{\pgf@y}{\tikz@lib@cal@yshift}%
        \pgftransformyshift{0.333\pgf@y}
        \tikzmonthcode%
      }
    }{}},
  every month/.append style={anchor=base}
]
\makeatother

/tikz/day 代码(稍微更容易理解)

这项合身业务似乎不那么优雅。

\pgfkeys{/tikz/day code =
  {
    \node (lower right) at (0,0) [above left,font=\Huge] {\tikzdaytext}; % Date label on each day
    \node (upper left) at (-\cellwidth,\cellheight) [below right,align=left,text width=\cellwidth-\pgflinewidth,font=\tiny,black] {\showtext}; % Adds week numbers
    \node (lower left) at (-\cellwidth,0) {};
    \node[draw, % day node
          fit=(lower right) (upper left) (lower left),
          inner sep=1mm,outer sep=0pt] {};
  }
}

如果我将所有日代码节点替换为这个节点:

\node[draw,minimum width=\cellwidth,minimum height=\cellheight,outer sep=0pt,inner sep=0pt] {}; % Day Box

这些框似乎水平移动了一些空间。这是为什么?我怎样才能使节点之间的距离为 0pt,以便日历看起来像:

在此处输入图片描述

完整代码

https://tex.stackexchange.com/a/170474/13552

其他相关链接

答案1

添加日期标签 ( day letter headings)

为了实现这一点,我们需要

  • 日宽 ( day xshift)
  • 日照高度 ( day yshift)

循环对于这个来说是有意义的

\foreach \d/\l in {0/Monday,1/Tuesday,2/Wednesday,3/Thursday,
                4/Friday,5/Saturday,6/Sunday} {---Create node---}
                

该节点可能看起来像这样:

    \node[above=-0.5ex,day heading,text width=\cellwidth,align=center]{\l};
    

(我将其替换above=-0.5exanchor=south

存储\d0 到 6。我们将其用作每天的多个倍数。例如,0 乘以一天的宽度等于零,换句话说,不要移动那一天。下一周的第二天(本例中为星期二)不应与星期一重叠,因此它移动了 1 个长度(一天的宽度)。第三天(星期三)移动了,依此类推2 * "width of day"

防止日期标签水平重叠

我们使用 PGF 相对坐标变换 (p. 1046) 调整每个节点的位置。

\pgf@ya和是什么\pgf@xa

这些是临时的 TeX 维度(第 751 页)。它们可用于存储节点放置计算中使用的数字。我们可以使用这些变量来存储实现上述日对齐计算的方程的全局“日宽度”和“日高度”变量。

您可以使用以下语法\pgf@ya进行设置:(维度是值+单位,例如)\pgf@xa\pgfmathsetlength{\pgf@ya}{---DIMENSION---}3ex

幕后:TikZ 日历库(tikzlibrarycalendar.code.tex)设置了以下维度:

\def\tikz@lib@cal@yshift{3ex}
\def\tikz@lib@cal@xshift{3.5ex}

xshift将节点延伸到原点的左侧。

day xshiftday yshift分别重新定义这些值。(\tikzoption{day xshift}{\def\tikz@lib@cal@xshift{#1}}& \tikzoption{day yshift}{\def\tikz@lib@cal@yshift{#1}}

改变日子

为了在循环中移动日期标签节点,我们首先需要获取“高度宽度”和“日期宽度”变量并将它们分配给,\pgf@ya以便\pgf@xa我们可以对它们进行一些算术运算。

\pgfmathsetlength{\pgf@ya}{\tikz@lib@cal@yshift}
\pgfmathsetlength{\pgf@xa}{\tikz@lib@cal@xshift}

下面只是将\d上面循环中的值乘以“日期宽度”变量,以实现“应用日期标签”部分中解释的所有内容。

\pgf@xa=\d\pgf@xa

下一步是将循环中一周中每一天的节点向右移动。首先,您可能会想到使用以下代码:

\pgftransformxshift{\pgf@xa}

请记住,每一天的宽度都是从一天的原点向左延伸的。这意味着节点将与每一天的原点对齐(右侧不对齐),而不是在一天的中间。

%\pgftransformxshift{originshift - width of the day/2}
\pgftransformxshift{\pgf@xa-\tikz@lib@cal@xshift/2}

除非出于某些原因,TikZ 无法使用 进行算术运算\tikz@lib@cal@xshift,所以作者决定这样做:

  • 初始化长度(\newlength{\cellwidth}并设置\setlength{\cellwidth}{\dimexpr\textwidth/7}
  • 分配\tikz@lib@cal@xshift给该长度\pgfkeys{/tikz/day xshift=\cellwidth} % Set width of days
  • 使用该长度进行计算

就像这样:

\pgftransformxshift{\pgf@xa-\cellwidth/2}

的值\cellwidth也用于设置text width每个节点的。

防止日期垂直重叠

相应的垂直移位设置如下:

\pgfkeys{/tikz/day yshift=\cellheight} % Set height of days
\newlength{\cellheight}
\setlength{\cellheight}{26mm}

每个节点将与调用它的日期的原点垂直对齐(每月应调用一次 - 每月的第一天)

一个解决方案就是将标签移动到一天的原点(第 1 天)上方一个“一天的高度”。

\pgftransformyshift{\pgf@ya}

您可能和我一样想知道为什么不能直接使用calc库并执行anchor=south如下操作:\node[anchor=south] at (\pgf@xa-\cellwidth/2,0) + (0,1cm) {\l};。事实是,我还没有尝试过。我只是想在探索这种可能性之前先了解给出的代码。

完成事情

日期标签每个月只能触发一次,因此可以使用 if/then 语句将其与第 1 天挂钩。

\ifdate{day of month=1}{---AFOREMENTIONED STUFF---}

我们希望它在整个日历范围内执行(我认为),因此您需要将所有这些都包装起来:

execute before day scope={---AFOREMENTIONED STUFF---}

然后我们必须使其成为一种可以在命令中调用的样式\calendar,因此我们将所有内容包装在一种tikz样式中:

\tikzstyle{day letter headings}=[---AFOREMENTIONED STUFF---]

最后,所有这些都需要用以下内容包装,因为 TikZ 使用符号@作为其宏。

\makeatletter
\makeatother

排版日历(\calendar[])

要使用日历命令,请使用day letter headings

day code可以自定义日期的绘制方式,需要使用它来确保对齐。我还在学习这个。

幕后:TikZ 日历库(tikzlibrarycalendar.code.tex)设置如下:

\tikzoption{day code}{\def\tikzdaycode{#1}}


\calendar[
    dates=2016-01-01 to 2016-01-last,
    week list,
    day headings={font=\footnotesize},
    day letter headings,
    day code={
        \node [anchor=base east,draw,minimum width=\cellwidth,minimum height=\cellheight] (daybox) {}; % Draw the Day Boxes Using anchor=base east (causes the xshift to move left)
        \node[name=\pgfcalendarsuggestedname,every day,anchor=north east,font=\huge] at (daybox.north east) {\tikzdaytext}; % Date Number
        \node (upper left) at (-\cellwidth,\cellheight) [anchor=north west,align=left,text width=\cellwidth-\pgflinewidth,font=\tiny,black]  at (daybox.north west){\showtext}; % Week Day
        },
]

日期标题的参数将被传递给样式day heading,供日期标签节点使用。

其他的东西

every day日期数字节点中的键是什么?

幕后:TikZ 日历库(tikzlibrarycalendar.code.tex)设置如下:

\tikzoption{days}{\tikzstyle{every day}+=[#1]}
\tikzstyle{every day}=[anchor=base east]

关键是什么name=\pgfcalendarsuggestedname


添加月份标签 ( month label above centered)

---回答未完成---更多内容即将发布……

相关内容