4

I have a figure with open (white) arrow heads. Paths that I draw might overlap with arrow heads that were drawn earlier by TikZ and therefore are placed in the foreground. I do not like how this looks and I would like all arrow heads to be placed on the foreground so that no paths are placed on top of the arrow heads.

This description is vague, but with the MWE it hopefully makes sense.

MWE

\documentclass{standalone}

\usepackage{pgfplots}
\pgfplotsset{compat = newest}
\usetikzlibrary{arrows.meta}

\tikzset{%
    state/.style = {%
        draw, circle, minimum size = 4, inner sep = 0, fill = black
    }%
}% 

\tikzset{%
    dashedarrow/.style = {%
        draw, densely dashed, > = {Latex[width = 1.7mm, length = 2.2mm, open, fill = white]}, ->
    }%
}% 

\begin{document}%
\begin{tikzpicture}%

\node[state] (0) at (0,0) {};
\node[state] (1) at (1,0) {};
\node[state] (2) at (0,1) {};

\path[dashedarrow] (1) edge[bend left = 20] (2);
\path[dashedarrow] (2) edge[bend left = 20] (0);

\end{tikzpicture}%
\end{document}%

The MWE produces

Result of the MWE

By simply changing the order of the two \path[dashedarrow] ... lines I get the result that I want:

Required result

However, there is no guarantee that this solution works when I increase the number of arrows: there might not exist an order for which each arrow head is in the foreground.

Is there a way in which I can force all arrow heads to be drawn on the foreground such that nothing will be drawn over them? You can assume that the arrow heads are not drawn so close to each other that they might touch or overlap.

  • 3
    See The layer System Part X of the tikz documentation, It might help you – flav Oct 24 '16 at 12:27
  • @flav, thanks for the comment. I went through that section, but it seems that it places everything within a scope on a specific layer. I foresee a lot of trouble trying to place the dashed paths on the main layer and the arrow heads on a separate foreground layer. – Ritz Oct 24 '16 at 14:53
3

Using the markings library you can instruct tikz to draw the arrows on a top layer. This requires changing the edge notation to to (as edge doesn't seem to add to the path so that the marking can be applied).

\documentclass{standalone}

\usepackage{tikz}
\pgfplotsset{compat = newest}
\usetikzlibrary{arrows.meta, decorations.markings}
\pgfdeclarelayer{arrowlayer}
\pgfsetlayers{main,arrowlayer}
\tikzset{%
    state/.style = {%
        draw, circle, minimum size = 4, inner sep = 0, fill = black
    }%
}%

\tikzset{%
    dashedarrow/.style = {%
        draw, densely dashed, > = {Latex[width = 1.7mm, length = 2.2mm, open, fill = white]},
        decoration={markings, mark=at position 1 with {\begin{pgfonlayer}{arrowlayer}\arrow{>}\end{pgfonlayer}}},
        postaction={decorate}
    }%
}%


\begin{document}%
\begin{tikzpicture}%

\node[state] (0) at (0,0) {};
\node[state] (1) at (1,0) {};
\node[state] (2) at (0,1) {};

\path[dashedarrow] (1) to[bend left = 20] (2);
\path[dashedarrow] (2) to[bend left = 20] (0);

\end{tikzpicture}%
\end{document}%

arrows on top layer

2

Update

After some source code reviewing I finally get it right. Consider adding these lines into your code.

\pgfdeclarelayer{foreground}
\pgfsetlayers{main,foreground}

\makeatletter
\let\pgf@arrow@draw@arrow@old\pgf@arrow@draw@arrow
\def\pgf@arrow@draw@arrow#1#2{
    \begin{pgfonlayer}{foreground}
        \pgf@arrow@draw@arrow@old{#1}{#2}
    \end{pgfonlayer}
}
\makeatother

Example

Notice that although arrowheads are covering each other, they are not covered by anything else.

\documentclass[tikz]{standalone}
\usetikzlibrary{arrows.meta}

\pgfdeclarelayer{background}
\pgfdeclarelayer{foreground}
\pgfsetlayers{background,main,foreground}

\makeatletter
\let\pgf@arrow@draw@arrow@old\pgf@arrow@draw@arrow
\def\pgf@arrow@draw@arrow#1#2{
    \begin{pgfonlayer}{foreground}
        \pgf@arrow@draw@arrow@old{#1}{#2}
    \end{pgfonlayer}
}
\makeatother

\begin{document}

\tikz[scale=10]{
    \foreach\i in{1,...,100}{
        \draw[->,>={Latex[length=30,open,fill=yellow]}](rnd,rnd)--(rnd,rnd);
    }
}

\end{document}

Old answer

The idea of the following is that by setting a large dash phase it is possible to hide the path, drawing only the arrow head. If you would like to repeat every \draw command twice: once for path and the once for arrowhead, then layer system is unnecessary.

\documentclass[tikz]{standalone}
\usetikzlibrary{arrows.meta}
\tikzset{%
    state/.style = {%
        draw, circle, minimum size = 4, inner sep = 0, fill = black
    }%
}% 
\tikzset{%
    dashed only/.style = {
        draw, densely dashed
    },
    arrow only/.style = {%
        draw, >={Latex[width = 1.7mm, length = 2.2mm, open, fill = white]}, ->,
        dash pattern=on 0 off1000, dash phase=500
    }%
}% 

\begin{document}
\begin{tikzpicture}[]%
\node[state] (0) at (0,0) {};
\node[state] (1) at (1,0) {};
\node[state] (2) at (0,1) {};
\path[dashed only] (1) to[bend left = 20] (2);
\path[dashed only] (2) to[bend left = 20] (0);
\path[arrow only] (1) to[bend left = 20] (2);
\path[arrow only] (2) to[bend left = 20] (0);
\end{tikzpicture}%

\end{document}%

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.