6

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. Aug 8 '14 at 11:52
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. Aug 10 '14 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. Aug 10 '14 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
    Oct 2 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.

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.