I am drawing curved arrows in tikz-cd, using the method devised by @AndréC in this answer. There are situations where I want to shorten these arrows, proportional to their arc length. However, the naïve solution (using shorten
) is not suitable, as it creates distorted curves (as discussed, for instance, in this question). As an example (Example 1), the following two curves have the same input path, but the red curve has been shorten
ed. What should happen is the red curve should overlay the black curve.
Note that it is not just the position of the shorten
ed curve that is incorrect: the shape is incorrect too: in the example (Example 2) below, I've positioned the curves so they have the same apex, but the shorten
ed curve does not overlay the original (the amount of distortion depends on the curve width and height).
The other issue with shorten
is that it requires an absolute length to shorten by, whereas I want to specify it proportionally with respect to the length of the curve itself.
I attempted to manually draw an arrow head with decorations.markings
, but this does not properly calculate the right size for the arrowhead (or take into account the existing style of the head or tail). In the example below (Example 3), the arrow head further up the curve should be the same size as the one at the tip.
My idea was to shorten this arrow using a custom dash pattern
, but this seems like a hack that is likely in practice to fail in edge cases. Ideally, the curve path itself should be changed, which would handle the existing style/arrowheads/tails/etc. The option pgfpathcurvebetweentime
seemed like a possible solution, but I could not figure out how to integrate it with the custom curve style in the two examples.
How might one add an option to the custom curve style to allow the curve to be shortened (e.g. curve={height=-40pt, shorten=0.2}
)? In practice, shortening symmetrically from both ends is usually sufficient, but having options to shorten the start and end differently would be even better if it doesn't add much extra complexity.
For a demonstration of what I intend by "shortening a curved arrow", see @Thruston's example.
Example 1
\documentclass{article}
\usepackage{tikz-cd}
\usetikzlibrary{calc}
\begin{document}
{\tikzset{curve/.style={settings={#1},to path={(\tikztostart)
.. controls ($(\tikztostart)!\pv{pos}!(\tikztotarget)!\pv{height}!270:(\tikztotarget)$)
and ($(\tikztostart)!1-\pv{pos}!(\tikztotarget)!\pv{height}!270:(\tikztotarget)$)
.. (\tikztotarget)\tikztonodes}},
settings/.code={\tikzset{quiver/.cd,#1}
\def\pv##1{\pgfkeysvalueof{/tikz/quiver/##1}}},
quiver/.cd,pos/.initial=0.35,height/.initial=0}
\[\begin{tikzcd}
{\bullet} & {\bullet}
\arrow[from=1-1, to=1-2, curve={height=-40pt}, shorten <= 30pt, shorten >= 30pt, color=red]
\arrow[from=1-1, to=1-2, curve={height=-40pt}]
\end{tikzcd}\]}
\end{document}
Example 2
\documentclass{article}
\usepackage{tikz-cd}
\usetikzlibrary{calc}
\begin{document}
{\tikzset{curve/.style={settings={#1},to path={(\tikztostart)
.. controls ($(\tikztostart)!\pv{pos}!(\tikztotarget)!\pv{height}!270:(\tikztotarget)$)
and ($(\tikztostart)!1-\pv{pos}!(\tikztotarget)!\pv{height}!270:(\tikztotarget)$)
.. (\tikztotarget)\tikztonodes}},
settings/.code={\tikzset{quiver/.cd,#1}
\def\pv##1{\pgfkeysvalueof{/tikz/quiver/##1}}},
quiver/.cd,pos/.initial=0.35,height/.initial=0}
\[\begin{tikzcd}
{\bullet} &&& {\bullet}
\arrow[from=1-1, to=1-4, curve={height=-60pt}, shorten <= 30pt, shorten >= 30pt, color=red, yshift=-11pt]
\arrow[from=1-1, to=1-4, curve={height=-60pt}]
\end{tikzcd}\]}
\end{document}
Example 3
\documentclass{article}
\usepackage{tikz-cd}
\usetikzlibrary{calc}
\usetikzlibrary{decorations.markings}
\begin{document}
{\tikzset{curve/.style={settings={#1},to path={(\tikztostart)
.. controls ($(\tikztostart)!\pv{pos}!(\tikztotarget)!\pv{height}!270:(\tikztotarget)$)
and ($(\tikztostart)!1-\pv{pos}!(\tikztotarget)!\pv{height}!270:(\tikztotarget)$)
.. (\tikztotarget)\tikztonodes},
% Arrow head and tail
decoration={
markings,
mark=at position 0.8 with {\arrow{>}}}
, postaction={decorate}},
%
settings/.code={\tikzset{quiver/.cd,#1}
\def\pv##1{\pgfkeysvalueof{/tikz/quiver/##1}}},
quiver/.cd,pos/.initial=0.35,height/.initial=0}
\[\begin{tikzcd}
{\bullet} & {\bullet}
\arrow[Rightarrow, from=1-1, to=1-2, curve={height=-40pt}]
\end{tikzcd}\]}
\end{document}
yshift=5pt
?