Update 2
The discussion continues on Github where the latest work in progress (and possible future updates) can be found. As I was able to fix all of the problems in the code below, I consider this question to be solved.
Original problem
The tikz/double
option which is used by tikz/commuting diagrams/Rightarrow
internally creates a wide black line and a slightly less wide white line on top of it to display what looks like a double stroked path (see pgf manual, /tikz/double=
). This causes (at least) two types of visual glitches. Notably, several viewers do not display both "strokes" of the path on all zoom levels, as the white part sometimes completely overrides the black path (discussed here, see also the screenshot below). Furthermore, there is a spurious horizontal line at the tail and before the head of the arrow (discussed here). See the pictures below for details.
Work in progress [Update 1]
To remedy these issues, I decided to define a modification of Rightarrow
which draws two thin lines instead.
\documentclass{minimal}
\usepackage{tikz}
\usetikzlibrary{calc,cd}
\newlength{\eqoffset}
\makeatletter
% relative coordinates: (0,0) is the arrow's tail, x points towards the head,
% y points perpendicular, unit distance is \eqoffset
\newcommand{\relptstart}[2]{($($(k0)!#1*\eqoffset+\pgf@shorten@start@additional!0:(k1)$)!#2*\eqoffset!90:(k1)$)}
% (0,0) is the arrow's tip, rest is the same
\newcommand{\relptend}[2]{($($(k1)!#1*\eqoffset-\pgf@shorten@end@additional
-2*\eqoffset-.5*\pgflinewidth!180:(k0)$)!#2*\eqoffset!-90:(k0)$)}
\tikzcdset{
nRightarrow/.style={line join=round,
no head,
/tikz/commutative diagrams/@shiftabletopath,
execute at begin to = {
% Do not use tikzcd@noda or tikzcd@x here, it causes interference.
% Use new names instead
\path (\tikztostart) -- (\tikztotarget) coordinate[pos=0] (k0) coordinate[pos=1] (k1);
\pgfpointnormalised{\pgfpointdiff{\pgfpointanchor{k1}{center}}{\pgfpointanchor{k0}{center}}}
\pgfgetlastxy{\kdx}{\kdy}
\tikzset{
to path={
% arrow body
% the .06 is from \pgftransformxshift{.06\pgfutil@tempdima}
\relptstart{0}{1}
-- \relptend{-.06}{1}
{
% correct vertical position, more central horizontal position
% [xshift=-\kdy*\eqoffset, yshift=\kdx*\eqoffset]
% matches original Rightarrow more closely
[xshift=-\kdy*\eqoffset-\kdx*(\eqoffset+.25*\pgflinewidth),
yshift=\kdx*\eqoffset-\kdy*(\eqoffset+.25*\pgflinewidth)]
\tikztonodes}
\relptstart{0}{-1}
-- \relptend{-.06}{-1}
% arrow tip
% fake the round cap by using round joins and drawing the path twice with a turnaround at the caps
\relptend{2}{0} % tip to top end
.. controls \relptend{1}{0.05} and \relptend{-0.75}{1.25} ..
\relptend{-1.4}{2.65} % top end back to tip
.. controls \relptend{-0.75}{1.25} and \relptend{1}{0.05} ..
\relptend{2}{0} % tip to bottom end
.. controls \relptend{1}{-0.05} and \relptend{-0.75}{-1.25} ..
\relptend{-1.4}{-2.65} % bottom end back to tip
.. controls \relptend{-0.75}{-1.25} and \relptend{1}{-0.05} ..
\relptend{2}{0}
% Add a degenerate path segment at the end so shorten < and shorten > are not applied again
(k1)
}}
}}
}
\makeatother
\begin{document}
\setlength{\eqoffset}{.225ex}
\begin{tikzcd}
a_1
\ar[dr, red, Rightarrow, shift={(0pt, 4pt)}, "l", "m"']
\ar[dr, nRightarrow, shift={(0pt, 4pt)}, green, opacity=.5, "l", "m"']
& a_2
\ar[dr, red, Rightarrow, shift left=7pt, shorten <=2pt, shorten >=3pt, "l"]
\ar[dr, blue, shift left=7pt, nRightarrow, shorten <=2pt, shorten >=3pt, opacity=.5, "l"]
\ar[dr, green, nRightarrow, shift left=7pt, shorten <=2pt, shorten >=3pt, opacity=.5, "l"]
& a_3 & a_4
\ar[d, red, Rightarrow, shorten <=2pt, shorten >=3pt, "l", "m"']
\ar[d, green, nRightarrow, shorten <=2pt, shorten >=3pt, opacity=.5, "l", "m"']
\\
b_1 & b_2 & b_3 & b_4
\end{tikzcd}
\end{document}
Glitches in Rightarrow:
Known issues
- This approach will never work with a custom specification of
to path
. - As of now,
shift left
only works if specified beforenRightarrow
, seen in the green and blue arrows from a2 to b3. - The label position does not exactly match
Rightarrow
, especially ifnear start
,near end
,shorten <
, orshorten >
is specified. Personally, I think the new label position is just as good or better, as the label position ofRightarrow
sometimes is very close to the arrow head.
Other approaches
I also tried the following:
- Use decorations and meta-decorations: This works to a degree, but sub-pt precision is difficult, and I found no reliable way to have the decoration end at exactly the right point.
- Define a
\newcommand
which calls\ar
three times, withshift left
,shift right
, anddraw=none
plus a custom tip: This works to a degree, but I would very much prefer to have this as a tikz style, and I had some reliability issues.
Thanks in advance for any help!
\documentclass
, includes all relevant\usepackage
commands, ends with\end{document}
and compiles without errors, even if it does not produce your desired output.