Automatically positioning node shape on "to path" in Tikz (for outlined, transparent arrows)

This implements rotation (had to use rotate, not shape border rotate, don't know why) and sets the position correctly (by removing pos=0.5 and adding anchor=tip). I used inner sep to set the width of the arrow, because text width/minimum width didn't work (don't know why).

\documentclass{standalone}

\usepackage{tikz}
\usetikzlibrary{calc,shapes.arrows}

\begin{document}

\begin{tikzpicture}[
  fat arrow/.style={draw,red,
    every to/.style={
      to path={
        let \p1 = ($(\tikztotarget)-(\tikztostart)$),
            \n1 = {veclen(\x1,\y1)},
            \n2 = {mod(scalar(atan2(\y1,\x1))+360, 360)} % calculate angle in range [0,360)
        in
        -- (\tikztotarget)
        node[draw, blue,
             inner xsep=0pt,inner ysep=5pt, % use inner ysep to set width
             minimum height=\n1-\pgflinewidth,
             single arrow,
             rotate=\n2, % not shape border rotate, because that for some reason didn't work
             anchor=tip, % anchor=tip added, pos=0.5 removed
             #1          % options passed to fat arrow style are added here
             ]
          {} \tikztonodes}
  }},
  fat arrow/.default= % set empty default for argument to fat arrow
]
    \fill[yellow] (-.2,.5) rectangle (2.2,1.5);
    \path (0,2) node[draw] (A) {A}
          (1,0) node[draw] (B) {B}
          (2,2) node[draw] (C) {C}
          (2,0) node[draw] (D) {D}
          ;
    \path[fat arrow] (A.south east) to (B.north west);
    \path[fat arrow] (C.south) to (D.north);
\end{tikzpicture}

\end{document}

Assuming you only use this between nodes, Kpym's suggestion in the comment below can be used to figure out the start/end anchors of the arrow. With the code below,

\path[fat arrow] (A) to (B);
\path[fat arrow] (C) to (D);

gives:

enter image description here

\documentclass[border=5mm]{standalone}

\usepackage{tikz}
\usetikzlibrary{calc,shapes.arrows}

\begin{document}

\begin{tikzpicture}[
  fat arrow/.style={draw,red,
    every to/.style={
      to path={
        let \p1 = ($(\tikztotarget)-(\tikztostart)$),
            \n1 = {int(mod(scalar(atan2(\y1,\x1))+360, 360))}, % calculate angle in range [0,360)
            \p2 = ($(\tikztotarget.\n1+180)-(\tikztostart.\n1)$),
            \n2 = {veclen(\x2,\y2)}
        in
        -- (\tikztotarget)
        node[draw, blue,
             inner xsep=0pt,inner ysep=5pt, % use inner ysep to set width
             minimum height=\n2-\pgflinewidth,
             single arrow,
             rotate=\n1, % not shape border rotate, because that for some reason didn't work
             anchor=tip, % anchor=tip added, pos=0.5 removed
             #1          % arguments passed to fat arrow added here
             ]
          at (\tikztotarget.\n1+180)
          {} \tikztonodes}
  }},
  fat arrow/.default= % empty default for argument of fat arrow
]
    \fill[yellow] (-.2,.5) rectangle (2.2,1.5);
    \path (0,2) node[draw] (A) {A}
          (1,0) node[draw] (B) {B}
          (2,2) node[draw] (C) {C}
          (2,0) node[draw] (D) {D}
          ;
    \path[fat arrow] (A) to (B);
    \path[fat arrow] (C) to (D);
\end{tikzpicture}

\end{document}

Addendum:

Following marmot's suggestion, I added the possibility of passing options to the arrow node, with an (optional) argument to fat arrow. I did this for both code blocks above. So for example, with

\path[fat arrow={densely dotted,thick,red}] (C) to (D);

you get

enter image description here


UPDATE: Completely switching gears and drawing the arrow as a decoration. (I also made the answer a bit more concise, I hope.)

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{decorations,decorations.text} %  decorations.text just 4 fun
\pgfkeys{/tikz/.cd,
    outlined arrow width/.store in=\OutlinedArrowWidth,
    outlined arrow width=10pt,
    outlined arrow step/.store in=\OutlinedArrowStep,
    outlined arrow step=1pt,
    outlined arrow length/.store in=\OutlinedArrowLength,
    outlined arrow length=5pt,
}

\pgfdeclaredecoration{outlined arrow}{initial}
{% initial arrow butt
\state{initial}[width=\OutlinedArrowStep,next state=cont] {
    \pgfmoveto{\pgfpoint{\OutlinedArrowStep}{\OutlinedArrowWidth/2}}
    \pgfpathlineto{\pgfpoint{0.3\pgflinewidth}{\OutlinedArrowWidth/2}}
    \pgfpathlineto{\pgfpoint{0.3\pgflinewidth}{-\OutlinedArrowWidth/2}}
    \pgfpathlineto{\pgfpoint{1pt}{-\OutlinedArrowWidth/2}}
    \pgfcoordinate{lastup}{\pgfpoint{1pt}{\OutlinedArrowWidth/2}}
    \pgfcoordinate{lastdown}{\pgfpoint{1pt}{-\OutlinedArrowWidth/2}}
    \xdef\marmotarrowstart{0}
  }
  \state{cont}[width=\OutlinedArrowStep]{
    \ifdim\pgfdecoratedremainingdistance>\OutlinedArrowLength% continue the outlined path
     \pgfmoveto{\pgfpointanchor{lastup}{center}}
     \pgfpathlineto{\pgfpoint{\OutlinedArrowStep}{\OutlinedArrowWidth/2}}
     \pgfcoordinate{lastup}{\pgfpoint{\OutlinedArrowStep}{\OutlinedArrowWidth/2}}
     \pgfmoveto{\pgfpointanchor{lastdown}{center}}
     \pgfpathlineto{\pgfpoint{\OutlinedArrowStep}{-\OutlinedArrowWidth/2}}
     \pgfcoordinate{lastdown}{\pgfpoint{\OutlinedArrowStep}{-\OutlinedArrowWidth/2}}
    \else
     \ifnum\marmotarrowstart=0% draw the arrow head
     \pgfmoveto{\pgfpointadd{\pgfpointanchor{lastup}{center}}{\pgfpoint{-0.5\pgflinewidth}{0}}}
     \pgflineto{\pgfpoint{-0.5\pgflinewidth}{\OutlinedArrowWidth}}
     \pgflineto{\pgfpointadd{\pgfpointdecoratedpathlast}{\pgfpoint{-0.5\pgflinewidth}{0}}}
     \pgflineto{\pgfpoint{-0.5\pgflinewidth}{-\OutlinedArrowWidth}}
     \pgflineto{\pgfpointadd{\pgfpointanchor{lastdown}{center}}{\pgfpoint{-0.5\pgflinewidth}{0}}}
     \xdef\marmotarrowstart{1}
     \else
     \fi
    \fi%
  }
  \state{final}[width=5pt]
  { % perhaps unnecessary but doesn't hurt either
    \pgfmoveto{\pgfpointdecoratedpathlast}
  }
}
\begin{document}


\begin{tikzpicture}[decoration=outlined arrow,font=\sffamily]
    \path (0,0) node[draw] (A) {A}
          (0,4) node[draw] (B) {B}
          (4,0) node[draw] (C) {C}
          (4,4) node[draw] (D) {D}
          ;
  \fill[green] (-1,0.5) rectangle (2.5,1.5);
  \draw(A.north west) -- (D.south east); 
  \draw[decorate,blue,opacity=0.5] (C) to (D);
  \draw[decorate,red,opacity=0.5,line width=2pt,outlined arrow length=10pt] (A) to (B);
  \draw[decorate,outlined arrow length=15pt] (A.east) to[out=0,in=-180] (D.west);
  \fill[decoration={text along path, text={~here is some text inside an arrow},
  raise=-2.5pt},decorate]
  (A.east) to[out=0,in=-180] (D.west);
\end{tikzpicture}  
\end{document}

enter image description here

This works for straight arrows and for curved arrows.

POSSIBLE IMPROVEMENTS: One may use the open arrow heads from the arrows.meta library and bending.

ORIGINAL ANSWER: There are already excellent posts on drawing outlined (or, more generally, two-colored) arrows, so you could just use them here. Then you can use opacity in the usual way.

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{calc,shapes.arrows}
\usetikzlibrary{arrows.meta}
\tikzset{
  my fat arrow/.style args={width #1 line width #2}{
    -{Triangle[length=#1,width={3*#1}]},line width=#1,, % outer arrow
    postaction={draw,-{Triangle[length={#1-2*#2},width={3*#1-4*sqrt(2)*#2}]},white,
    line width={#1-2*#2},shorten <=#2,shorten >=#2,opacity=1}, % second arrow
  }
}

\begin{document}

\begin{tikzpicture}
    \path (0,0) node[draw] (A) {A}
          (0,2) node[draw] (B) {B}
          (2,0) node[draw] (C) {C}
          (2,2) node[draw] (D) {D}
          ;
  \draw[my fat arrow=width 3mm line width 1pt,blue,opacity=0.5] (C) to (D);
  \draw[my fat arrow=width 3mm line width 0.9pt,red,opacity=0.5] (A) to (B);
\end{tikzpicture}

\end{document}

enter image description here

Tags:

Tikz Pgf