这是使用 tikz 绘制的流程图。代码量很大。一些对象的位置是通过反复试验计算出来的。我该如何简化它。此外,如何使连接块 4 和波浪线的箭头变直?
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric, arrows}
\usetikzlibrary{decorations.pathreplacing,decorations.markings,snakes}
\tikzset
{
process/.style={rectangle, minimum width=2cm, minimum height=1cm, align=center, text width=2cm, draw},
connector/.style={circle, minimum width=1cm, minimum height=0.5cm, align=center, text width=1cm, draw},
arrow/.style={thick, ->, >=stealth},
database/.style={
cylinder,
shape border rotate=90,
aspect=0.25,
draw
}
}
\tikzset{snake it/.style={decorate, decoration=snake}}
\begin{document}
\begin{tikzpicture}
\node (p0){Layers in system xyz};
\node (a) [process, below of=p0, text width=6cm] {Block 1};
\node (b) [process, below of=a, yshift=-1cm, text width=6cm] {Block 2};
\node (c) [process, below of=b, yshift=-1cm, text width=6cm] {Block 3};
\node (d) [process, below of=c, yshift=-1cm, text width=6cm] {Block 4};
\node (e) [process, below of=d, yshift=-3cm, text width=6cm] {Block 5};
\node (f) [process, right of=e, xshift=7cm, text width=6cm] {Block 6};
\path (a.south) -- (a.south east) coordinate[pos=0.5] (a1);
\path (a.south) -- (a.south west) coordinate[pos=0.5] (a2);
\path (b.north) -- (b.north east) coordinate[pos=0.5] (b1);
\path (b.north) -- (b.north west) coordinate[pos=0.5] (b2);
\path (b.south) -- (b.south east) coordinate[pos=0.5] (b3);
\path (b.south) -- (b.south west) coordinate[pos=0.5] (b4);
\path (c.north) -- (c.north east) coordinate[pos=0.5] (c1);
\path (c.north) -- (c.north west) coordinate[pos=0.5] (c2);
\path (c.south) -- (c.south east) coordinate[pos=0.5] (c3);
\path (c.south) -- (c.south west) coordinate[pos=0.5] (c4);
\path (d.north) -- (d.north east) coordinate[pos=0.5] (d1);
\path (d.north) -- (d.north west) coordinate[pos=0.5] (d2);
\path (d.south) -- (d.south east) coordinate[pos=0.5] (d3);
\path (d.south) -- (d.south west) coordinate[pos=0.5] (d4);
\path [draw,snake it] (-3,-9) -- node[right, xshift=4 cm] { n/w}(3,-9);
\draw[latex-] (a1) -- (b1);
\draw[latex-] (b2) -- (a2);
\draw[latex-] (b3) -- (c1);
\draw[latex-] (c2) -- (b4);
\draw[latex-] (c3) -- (d1);
\draw[latex-] (d2) -- (c4);
\draw[latex-] (1.5,-8.5) -- node[right] {hi} (d3);
\draw[latex-] (d4) -- (-1.5,-8.5);
\draw[latex-] (1.5,-10.5) -- (1.5,-9.5);
\draw[latex-] (-1.5,-9.5) -- (-1.5,-10.5);
\draw [dashed] (e.east) -- (f.west);
\node[database] (db1) at (-2,-13) {DB1};
\node[database] (db2) at (2,-13) {DB2};
\node[database] (db3) at (6,-13) {DB3};
\node[database] (db4) at (10,-13) {DB4};
\end{tikzpicture}
\end{document}
答案1
这是对原始问题的回应,在图表被 OP 追溯扩展之前!
这使用chains
库来创建标题、蛇形线,并使用单个循环创建 4 个块。主要块之间的箭头作为同一循环的一部分绘制。最后,按照相同的模式绘制往返于蛇形线的箭头。
\documentclass[tikz, border=20pt]{standalone}
\usetikzlibrary{chains,arrows.meta,decorations.pathmorphing}
\begin{document}
\begin{tikzpicture}
[start chain=main going below, every on chain/.append style={align=center, text width=60mm, minimum height=10mm}, >={LaTeX[]}]
\node [on chain] {Layers in system xyz};
\foreach \i [remember=\i as \iprior] in {1,...,4}
{
\node (block \i) [on chain, draw] {Block \i};
\ifnum\i>1
\draw [->] (block \iprior.south) +(-15mm,0) coordinate (b\i) -- (block \i.north -| b\i);
\draw [<-] (block \iprior.south) +(15mm,0) coordinate (k\i) -- (block \i.north -| k\i);
\fi
}
\node (squiggle) [on chain] {};
\draw [decorate, decoration={snake}] (squiggle.west) -- (squiggle.east);
\draw [->] (block 4.south -| b4) -- (squiggle -| b4);
\draw [<-] (block 4.south -| k4) -- (squiggle -| k4);
\end{tikzpicture}
\end{document}
这可以进一步缩短,但我认为这样会变得不那么容易理解。
编辑
这是对原帖作者大量扩展图表后修改后的问题的回应。
同样,这将chains
库与一些循环和一些条件一起使用。它还使用该quotes
库使通过箭头添加节点变得更容易。它被设计为可扩展的,以便可以轻松地将标签添加到图中的任何箭头。
\documentclass[tikz, border=20pt]{standalone}
\usetikzlibrary{chains,arrows.meta,decorations.pathmorphing,quotes}
\begin{document}
\begin{tikzpicture}
[start chain=main going below, every on chain/.append style={align=center, text width=60mm, minimum height=10mm}, >={LaTeX[]}, every edge quotes/.append style={midway, auto, font=\small}, every label/.append style={font=\small}]
\node [on chain] {Layers in system xyz};
\foreach \i [remember=\i as \iprior] in {1,...,6}
{
\ifnum\i=5
\node (block s) [on chain, label=right:n/w] {};
\draw [decorate, decoration={snake}] (block s.west) -- (block s.east);
\else
\ifnum\i>5
\node (block \iprior) [on chain, draw] {Block \iprior};
\else
\node (block \i) [on chain, draw] {Block \i};
\fi
\fi
}
\foreach \i/\j/\k [remember=\i as \iprior (initially 1)] in {2//,3//,4//,s//hi,5//}
{
\draw (block \iprior.south) +(-15mm,0) coordinate (b\i) edge ["\j", ->] (block \i.north -| b\i);
\draw (block \iprior.south) +(15mm,0) coordinate (k\i) edge ["\k", <-] (block \i.north -| k\i);
}
\node (block 6) [on chain=going right, draw, join=by {dashed}] {Block 6};
\end{tikzpicture}
\end{document}
在底部添加啤酒桶留给读者作为练习。
编辑 编辑
添加啤酒桶:
完整代码
\documentclass[tikz, border=20pt]{standalone}
\usetikzlibrary{chains,arrows.meta,decorations.pathmorphing,quotes,shapes.geometric}
\begin{document}
\begin{tikzpicture}
[start chain=main going below, every on chain/.append style={align=center, text width=60mm, minimum height=10mm}, >={LaTeX[]}, every edge quotes/.append style={midway, auto, font=\small}, every label/.append style={font=\small}, database/.style={cylinder, shape border rotate=90, aspect=0.25, draw}]
\node [on chain] {Layers in system xyz};
\foreach \i [remember=\i as \iprior] in {1,...,6}
{
\ifnum\i=5
\node (block s) [on chain, label=right:n/w] {};
\draw [decorate, decoration={snake}] (block s.west) -- (block s.east);
\else
\ifnum\i>5
\node (block \iprior) [on chain, draw] {Block \iprior};
\else
\node (block \i) [on chain, draw] {Block \i};
\fi
\fi
}
\foreach \i/\j/\k [remember=\i as \iprior (initially 1)] in {2//,3//,4//,s//hi,5//}
{
\draw (block \iprior.south) +(-15mm,0) coordinate (b\i) edge ["\j", ->] (block \i.north -| b\i);
\draw (block \iprior.south) +(15mm,0) coordinate (k\i) edge ["\k", <-] (block \i.north -| k\i);
}
\node (block 6) [on chain=going right, draw, join=by {dashed}] {Block 6};
\path [every node/.style=database] (b5 |- block 5.south) +(0,-10mm) node (db1) {DB1} (k5 |- db1) node {DB2} (block 6.south |- db1) +(-15mm,0) node (db3) {DB3} +(15mm,0) node {DB4};
\end{tikzpicture}
\end{document}
解释
从传递给的选项开始tikzpicture
:
[start chain=main going below,
这将创建一个名为 的链main
,其方向向下。因此,添加的每个节点都将添加到前一个节点的下方。
every on chain/.append style={align=center, text width=60mm, minimum height=10mm},
每个使用该样式的节点on chain
,即添加到任何类型的链中的每个节点都将具有给定的样式属性,即最小高度为 1 厘米、文本宽度为 6 厘米、文本对齐到中心。
>={LaTeX[]},
每个箭头尖默认都是这种类型(使用arrows.meta
替换的库中的新语法arrows
)。
every edge quotes/.append style={midway, auto, font=\small},
该quotes
库允许您说出诸如... edge ["great label"] ...
作为简写的内容... edge node {great label} ...
。every edge quotes
设置要应用于以这种方式指定的所有节点的样式。
every label/.append style={font=\small},
所有label
节点都将使用小文本。
database/.style={cylinder, shape border rotate=90, aspect=0.25, draw}]
来自您代码的风格。
\node [on chain] {Layers in system xyz};
链上的第一个节点称为main
。
\foreach \i [remember=\i as \iprior] in {1,...,6}
用一个变量开始一个循环\i
,该变量将取值1
,然后2
,然后 ... 6
。在第一个循环之后, 的先前值\i
将作为 可用\iprior
。因此,当 时,将\i
是。2
\iprior
1
{% everything here to be repeated for each \i
\ifnum\i=5
如果\i
是5
,我们想创建特殊的蛇形物件,而不是块。我们称之为block s
。我们像往常一样将其添加到链中。
\node (block s) [on chain, label=right:n/w] {};
\draw [decorate, decoration={snake}] (block s.west) -- (block s.east);
\else
如果我们不处理特殊情况,那么我们区分两种情况:蛇之前的块和蛇之后的块。
\ifnum\i>5% blocks after the snake i.e. block 5
\node (block \iprior) [on chain, draw] {Block \iprior};
在这种情况下,我们想要的先前的值\i
,因为尽管我们没有创建常规块,但\iprior
我们的蛇却踩到了的值。\i
\else% blocks before the snake i.e. blocks 1-4
\node (block \i) [on chain, draw] {Block \i};
\fi
\fi
}
完成1-5号方块和蛇的绘制。
\foreach \i/\j/\k [remember=\i as \iprior (initially 1)] in {2//,3//,4//,s//hi,5//}
这里有三个变量。同样, 的先前值\i
保存为\iprior
。在循环的第一次迭代中,\iprior
将等于1
。我们从 开始\i
,2
因为我们不希望箭头进出块 1 的顶部。
该语法a/b/c
意味着设置\i
为a
、\j
到b
和\k
到c
。i
这里是绘制箭头进入和离开的块的编号,\j
和\k
是这些箭头应采用的任何标签。
{% repeat this set for each triplet of values \i, \j and \k
\draw (block \iprior.south) +(-15mm,0) coordinate (b\i) edge ["\j", ->] (block \i.north -| b\i);
\draw (block \iprior.south) +(15mm,0) coordinate (k\i) edge ["\k", <-] (block \i.north -| k\i);
这就是quotes
使用这个东西的地方。它设置\j
和\k
作为绘制箭头的标签节点。表示与( )(a -| b)
位于同一架子上且位于与()位于同一地面点上方的点,即坐标从和坐标从。a
-
b
|
x
b
y
a
}
完成三元组集合的循环。
\node (block 6) [on chain=going right, draw, join=by {dashed}] {Block 6};
添加块 6,这意味着我们希望链条朝不同的方向发展,因此on chain
我们说而不是on chain=going right
。在这里,我们告诉 TikZ 使用一条线将块连接到前一个块dashed
。(上面不能使用它,因为join
不会给你 2 个箭头 - 只有 1 个。)
最后,在底部添加啤酒桶。这是使用|-
上面解释的语法。
\path [every node/.style=database] (b5 |- block 5.south) +(0,-10mm)
x
从坐标点b5
(之前定义)开始,y
然后block5.south
向下 10 毫米。
node (db1) {DB1}
创建第一个数据库,并将其命名为db1
。
(k5 |- db1) node {DB2}
将第二个数据库k5
与第一个数据库对齐。
(块 6.南 |- db1)+(-15mm,0)节点(db3){DB3}
我们没有b6
,k6
所以我们需要通过向左移动 15 毫米来手动调整左右以放置第三个数据库......
+(15mm,0) node {DB4};
向右 15 毫米处放置第四个。
答案2
这是另一个选项,不像cfr's answer
。这里的主要思想是利用positioning
和calc
库来放置元素。可以使用更多的 lopps,但我决定牺牲简洁性来追求清晰度:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric, arrows,positioning,calc}
\usetikzlibrary{decorations.pathreplacing,decorations.markings,snakes}
\tikzset
{
process/.style={rectangle, minimum width=2cm, minimum height=1cm, align=center, text width=6cm, draw},
connector/.style={circle, minimum width=1cm, minimum height=0.5cm, align=center, text width=1cm, draw},
arr/.style={->, >=latex},
revarr/.style={<-, >=latex},
database/.style={
cylinder,
shape border rotate=90,
aspect=0.25,
draw
},
}
\tikzset{snake it/.style={decorate, decoration=snake}}
\begin{document}
\begin{tikzpicture}
\def\Shift{40pt}
\node (p0){Layers in system xyz};
\node (1) [process, below=of p0] {Block 1};
\node (2) [process, below=of 1] {Block 2};
\node (3) [process, below=of 2] {Block 3};
\node (4) [process, below=of 3] {Block 4};
\coordinate[below=1.3cm of 4] (5);
\node (6) [process, below=1.3cm of 5] {Block 5};
\node (7) [process, right=of 6] {Block 6};
\path[draw,snake it]
(3.south west|-5) -- (3.south east|-5) node[right] { n/w} ;
\foreach \Valor in {1,...,3}
{
\draw[arr]
([xshift=-\Shift]\Valor.south) -- ([xshift=-\Shift]\the\numexpr\Valor+1\relax.north);
\draw[revarr]
([xshift=\Shift]\Valor.south) -- ([xshift=\Shift]\the\numexpr\Valor+1\relax.north);
}
\draw[revarr,shorten >= 0.3cm]
([xshift=-\Shift]4.south) -- ([xshift=-\Shift]5.north);
\draw[revarr,shorten <= 0.3cm]
([xshift=-\Shift]5.south) -- ([xshift=-\Shift]6.north);
\draw[arr,shorten >= 0.3cm]
([xshift=\Shift]4.south) -- ([xshift=\Shift]5.north);
\draw[arr,shorten <= 0.3cm]
([xshift=\Shift]5.south) -- ([xshift=\Shift]6.north);
\draw[dashed]
(6) -- (7);
\path
node[database]
(db1) at ([yshift=-1cm] $(6.south west)!0.25!(6.south east) $ ) {DB1}
node[database]
(db2) at ([yshift=-1cm] $(6.south west)!0.75!(6.south east) $ ) {DB2}
node[database]
(db3) at ([yshift=-1cm] $(7.south west)!0.25!(7.south east) $ ) {DB3}
node[database]
(db4) at ([yshift=-1cm] $(7.south west)!0.75!(7.south east) $ ) {DB4};
\end{tikzpicture}
\end{document}