I have a simple custom TikZ path style, which may be reduced to the following style:
\tikzset{custom/.style={
to path={
(\tikztostart) ..
controls ($(\tikztostart)!.3!(\tikztotarget)$)
and ($(\tikztostart)!.7!(\tikztotarget)$)
.. (\tikztotarget)\tikztonodes}
}}
(In this example the control points are essentially useless, because there is no curve, but this is representative of the problem with my actual style, which is more complicated.)
For paths between nodes with short labels, this is fine. However, for nodes whose labels are longer than 30% of the distance between the centre of the start node and the centre of the target node, there are rendering issues, because the control points lie within the node label, and so arrowheads point in the wrong direction.
For example, the code:
\documentclass{article}
\usepackage{tikz-cd}
\usetikzlibrary{calc}
\begin{document}
\tikzset{custom/.style={
to path={
(\tikztostart) ..
controls ($(\tikztostart)!.3!(\tikztotarget)$)
and ($(\tikztostart)!.7!(\tikztotarget)$)
.. (\tikztotarget)\tikztonodes}
}}
\[\begin{tikzcd}
X & X
\arrow[custom, from=1-1, to=1-2]
\end{tikzcd}\]
\[\begin{tikzcd}
XXXXXXXXX & XXXXXXXXX
\arrow[custom, from=1-1, to=1-2]
\end{tikzcd}\]
\end{document}
produces:
Notice that the first arrow is fine, but the second arrow has the arrowhead pointing in the wrong direction.
My mental model for the path calculation here is obviously incorrect. I expect \tikztostart
to refer to the centre of the start node, and \tikztoend
to refer to the centre of the end node. (Certainly this seems to be the case if we make the control points vertically offset, introducing a curve.) Then (\tikztostart)!.3!(\tikztotarget)
represents a point 30% of the distance from the centre of the start node to the centre of the end node, and similarly for (\tikztostart)!.7!(\tikztotarget)
. The path should then be trimmed so that it lies outside the bounding box of the start and end nodes, and an arrowhead drawn at the end of the path.
However, this is clearly not what is happening, otherwise the arrowhead would point in the correct direction: instead, the path appears to be starting at the point where the path is first visible (i.e. to the right of the start node bounding box), and ending at the point where the path is last visible (i.e. to the left of the target node bounding box). The control points do then appear to be based on the centre of the start and end nodes, as I expect. But I don't understand this behaviour, because \tikztostart
and \tikztoend
appears to be behaving differently for (1) the start and end co-ordinates and (2) the control points. I.e. for (1) they are based on the path after cropping to not overlap the label bounding boxes, whereas for (2) they are based on the node centres.
I therefore have two questions:
- What is wrong with my mental model, as described above?
- How can the path style be fixed so that it behaves as I expect it to (i.e. so that it fits my mental model above)? (In particular, this would mean that the arrowhead always points in the correct direction.)
shift left
and various other transformation keys).(<node name>)
will always refer to the center. In(<node name>) .. (<coordinate>)
TikZ finds the point on the border of the node that is in direction of(<coordinate>)
, no matter whether that coordinate is outside of the node. I don't understand what you mean by the calculations or their order. Tikz looks at the start node and the 1st control point and puts the start point on the border do the node. Then it looks at the target node and the 2md control point and finds the border. These four points make up the Bézier curve.intersections
andspath3
can do it, kinda, but it's not the most convenient approach, though with a limited set of nodes we can make it as good as possible.) As I said, we could manually find the border points in the direction of the control points and use them for the .3/.7 calculation. The curve will be a bit different, of course, then, but it's much less work. (How important is it how the curves will be calculated?)(<node name>)
behaved differently in those two different contexts (this is counterintuitive to me). As you say, in that case no cropping is necessary. I need to think a little bit about what an acceptable solution would be in light of this. I'll reply again in a little while.