
Я пытаюсь создать что-то похожее на фрагмент блокнотной бумаги в tcolorbox
среде, рисуя горизонтальные линии и вертикальную линию. Проблема, с которой я сталкиваюсь, заключается в том, что я не знаю, как определить верхний предел количества линий, если я не закодирую их жестко. Это вызывает проблему, когда цветной блок разрывается на странице, а блоки имеют разную высоту. Линии рисуются снизу блока. Если блок имеет две разные длины, то сложно сделать так, чтобы линии выглядели так, будто они были равномерно распределены сверху.
Как мне получить высоту tcolorbox? Я пробовал\tcbвысотатекстано использование этого для вертикальной линии даже не работает. Кроме того, я не знаю, как написать цикл с разделением событий. Предпочтительно, чтобы линии были размером с межстрочный интервал документа, но это не обязательно. После получения высоты мне нужно, чтобы рисование линии начиналось с верха поля, а не с низа.
\documentclass[letterpaper, 10pt]{article}
\usepackage[skins, raster, breakable]{tcolorbox}
\usepackage{tikz}
\usetikzlibrary{decorations,decorations.markings,optics}
\usepackage[english]{babel}
\usepackage{blindtext}
\begin{document}
\pagestyle{empty}
\tikzset{normal lines/.style={gray, very thin}}
\tcbset{paper/.style={enhanced,colback=green!10,colframe=green!65!black,width=\textwidth,breakable,left=1.3in,
overlay={
\begin{tcbclipframe}
\foreach \y in {0.25, 0.5,...,10.25}
\draw[style=normal lines](0,\y in) -- (8.5in, \y in);
\draw[style=normal lines] (1.25in,0)--(1.25in, 3in);
\end{tcbclipframe}
}
}
}
\blindtext[5]
\begin{tcolorbox}[paper]
\blindtext[2]
\end{tcolorbox}
\end{document}
решение1
Я предлагаю сделать это с помощью tcolorbox
подскина enhanced
(который подходит для бьющихся коробок). В коде, приведенном ниже, мы определяем скин с именем, paper
который является производным от enhanced
, и заставляем tcolorbox
стиль paper
выполняться skin=paper
(среди прочего, например, устанавливать желаемые цвета рамки и фона). Мы также определяем три подскина paperfirst
, papermiddle
и paperlast
соответственно производные от enhancedfirst
, enhancedmiddle
и enhancedlast
; они позволяют нам придать желаемый вид коробке во всех случаях (неразбитый, сломанный сверху и не сломанный снизу, сломанный снизу и не сломанный сверху, сломанный и сверху, и снизу).
Так как enhanced
скин задает /tcb/geometry nodes=true
, он определяет узлы с именами frame
, interior
, segmentation
, и title
, которые позволяют нам получить доступ к интересным точкам tcolorbox
. Здесь можно использовать или frame
для interior
вычисления высоты блока (они не дают точно такого же результата, как /tcb/leftrule
, /tcb/toprule
, /tcb/rightrule
и /tcb/bottomrule
принадлежат , frame
но не interior
). В paper
скине, определенном ниже, мы используем interior
узел для вычисления количества горизонтальных линий для рисования и подходящих комбинаций frame
и interior
для протяженности вертикальной линии в зависимости от того, разорван ли блок сверху и разорван ли он снизу. Расчет количества горизонтальных линий для рисования можно выполнить с помощью \pgfmathtruncatemacro
, например (это также можно сделать с помощью int()
внутри \pgfmathsetmacro
вызова).
Примечание: Я внес небольшое изменение в ваш normal lines
стиль. Он line width
больше, но правила нарисованы с помощью opacity=...
, как определено в /tcb/paper/rule opacity
. Этот рисунок сделан внутри , transparency group
цель которого — убедиться, что пересечения правил не темнее других мест в правилах.
\documentclass{article}
\usepackage{tcolorbox}
\tcbuselibrary{breakable, skins}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{lipsum}
\makeatletter
\tikzset{normal lines/.style={gray, thin}}
\tcbset{paper/left margin/.initial=1.25in,
paper/line spacing/.initial=1cm,
paper/rule opacity/.initial=0.4,
paper/.style={
skin=paper, colback=green!10, colframe=green!65!black,
breakable, left=1.3in,
}
}
\newif\if@paper@broken@top
\newif\if@paper@broken@bottom
\pgfkeys{/tcb/paper/broken top/.is if=@paper@broken@top,
/tcb/paper/broken bottom/.is if=@paper@broken@bottom
}
% The various parts don't have the same skin when a box is broken. This also
% influences where we want the vertical rule to extend to.
\tcbsubskin{paperfirst}{enhancedfirst}{
paper/broken top=false, paper/broken bottom=true
}
\tcbsubskin{papermiddle}{enhancedmiddle}{
paper/broken top=true, paper/broken bottom=true
}
\tcbsubskin{paperlast}{enhancedlast}{
paper/broken top=true, paper/broken bottom=false
}
\tcbsubskin{paper}{enhanced}{
skin first=paperfirst, skin middle=papermiddle, skin last=paperlast,
paper/broken top=false, paper/broken bottom=false,
overlay={
\begin{tcbclipinterior}
\begin{scope}[opacity=\pgfkeysvalueof{/tcb/paper/rule opacity},
transparency group]
% Make sure the vertical rule extends exactly as far as we want, depending
% on where the box is broken.
\if@paper@broken@top
\coordinate (top for vert rule) at (frame.north west);
\else
\coordinate (top for vert rule) at (interior.north west);
\fi
%
\if@paper@broken@bottom
\coordinate (bottom for vert rule) at (frame.south west);
\else
\coordinate (bottom for vert rule) at (interior.south west);
\fi
%
\draw[transform canvas={xshift=\pgfkeysvalueof{/tcb/paper/left margin}},
style=normal lines] (top for vert rule) -- (bottom for vert rule);
%
\path let \p1=($(interior.north)-(interior.south)$) in
\pgfextra{%
\pgfmathtruncatemacro{\tmp}{veclen(\p1) /
\pgfkeysvalueof{/tcb/paper/line spacing}}%
\xdef\paperskin@nblines{\tmp}};
\foreach \i in {1,..., \paperskin@nblines} {
\pgfmathsetlengthmacro{\paperskin@shift}{
-\i*\pgfkeysvalueof{/tcb/paper/line spacing}}
\draw[style=normal lines]
([yshift=\paperskin@shift]interior.north west) --
([yshift=\paperskin@shift]interior.north east);
}
\end{scope}
\end{tcbclipinterior}
},
}
\makeatother
\pagestyle{empty}
\begin{document}
\lipsum[1]
\begin{tcolorbox}[paper]
\lipsum[2]
\end{tcolorbox}
\lipsum[3]
\begin{tcolorbox}[paper]
\lipsum[4-5]
\end{tcolorbox}
\end{document}
Неразбитая коробка:
first
часть сломанной коробки:
last
часть сломанной коробки:
Часть middle
(сломанная сверху)и(внизу) также будет нарисовано правильно, с вертикальной линейкой, простирающейся как раз настолько, насколько это необходимо:
Примечание: следующая часть моего кода:
\tcbsubskin{paper}{enhanced}{
...
overlay={
...
% Make sure the vertical rule extends exactly as far as we want, depending
% on where the box is broken.
\if@paper@broken@top
\coordinate (top for vert rule) at (frame.north west);
\else
\coordinate (top for vert rule) at (interior.north west);
\fi
%
\if@paper@broken@bottom
\coordinate (bottom for vert rule) at (frame.south west);
\else
\coordinate (bottom for vert rule) at (interior.south west);
\fi
можно записать и так:
\newcommand*{\paper@defcoord}[3]{
\coordinate (#2 for vert rule) at (#1.#3 west);
}
\tcbsubskin{paper}{enhanced}{
...
overlay={
...
% Make sure the vertical rule extends exactly as far as we want, depending
% on where the box is broken.
\edef\tmp{\if@paper@broken@top frame\else interior\fi}
\expandafter\paper@defcoord\expandafter{\tmp}{top}{north}
\edef\tmp{\if@paper@broken@bottom frame\else interior\fi}
\expandafter\paper@defcoord\expandafter{\tmp}{bottom}{south}
но первый способ кажется гораздо более простым для чтения, поэтому я решил оставить его в полном примере.
решение2
Вместо сетки, нарисованной от руки, можно использовать TikZ
сетку с большим xstep
. Следующий код показывает возможное решение (вдохновленное примером в tcolorbox
документации, стр. 131). Это не решает проблему с разбитыми ящиками и корректировкой вертикального положения.
\documentclass{article}
\usepackage[most]{tcolorbox}
\usepackage{lmodern}
\usepackage{blindtext}
\newtcolorbox{notebook}{
enhanced,
breakable,
colback=green!10,
colframe=green!65!black,
left=1.3in,
underlay={%
\begin{tcbclipinterior}
\draw[help lines, ystep=\baselineskip, xstep=\linewidth,
shift={(interior.north west)}](interior.south west) grid (interior.north east);
\draw[help lines] ([xshift=1.25in]interior.north west)--
([xshift=1.25in]interior.south west);
\end{tcbclipinterior}}
}
\begin{document}
\blindtext[1]
\begin{notebook}
\blindtext[3]
\end{notebook}
\end{document}