1

I have a custom tikz node with a design along the top and left side, and would like to center its text in the bottom-right section of the node. For example, I would like to center the text in section D of the node, below:

+---+-----------+
| A |     C     |
+---+-----------+
|   |           |
|   |           |
| B |     D     |
|   |           |
|   |           |
+---+-----------+

Using the option, text centered, causes it to be centered with respect to the whole shape, not just section D. How may I center it with respect to the bounds of just D? In HTML I could use the options, padding-left and padding-top, but I haven't been able to find comparable options for tikz nodes.

Edit: This is what I have so far:

\PassOptionsToPackage{usenames,dvipsnames}{xcolor}
\RequirePackage{luatex85}
\documentclass[tikz]{standalone}
\usepackage{tikz}
\usepackage{xcolor}
\usepackage{makeshape}

\usetikzlibrary{
  automata,
  shadows.blur,
}

\makeatletter
\def\band{10pt}
\def\internalstorageAnchorpath{
   \pgf@xa=\ctbnex
   \pgf@ya=\ctbney
   \advance\pgf@xa by \band
   \advance\pgf@ya by \band
   \mincorrect{\pgf@xa}{\pgfshapeminwidth}
   \advance\pgf@xa\pgfshapeouterxsep
   \mincorrect{\pgf@ya}{\pgfshapeminheight}
   \advance\pgf@ya\pgfshapeouterysep
   \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
   \pgfpathlineto{\pgfpoint{\pgf@xa}{-\pgf@ya}}
   \pgfpathlineto{\pgfpoint{-\pgf@xa}{-\pgf@ya}}
   \pgfpathlineto{\pgfpoint{-\pgf@xa}{\pgf@ya}}
   \pgfpathclose
}
\def\internalstorageBackground{
   \pgf@xa=\ctbnex
   \pgf@ya=\ctbney
   \advance\pgf@xa by \band
   \advance\pgf@ya by \band
   \mincorrect{\pgf@xa}{\pgfshapeminwidth}
   \mincorrect{\pgf@ya}{\pgfshapeminheight}
   \pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
   \pgfpathlineto{\pgfpoint{\pgf@xa}{-\pgf@ya}}
   \pgfpathlineto{\pgfpoint{-\pgf@xa}{-\pgf@ya}}
   \pgfpathlineto{\pgfpoint{-\pgf@xa}{\pgf@ya}}
   \pgfpathclose
   \advance\pgf@xa by -\band
   \pgfpathmoveto{\pgfpoint{-\pgf@xa}{\pgf@ya}}
   \pgfpathlineto{\pgfpoint{-\pgf@xa}{-\pgf@ya}}
   \advance\pgf@xa by \band
   \advance\pgf@ya by -\band
   \pgfpathmoveto{\pgfpoint{-\pgf@xa}{\pgf@ya}}
   \pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@ya}}
}
\pgfdeclareshape{internalstorage}{
   \setpaths{\internalstorageAnchorpath}{\internalstorageBackground}
   \savedanchor{\northeast}{
      \pgf@x = \ctbnex
      \advance\pgf@x by \band
      \mincorrect{\pgf@x}{\pgfshapeminwidth}
      \advance\pgf@x\pgfshapeouterxsep
      \pgf@y = \ctbney
      \mincorrect{\pgf@y}{\pgfshapeminheight}
      \advance\pgf@y\pgfshapeouterysep
   }
   \anchor{north}{ \northeast \pgf@x=0pt }
   \anchor{north east}{ \northeast }
   \anchor{east}{ \northeast \pgf@y=0pt }
   \anchor{south east}{ \northeast \pgf@y=-\pgf@y }
   \anchor{south}{ \northeast \pgf@x=0pt \pgf@y=-\pgf@y }
   \anchor{south west}{ \northeast \pgf@x=-\pgf@x \pgf@y=-\pgf@y }
   \anchor{west}{ \northeast \pgf@x=-\pgf@x \pgf@y=0pt }
   \anchor{north west}{ \northeast \pgf@x=-\pgf@x }
}
\makeatother

\begin{document}

\begin{tikzpicture}[
    >=stealth,
    every state/.style={
      font=\small,
      blur shadow,
      thick,
    },
    internal storage/.style={
      state,
      internalstorage,
      text width=5em,
      text centered,
      top color=BlueViolet!60,
      bottom color=BlueViolet!20,
    },
  ]
  \node[state, internal storage, text centered] {foo bar baz qux quux quo};
\end{tikzpicture}

\end{document}

The generated node looks like the following:

internal storage

As you can see, the alignment of the text looks funny because it isn't centered with respect to the decorations.

4
  • No, I'm trying to center text within a section of a custom node. As far as I know, the matrix library is only useful for aligning nodes with respect to each other.
    – Dylon
    Dec 3, 2018 at 23:51
  • With node labels, you can specify shift offsets. I'm looking for something equivalent for node contents.
    – Dylon
    Dec 3, 2018 at 23:52
  • 1
    Welcome to TeX.SX! What have you tried? Can you please post a minimal working example with your "custom code" so that we have something to work from. In additional to making it much easier for people to help you, a MWE will also help to clarify what you want. A MWE should compile and be as small as possible to demonstrate your problem.
    – user30471
    Dec 3, 2018 at 23:54
  • Updated. Please review my post again.
    – Dylon
    Dec 4, 2018 at 0:29

3 Answers 3

1

You could draw internalstorage node as a regular one, but place its contents using a label node on its lower right corner. If you fixes label's size and outer node's size and know the difference between them, you can draw internal lines with path picture options which survives to a fill option. These nodes are compatible with matrix.

This is an example:

\documentclass[tikz,border=2mm]{standalone} 
\usetikzlibrary{positioning}

\begin{document}
\begin{tikzpicture}[%
    internalstorage/.style={%
        minimum size=2.5cm,
        draw,
        thick,
        text width=5em,
        top color=purple!60,
        bottom color=purple!20,
        label={[minimum size=2cm,
                text width=5em,
                font=\small,
                text centered,
                anchor=south east]
                south east:#1
        },
        path picture={
            \draw ([xshift=5mm]path picture bounding box.south west)--([xshift=5mm]path picture bounding box.north west);
            \draw ([yshift=-5mm]path picture bounding box.north west)--([yshift=-5mm]path picture bounding box.north east);
        }
    }
]

\matrix[row sep=1mm, column sep=1mm] (a) {
\node[internalstorage=foo bar baz qux quux quo] {};
&
\node[internalstorage=foo] {};
\\
\node[internalstorage=foo bar baz] {};
&
\node[internalstorage=foo bar baz qux quux] {};
\\
};
\end{tikzpicture}

\end{document}

enter image description here

3
  • This looks amazing, but I cannot get your example to work. If I remove the styling on the label it works but the label is then placed on the outside of the node to the south east. Do you have a special set up that lets it work?
    – Dylon
    Dec 4, 2018 at 11:02
  • @Dylon I'm not sure to understand the problem. The styling on the label makes it works, you need to place south east anchor of label on south east anchor of main node to obtain the special alignment. What do you want to avoid from label style?
    – Ignasi
    Dec 4, 2018 at 11:17
  • I figured it out: I placed a newline between the opening square bracket in the label style and minimum size, which caused the parser to err. Removing it resolved the issue. This is great, thanks!
    – Dylon
    Dec 4, 2018 at 11:21
2

Congratulations to your nice example! But I still keep advertizing matrix.

\PassOptionsToPackage{usenames,dvipsnames}{xcolor}
\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{matrix,calc}
\begin{document}
\begin{tikzpicture}[row 1 column 1/.style={align=left},
row 1 column 2/.style={align=right,text width=4em},
row 2 column 1/.style={align=left},
row 2 column 2/.style={text centered,text width=5em},
every node/.append style={draw},column sep=-\pgflinewidth,row
sep=-\pgflinewidth,]

\matrix[matrix of nodes,draw,top color=BlueViolet!60,
      bottom color=BlueViolet!20,inner sep=0pt,nodes={draw=none,inner sep=4pt}] (mat)
  {
   A & B\\
    C & foo bar baz qux quux quo\\
  };
\path ($(mat-1-1.east)!0.5!(mat-1-2.west)$) coordinate (aux1)
($(mat-1-1.south)!0.5!(mat-2-1.north)$) coordinate (aux2);
\draw (mat.north -| aux1) -- (mat.south -| aux1)
(mat.west |- aux2) -- (mat.east |- aux2) ;
\end{tikzpicture}
\end{document}

enter image description here

This is a quick attempt to define a style. My first attempt to draw the separator lines with append after command did not succeed, so I added a command for that (temporarily).

\PassOptionsToPackage{usenames,dvipsnames}{xcolor}
\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{matrix,calc}
\begin{document}
\tikzset{fancy matrix/.style={row 1 column 1/.style={align=left},
row 1 column 2/.style={align=right,text width=4em},
row 2 column 1/.style={align=left},
row 2 column 2/.style={text centered,text width=5em},
matrix of nodes,draw,top color=BlueViolet!60,
bottom color=BlueViolet!20,inner sep=0pt,nodes={draw=none,inner sep=4pt},
append after command={}
}}
\newcommand{\DrawMatrixSeparators}[2][]{
\draw[#1] ($(#2-1-1.east)!0.5!(#2-1-2.west)$) coordinate (aux1)
($(#2-1-1.south)!0.5!(#2-2-1.north)$) coordinate (aux2)
(#2.north -| aux1) -- (#2.south -| aux1)
(#2.west |- aux2) -- (#2.east |- aux2);}
\begin{tikzpicture}[]

\matrix[fancy matrix] (mat)
  {
   A & B\\
    C & foo bar baz qux quux quo\\
  };
\DrawMatrixSeparators{mat}  
\end{tikzpicture}
\end{document}
8
  • I don't have a problem with node alignment, but text alignment within a node.
    – Dylon
    Dec 4, 2018 at 0:30
  • Please review my original post again. I've updated it with more information.
    – Dylon
    Dec 4, 2018 at 0:40
  • Is the foo... text centered in the lower right area? Looks like closer to left margin than right one.
    – Sigur
    Dec 4, 2018 at 0:48
  • @Sigur Yes, there was an asymmetry cause by the inner sep of the ambient matrix node. I was actually already fixing this when I saw your comment, but yes, good catch thanks!
    – user121799
    Dec 4, 2018 at 0:50
  • The "internal storage" node is for a flowchart, is there a way I can draw it using a matrix internally? I'd like to reuse it in other places.
    – Dylon
    Dec 4, 2018 at 0:52
0

This works, but isn't perfect. I'll revise it as I strengthen my tikz fu.

enter image description here

\PassOptionsToPackage{usenames,dvipsnames}{xcolor}
\RequirePackage{luatex85}
\documentclass[tikz]{standalone}
\usepackage{tikz}
\usepackage{makeshape}
\usepackage{xcolor}

\usetikzlibrary{
  automata,
  matrix,
  shadows.blur,
}

\begin{document}

\def\padding{10pt}

\makeatletter
\def\internalStorageAnchorPath{
   \pgf@xa=\ctbnex
   \pgf@ya=\ctbney
   \mincorrect{\pgf@xa}{\pgfshapeminwidth}
   \advance\pgf@xa\pgfshapeouterxsep
   \mincorrect{\pgf@ya}{\pgfshapeminheight}
   \advance\pgf@ya\pgfshapeouterysep
   \pgfpathmoveto{\pgfpoint{\pgf@xa}{-\pgf@ya}}
   \advance\pgf@xa by \padding
   \pgfpathlineto{\pgfpoint{-\pgf@xa}{-\pgf@ya}}
   \advance\pgf@ya by \padding
   \pgfpathlineto{\pgfpoint{-\pgf@xa}{\pgf@ya}}
   \advance\pgf@xa by -\padding
   \pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@ya}}
   \pgfpathclose
}
\def\internalStorageBackgroundPath{
   \pgf@xa=\ctbnex
   \pgf@ya=\ctbney
   \mincorrect{\pgf@xa}{\pgfshapeminwidth}
   \mincorrect{\pgf@ya}{\pgfshapeminheight}
   \pgfpathmoveto{\pgfpoint{\pgf@xa}{-\pgf@ya}}
   \pgfpathlineto{\pgfpoint{-\pgf@xa}{-\pgf@ya}}
   \pgfpathlineto{\pgfpoint{-\pgf@xa}{\pgf@ya}}
   \pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@ya}}
   \pgfpathclose
}
\pgfdeclareshape{internalstorage}{
  \setpaths{\internalStorageAnchorPath}{\internalStorageBackgroundPath}
  \savedanchor{\northeast}{
    \pgf@x = \ctbnex
    \mincorrect{\pgf@x}{\pgfshapeminwidth}
    \advance\pgf@x\pgfshapeouterxsep
    \pgf@y = \ctbney
    \mincorrect{\pgf@y}{\pgfshapeminheight}
    \advance\pgf@y\pgfshapeouterysep
  }
  \anchor{south east}{\northeast \pgf@y=-\pgf@y}
  \anchor{south}{\northeast \pgf@x=0pt \pgf@y=-\pgf@y}
  \anchor{south west}{\northeast \pgf@x=-\pgf@x \pgf@y=-\pgf@y}
  \anchor{west}{\northeast \pgf@x=-\pgf@x \pgf@y=0pt}
  \anchor{north west}{\northeast \pgf@x=-\pgf@x}
  \anchor{north}{\northeast \pgf@x=0pt}
  \anchor{north east}{\northeast}
  \anchor{east}{\northeast \pgf@y=0pt}
}
\makeatother

\begin{tikzpicture}[
    >=stealth,
    every state/.style={
      font=\small,
      blur shadow,
      thick,
    },
    every edge/.append style={
      ->,
      thick,
    },
    process/.style={
      state,
      rectangle,
      text width=10em,
      text centered,
      rounded corners,
      top color=orange!60,
      bottom color=orange!20,
    },
    internal storage/.style={
      state,
      internalstorage,
      draw=none,
      blur shadow={
        shadow opacity=0
      },
      font=\small,
      text width=5em,
      text centered,
      append after command={
        \pgfextra{
          \draw[
            thick,
            blur shadow,
            top color=BlueViolet!60,
            bottom color=BlueViolet!20
          ]  (\tikzlastnode.south east)
          -- ( $(\tikzlastnode.south west) + (-\padding, 0)$ )
          -- ( $(\tikzlastnode.north west) + (-\padding, \padding)$ )
          -- ( $(\tikzlastnode.north east) + (0, \padding)$ )
          -- cycle;
          \draw[thick] ( $(\tikzlastnode.north west) + (-\padding, 0)$ )
                    -- (\tikzlastnode.north east);
          \draw[thick] ( $(\tikzlastnode.north west) + (0, \padding)$ )
                    -- (\tikzlastnode.south west);
        }
      },
    },
  ]
  \matrix (m)[matrix of nodes, column sep=8mm, row sep=6.5mm, align=center, nodes={rectangle, draw, anchor=center}]{
    |[process]| {north west} & |[process]|          {north           } & |[process]| {north east} \\
    |[process]| {west      } & |[internal storage]| {Internal Storage} & |[process]| {east      } \\
    |[process]| {south west} & |[process]|          {south           } & |[process]| {south east} \\
  };
  \draw (m-1-1) edge (m-2-2);
  \draw (m-1-2) edge (m-2-2);
  \draw (m-1-3) edge (m-2-2);
  \draw (m-2-3) edge (m-2-2);
  \draw (m-3-3) edge (m-2-2);
  \draw (m-3-2) edge (m-2-2);
  \draw (m-3-1) edge (m-2-2);
  \draw (m-2-1) edge (m-2-2);
\end{tikzpicture}

\end{document}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .