Tikz弯曲箭头重叠节点

Tikz弯曲箭头重叠节点

我希望有人能帮我解决这个问题。我已经搜索过了,但似乎没有一个解决方案可行。我试图绘制一个简单的图形,但弯曲边缘确实与我的节点重叠。这当然是不可取的。我目前有:

\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

这不是一个完全自动化的解决方案,但是它展示了一些(希望)有用的技巧。

该图分三个阶段绘制:

  1. 第一阶段绘制节点并为其命名。此部分的代码与您的代码相同,但我还定义了两个额外的辅助坐标,一个位于最上方的“下载器”框的顶部,另一个位于“DNS 解析器”框的下方。
  2. 与节点 3、4 和 5 无关的边使用to语法 而不是单独绘制edge node [right] {},因为大多数边都没有标记,并且不需要那些人工空节点。该线(1) to (2)用节点标记midway
  3. 与节点 3、4 和 5 相关的边以循环方式绘制。对于每个“下载器”,绘制三条边:
    1. (2) 一条直线
    2. 一条曲线朝 (2.north) 方向延伸,穿过所有“下载者”上方
    3. 一条曲线从“DNS 解析器”下方穿过,向南(1.南)

这些曲线比较棘手。我使用了outinlooseness来控制曲率,但也利用了辅助坐标topbottom来更好地控制总体形状。每条“顶部”曲线都经过两个水平对齐的点,坐标为(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

答案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}

在此处输入图片描述

相关内容