如何根据同一行中的节点设置 tikz 节点的宽度

如何根据同一行中的节点设置 tikz 节点的宽度

我想要创建以下 tikzpicture:

在此处输入图片描述

我现在有的是这样的:

\documentclass{article}
\usepackage[showframe]{geometry}
\usepackage{tikz}
\usetikzlibrary{positioning,backgrounds}
\begin{document}
\noindent\begin{tikzpicture}[background rectangle/.style={fill=gray!25}, show background rectangle,every node/.style={inner sep=0pt,outer sep=0pt,draw}]

\begin{scope}[local bounding box=scope1]
\path[use as bounding box] (0,0) rectangle (.5\textwidth,0);
\filldraw (0,0) circle (2pt); 
\node [text width=0.5\textwidth, align=left,anchor=north west](n1) {scope 1, node 1};
\node [below = 0pt of n1.south west,anchor=north west] (n2) {scope 1, node 2};
\node [below left = 0pt and 0pt of n2.north east,anchor=north west,align=left,text width=5.1cm] (n3) {scope 1, node 3 that includes longer text to be broken into lines};
\end{scope}

\begin{scope}[shift={(scope1.north east)},anchor=north west]
\node [text width=0.5\textwidth, align=left](n1) {scope 2, node 1};
\node [below = 0pt of n1.south west,anchor=north west] (n2) {scope 2, node 2};
\node [below left = 0pt and 0pt of n2.north east,anchor=north west,align=left,text width=5.1cm] (n3) {scope 2, node 3 which also includes longer text to be broken into lines};
\end{scope}

\end{tikzpicture}
\end{document}

在此处输入图片描述

我需要两件事的帮助:

  1. 我如何定义节点的宽度,以便和n3的总宽度等于(即)?目前我将其设置为 5.1cm,因为它看起来不错,但如果我更改节点 2 的内容,则节点 3 的尺寸也应该改变。我如何利用为第一个范围创建的边界框?n2n3n1.5\textwidth

  2. 如何在两个范围之间插入分隔符(例如第一张图中用黄色绘制的分隔符)?为什么两个范围的宽度超出了textwidth?虽然左右两侧都有灰色边缘outer sep=0pt

答案1

背景矩形有内边距(称为),因此它显示的灰色部分比实际内容多。使用inner frame [xy]septight background来改变这种情况。
此外,线宽(任何路径的线宽,不仅是节点,与任何外部 sep 无关)都会影响图片的最终边界框,这也会稍微偏离图片的最终位置(并会导致水平框过满)。
在原始设置中,您可以使用 覆盖边界框的水平测量值trim left=0pt, trim right=\textwidth。在下面的代码中,我使用 ,±.5\textwidth因为我创建了以原点为中心的图片。

为了创建具有与其他节点相关的大小的节点,它们是fit通过设置文本宽度/高度/深度来工作的库,如果您希望节点实际具有文本,则这很糟糕。

我的ext.positioning-plus库使用该库做类似的事情fit,但是通过使用和来控制新节点的大小minimum widthminimum height这对于在节点中包含文本更有利,但对于长度超过节点容纳长度的文本需要做一些工作。

我在这里使用一个非常基本的text width between键,它使用calc库来测量任意两点之间的距离X维度,并用它来设置text width节点的。我们需要inner xsep在这里减去两次(这样最终的节点才能真正覆盖面积内部 xsep)。这基本上是一种设置固定宽度而不是最小宽度。(对于其他形状,因子 2 不同。)

为了同步节点的大小,我可以提供ext.node-families图书馆我的tikz-ext包裹

每个node family={height=row1}设置了的节点共享相同的minimum height。这将使每个节点中的文本垂直居中对齐。

蓝色节点以及黄色分隔符(也是一个节点)将跨越相同的垂直空间。

代码(节点系列)

\documentclass{article}
\usepackage[showframe]{geometry}
\usepackage{tikz, amsmath}
\makeatletter % https://tex.stackexchange.com/a/656319/16595
\tikzset{parse let/.code={\def\tikz@cc@stop@let in{}\tikz@let@command et #1in}}
\makeatother
\usetikzlibrary{calc, positioning, backgrounds, ext.node-families}
\tikzset{
  text width between/.style args={#1 and #2}{
    parse let={\p@=($(#2)-(#1)$)},
    text width/.expanded={abs(\x@)-2*(\noexpand\pgfkeysvalueof{/pgf/inner xsep}}}}
\begin{document}
\noindent
\begin{tikzpicture}[
  background rectangle/.style={fill=gray!25},
  show background rectangle, tight background,
  trim left=-.5\textwidth, trim right=.5\textwidth,
  every node/.style={outer sep=+0pt},
  Yellow/.style={fill=yellow, node family={height=row1}},
  Blue/.style  ={fill=blue,   node family={height=row1}, text=white},
  Red/.style   ={fill=red,   align=center},
  Green/.style ={fill=green, align=center},
  node distance=+0pt
]
\node[Yellow] (sep) {};
\node[Blue, left=of sep,  text width between={-.5\textwidth,0 and sep.west}]
  (Blue-left) {scope 1, node 1 $\displaystyle e^x = \cfrac{1}{1 - \cfrac{x}{1 + x -
                               \cfrac{\frac{1}{2}x}{1 + \frac{1}{2}x - \ddots}}}$};
\node[Blue, right=of sep, text width between={ .5\textwidth,0 and sep.east}]
  (Blue-right) {scope 1, node 1};

\node[Red, below right=of Blue-left.south  west] (Red-left)  {scope 1,\\ node 2};
\node[Red, below right=of Blue-right.south west] (Red-right) {scope 1,\\ node 2};

\node[Green, below left=of Blue-left.south east,
     text width between=Red-left.east and Blue-left.east]
  (Red-left) {scope 1, node 3 that includes longer text to be broken into lines};

\node[Green, below left=of Blue-right.south east,
     text width between=Red-right.east and Blue-right.east]
  (Red-left) {scope 2, node 3 which also includes longer text to be broken into lines
    \dots\ and here's an extra linre};
\end{tikzpicture}
\end{document}

代码(不含节点系列)

\documentclass{article}
\usepackage[showframe]{geometry}
\usepackage{tikz, amsmath}
\makeatletter % https://tex.stackexchange.com/a/656319/16595
\tikzset{parse let/.code={\def\tikz@cc@stop@let in{}\tikz@let@command et #1in}}
\makeatother
\usetikzlibrary{calc, positioning, backgrounds}
\tikzset{
  text width between/.style args={#1 and #2}{
    parse let={\p@=($(#2)-(#1)$)},
    text width/.expanded={abs(\x@)-2*(\noexpand\pgfkeysvalueof{/pgf/inner xsep}}},
  minimum height of three nodes/.style n args={3}{
    parse let={\p1=($(#1.north)-(#1.south)$),
               \p2=($(#2.north)-(#2.south)$),
               \p3=($(#3.north)-(#3.south)$),
               \n@={max(\y1,\y2,\y3)}},
    minimum height/.expanded={\n@}}}
\DeclareDocumentCommand{\tikzthreenodessameheight}{O{} m O{} m O{} m}{
  \node[#1,alias=@1,overlay,path only,outer ysep=+0pt]{\phantom{#2}};
  \node[#3,alias=@2,overlay,path only,outer ysep=+0pt]{\phantom{#4}};
  \node[#5,alias=@3,overlay,path only,outer ysep=+0pt]{\phantom{#6}};
  \node[#1,minimum height of three nodes={@1}{@2}{@3}] {#2};
  \node[#3,minimum height of three nodes={@1}{@2}{@3}] {#4};
  \node[#5,minimum height of three nodes={@1}{@2}{@3}] {#6};}
\begin{document}
\noindent
\begin{tikzpicture}[
  background rectangle/.style={fill=gray!25},
  show background rectangle, tight background,
  trim left=-.5\textwidth, trim right=.5\textwidth,
  every node/.style={outer sep=+0pt},
  Yellow/.style={fill=yellow},
  Blue/.style  ={fill=blue,   text=white},
  Red/.style   ={fill=red,   align=center},
  Green/.style ={fill=green, align=center},
  node distance=+0pt
]
\tikzthreenodessameheight
  [Yellow, name=sep]{}
  [Blue, left=of sep, name=Blue-left,
   text width between={-.5\textwidth,0 and sep.west}]
  {scope 1, node 1 $\displaystyle e^x = \cfrac{1}{1 - \cfrac{x}{1 + x -
                          \cfrac{\frac{1}{2}x}{1 + \frac{1}{2}x - \ddots}}}$}
  [Blue, right=of sep, text width between={ .5\textwidth,0 and sep.east}, name=Blue-right]
  {scope 1, node 1};

\node[Red, below right=of Blue-left.south  west] (Red-left)  {scope 1,\\ node 2};
\node[Red, below right=of Blue-right.south west] (Red-right) {scope 1,\\ node 2};

\node[Green, below left=of Blue-left.south east,
     text width between=Red-left.east and Blue-left.east]
  (Red-left) {scope 1, node 3 that includes longer text to be broken into lines};

\node[Green, below left=of Blue-right.south east,
     text width between=Red-right.east and Blue-right.east]
  (Red-left) {scope 2, node 3 which also includes longer text to be broken into lines
    \dots\ and here's an extra linre};
\end{tikzpicture}
\end{document}

输出

在此处输入图片描述

答案2

默认情况下,使用tcbraster(或tcbitemize) fromtcolorbox, we can leave the package to do all the work for us. The栅格use\texwidth`,每个栅格列具有相同的宽度,但也可以手动调整它们。

\documentclass{article}
\usepackage[showframe]{geometry}
\usepackage[most]{tcolorbox}

\begin{document}

\begin{tcbitemize}[raster every box/.style={sharp corners,  
    fontupper=\sffamily, colupper=white, boxrule=0pt, halign=center},
    raster left skip=0pt, raster right skip=0pt, 
    raster before skip=0pt, raster row skip=0pt, 
    raster after skip=0pt, raster valign=top]
    \tcbitem[colback=blue!90!black] scope 1, node 1
    \tcbitem[colback=blue!90!black] scope 2, node 1
    \tcbitem[blankest, raster column skip=0pt]
        \begin{tcbitemize}[raster force size=false]
            \tcbitem[colback=red!90!black, width=.4\linewidth] scope 1, node 2
            \tcbitem[colback=green!90!black, width=.6\linewidth] scope 1, node 3 that includes longer text to be broken into lines
        \end{tcbitemize}
    \tcbitem[blankest, raster column skip=0pt]
        \begin{tcbitemize}[raster force size=false]
            \tcbitem[colback=red!90!black, width=.4\linewidth] scope 2, node 2
            \tcbitem[colback=green!90!black, width=.6\linewidth] scope 2, node 3 which also includes longer text to be broken into lines
        \end{tcbitemize}
\end{tcbitemize}
\end{document}

在此处输入图片描述

答案3

在此处输入图片描述

我尝试接近您的初始代码。但是有一个问题没有考虑:如果右上节点的高度大于左上节点的高度会发生什么。解决方案可能是反转构造并以右上节点为参考。

代码

\documentclass{article}
\usepackage[showframe]{geometry}
\usepackage{lipsum}
\usepackage{tikz}
\usetikzlibrary{calc, positioning}

\begin{document}

\lipsum[1]
\bigskip

\tikzset{%
  T/.style={blue!50!black, fill=blue!50!black, text=white,
    minimum width=0.48\textwidth, text width=0.48\textwidth-1ex
  },
  BW/.style={green!50!black, fill=green!70!black, text=black,
    minimum width=0.17\textwidth, text width=0.17\textwidth-1ex
  },
  BE/.style={red!75!black, fill=red!95!black, text=black,
    minimum width=0.30\textwidth, text width=0.30\textwidth-1ex,
  }
}
\noindent\begin{tikzpicture}[%
  every node/.style={draw, inner sep=1ex, outer sep=0pt, align=center,
  minimum height=7ex}
  ]
  \node[T, anchor=north west] at (0, 0)
  (nTW) {\bfseries \lipsum[2]};
  \node[BW, below=0pt of nTW.south west, anchor=north west]
  (n2) {scope 1, node 2};
  \node[BE, below left=0pt and 0pt of n2.north east, anchor=north west]
  (n3) {scope 1, node 3 that includes longer text to be broken into lines};

  \path ($(nTW.south) -(nTW.north)$);
  \pgfgetlastxy{\newW}{\newH}

  \node[T, right=.02\textwidth of nTW.north east,
  anchor=north west, minimum height={-\newH}]
  (nTE) {\bfseries scope 2, node 1};
  \node[BW, below=0pt of nTE.south west, anchor=north west]
  (n2E) {scope 2, node 2};
  \node[BE, below left=0pt and 0pt of n2E.north east, anchor=north west]
  (n3E) {scope 2, node 3 that includes longer text to be broken
    into lines; can be longer than the West corresponding node};

  \fill[yellow!90!red] (nTW.north east) rectangle (nTE.south west);
\end{tikzpicture}
\end{document}

答案4

替代建议。我的代码技术性较差(但可能也不太优雅?)。

您可以调整黄色分隔符的宽度(\yellowGap在我的代码中),以及节点 1 的宽度的百分比(percentAmount,0 到 100 之间的整数,但最好不要选择太接近 0 或 100 的值以避免列非常窄),以获得节点 2 的宽度。

最后,您可以调整节点内 sep 的长度\innerXSep

\documentclass[a4paper,10pt]{article}
\usepackage[showframe]{geometry}
\usepackage[x11names]{xcolor}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{calc}

\newlength{\yellowGap}
\setlength{\yellowGap}{3mm}
\newcounter{percentAmount}
\setcounter{percentAmount}{40}% =40% of the width of the first node. Value needs to be integer
\newlength{\innerXSep}
\setlength{\innerXSep}{.3333em}% default value

\newlength{\mainNodeWidth}
\setlength{\mainNodeWidth}{(\textwidth-\yellowGap)/2}
\newlength{\secondNodeWidth}
\setlength{\secondNodeWidth}{\mainNodeWidth*\value{percentAmount}/100}
\newlength{\thirdNodeWidth}
\setlength{\thirdNodeWidth}{\mainNodeWidth-\secondNodeWidth}

\begin{document}

\noindent\begin{tikzpicture}[outer sep=0pt,inner xsep=\innerXSep,text=white]
    \node[text width=\mainNodeWidth-2\innerXSep,fill=DodgerBlue3,align=center]  (mainLeft) {Scope 1, Node 1};
    \node[text width=\secondNodeWidth-2\innerXSep,fill=Firebrick2,align=center,anchor=north west] (secondLeft) at (mainLeft.south west) {Scope 1,\\Node 2};
    \node[text width=\thirdNodeWidth-2\innerXSep,fill=Green3,align=center,anchor=north west] (thirdLeft) at (secondLeft.north east) {Scope 1, Node 3\\ that includes longer text to be broken into lines};
    \fill[DarkGoldenrod1] (mainLeft.north east) rectangle ($(mainLeft.south east)+(\yellowGap,0)$);
    \node[text width=\mainNodeWidth-2\innerXSep,fill=DodgerBlue3,align=center,anchor=north west]    (mainRight) at ($(mainLeft.north east)+(\yellowGap,0)$) {Scope 2, Node 1};
    \node[text width=\secondNodeWidth-2\innerXSep,fill=Firebrick2,align=center,anchor=north west] (secondRight) at (mainRight.south west) {Scope 2,\\Node 2};
    \node[text width=\thirdNodeWidth-2\innerXSep,fill=Green3,align=center,anchor=north west] at (secondRight.north east) {Scope 2, Node 3\\ which also includes longer text to be broken into lines};
\end{tikzpicture}
\end{document}

在此处输入图片描述

相关内容