Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I'm trying to make a tikz diagram in which I can place nodes with long pieces of text, one above the other, such that I can specify sections which are to be centered (things outside these sections are then dragged along) with a vertical arrow connecting the centers of the centered sections.

That's kind of a jumble of words, so to give an example, I'd like something like this:

\begin{tikzpicture}
\node (a) at (0,1) {really long stuff \centerthis{blahh} other stuff};
\node (b) at (0,0) {more stuff \centerthis{blah blah blah} possibly other stuff};
\draw[->] (a) -- (b);
\end{tikzpicture}

to automatically produce this:

            really long stuff (blahh) other stuff
                                 |
                                 |
                                 v
               more stuff (blah blah blah) possibly other stuff

so that the center of (blahh) is at (0,1) and the center of (blah blah blah) is at (0,0).

The main things I'm looking for in a solution are that

  • I want to avoid any manual adjustment of distances or sizes.
  • I want everything to appear on the same baseline. For example, I tried making 6 nodes, for upper and lower left, middle, and right, and when one of them had a descender and the others did not, it looked off. Perhaps there's a way around this?

Apologies for not having more to offer, but I'm simply stuck on this. Of course, the hypothetical code I used above is just an idea, if you see another way of setting up a solution (as I'm sure there are many), please post it as well.

share|improve this question

2 Answers 2

up vote 3 down vote accepted

If you can get away with 6 nodes with (almost) proper alignment

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{positioning}
\begin{document}
\begin{tikzpicture}[every node/.style={outer sep=0,inner sep=0,text depth=0.3ex},
                    node distance=0.3em]
\node (a) at (0,1) {Blaaaahh};
\node[left=of a.west] {really long stuff};
\node[right=of a.east] {other stuff};

\node[below= 1 cmof a] (b) {blah blah blah};
\node[left=of b.west] {asymmetric};
\node[right=of b.east] {lipsum stuff};
\draw[-latex] (a) -- (b);
\end{tikzpicture}
\end{document}

enter image description here

Oherwise, probably a \tikzmark answer is on its way.

share|improve this answer

Solution “Complicated”

This solution calculates the amount of xshift that both nodes have to be moved so that the middle of the to-centered part lays on the at (x,y) point.
These xshift amounts are then again used for the arrow that is to be drawn.

This solution uses the calc packacke.

This solution provides:

  • Style CenterLCRa/b that takes three arguments:
    1. the left part of the text,
    2. the center part of the text (which is only used for the definition of \LCR, see below) and
    3. the right part of the text.
  • Macro \LCR that is set after the style CenterLCRa/b is used. It simply contains the node's text so that it doesn't have to be typed again.
  • Path style LCR that draws the line between the (new) centers.
  • Internally: Lengths \WidthOfLeft, \WidthOfRight and \xShiftA/B, macros \tikzCenterLCRa/b and TikZ styes centerLCRa/b

Code

\documentclass[tikz,border=2pt]{standalone}
\usepackage{tikz,calc}
\newlength{\WidthOfLeft}
\newlength{\WidthOfRight}
\newlength{\xShiftA}
\newlength{\xShiftB}

\newcommand{\tikzCenterLCRa}[3]{% #1 = L, #2 = C, #3 = R
    \setlength{\WidthOfLeft}{\widthof{#1}}%
    \setlength{\WidthOfRight}{\widthof{#3}}%
    \setlength{\xShiftA}{-.5\WidthOfLeft+.5\WidthOfRight}
    \global\xShiftA=\xShiftA\relax%
    \def\LCR{#1#2#3}
}
\newcommand{\tikzCenterLCRb}[3]{% #1 = L, #2 = C, #3 = R
    \setlength{\WidthOfLeft}{\widthof{#1}}%
    \setlength{\WidthOfRight}{\widthof{#3}}%
    \setlength{\xShiftB}{-.5\WidthOfLeft+.5\WidthOfRight}
    \global\xShiftB=\xShiftB\relax
    \def\LCR{#1#2#3}
}
\tikzset{
    centerLCRa/.code n args={3}{\tikzCenterLCRa{#1}{#2}{#3}},
    CenterLCRa/.style n args={3}{
        centerLCRa={#1}{#2}{#3},
        xshift=\the\xShiftA
    },
    centerLCRb/.code n args={3}{\tikzCenterLCRb{#1}{#2}{#3}},
    CenterLCRb/.style n args={3}{
        centerLCRb={#1}{#2}{#3},
        xshift=\the\xShiftB
    },
    LCR/.style={
        to path={
            ([xshift=-\the\xShiftA]\tikztostart) -- ([xshift=-\the\xShiftB]\tikztotarget) \tikztonodes
        }
    }
}

\begin{document}
\begin{tikzpicture}[every node/.style=draw]
\node[CenterLCRa={really long stuff }{xxx}{ other stuff}]             (a) at (0,1) {\LCR};
\node[CenterLCRb={more stuff }{blah xxx blah}{ possibly other stuff}] (b) at (0,0) {\LCR};
\draw[->] (a.south) to[LCR] (b.north);
\end{tikzpicture}
\end{document}

Output

Output with a lot of calculations

Solution “Dirty”

Nodes bigger than their content

This solution has the disadvantage of using boxes that are bigger than their content, so that the final node will be wider than usual (bounding box, drawing mechanism).

Code

\documentclass[tikz,border=2pt]{standalone}
\usepackage{calc}
\newlength{\WidthOfLeft}
\newlength{\WidthOfRight}
\newcommand{\centerLCR}[3]{%
    \settowidth{\WidthOfLeft}{#1}%
    \settowidth{\WidthOfRight}{#3}%
    \ifdim\WidthOfLeft<\WidthOfRight\relax%
        \setlength{\WidthOfLeft}{\WidthOfRight}%
    \fi%
    \makebox[\WidthOfLeft][r]{#1}#2\makebox[\WidthOfLeft][l]{#3}%
}
\begin{document}
\begin{tikzpicture}
\node (a) at (0,1) {\centerLCR{really long stuff }{blahh}{ other stuff}};
\node (b) at (0,0) {\centerLCR{more stuff }{blah blah blah}{ possibly other stuff}};
\draw[->] (a) -- (b);
\end{tikzpicture}
\begin{tikzpicture}[every node/.style=draw]
\node (a) at (0,1) {\centerLCR{really long stuff }{blahh}{ other stuff}};
\node (b) at (0,0) {\centerLCR{more stuff }{blah blah blah}{ possibly other stuff}};
\draw[->] (a) -- (b);
\end{tikzpicture}
\end{document}

Output

Output without draw
Output with draw

Nodes smaller than their content

If the boxes use rather the smaller width, i.e.

\ifdim\WidthOfLeft>\WidthOfRight\relax% > instead of <

then the bounding box is even worse. (See cut-off "her stuff" in output.)
This won't be a problem if there's more around these nodes.

Output

Sub-Output without draw
Sub-Output with draw

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.