
Я хочу создать следующую 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}
Мне нужна помощь по двум вопросам:
Как мне определить ширину узла
n3
, чтобы общая ширинаn2
иn3
была равнаn1
(которая равна.5\textwidth
)? На данный момент я установил ее на 5,1 см, потому что она выглядит нормально, но если я изменю содержимое узла 2, то размер узла 3 также должен измениться. Как мне использовать ограничивающую рамку, которую я создал для первой области видимости?Как мне вставить разделитель между двумя областями (например, тот, что нарисован желтым на первой картинке)? Почему ширина двух областей выходит за пределы
textwidth
? Слева и справа есть серое поле, хотяouter sep=0pt
.
решение1
Фоновый прямоугольник имеет отступ (который называется ), поэтому он отображается более серым цветом, чем фактическое содержимое. Используйтеinner frame [xy]sep
tight background
чтобы изменить это.
Кроме того, ширина линии (любого пути, не только узлов, независимо от любых внешних разделителей) будет способствовать окончательному ограничивающему прямоугольнику изображения, что также немного сбивает окончательное размещение изображения (и приводит к переполнению hbox).
В вашей исходной настройке вы можете перезаписать горизонтальное измерение ограничивающего прямоугольника, используя trim left=0pt, trim right=\textwidth
. В моем коде ниже я использую , ±.5\textwidth
потому что я создаю изображение, центрированное относительно начала координат.
Для создания узлов, имеющих размеры, соответствующие другим узлам, используется библиотека fit
, которая устанавливает ширину/высоту/глубину текста, что плохо, если вы хотите, чтобы узлы действительно имели текст.
Моя ext.positioning-plus
библиотека делает похожие вещи, используя fit
библиотеку , но контролирует размер нового узла с помощью minimum width
и minimum height
, что лучше для размещения текста в узле, но требует некоторой работы для текста, который длиннее, чем тот, который может поместиться в узле.
Я использую здесь очень простой text width between
ключ, который используетcalc
библиотеку для измерения расстояния между двумя произвольными точками вИксизмерение и использует его для установки 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) from
tcolorbox \texwidth) по умолчанию каждый столбец растра имеет одинаковую ширину, но их также можно настроить вручную., we can leave the package to do all the work for us. The
use
\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.
Наконец, вы можете отрегулировать длину внутреннего разделителя в узлах \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}