我希望有人能帮我解决这个问题。我已经搜索过了,但似乎没有一个解决方案可行。我试图绘制一个简单的图形,但弯曲边缘确实与我的节点重叠。这当然是不可取的。我目前有:
\documentclass[10pt]{article}
\usepackage{tikz}
\usetikzlibrary{arrows}
\usetikzlibrary{positioning}
\begin{document}
\begin{tikzpicture}[->,>=stealth',auto,node distance=2cm,
thick,main node/.style={draw,font=\sffamily\Large\bfseries}]
\node[main node, rectangle, align=center] (1) {Crawling \\ Application};
\node[main node, circle, align=center] (2) [right =of 1] {Crawl \\ Manager};
\node[main node, rectangle] (3) [right =of 2] {Downloader};
\node[main node, rectangle] (4) [right =of 2, below =of 3] {Downloader};
\node[main node, rectangle] (5) [right =of 2, above =of 3] {Downloader};
\node[main node, rectangle, align=center] (6) [below =of 2] {DNS \\ resolver};
\path[every node/.style={font=\sffamily\small}]
(1) edge node [right] {URL requests} (2)
(2) edge node [right] {} (3)
(2) edge node [right] {} (4.west)
(2) edge node [right] {} (5.west)
(2) edge node [below] {} (6)
(3.east) edge[bend right, out=180,in=270] node [left] {} (2.north)
(4.east) edge[bend right, out=180,in=270] node [left] {} (2.north)
(5.east) edge[bend right, out=180,in=270] node [left] {} (2.north)
(3.east) edge[bend left, out=180,in=90] node [left] {} (1.south)
(4.east) edge[bend left, out=180,in=90] node [left] {} (1.south)
(5.east) edge[bend left, out=180,in=90] node [left] {} (1.south);
\end{tikzpicture}
\end{document}
我希望弯曲的箭头弯曲,这样进入圆圈的箭头位于最高的“下载器”矩形上方,而进入矩形的箭头位于“DNS 解析器”矩形下方。如果可能的话,它们应该在途中汇聚,这样就只有一条线。但这是可选的。而且,如果需要一些 Tex-magic,我需要稍后在上方箭头上方放置一个标签,在下方箭头下方放置一个标签。
谢谢您的帮助!
答案1
这不是一个完全自动化的解决方案,但是它展示了一些(希望)有用的技巧。
该图分三个阶段绘制:
- 第一阶段绘制节点并为其命名。此部分的代码与您的代码相同,但我还定义了两个额外的辅助坐标,一个位于最上方的“下载器”框的顶部,另一个位于“DNS 解析器”框的下方。
- 与节点 3、4 和 5 无关的边使用
to
语法 而不是单独绘制edge node [right] {}
,因为大多数边都没有标记,并且不需要那些人工空节点。该线(1) to (2)
用节点标记midway
。 - 与节点 3、4 和 5 相关的边以循环方式绘制。对于每个“下载器”,绘制三条边:
- (2) 一条直线
- 一条曲线朝 (2.north) 方向延伸,穿过所有“下载者”上方
- 一条曲线从“DNS 解析器”下方穿过,向南(1.南)
这些曲线比较棘手。我使用了out
、in
和looseness
来控制曲率,但也利用了辅助坐标top
和bottom
来更好地控制总体形状。每条“顶部”曲线都经过两个水平对齐的点,坐标为(top)
和(top-|bottom)
,加上一个小的偏移 ,取决于循环迭代,以避免所有线条重叠在一条线上。底部曲线也使用了类似的策略。
这是代码:
\documentclass[tikz, border=5pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{arrows}
\usetikzlibrary{positioning,calc}
\begin{document}
\begin{tikzpicture}[->,>=stealth',auto,node distance=2cm,
thick,main node/.style={draw,font=\sffamily\Large\bfseries}]
% Phase 1
\node[main node, rectangle, align=center] (1) {Crawling \\ Application};
\node[main node, circle, align=center] (2) [right =of 1] {Crawl \\ Manager};
\node[main node, rectangle] (4) [right =of 2] {Downloader};
\node[main node, rectangle] (3) [right =of 2, below =of 4] {Downloader};
\node[main node, rectangle] (5) [right =of 2, above =of 4] {Downloader};
\node[main node, rectangle, align=center] (6) [below =of 2] {DNS \\ resolver};
\coordinate[above=of 5.north east] (top);
\coordinate[below=of 6.south east] (bottom);
% Phase 2
\draw (1) edge node[above, midway, font=\sffamily\small] {URL requests} (2) ;
\draw (2) to (6);
% Phase 3
\foreach \n in {3,4,5} {
\draw (2) to (\n.west);
\draw (\n.east) to[out=10,in=0,looseness=1.8] ($(top)+(0,-\n/3)$) to ($(top-|bottom)+(0,-\n/3)$) to[out=180,in=90] (2.north);
\draw (\n.east) to[out=-20,in=0,looseness=1.2] ($(bottom-|top)+(0,2-\n/3)$) to ($(bottom)+(0,2-\n/3)$)
to[out=180,in=-90] (1.south);
}
\end{tikzpicture}
\end{document}
更新。我刚刚注意到楼主的可选要求”如果可能的话,它们应该在路上汇合,这样就只有一条线。但这是可选的。“
事实上,解决方案更简单,因为不需要计算来在循环的每次迭代中“移动”辅助坐标:
\documentclass[tikz, border=5pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{arrows}
\usetikzlibrary{positioning,calc}
\begin{document}
\begin{tikzpicture}[->,>=stealth',auto,node distance=2cm,
thick,main node/.style={draw,font=\sffamily\Large\bfseries}]
\node[main node, rectangle, align=center] (1) {Crawling \\ Application};
\node[main node, circle, align=center] (2) [right =of 1] {Crawl \\ Manager};
\node[main node, rectangle] (4) [right =of 2] {Downloader};
\node[main node, rectangle] (3) [right =of 2, below =of 4] {Downloader};
\node[main node, rectangle] (5) [right =of 2, above =of 4] {Downloader};
\node[main node, rectangle, align=center] (6) [below =of 2] {DNS \\ resolver};
\coordinate[above=of 5.north east] (top);
\coordinate[below=of 6.south east] (bottom);
% Phase 2
\draw (1) edge node[above, midway, font=\sffamily\small] {URL requests} (2) ;
\draw (2) to (6);
% Phase 3
\foreach \n in {3,4,5} {
\draw (2) to (\n.west);
\draw (\n.east) to[out=10,in=0,looseness=1] (top) to (top-|bottom) to[out=180,in=90, looseness=0.7] (2.north);
\draw (\n.east) to[out=-20,in=0,looseness=1] (bottom-|top) to (bottom) to[out=180,in=-90, looseness=1] (1.south);
}
\end{tikzpicture}
\end{document}
答案2
另一种选择是,无需弯曲线条......并且节点的代码更简洁:
\documentclass[tikz, border=5pt]{standalone}
\usetikzlibrary{arrows, positioning, quotes}
\begin{document}
\begin{tikzpicture}[auto, thick,
node distance = 1cm and 2.4 cm,
main node/.style = {draw, font=\sffamily\Large\bfseries, align=center},
every quotes label/.style = {font=\sffamily\footnotesize}
]
\node[main node] (1) {Crawling \\ Application};
\node[main node, circle, right=of 1] (2) {Crawl \\ Manager};
\node[main node, right=of 2] (3) {Downloader};
\node[main node, below=of 3] (4) {Downloader};
\node[main node, above=of 3] (5) {Downloader};
\node[main node, below=of 2] (6) {DNS \\ resolver};
\coordinate[above=of 5.north] (top);
\coordinate[below=of 6.south] (bottom);
%
\draw[-stealth']
(1) edge ["URL requests"] (2)
(2) edge (3)
(2) edge (4.west)
(2) edge (5.west)
(2) edge (6);
%
\draw[-stealth', rounded corners=5mm]
([yshift= 1mm] 3.east) -- ++ (0.5,0) |- (top) -| (2);
\draw[-stealth', rounded corners=5mm]
([yshift=-1mm] 3.east) -- ++ (1.0,0) |- (bottom) -| (1);
\draw[rounded corners=5mm]
([yshift= 1mm] 4.east) -- ++ (0.5,0) |- (top)
([yshift= 1mm] 5.east) -- ++ (0.5,0) |- (top)
([yshift=-1mm] 4.east) -- ++ (1.0,0) |- (bottom)
([yshift=-1mm] 5.east) -- ++ (1.0,0) |- (bottom);
\end{tikzpicture}
\end{document}