我正在尝试使用 tikz 为项目制作可重复使用的元素,但无法整齐地对齐元素。稍后我将从 CSV 文件中为这些元素提供内容,但一次只做一步。
它是一个外框,其垂直中心包含一个 25x25mm 的图像框,旁边有 3 个节点,包含标题文本、描述文本和可变大小的表格。外框和图像框都在控制范围内,但正确定位其他三个节点给我带来了一些麻烦。
我希望 ProdHeader 节点、ProdDesc 节点和 ProdTable 的集体边界框的垂直中心与图像框的垂直中心对齐。
我尝试了几种不同的方法
- 将它们放在矩阵中。虽然这确实有助于定位,但矩阵与嵌套表配合得并不好。
- 将它们作为 \tikz\node 嵌套在主节点内也可以正确定位它们,但是会使它们继承不应该继承的属性。
- 将它们放置在表格环境 (tabular、tabularx、NiceTabular、tblr) 中,再次,问题主要在于嵌套表格不能很好地播放。
- 当前尝试正在尝试适应,但由于适应需要首先放置节点,因此这并没有真正的帮助。
最基本的解决方案是将 ProdDesc.west(中间元素)锚定在 imagebox.east 旁边,但这会使外部框向下延伸的距离比向上延伸的距离更远,看起来很糟糕,如下所示:
我的代码:
\documentclass{article}
\usepackage{tikz}
\usepackage{tabularray}
\usetikzlibrary{positioning,fit,backgrounds,calc}
\begin{document}
\begin{tikzpicture} [remember picture, overlay]
%coordinate for use in fitting the outerbox correctly; box extended beyond page is intentional
\node [anchor=west] (start) at (current page.west){};
%imagebox placement, works as intended
\node[draw, text width=25mm, minimum height=25mm, anchor=west, baseline=center](imagebox) at ($(start)+(12mm,0)$) {\includegraphics[keepaspectratio,height=25mm, width=25mm,clip]{example-image}};
%placing ProdDesc first, such that ProdHeader and ProdTable can be placed relatively to it.
\node[text width=80mm, minimum height=5mm, right= 2mm of imagebox.east] (ProdDesc){long\\description\\for\\emphasis\\of\\a\\real\\situation\\with\\lots\\of\\text};
\node[text width=80mm, above= 2mm of ProdDesc.north] (ProdHeader){\huge{Header}};
\node [below=2mm of ProdDesc.south](ProdTable){
\begin{tblr}
{width=80mm,colspec={*{3}{X}}}
test & test & text \\
test & test & test \\
test & test & test \\
\end{tblr}};
%making the fit boxes
\begin{scope}[on background layer]
\node [inner ysep=0, minimum width=80mm,draw=blue, dashed, fit = (ProdHeader) (ProdDesc) (ProdTable)](CompBox) {};
\node [inner ysep =2mm, minimum width= 130mm, draw, fit= (start) (imagebox) (CompBox)] (outerbox){};
\end{scope}
\end{tikzpicture}
\end{document}
是否有一种优雅的方法可以将一组节点分组或围绕一组节点制作一个边界框以便放置?由于此元素将多次重复使用,因此我依赖于相对定位。
答案1
您可能可以按不同的顺序放置节点。我假设图像的宽度始终为 25 毫米,因此 的左边框(ProdDesc)
与 的距离始终相同(start)
。
因此,我建议您首先定位(ProdDesc)
,(ProdHead)
和(ProdTable)
,fit
(CompBox)
然后再定位(imagebox)
相对于(CompBox)
:
\documentclass{article}
\usepackage{tikz}
\usepackage{tabularray}
\usetikzlibrary{positioning, fit, backgrounds}
\begin{document}
\begin{tikzpicture}[overlay, remember picture]
%coordinate for use in fitting the outerbox correctly; box extended beyond page is intentional
\coordinate (start) at (current page.west);
%placing ProdDesc first, such that ProdHeader and ProdTable can be placed relatively to it.
\node[text width=80mm, minimum height=5mm, anchor=west]
(ProdDesc) at ([shift={(41.5mm,0)}]start)
{long\\description\\for\\emphasis\\of\\a\\real\\situation\\with\\lots\\of\\text};
\node[text width=80mm, above=2mm of ProdDesc.north]
(ProdHeader) {\huge{Header}};
\node[below=2mm of ProdDesc.south]
(ProdTable) {
\begin{tblr}
{width=80mm,colspec={*{3}{X}}}
test & test & text \\
test & test & test \\
test & test & test \\
\end{tblr}
};
%making the fit boxes
\begin{scope}[on background layer]
\node[inner ysep=0, minimum width=80mm, draw=blue, dashed, fit={(ProdHeader) (ProdDesc) (ProdTable)}]
(CompBox) {};
\end{scope}
%imagebox placement, works as intended
\node[draw, text width=25mm, minimum height=25mm, anchor=east, baseline=center]
(imagebox) at ([shift={(-2mm,0)}]CompBox.west)
{\includegraphics[keepaspectratio, height=25mm, width=25mm, clip]{example-image}};
\begin{scope}[on background layer]
\node[inner ysep=2mm, minimum width=130mm, draw, fit={(start) (imagebox) (CompBox)}]
(outerbox) {};
\end{scope}
\end{tikzpicture}
\end{document}
答案2
这是一个不使用 Tikz 的方法。基本思路:
- 定义宏
\intro
,它接受 4 个参数 - 放一个
\parbox
用于图片,另一个用于文本
您将在文档中找到 4 个使用示例:
- 有详细描述
- 描述最少且无表格
- 使用表格
- some
\tikz{}
作为第四个参数
布局和定位由长度决定:
\hspace{12mm}
\parbox{30mm}
...\parbox{9cm}
...
是的,没有理由不能互换第 3 次和第 4 次调用,即将表格放在使用此宏的描述之前。
回想一下,您需要将 a%
作为每行的最后一个元素,以避免排版时留下的空格造成麻烦。
\frame
您可能更喜欢使用\fbox
或,而不是使用\framebox
。
\documentclass[10pt,a4paper]{article}
\usepackage{tabularray}
\usepackage{graphicx}
\usepackage{lipsum}
\usepackage{tikz}
% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\newcommand\intro[4]{% image, header, decr, table
\frame{% ~~~ put a frame on it ~~~~~~~~~~
% ~~~ image ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\hspace{12mm}% moving image to the right
\parbox{30mm}{% will leave 5mm empty space to the right
\includegraphics[keepaspectratio,%
height=25mm, width=25mm,clip]{#1}}%
% ~~~ Text ~~~~~~~~~~~~~~~~~~~~~~~
\parbox{9cm}{% width of the text part
\smallskip% some vertical space; or use \vspace{•}
% ~~~ header {font localized} ~~~~~
{\huge{#2}}%
\smallskip%
% ~~~ Description ~~~~~~~~~
#3%
\bigskip%
% ~~~ Table or whatever ~~~~~~~~
#4%
\smallskip}}}
% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\begin{document}
\intro{example-image}{This is the start}
{\lipsum[1]}{
\begin{tabular}{lll}
1 & abc & def\\
2 & ghi & jkl\\
\end{tabular}}
\bigskip
\intro{example-image}{Something else}{Very short description}{}
\bigskip
\intro{example-image}{Something else}{Somewhat short description}{
\begin{tblr}
{width=80mm,colspec={*{3}{X}}}
test & test & text \\
test & test & test \\
test & test & test \\
\end{tblr}
}
\bigskip
\intro{example-image}{Something else}{Lazy description}{
\tikz{
\draw[red] (0,0) to[out=-10,in=140] (5,1);
}
}
\end{document}
答案3
我最初的理解是图像必须绝对定位在页面上(相对于节点start
),并且当内容发生CompBox
变化时不能移动。
看来情况并非如此。无论如何,我都会发布一个答案来做到这一点。
由于的大小CompBox
不是恒定的,因此想法是将其保存在一个盒子里
\newsavebox{\Prodbox}
\sbox{\Prodbox}{%
\begin{tikzpicture}
\node[text width=80mm, minimum height=5mm] (ProdDesc){long\\description\\for\\emphasis\\of\\a\\real\\situation\\with\\lots\\of\\text};
\node[text width=80mm, above= 2mm of ProdDesc.north] (ProdHeader){\huge{Header}};
\node [below=2mm of ProdDesc.south](ProdTable){
\begin{tblr}
{width=80mm,colspec={*{3}{X}}}
test & test & text \\
test & test & test \\
test & test & test \\
\end{tblr}};
\end{tikzpicture}
}
并在稍后的节点中调用它
\node[right=2mm of imagebox.east] (ProdBox) {\usebox{\Prodbox}};
请注意,不需要\Prodbox
包含tikzpicture
。您可以简单地使用 来minipage
代替。
完整代码(附有更大的代码ProdTable
用于演示):
\documentclass{article}
\usepackage{tikz}
\usepackage{tabularray}
\usetikzlibrary{positioning,fit,backgrounds,calc}
\begin{document}
\newsavebox{\Prodbox}
\sbox{\Prodbox}{%
\begin{tikzpicture}
\node[text width=80mm, minimum height=5mm] (ProdDesc){long\\description\\for\\emphasis\\of\\a\\real\\situation\\with\\lots\\of\\text};
\node[text width=80mm, above= 2mm of ProdDesc.north] (ProdHeader){\huge{Header}};
\node [below=2mm of ProdDesc.south](ProdTable){
\begin{tblr}
{width=80mm,colspec={*{3}{X}}}
test & test & text \\
test & test & test \\
test & test & test \\
test & test & test \\
test & test & test \\
test & test & test \\
test & test & test \\
test & test & test \\
test & test & test \\
test & test & test \\
test & test & test \\
test & test & test \\
test & test & test \\
\end{tblr}};
\end{tikzpicture}
}
\begin{tikzpicture} [remember picture, overlay]
% coordinate for use in fitting the outerbox correctly; box extended beyond page is intentional
\node [anchor=west] (start) at (current page.west){};
% imagebox placement, works as intended
\node[draw, text width=25mm, minimum height=25mm, anchor=west, baseline=center](imagebox) at ($(start)+(12mm,0)$) {\includegraphics[keepaspectratio,height=25mm, width=25mm,clip]{example-image}};
% recall \Prodbox where you want
\node[right=2mm of imagebox.east] (ProdBox) {\usebox{\Prodbox}};
% making the fit boxes
\begin{scope}[on background layer]
\node [inner ysep=0, minimum width=80mm,draw=blue, dashed, fit = (ProdBox)](CompBox) {};
\node [inner ysep =2mm, minimum width= 130mm, draw, fit= (start) (imagebox) (CompBox)] (outerbox){};
\end{scope}
\end{tikzpicture}
\end{document}