8

I have browsed arrows.meta and arrows library. They are fantastic.

However, I want to have a custom image/shape as arrow tip e.g. an image of glove as arrow tip or shapes of $PO_4^{3-}$ group as arrow tips.

I looked at \pgfdeclarearrow macro. I could not use a \node inside this macro; nor I could place \includegraphics in it. The code is tried is basically many trial and error with following code given in manual (update: Added MWE)

\RequirePackage{luatex85}
\documentclass[crop,tikz]{standalone}
\usepackage{pgfplots}
\usepackage{tikz}
\usetikzlibrary{arrows,arrows.meta}
\begin{document}

\pgfdeclarearrow{
    name = foo,
    parameters = { \the\pgfarrowlength },
    setup code = {
        % The different end values:
        \pgfarrowssettipend{.25\pgfarrowlength}
        \pgfarrowssetlineend{-.25\pgfarrowlength}
        \pgfarrowssetvisualbackend{-.5\pgfarrowlength}
        \pgfarrowssetbackend{-.75\pgfarrowlength}
        % The hull
        \pgfarrowshullpoint{.25\pgfarrowlength}{0pt}
        \pgfarrowshullpoint{-.75\pgfarrowlength}{.5\pgfarrowlength}
        \pgfarrowshullpoint{-.75\pgfarrowlength}{-.5\pgfarrowlength}
        % Saves: Only the length:
        \pgfarrowssavethe\pgfarrowlength
    },
    drawing code = {
        % Attempt here.
        \pgfsetdash{}
        \pgftext[left]{$X$}
        \pgfusepathqfill
    },
    defaults = {length=4}
}

\begin{tikzpicture}[scale=1, every node/.style={} ]
    \node[thick] at (0,0) {+};
    \draw[gray!20] (-5,-5) grid (5,5);
    \draw[foo-foo] (0,0) -- (3cm,0);
    %\draw[-foo] (0,1) -- (10cm,1);
\end{tikzpicture}    

\end{document}

This is the first time I am trying to write a custom anything in tikz. I have a working solution where I put a node with given shape or graphic, and draw an arrow till it touches it boundary. But it would be good if I can exploit pgf internals to achieve the same.

  • 1
    Perhaps \pgfdeclareimage and \pgftext+\pgfuseimage (see manual chapter 105.3) can be used. (I don't actually know if that is the case.) – Torbjørn T. May 4 '17 at 12:10
  • We would really appreciate a full MWE instead of a code fragment. – John Kormylo May 4 '17 at 13:58
9

The package tikz-cd provides a chance to use arbitrary thing as arrow tips. For example

\documentclass[border=10pt,tikz]{standalone}
\usepackage{tikz-cd}
\begin{document}

\def\POfourthree{PO_4^{3-}}
\def\exampleimagea{\includegraphics[height=2ex]{example-image-a}}

\tikzset{
    PO43/.tip={Glyph[glyph math command=POfourthree,glyph length=3em]},
    exA/.tip={Glyph[glyph math command=exampleimagea,glyph length=3ex]},
}

\tikz[line width=.53pt]\draw[-PO43](0,0)to[bend right](3,0);
\tikz[line width=.53pt]\draw[-exA](0,0)to[bend right](3,0);
\tikz[line width=.53pt]\draw[PO43-exA](0,0)to[bend right](3,0);

\end{document}


As you can see, the thing might be clipped inappriately. Here is how to fix it

\makeatletter
\pgfqkeys{/pgf/arrow keys}{
    glyph width/.code={\pgfarrowsaddtooptions{\pgfmathsetlengthmacro\tikzcd@glyph@wid{#1}}},
}
\pgfdeclarearrow{
  name=Tall Glyph,
  cache=false,
  bending mode=none,
  parameters={\tikzcd@glyph@len,\tikzcd@glyph@wid,\tikzcd@glyph@shorten},
  setup code={
    \pgfarrowssettipend{\tikzcd@glyph@len\advance\pgf@x by\tikzcd@glyph@shorten}},
  defaults={
    glyph axis=axis_height,
    glyph length=+0.9ex,
    glyph width=+3.0ex,
    glyph shorten=+-0.1ex},
  drawing code={
    \show\tikzcd@glyph@wid
    \pgfpathrectangle{\pgfpoint{+0pt}{.5ex-.5*\tikzcd@glyph@wid}}%
                     {\pgfpoint{+\tikzcd@glyph@len}{\tikzcd@glyph@wid}}%
    \pgfusepathqclip%
    \pgftransformxshift{+\tikzcd@glyph@len}%
    \pgftransformyshift{+-\tikzcd@glyph@axis}%
    \pgftext[right,base]{\tikzcd@glyph}}}
\tikzset{
    PO43/.tip={Tall Glyph[glyph math command=POfourthree,glyph length=3em,glyph width=4ex]},
    exA/.tip={Tall Glyph[glyph math command=exampleimagea,glyph length=3ex,glyph width=4ex]},
}

\tikz[line width=.53pt]\draw[-PO43](0,0)to[bend right](3,0);
\tikz[line width=.53pt]\draw[-exA](0,0)to[bend right](3,0);
\tikz[line width=.53pt]\draw[PO43-exA](0,0)to[bend right](3,0);

  • Errata: One should delete the \show line. And the rectangle part should be \pgfpathrectangle{\pgfpoint{+0pt}{.5*\tikzcd@glyph@wid}}%. – Symbol 1 May 4 '17 at 17:37
  • This is convenient to use. Is there a way to pass \small or \tiny options to glyh math command? I tried the obvious but it seems to ignore the font options. Moreover, does it support passing any tikz node shape to arrow tip? – Dilawar May 5 '17 at 3:52
  • @Dilawar In the definition, \pgftext[right,base]{\tikzcd@glyph}}} is itself a node. (It is actually a simpler version of a node.) You might replace that line by a \node[right,base,circle,draw=red,...etc]{} and see what happen. – Symbol 1 May 5 '17 at 14:19
6

Not really an arrow (I tried but failed), but it can be useful nevertheless:

\documentclass[border=3mm]{standalone}
\usepackage{tikz}
\usepackage{graphicx}
\usetikzlibrary{decorations.markings}
\def\hand{\includegraphics[width=3mm]{hand.png}}
\tikzset{
 -hand/.style = {
    decoration = { 
       markings, 
       mark=at position -4mm with { \node[anchor=190,transform shape, inner sep=0pt] {\hand}; } },
       postaction = decorate,
       shorten >=4mm,
    }
}

\begin{document}
\begin{tikzpicture}
    \node[draw] (start) at (0,0) {Start};
    \node[draw] (finish) at (1,2) {Finish};
    \draw[-hand] (start) to[bend left] (finish);
    \draw[-hand] (finish) to[bend left] (start);
\end{tikzpicture}
\end{document}

Result

Update: dealing with edges

This trick can also be used with edges. The following example shows how (the -hand option has to be used in the edge):

\tikzset{
 -hand/.style = {
    decoration = { 
       markings, 
       mark=at position -3mm with { \node[anchor=west,transform shape, inner sep=0pt] {\hand}; } },
       postaction = decorate,
       shorten >=3mm,
    }
}
\begin{tikzpicture}
    \node[draw] (start) at (0,0) {Start};
    \node[draw] (finish) at (1,2) {Finish};
    \draw (start) edge[bend right, -hand] (finish)
          (finish) edge[bend right, -hand] (start);
\end{tikzpicture}

Result:

Result with edge

Update's update

For some unknown reason, the "edges" version behaves better than the path version, in the sense that the required position of the "arrowhead" as decoration matches exactly the width of the included picture (-3mm), and the same value (3mm) can be used for option shorten >. In the path version extra manual finetuning was required, but this is not neccessary in the edge version. This allows to easily parametrize the size of the arrow head as follows:

\tikzset{
 -hand/.style = {
    decoration = { 
       markings, 
       mark=at position -#1 with { 
           \node[anchor=west, transform shape, inner sep=0pt] 
                 {\includegraphics[width=#1]{hand.png}}; 
          }
       },
       postaction=decorate,
       shorten >=#1,
    },
 -hand/.default=3mm,
}

This way, we can specify the size of the hand (it will be 3mm by default), as the following example shows:

\begin{tikzpicture}
    \node[draw] (start) at (0,0) {Start};
    \node[draw] (finish) at (1,2) {Finish};
    \draw (start) edge[bend right, -hand] (finish)
         (finish) edge[bend right, -hand=5mm] (start);
\end{tikzpicture}

Result

  • I can pass any arbitrary tikz node as arrow tip which is very nice. However a to[ ] b works but not a edge[ ] b. In later case, it complains that Package pgf Error: I cannot decorate an empty path. . Is there a way to make it work with both to and edge option? – Dilawar May 5 '17 at 3:58
  • For edges you have to pass the [-hand] option to the edge, instead of the path. Also, at least in my example, you have to tweak the hardcoded distances and sizes. See my update. – JLDiaz May 5 '17 at 7:14

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.