4

I try to draw a very thick edge between two specific anchors of nodes. In reality, they target segments of multipart nodes, but I kept it simple for this example.

\documentclass[tikz]{standalone}
\usetikzlibrary{positioning}

\begin{document}
\begin{tikzpicture}[every node/.style={draw}]
  \node (A) {A};
  \node[below right=1 and 2 of A] (B) {B};
  \draw[line width=7] (A.east) to (B.west);
\end{tikzpicture}
\end{document}

This results in ugly gaps where the edge meets the node.

gaps

I am aware that I could put the edge in a scope on background layer using the backgrounds TikZ library. This would get rid of the part overlapping into the nodes. But it would not fix the gaps where the edge is too short to reach the node border.

  • Setting line cap=rect is not enough to close it when the edge has a rather steep angle.
  • Elongating the edge could make it pop out the other side of the node.

How can I reach a seamless connection between edge and node, looking somewhat like the following picture?

enter image description here

3

I would be inclined to simply fill a path rather than drawing a line:

  \fill (A.east) +(0,3.5pt) -- ([yshift=3.5pt]B.west) -- +(0,-7pt) -- ([yshift=-3.5pt]A.east) -- cycle;

filled path faking line

This leaves an annoying, albeit slight, gap visible here between the 'line' and the border of node A. To avoid this, draw the filled area, also:

\filldraw (A.east) +(0,3.5pt) -- ([yshift=3.5pt]B.west) -- +(0,-7pt) -- ([yshift=-3.5pt]A.east) -- cycle;

fill-draw faking line

Complete code:

\documentclass[tikz,border=20pt]{standalone}
\usetikzlibrary{positioning}

\begin{document}
\begin{tikzpicture}
  [every node/.style={draw}]
  \node (A) {A};
  \node [below right=1 and 2 of A] (B) {B};
  \filldraw (A.east) +(0,3.5pt) -- ([yshift=3.5pt]B.west) -- +(0,-7pt) -- ([yshift=-3.5pt]A.east) -- cycle;
\end{tikzpicture}
\end{document}

EDIT

For convenience, you could define a pic to handle some of this automatically. The following defines 2 such: lr connection for left-to-right (ish) connections and tb connection for up-down (ish) connections. Obviously, you'd have to do a bit more work to enable options for 'mixed' modes e.g. from a .north anchor to an .east one. But the same idea could be used - only the from and to would be crucially different in this case.

The basic syntax is as follows:

\pic [lr connect={from=<point to connect from>, to=<point to connect to>, line width=<connector width>}, <other tikz options>] {lr connection};

for left-right connections and

\pic [tb connect={from=<point to connect from>, to=<point to connect to>, line width=<connector width>}, <other tikz options>] {tb connection};

for top-bottom connections.

Here's an extremely ugly illustration of the possible output:

ugly demo

\begin{tikzpicture}
  [every node/.style={draw}]
  \node (A) {A};
  \node [below right=1 and 2 of A] (B) {B};
  \pic [lr connect={from=A.east, to=B.west, line width=7pt}] {lr connection};
  \pic [lr connect={from=B.east, to={4,0}}] {lr connection};
  \node (C) at (6,-1) {C};
  \pic [lr connect={from={4,0}, to=C.west}, blue] {lr connection};
  \pic [lr connect={from=C.west, to=B.east, line width=5pt}, green] {lr connection};
  \node (D) [below left=of B -| C] {D};
  \node (E) [below left=of B] {E};
  \pic [tb connect={from=C.south, to=D.north, line width=7pt}, red] {tb connection};
  \pic [tb connect={from=E.north, to=A.south, line width=6pt}, orange] {tb connection};
  \pic [lr connect={from=D.west, to=E.east, line width=10pt}, magenta] {lr connection};
\end{tikzpicture}

EDIT 2

You can define commands \lrconnect[<optional arguments for tikz>]{<connection options>} and \tbconnect[<tikz options>]{<connection options>} for further convenience.

Then the same ugly output can be specified as

\begin{tikzpicture}
  [every node/.style={draw}]
  \node (A) {A};
  \node [below right=1 and 2 of A] (B) {B};
  \lrconnect{from=A.east, to=B.west, line width=7pt};
  \lrconnect{from=B.east, to={4,0}};
  \node (C) at (6,-1) {C};
  \lrconnect[blue]{from={4,0}, to=C.west};
  \lrconnect[green]{from=C.west, to=B.east, line width=5pt};
  \node (D) [below left=of B -| C] {D};
  \node (E) [below left=of B] {E};
  \tbconnect[red]{from=C.south, to=D.north, line width=7pt};
  \tbconnect[orange]{from=E.north, to=A.south, line width=6pt};
  \lrconnect[magenta]{from=D.west, to=E.east, line width=10pt};
\end{tikzpicture}

However, this also offers some more interesting possibilities. For example:

fancier stuff

can be produced using something like

\begin{tikzpicture}
  [
    every node/.style={fill=blue!75, text=white, font=\bfseries},
    tb connect={line width=7pt},
    lr connect={line width=7pt},
    draw=blue!25,
  ]
  \node (A) {A};
  \node [below right=1 and 2 of A] (B) {B};
  \node (C) at (6,-1) {C};
  \node (D) [below left=of B -| C] {D};
  \node (E) [below left=of B] {E};
  \foreach \i/\j in {A.east/B.west,C.west/B.east,D.west/E.east}
  {
    \lrconnect[left color=blue, right color=green]{from=\i,to=\j};
    \foreach \k in {.9,.8,...,.1}
    \lrconnect[fill=white, fill opacity=.75-.75*\k, draw=none]{from=\i,to=\j,line width=\k*7pt};
  }
  \foreach \i/\j in {C.south/D.north,E.north/A.south}
  {
    \tbconnect[left color=blue, right color=magenta]{from=\i,to=\j};
    \foreach \k in {.9,.8,...,.1}
    \tbconnect[fill=white, fill opacity=.75-.75*\k, draw=none]{from=\i,to=\j,line width=\k*7pt};
  }
\end{tikzpicture}

Complete code

\documentclass[tikz,border=20pt,multi]{standalone}
\usetikzlibrary{positioning}
\tikzset{
  lr connection/.pic={
    \filldraw [pic actions] (\myconnectfrom) +(0,.5*\myconnectwidth) -- ([yshift=.5*\myconnectwidth]\myconnectto) -- +(0,-\myconnectwidth) -- ([yshift=-.5*\myconnectwidth]\myconnectfrom) -- cycle;
  },
  lr connect/.code={
    \tikzset{
      lr connections/.cd,
      #1
    },
  },
  lr connections/.cd,
  from/.store in=\myconnectfrom,
  to/.store in=\myconnectto,
  line width/.store in=\myconnectwidth,
  from={0,0},
  to={0,0},
  line width=.4pt,
  /tikz/.cd,
  tb connection/.pic={
    \filldraw [pic actions] (\myconnectfrom) +(.5*\myconnectwidth,0) -- ([xshift=.5*\myconnectwidth]\myconnectto) -- +(-\myconnectwidth,0) -- ([xshift=-.5*\myconnectwidth]\myconnectfrom) -- cycle;
  },
  tb connect/.code={
    \tikzset{
      tb connections/.cd,
      #1
    },
  },
  tb connections/.cd,
  from/.store in=\myconnectfrom,
  to/.store in=\myconnectto,
  line width/.store in=\myconnectwidth,
  from={0,0},
  to={0,0},
  line width=.4pt,
}
\newcommand*\lrconnect[2][]{%
   \pic [lr connect={#2}, #1] {lr connection}}
\newcommand*\tbconnect[2][]{%
   \pic [tb connect={#2}, #1] {tb connection}}
\begin{document}
\begin{tikzpicture}
  [every node/.style={draw}]
  \node (A) {A};
  \node [below right=1 and 2 of A] (B) {B};
  \pic [lr connect={from=A.east, to=B.west, line width=7pt}] {lr connection};
  \pic [lr connect={from=B.east, to={4,0}}] {lr connection};
  \node (C) at (6,-1) {C};
  \pic [lr connect={from={4,0}, to=C.west}, blue] {lr connection};
  \pic [lr connect={from=C.west, to=B.east, line width=5pt}, green] {lr connection};
  \node (D) [below left=of B -| C] {D};
  \node (E) [below left=of B] {E};
  \pic [tb connect={from=C.south, to=D.north, line width=7pt}, red] {tb connection};
  \pic [tb connect={from=E.north, to=A.south, line width=6pt}, orange] {tb connection};
  \pic [lr connect={from=D.west, to=E.east, line width=10pt}, magenta] {lr connection};
\end{tikzpicture}
\begin{tikzpicture}
  [every node/.style={draw}]
  \node (A) {A};
  \node [below right=1 and 2 of A] (B) {B};
  \lrconnect{from=A.east, to=B.west, line width=7pt};
  \lrconnect{from=B.east, to={4,0}};
  \node (C) at (6,-1) {C};
  \lrconnect[blue]{from={4,0}, to=C.west};
  \lrconnect[green]{from=C.west, to=B.east, line width=5pt};
  \node (D) [below left=of B -| C] {D};
  \node (E) [below left=of B] {E};
  \tbconnect[red]{from=C.south, to=D.north, line width=7pt};
  \tbconnect[orange]{from=E.north, to=A.south, line width=6pt};
  \lrconnect[magenta]{from=D.west, to=E.east, line width=10pt};
\end{tikzpicture}
\begin{tikzpicture}
  [
    every node/.style={fill=blue!75, text=white, font=\bfseries},
    tb connect={line width=7pt},
    lr connect={line width=7pt},
    draw=blue!25,
  ]
  \node (A) {A};
  \node [below right=1 and 2 of A] (B) {B};
  \node (C) at (6,-1) {C};
  \node (D) [below left=of B -| C] {D};
  \node (E) [below left=of B] {E};
  \foreach \i/\j in {A.east/B.west,C.west/B.east,D.west/E.east}
  {
    \lrconnect[left color=blue, right color=green]{from=\i,to=\j};
    \foreach \k in {.9,.8,...,.1}
    \lrconnect[fill=white, fill opacity=.75-.75*\k, draw=none]{from=\i,to=\j,line width=\k*7pt};
  }
  \foreach \i/\j in {C.south/D.north,E.north/A.south}
  {
    \tbconnect[left color=blue, right color=magenta]{from=\i,to=\j};
    \foreach \k in {.9,.8,...,.1}
    \tbconnect[fill=white, fill opacity=.75-.75*\k, draw=none]{from=\i,to=\j,line width=\k*7pt};
  }
\end{tikzpicture}
\end{document}
  • The example I presented here is a simplified version. My real use case actually defines outer sep=0 globally because all the shapes are filled but not drawn, so I could even your first solution is very applicable for me. – XZS Oct 30 '15 at 0:24
  • @XZS Please see edit. I'm not sure how useful this is, but I was procrastinating. – cfr Oct 30 '15 at 1:33
  • This could be quite useful for the picture I am striving for. Thank you. – XZS Oct 30 '15 at 1:42
  • I added command versions as I think these are easier to use. – cfr Oct 30 '15 at 2:26
2

Is there request that line should be between (A.east) and B.west? See if \draw[...] (A.center) -- (B.center) on background layer is acceptable for you:

enter image description here

For above picture you need TikZ library backgrounds and define fill for nodes:

\documentclass[border=3mm,
               tikz,
               preview
               ]{standalone}
\usetikzlibrary{backgrounds,positioning}

    \begin{document}
\begin{tikzpicture}[every node/.style={draw,fill=white}]
      \node (A) {A};
      \node[below right=1 and 2 of A] (B) {B};
    \scoped[on background layer]
\path   let \p1 = (A.center),
            \p2 = (B.center),
            \n1 = {veclen(\y2-\y1,\x2-\x1)} in
    (A.east) to node[sloped, fill=black,
                     minimum width=\n1, 
                     minimum height=3pt] {} 
    (B.west);
    \end{tikzpicture}
        \end{document}

Edit: As you note in comment (and I before overlooked in your question) you will replace the line with some (multi part) node. Therefore I now replace a previous line with empty node with width of 5pt and fill=black by which I mimic previous line. You can replace this node with your real one ... however, if the node will has higher minimum height, their ends will not be chopped with nodes A and B ... .

You can see, that I calculated minimum width of node as distance between centers of nodes A and B. If this distance will be adequate for your real node. It can be dependent from node height.

Is this what you looking for?

Edit (2): I will try once again to guess, what is the problem ... so another solution, which consider multi-part nodes (determined by split rectangle) and connecting different parts by (very thick?) lines:

enter image description here

Code for this solution is relatively simple:

\documentclass[border=3mm,
               tikz,
               preview
               ]{standalone}
\usetikzlibrary{backgrounds,positioning}

     \begin{document}
\begin{tikzpicture}[
    every node/.style={draw,fill=white},
    shorten <>/.style={shorten >=#1, shorten <=#1}]
  \node[rectangle split, rectangle split parts=3] (A) 
        {A1\nodepart{two}A2\nodepart{three}A3};
  \node[rectangle split, rectangle split parts=3,
        below right=1 and 2 of A] (B) 
        {B1\nodepart{two}B2\nodepart{three}B3};
\begin{scope}[on background layer]
\draw[line width=4pt,red!50,
      shorten <>=-4pt]   (A.one east) -- (B.three west);
\draw[line width=4pt,teal!50,
      shorten <>=-4pt]   (A.two east) -- (B.one west);
\end{scope}
\end{tikzpicture}
     \end{document}

Extension of lines I select equal to line width, which is adequate for line slope above 45 degree ... I t can be simple calculated with basic geometry :-)

Note: This solution is not appropriate for lines with arrows on the end, they will be partly covered by nodes. In this case a solution can be used decorated path with arrow somewhere on line between its ends.

  • Yes, the lines have to end at specific anchors. As written in the question, they should be able to point at segments of multipart nodes. – XZS Oct 29 '15 at 22:35
  • @XZS, ok, I correct my answer, however, it is not as simple as befor :-) – Zarko Oct 29 '15 at 23:21
  • I don't think the line is being replaced by a multi-part node. Isn't the idea that the nodes (A and B) are, in fact, parts of multi-part nodes? Maybe I've misunderstood the question or your answer, but that's how I understood it.... – cfr Oct 30 '15 at 0:01
  • @cfr is right, the nodes A and B are to be replaced by more complex constructs. The computation of minimum width is valuable nonetheless. – XZS Oct 30 '15 at 0:20
  • @XZS, now I'm confused. It seems now, that my first version of mine answer was correct .. if Now I understand your question correctly, in real case you will have to (or more) multi-part nodes and you like to their connect different parts? With lines with 7pt width? P – Zarko Oct 30 '15 at 0:38

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.