思维导图中带箭头的曲线连接

思维导图中带箭头的曲线连接

对于我的思维导图,我想用箭头替换连接末尾的“火山”。

由于连接应该是弯曲的,因此我使用这个答案。我尝试了很多次,但不幸的是,我对 tikz/pgf 的了解不足以正确绘制箭头。我认为箭头最好定义在第二座火山最初的定义处。此时,我在代码中留下了相关注释。

以下是我目前所掌握的信息:

\documentclass[tikz,border=0pt]{standalone}
\usetikzlibrary{positioning, mindmap}

\makeatletter
\newdimen\pgfutil@tempdimc

\pgfdeclaredecoration{circle connection boomerang}{initial}
{
  \state{initial}[width=0pt,next state=boomerang]
  {
    {
    \pgftransformxshift{-\pgfkeysvalueof{/pgf/decoration/start radius}}%
    \pgftransformrotate{\pgfdecorationsegmentaspect}%%%
    \pgfpathmoveto{\pgfpointpolar{\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/start radius}}}
    \pgfpatharc{\pgfdecorationsegmentangle}{-\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/start radius}}
    \pgfutil@tempcnta=-\pgfdecorationsegmentangle\relax
    \advance\pgfutil@tempcnta by90\relax
    \pgfmathsetlength\pgfutil@tempdima{\pgfkeysvalueof{/pgf/decoration/start radius}}
    \pgfmathsetlength\pgfutil@tempdimb{\pgfdecorationsegmentamplitude}
    \pgfpathcurveto
    {\pgfpointadd
      {\pgfpointpolar{-\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/start radius}}}
      {\pgfpointpolar{\the\pgfutil@tempcnta}{.25\pgfutil@tempdima}}}
    {\pgfqpoint{1.25\pgfutil@tempdima}{-.5\pgfutil@tempdimb}}
    {\pgfqpoint{1.5\pgfutil@tempdima}{-.5\pgfutil@tempdimb}}
    \pgfpathlineto{\pgfpoint{1.5\pgfutil@tempdima}{.5\pgfutil@tempdimb}}
    \pgfutil@tempcnta=\pgfdecorationsegmentangle\relax
    \advance\pgfutil@tempcnta by-90\relax
    \pgfpathcurveto
    {\pgfpoint{1.25\pgfutil@tempdima}{.5\pgfutil@tempdimb}}
    {\pgfpointadd
      {\pgfpointpolar{\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/start radius}}}
      {\pgfpointpolar{\the\pgfutil@tempcnta}{.25\pgfutil@tempdima}}}
    {\pgfpointpolar{\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/start radius}}}
    \pgfpathclose
    }
  }
  \state{boomerang}[width=0pt,next state=end]
  {
    \pgfmathsetlength\pgfutil@tempdima{\pgfkeysvalueof{/pgf/decoration/start radius}}%
    \pgfmathsetlength\pgfutil@tempdimb{\pgfkeysvalueof{/pgf/decoration/end radius}}%
    \pgfmathsetlength\pgfutil@tempdimc{\pgfdecorationsegmentamplitude}%
    \pgftransformxshift{-\pgfutil@tempdima}
    \pgfpathmoveto
    {\pgfpointadd
      {\pgfpointpolar{\pgfdecorationsegmentaspect}{1.5\pgfutil@tempdima}}
      {\pgfpointpolar{\pgfdecorationsegmentaspect-90}{.5\pgfutil@tempdimc}}}
    \pgftransformxshift{\pgfdecoratedremainingdistance+\pgfutil@tempdima+\pgfutil@tempdimb}
    \pgfpathquadraticcurveto
    {\pgfpoint{-.5\pgfdecoratedremainingdistance-\pgfutil@tempdimb}{(.5\pgfdecoratedremainingdistance+.5\pgfutil@tempdima+.5\pgfutil@tempdimb)*tan(\pgfdecorationsegmentaspect)-.5\pgfutil@tempdimc}}
     {\pgfpointadd
      {\pgfpointpolar{-\pgfdecorationsegmentaspect}{-1.5\pgfutil@tempdimb}}
      {\pgfpointpolar{-\pgfdecorationsegmentaspect-90}{.5\pgfutil@tempdimc}}}
    \pgfpathlineto{\pgfpointadd
      {\pgfpointpolar{-\pgfdecorationsegmentaspect}{-1.5\pgfutil@tempdimb}}
      {\pgfpointpolar{-\pgfdecorationsegmentaspect+90}{.5\pgfutil@tempdimc}}}
    \pgftransformxshift{-\pgfdecoratedremainingdistance-\pgfutil@tempdima-\pgfutil@tempdimb}
    \pgfpathquadraticcurveto
    {\pgfpoint{.5\pgfdecoratedremainingdistance+\pgfutil@tempdima}{(.5\pgfdecoratedremainingdistance+.5\pgfutil@tempdima+.5\pgfutil@tempdimb)*tan(\pgfdecorationsegmentaspect)+.5\pgfutil@tempdimc}}
    {\pgfpointadd
      {\pgfpointpolar{\pgfdecorationsegmentaspect}{1.5\pgfutil@tempdima}}
      {\pgfpointpolar{\pgfdecorationsegmentaspect+90}{.5\pgfutil@tempdimc}}}
    \pgfpathclose
  }
  \state{end}[width=0pt,next state=final]
  {
    {
    % the arrow should be defined here
    %
    % original code producing the "volcano"
    % \pgftransformxshift{\pgfdecoratedremainingdistance}%
    % \pgftransformxscale{-1}%
    % \pgftransformxshift{-\pgfkeysvalueof{/pgf/decoration/end radius}}%
    % \pgftransformrotate{\pgfdecorationsegmentaspect}%%%
    % \pgfpathmoveto{\pgfpointpolar{\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/end radius}}}
    % \pgfpatharc{\pgfdecorationsegmentangle}{-\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/end radius}}
    % \pgfutil@tempcnta=-\pgfdecorationsegmentangle\relax
    % \advance\pgfutil@tempcnta by90\relax
    % \pgfmathsetlength\pgfutil@tempdima{\pgfkeysvalueof{/pgf/decoration/end radius}}
    % \pgfmathsetlength\pgfutil@tempdimb{\pgfdecorationsegmentamplitude}%
    % \pgfpathcurveto
    % {\pgfpointadd
    %   {\pgfpointpolar{-\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/end radius}}}
    %   {\pgfpointpolar{\the\pgfutil@tempcnta}{.25\pgfutil@tempdima}}}
    % {\pgfqpoint{1.25\pgfutil@tempdima}{-.5\pgfutil@tempdimb}}
    % {\pgfqpoint{1.5\pgfutil@tempdima}{-.5\pgfutil@tempdimb}}
    % \pgfpathlineto{\pgfpoint{1.5\pgfutil@tempdima}{.5\pgfutil@tempdimb}}
    % \pgfutil@tempcnta=\pgfdecorationsegmentangle\relax
    % \advance\pgfutil@tempcnta by-90\relax
    % \pgfpathcurveto
    % {\pgfpoint{1.25\pgfutil@tempdima}{.5\pgfutil@tempdimb}}
    % {\pgfpointadd
    %   {\pgfpointpolar{\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/end radius}}}
    %   {\pgfpointpolar{\the\pgfutil@tempcnta}{.25\pgfutil@tempdima}}}
    % {\pgfpointpolar{\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/end radius}}}
    % \pgfpathclose
    }
  }
  \state{final}
  {}
}
\tikzoption{circle connection boomerang switch color}{\tikz@parse@switch@boomerang#1\pgf@unique}
\def\tikz@parse@switch@boomerang from (#1) to (#2) by #3\pgf@unique{%
  \tikzset{to path={%
      \pgfextra{%
        \tikz@lib@mindmap@check{\tikztostart}%
        \tikz@compute@circle@radii\tikz@compute@segmentamplitude%
        \global\let\tikz@lib@save@start=\tikztostart%
        \global\let\tikz@lib@save@target=\tikztotarget%
        \pgfkeysgetvalue{/pgf/decoration/start radius}\pgf@temp%
        \global\let\tikz@lib@saved@start@radius=\pgf@temp%
        \pgfkeysgetvalue{/pgf/decoration/end radius}\pgf@temp%
        \global\let\tikz@lib@saved@end@radius=\pgf@temp%
      }%
      [every circle connection bar]
      decorate [decoration={circle connection boomerang,aspect=#3}]
      { -- (\tikztotarget) \tikztonodes} 
    },
    append after command={
      [fill=none,draw=none,path picture=\tikz@lib@shade@pic]
      \pgfextra{
        \pgfutil@colorlet{tikz@switch@from}{#1}%
        \pgfutil@colorlet{tikz@switch@to}{#2}%
      }
    }
  }
}

\pgfdeclarehorizontalshading[tikz@switch@from,tikz@switch@to]{tikz@shade@bar}{10000bp}{%
  color(0pt)=(tikz@switch@from);
  color(100bp)=(tikz@switch@to)}

\tikzset{%
  concept color and bend/.code 2 args=
  {
    \let\tikz@old@concept@color=\tikz@concept@color%
    \def\tikz@edge@to@parent@path{
      (\tikzparentnode)
      to[circle connection boomerang switch color=from (\tikz@old@concept@color) to (#1) by #2]
      (\tikzchildnode)}
    \def\tikz@concept@color{#1}%
  }
}
   
\begin{document}
\begin{tikzpicture}
  \node[draw, circle, red] (n) {$n$};
  \node[draw, circle] (m) [below = of n] {$m$};
  \draw (n) to[circle connection boomerang switch color=from (red) to (black) by -5] (m);
\end{tikzpicture}
\end{document}

制作

在此处输入图片描述

结果应该是这样的:

在此处输入图片描述

答案1

我可能忽略了一些东西,但这似乎看起来很正确(从不同角度测试):

\documentclass[tikz,border=0pt]{standalone}
\usetikzlibrary{positioning, mindmap}

\makeatletter
\newdimen\pgfutil@tempdimc

\pgfdeclaredecoration{circle connection boomerang}{initial}
{
  \state{initial}[width=0pt,next state=boomerang]
  {
    {
    \pgftransformxshift{-\pgfkeysvalueof{/pgf/decoration/start radius}}%
    \pgftransformrotate{\pgfdecorationsegmentaspect}%%%
    \pgfpathmoveto{\pgfpointpolar{\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/start radius}}}
    \pgfpatharc{\pgfdecorationsegmentangle}{-\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/start radius}}
    \pgfutil@tempcnta=-\pgfdecorationsegmentangle\relax
    \advance\pgfutil@tempcnta by90\relax
    \pgfmathsetlength\pgfutil@tempdima{\pgfkeysvalueof{/pgf/decoration/start radius}}
    \pgfmathsetlength\pgfutil@tempdimb{\pgfdecorationsegmentamplitude}
    \pgfpathcurveto
    {\pgfpointadd
      {\pgfpointpolar{-\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/start radius}}}
      {\pgfpointpolar{\the\pgfutil@tempcnta}{.25\pgfutil@tempdima}}}
    {\pgfqpoint{1.25\pgfutil@tempdima}{-.5\pgfutil@tempdimb}}
    {\pgfqpoint{1.5\pgfutil@tempdima}{-.5\pgfutil@tempdimb}}
    \pgfpathlineto{\pgfpoint{1.5\pgfutil@tempdima}{.5\pgfutil@tempdimb}}
    \pgfutil@tempcnta=\pgfdecorationsegmentangle\relax
    \advance\pgfutil@tempcnta by-90\relax
    \pgfpathcurveto
    {\pgfpoint{1.25\pgfutil@tempdima}{.5\pgfutil@tempdimb}}
    {\pgfpointadd
      {\pgfpointpolar{\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/start radius}}}
      {\pgfpointpolar{\the\pgfutil@tempcnta}{.25\pgfutil@tempdima}}}
    {\pgfpointpolar{\pgfdecorationsegmentangle}{\pgfkeysvalueof{/pgf/decoration/start radius}}}
    \pgfpathclose
    }
  }
  \state{boomerang}[width=0pt,next state=end]
  {
    \pgfmathsetlength\pgfutil@tempdima{\pgfkeysvalueof{/pgf/decoration/start radius}}%
    \pgfmathsetlength\pgfutil@tempdimb{10pt}%                   % <-- changeable
    \pgfmathsetlength\pgfutil@tempdimc{\pgfdecorationsegmentamplitude}%
    \pgftransformxshift{-\pgfutil@tempdima}
    \pgfpathmoveto
    {\pgfpointadd
      {\pgfpointpolar{\pgfdecorationsegmentaspect}{1.5\pgfutil@tempdima}}
      {\pgfpointpolar{\pgfdecorationsegmentaspect-90}{.5\pgfutil@tempdimc}}}
    \pgftransformxshift{\pgfdecoratedremainingdistance+\pgfutil@tempdima+\pgfutil@tempdimb}
    \pgfpathquadraticcurveto
    {\pgfpoint{-.5\pgfdecoratedremainingdistance-\pgfutil@tempdimb}{(.5\pgfdecoratedremainingdistance+.5\pgfutil@tempdima+.5\pgfutil@tempdimb)*tan(\pgfdecorationsegmentaspect)-.5\pgfutil@tempdimc}}
     {\pgfpointadd
      {\pgfpointpolar{-\pgfdecorationsegmentaspect}{-1.5\pgfutil@tempdimb}}
      {\pgfpointpolar{-\pgfdecorationsegmentaspect-90}{.5\pgfutil@tempdimc}}}
    \pgfpathlineto{\pgfpointadd
      {\pgfpointpolar{-\pgfdecorationsegmentaspect}{-1.5\pgfutil@tempdimb}}
      {\pgfpointpolar{-\pgfdecorationsegmentaspect+90}{.5\pgfutil@tempdimc}}}
    \pgftransformxshift{-\pgfdecoratedremainingdistance-\pgfutil@tempdima-\pgfutil@tempdimb}
    \pgfpathquadraticcurveto
    {\pgfpoint{.5\pgfdecoratedremainingdistance+\pgfutil@tempdima}{(.5\pgfdecoratedremainingdistance+.5\pgfutil@tempdima+.5\pgfutil@tempdimb)*tan(\pgfdecorationsegmentaspect)+.5\pgfutil@tempdimc}}
    {\pgfpointadd
      {\pgfpointpolar{\pgfdecorationsegmentaspect}{1.5\pgfutil@tempdima}}
      {\pgfpointpolar{\pgfdecorationsegmentaspect+90}{.5\pgfutil@tempdimc}}}
    \pgfpathclose
  }
  \state{end}[width=0pt,next state=final]
  {
    {
    \pgftransformxshift{\pgfdecoratedremainingdistance}%
    \pgftransformxscale{-1}
    \pgfmathsetlength\pgfutil@tempdima{10pt}%
    \pgftransformxshift{-\pgfutil@tempdima}%
    \pgfpathmoveto{\pgfpointpolar{\pgfdecorationsegmentaspect}{\pgfutil@tempdima}}
    \pgfpathlineto{\pgfpointadd
        {\pgfpointpolar{\pgfdecorationsegmentaspect-90}{-2pt}}  % <-- changeable
        {\pgfpointpolar{\pgfdecorationsegmentaspect}{1.5*\pgfutil@tempdima}}}
    \pgfpathlineto{\pgfpointadd
        {\pgfpointpolar{\pgfdecorationsegmentaspect-90}{2pt}}   % <-- changeable
        {\pgfpointpolar{\pgfdecorationsegmentaspect}{1.5*\pgfutil@tempdima}}}
    \pgfpathclose
    }
  }
  \state{final}
  {}
}
\tikzoption{circle connection boomerang switch color}{\tikz@parse@switch@boomerang#1\pgf@unique}
\def\tikz@parse@switch@boomerang from (#1) to (#2) by #3\pgf@unique{%
  \tikzset{to path={%
      \pgfextra{%
        \tikz@lib@mindmap@check{\tikztostart}%
        \tikz@compute@circle@radii\tikz@compute@segmentamplitude%
        \global\let\tikz@lib@save@start=\tikztostart%
        \global\let\tikz@lib@save@target=\tikztotarget%
        \pgfkeysgetvalue{/pgf/decoration/start radius}\pgf@temp%
        \global\let\tikz@lib@saved@start@radius=\pgf@temp%
        \pgfkeysgetvalue{/pgf/decoration/end radius}\pgf@temp%
        \global\let\tikz@lib@saved@end@radius=\pgf@temp%
      }%
      [every circle connection bar]
      decorate [decoration={circle connection boomerang,aspect=#3}]
      { -- (\tikztotarget) \tikztonodes} 
    },
    append after command={
      [fill=none,draw=none,path picture=\tikz@lib@shade@pic]
      \pgfextra{
        \pgfutil@colorlet{tikz@switch@from}{#1}%
        \pgfutil@colorlet{tikz@switch@to}{#2}%
      }
    }
  }
}

\pgfdeclarehorizontalshading[tikz@switch@from,tikz@switch@to]{tikz@shade@bar}{10000bp}{%
  color(0pt)=(tikz@switch@from);
  color(100bp)=(tikz@switch@to)}

\tikzset{%
  concept color and bend/.code 2 args=
  {
    \let\tikz@old@concept@color=\tikz@concept@color%
    \def\tikz@edge@to@parent@path{
      (\tikzparentnode)
      to[circle connection boomerang switch color=from (\tikz@old@concept@color) to (#1) by #2]
      (\tikzchildnode)}
    \def\tikz@concept@color{#1}%
  }
}
   
\begin{document}
\begin{tikzpicture}
  \node[draw, circle, red] (n) {$n$};
  \node[draw, circle] (m) [below = of n] {$m$};
  \draw (n) to[circle connection boomerang switch color=from (red) to (black) by 20] (m);
\end{tikzpicture}
\end{document}

在此处输入图片描述

请注意,我需要更改状态中的一行boomerang(第一个注释所在的行changeable)以使箭头固定大小,而不管它指向的节点的大小。

目前,箭头的大小在样式中是硬编码的,这可能不是最佳的。您可以通过更改注释标记的行中的值10pt-2pt来调整箭头的大小和宽度。2ptchangeable

另请注意,原始代码中似乎有一个错误此代码所基于的答案:如果将角度设置为更高的值,例如50,渐变将不再填充整个箭头,并且某些部分将变得透明,因此不可见。遗憾的是,我还没有找到解决这个问题的方法。

相关内容