7

I'm trying to draw an ERD diagram. I recycled code from a couple of posts around here and added my own spice, finally ending up with:


\documentclass[border=0.5in]{article}

\usepackage{tikz}
\usetikzlibrary{shapes.multipart}
\usetikzlibrary{matrix}
\usetikzlibrary{positioning}
\usetikzlibrary{calc}
\usepackage{scalefnt}
\usepackage{geometry}
\usepackage{pdflscape}

\makeatletter

\pgfarrowsdeclare{oone}{oone}
{
  \pgfarrowsleftextend{+0pt}%
  \pgfarrowsrightextend{+0pt}%
}
{
  \pgfutil@tempdima=0.25pt%
  \advance\pgfutil@tempdima by0.25\pgflinewidth%
  \pgfsetdash{}{+0pt}%
  \pgfsetmiterjoin%
  \pgfpathmoveto{\pgfqpoint{0\pgfutil@tempdima}{0\pgfutil@tempdima}}%
  \pgfpathlineto{\pgfqpoint{-8\pgfutil@tempdima}{-8\pgfutil@tempdima}}%
  \pgfpathmoveto{\pgfqpoint{0\pgfutil@tempdima}{0\pgfutil@tempdima}}%
  \pgfpathlineto{\pgfqpoint{-8\pgfutil@tempdima}{+8\pgfutil@tempdima}}%
  \pgfpathmoveto{\pgfqpoint{-12\pgfutil@tempdima}{-8\pgfutil@tempdima}}%
  \pgfpathlineto{\pgfqpoint{-12\pgfutil@tempdima}{+8\pgfutil@tempdima}}%
  \pgfusepathqstroke%
}

\pgfarrowsdeclare{one}{one}
{
  \pgfarrowsleftextend{+0pt}%
  \pgfarrowsrightextend{+0pt}%
}
{
  \pgfutil@tempdima=0.25pt%
  \advance\pgfutil@tempdima by0.25\pgflinewidth%
  \pgfsetdash{}{+0pt}%
  \pgfsetmiterjoin%
  \pgfpathmoveto{\pgfqpoint{0\pgfutil@tempdima}{0\pgfutil@tempdima}}%
  \pgfpathlineto{\pgfqpoint{-8\pgfutil@tempdima}{-8\pgfutil@tempdima}}%
    \pgfpathmoveto{\pgfqpoint{0\pgfutil@tempdima}{0\pgfutil@tempdima}}%
  \pgfpathlineto{\pgfqpoint{-8\pgfutil@tempdima}{+8\pgfutil@tempdima}}%
  \pgfusepathqstroke%
}


\pgfarrowsdeclare{many}{many}
{
  \pgfarrowsleftextend{+0pt}%
  \pgfarrowsrightextend{+0pt}%
}
{
  \pgfutil@tempdima=0.25pt%
  \advance\pgfutil@tempdima by0.25\pgflinewidth%
  \pgfsetdash{}{+0pt}%
  \pgfsetmiterjoin%
  \pgfpathmoveto{\pgfqpoint{0\pgfutil@tempdima}{0\pgfutil@tempdima}}%
  \pgfpathlineto{\pgfqpoint{-8\pgfutil@tempdima}{-8\pgfutil@tempdima}}%
    \pgfpathmoveto{\pgfqpoint{0\pgfutil@tempdima}{0\pgfutil@tempdima}}%
  \pgfpathlineto{\pgfqpoint{-8\pgfutil@tempdima}{+8\pgfutil@tempdima}}%
  \pgfpathmoveto{\pgfqpoint{-6\pgfutil@tempdima}{0\pgfutil@tempdima}}%
  \pgfpathlineto{\pgfqpoint{-14\pgfutil@tempdima}{-8\pgfutil@tempdima}}%
    \pgfpathmoveto{\pgfqpoint{-6\pgfutil@tempdima}{0\pgfutil@tempdima}}%
  \pgfpathlineto{\pgfqpoint{-14\pgfutil@tempdima}{+8\pgfutil@tempdima}}%
  \pgfusepathqstroke%
}

\pgfarrowsdeclare{omany}{omany}
{
  \pgfarrowsleftextend{+0pt}%
  \pgfarrowsrightextend{+0pt}%
}
{
  \pgfutil@tempdima=0.25pt%
  \advance\pgfutil@tempdima by0.25\pgflinewidth%
  \pgfsetdash{}{+0pt}%
  \pgfsetmiterjoin%
  \pgfpathmoveto{\pgfqpoint{0\pgfutil@tempdima}{0\pgfutil@tempdima}}%
  \pgfpathlineto{\pgfqpoint{-8\pgfutil@tempdima}{-8\pgfutil@tempdima}}%
    \pgfpathmoveto{\pgfqpoint{0\pgfutil@tempdima}{0\pgfutil@tempdima}}%
  \pgfpathlineto{\pgfqpoint{-8\pgfutil@tempdima}{+8\pgfutil@tempdima}}%
  \pgfpathmoveto{\pgfqpoint{-6\pgfutil@tempdima}{0\pgfutil@tempdima}}%
  \pgfpathlineto{\pgfqpoint{-14\pgfutil@tempdima}{-8\pgfutil@tempdima}}%
    \pgfpathmoveto{\pgfqpoint{-6\pgfutil@tempdima}{0\pgfutil@tempdima}}%
  \pgfpathlineto{\pgfqpoint{-14\pgfutil@tempdima}{+8\pgfutil@tempdima}}%
    \pgfpathmoveto{\pgfqpoint{-18\pgfutil@tempdima}{+8\pgfutil@tempdima}}%
  \pgfpathlineto{\pgfqpoint{-18\pgfutil@tempdima}{-8\pgfutil@tempdima}}%
  \pgfusepathqstroke%
}


\begin{document}


\tikzset{
    entity/.code={
        \tikzset{
            rounded corners,             
            name=#1,
            inner sep=2pt,
            every entity/.try,
            label=below:#1
        }%
        \def\entityname{#1}%
    },
    entity anchor/.style={matrix anchor=#1},
    every entity/.style={
            draw,
    },
    every property/.style={
        inner xsep=0.20cm, inner ysep=0.075cm, anchor=west, text width=1in
    },
    zig zag to/.style={
        to path={(\tikztostart) -| ($(\tikztostart)!#1!(\tikztotarget)$) |- (\tikztotarget)}
    },
    zig zag to/.default=0.5,
    many to one/.style={
        many-one, zig zag to
    },
    one to omany/.style={
        one-omany, zig zag to
    }
}
\def\property#1{\node[name=\entityname-#1, every property/.try]{#1};}
\def\properties{\begingroup\catcode`\_=11\relax\processproperties}
\def\processproperties#1{\endgroup%
    \def\propertycode{}%
    \foreach \p in {#1}{%
        \expandafter\expandafter\expandafter\gdef\expandafter\expandafter\expandafter\propertycode%
            \expandafter\expandafter\expandafter{\expandafter\propertycode\expandafter\property\expandafter{\p}\\}%
    }%
    \propertycode%
}


\begin{landscape}

\scalefont{0.5}


\begin{tikzpicture}[every node/.style={font=\ttfamily}, node distance=0.5in]




\matrix [entity=Rent] {
    \properties{
        ID : int(11), 
        StartDate :  datetime,
        EndDate : datetime,
        PickupDate : datetime,
        ReturnDate : datetime,
        PickupMiles : int(11),
        ReturnMiles : int(11),
        Missing :  bool, 
        VehicleVIN  :  varchar(255),
        EmployeeUsername :  varchar(255),
        CustomerID :  int(11),
        DepartureGarage :  int(11),
        ArrivalGarage : int(11),
        OfferID : int(11),
        Kasko : bool,
        TPI :  bool, 
        CDW :  bool,
        TW  :  bool,
        DER :  bool,
        RestrictAge :  bool,
        ExtraMileageUnits :  int(11)      
    }
};

\matrix [entity=Employee, above=of Rent] {
    \properties{
        Username :  varchar(255),
        Password :  varchar(255),        
        Name :  varchar(255),
        LastName :  varchar(255)
    }
};

\matrix [entity=Vehicle, left= of Rent] {
    \properties{
    VIN : varchar(255),
    Plate : varchar(255),
    Seating : int(11),
    Doors : int(11),
    4WD : bool,
    Year : int(11),
    Diesel : bool,
    Displacement : double,
    Consumption : double,
    LPG : bool,
    ManualShift : bit,
    Autonomy : double,
    Discriminator : int(11),
    ModelID : int(11),
    HousedInGarage : int(11),
    Retired : bool,
    FullHybrid : bool,
    Mileage : int(11)
    }
};

\draw[one to omany] (Vehicle) to (Rent);
\draw[one-omany] (Employee) to (Rent);

\end{tikzpicture}
\end{landscape}

\end{document}

Now, I would like to have the label inside the node, maybe with a separator or something. ATM I get:

whatiget

But I would rather have:

enter image description here

Can anybody suggest a way to do so?

Thank you a whole lot.

1
  • Natuerlich I could do with a custom command to manually get what I want. The closest I've come is \def\mylabel#1{\node[]{#1};} And then \matrix [entity=Rent] { \mylabel {Rent}\\ \properties{ ... But it's ugly, very very ugly. Commented Aug 8, 2014 at 11:52

2 Answers 2

7

I guess this is one way of doing it:

\documentclass[tikz,border=5]{standalone}

\usetikzlibrary{matrix}
\begin{document}
\tikzset{
    entity/.code={
        \tikzset{
            rounded corners,             
            name=#1,
            inner sep=2pt,
            every entity/.try,
        }%
        \def\entityname{#1}%
    },
    entity anchor/.style={matrix anchor=#1},
    every entity/.style={
            draw,
    },
    every property/.style={
        inner xsep=0.20cm, inner ysep=0.075cm, anchor=west, text width=1.75in
    }
}
\def\property#1{\node[name=\entityname-#1, every property/.try]{\propertysplit#1;};}
\def\properties{\begingroup\catcode`\_=11\relax\processproperties}
\def\processproperties#1{\endgroup%
    \gdef\propertycode{}%
    \foreach \p in {#1}{%
        \expandafter\expandafter\expandafter\gdef\expandafter\expandafter\expandafter\propertycode%
            \expandafter\expandafter\expandafter{\expandafter\propertycode\expandafter\property\expandafter{\p}\\}%
    }%
    \propertycode%
}
\def\propertysplit#1:#2;{#1:\hfill#2}

\def\entitynamenode{%
\node[every entity name/.try] (\entityname-name) {\entityname};
\draw (\entityname-name.south west) -- (\entityname-name.south east);
\\[1ex]
}
\tikzset{
  every entity name/.style={every property/.try, align=center}
}

\begin{tikzpicture}[every node/.style={font=\ttfamily}, node distance=0.5in]
\matrix [entity=Employee] {
    \entitynamenode
    \properties{
        Username :  varchar(255),
        Password :  varchar(255),        
        Name :  varchar(255),
        LastName :  varchar(255)
    }
};
\end{tikzpicture}   

\end{document}

enter image description here

3
  • Wonderful. You saved my life. Commented Aug 10, 2014 at 16:34
  • Would you please be so kind as to explain what you've done a little? It's not entirely clear to me, especially \node[every entity name/.try] (\entityname-name) {\entityname}; and I wouldn't know what to Google. Commented Aug 10, 2014 at 19:40
  • With the my current version of LaTeX, @mark-wibrow, this code seems not to compile, as it seems that there is an error related to \properties (Undefined } is raised, and errors near the : are raised, too). Any hints for solving my issue? I was able to replicate my problem by compiling the code on Overleaf: it.overleaf.com/read/yrpzjmzywhrk
    – jackb
    Commented Oct 2, 2021 at 12:17
0

In the end I resorted to this little hack, which is not perfect not good for space saving, but does an acceptable job:

    entity/.code={
        \tikzset{
            rounded corners,             
            name=#1,
            inner sep=10pt,
            every entity/.try,
            label={[xshift=0cm, font=\bfseries, yshift=-10.5pt]#1}
        }%
        \def\entityname{#1}%
    }
    

I'm shifting the label inside the box and I'm adding enough padding to accomodate it.

However, besides being a bit ugly - it still gives me no separator.

This can certainly be improved upon by somebody who actually knows what she/he's doing.

You must log in to answer this question.

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