Skip to content

Instantly share code, notes, and snippets.

@farawayboat
Created December 19, 2014 00:15
Show Gist options
  • Save farawayboat/294adaa6a1377f87c1cb to your computer and use it in GitHub Desktop.
Save farawayboat/294adaa6a1377f87c1cb to your computer and use it in GitHub Desktop.
% Manual of pgf-umlsd.sty, a convenient set of macros for drawing UML
% sequence diagrams.
% Written by Xu Yuan <[email protected]> from
% Southeast University, China.
% This file is part of pgf-umlsd
% you may get it at http://code.google.com/p/pgf-umlsd/
\documentclass{article}
\usepackage[margin=12mm]{geometry}
\usepackage{hyperref}
\usepackage[underline=true,rounded corners=false]{pgf-umlsd}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\usepackage{listings}
\usepackage{color}
\definecolor{listinggray}{gray}{0.92}
\lstset{ %
language=[LaTeX]TeX,
breaklines=true,
frame=single,
% frameround=tttt,
basicstyle=\footnotesize\ttfamily,
backgroundcolor=\color{listinggray},
keywordstyle=\color{blue}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\hypersetup{
colorlinks=true,
linkcolor=blue,
anchorcolor=black,
citecolor=olive,
filecolor=magenta,
menucolor=red,
urlcolor=blue
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand{\demo}[2][1]{
\begin{center}
\begin{tabular}{cc}
\begin{minipage}{.49\linewidth}
\centering
\resizebox{#1\linewidth}{!}{
\input{demo/#2}
}
\end{minipage}
&
\begin{minipage}{.45\linewidth}
\lstinputlisting{demo/#2}
\end{minipage}
\end{tabular}
\end{center}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand{\example}[2][1]{
\begin{center}
\resizebox{#1\linewidth}{!}{
\input{demo/#2}
}
\end{center}
\lstinputlisting{demo/#2}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{document}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\title{Drawing UML Sequence Diagram by using \texttt{pgf-umlsd}}
\author{\href{mailto:[email protected]}{Yuan Xu}}
\date{\today{}~(v0.7)}
\maketitle
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\begin{abstract}
\texttt{pgf-umlsd} is a LaTeX package for drawing UML Sequence
Diagrams. As stated by its name, it is based on a very popular
graphic package \texttt{PGF/TikZ}. This document presents the usage
of \texttt{pgf-umlsd} and collects some UML sequence diagrams as
examples. \texttt{pgf-umlsd} can be downloaded from
\href{http://code.google.com/p/pgf-umlsd/}{http://code.google.com/p/pgf-umlsd/}.
\end{abstract}
\tableofcontents
\section{The Essentials}
\subsection{Basic graphics objects}
\subsubsection{empty diagram}
\demo{empty}
\subsubsection{thread}
\demo[0.3]{thread}
\subsubsection{instance}
\demo[0.3]{instance}
\subsubsection{distance between threads and instances}
\demo{distance}
\subsubsection{customization}
The package has two options for customization: \texttt{underline} and
\texttt{rounded corners}, further customization see the example below:
\demo{customize}
\subsection{Call}
\subsubsection{call}
\demo[0.6]{call}
\subsubsection{call self}
\demo[0.6]{callself}
\subsubsection{message call}
\demo[0.6]{messcall}
\subsubsection{nested call}
\demo[0.6]{nested-call}
\subsection{Message}
\demo[0.6]{message}
Sometimes however, it takes a considerable amount of time to reach the
receiver (relatively speaking of course) . For example, a message
across a network. Such a non-instantaneous message is drawn as a
slanted arrow.
\demo[0.6]{non-instantaneous-message}
\subsection{Block}
\demo[0.6]{block}
\section{Manually adjustment}
The idea of \texttt{pgf-umlsd} is users only have to write the logic
of diagram, the program generates figure automatically. However, the
package can not handle all the use case, it still needs to be adjusted
manually.
\subsection{Level}
If the text on the arrows is more than one line (large function name
for example) it will overlap other things. \texttt{postlevel} can be
used to make the time (level) later.
\demo[0.6]{postlevel}
In the situation of multi-threads, some events happen at the same
time. \texttt{prelevel} can make the call earlier.
\demo[0.6]{prelevel}
\subsection{Bias of thread line}
In the situation of multi-threads, the instance cen be accessed at the
same time (e.g. two threads reading data at the same time). Currently,
we have to adjust the bias of thread line manually for this. Possible
parameters for \texttt{setthreadbias} are: \texttt{center},
\texttt{west} and \texttt{east}.
\demo[0.8]{threadbias}
\section{Examples}
\subsection{Single thread}
\example[0.8]{single-thread-example}
\subsection{Multi-threads}
\example[0.8]{multi-threads-example}
\subsection{Annotation}
\example[0.5]{sync-clock}
\subsection{Known Issue}
\texttt{pgf-umlsd} confilts with tikz \texttt{backgrounds} library.
\section{Acknowledgements}
Many people contributed to \texttt{pgf-umlsd} by reporting problems,
suggesting various improvements or submitting code. Here is a list of
these people:
\href{mailto:[email protected]}{Nobel Huang},
\href{mailto:[email protected]}{Dr. Ludger Humbert},
\href{mailto:[email protected]}{MathStuf},
\href{mailto:[email protected]}{Vlado Handziski},
\href{mailto:[email protected]}{Frank Morgner},
and \href{mailto:[email protected]}{Dirk Petrautzki}.
\end{document}
%%% Local Variables:
%%% mode: Tex-PDF
%%% TeX-master: t
%%% End:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Start of pgf-umlsd.sty
%
% Some macros for UML Sequence Diagrams.
% Home page of project: http://pgf-umlsd.googlecode.com/
% Author: Xu Yuan <[email protected]>, Southeast University, China
% Contributor: Nobel Huang <[email protected]>, Southeast University, China
%
% History:
% v0.7 2012/03/05
% - unify interface of call and callself
% - non-instantaneous message
% - bugfix: conflits with tikz library backgrounds
% v0.6 2011/07/27
% - Fix Issue 6 reported by [email protected]
% - diagram without a thread
% - allows empty diagram
% - New manual
% v0.5 2009/09/30 Fix Issue 2 reported by vlado.handziski
% - Nested callself is supported
% - Rename sdloop and sdframe to sdblock
% v0.4 2008/12/08 Fix Issue 1 reported by MathStuf:
% Nested sdloop environment hides outer loop
% v0.3 2008/11/10 in Berlin, fix for the PGF cvs version:
% - the list items in \foreach are not evaluated by default now,
% the `evaluate' opinion should be used
% v0.2 2008/03/20 create project at http://pgf-umlsd.googlecode.com/
% - use `shadows' library
% Thanks for Dr. Ludger Humbert's <[email protected]> feedback!
% - reduce the parameter numbers, the user can write the content
% of instance (such as no colon)
% - the user can redefine the `inststyle'
% - new option: switch underlining of the instance text
% - new option: switch rounded corners
% v0.1 2008/01/25 first release at http://www.fauskes.net/pgftikzexamples/
%
\NeedsTeXFormat{LaTeX2e}[1999/12/01]
\ProvidesPackage{pgf-umlsd}[2011/07/27 v0.6 Some LaTeX macros for UML
Sequence Diagrams.]
\RequirePackage{tikz}
\usetikzlibrary{arrows,shadows}
\RequirePackage{ifthen}
% Options
% ? the instance name under line ?
\newif\ifpgfumlsdunderline\pgfumlsdunderlinetrue
\DeclareOption{underline}{\pgfumlsdunderlinetrue}
\DeclareOption{underline=true}{\pgfumlsdunderlinetrue}
\DeclareOption{underline=false}{\pgfumlsdunderlinefalse}
% ? the instance box with rounded corners ?
\newif\ifpgfumlsdroundedcorners\pgfumlsdroundedcornersfalse
\DeclareOption{roundedcorners}{\pgfumlsdroundedcornerstrue}
\DeclareOption{roundedcorners=true}{\pgfumlsdroundedcornerstrue}
\DeclareOption{roundedcorners=false}{\pgfumlsdroundedcornersfalse}
\ProcessOptions
% new counters
\newcounter{preinst}
\newcounter{instnum}
\newcounter{threadnum}
\newcounter{seqlevel} % level
\newcounter{callevel}
\newcounter{callselflevel}
\newcounter{blocklevel}
% new an instance
% Example:
% \newinst[edge distance]{var}{name:class}
\newcommand{\newinst}[3][0.2]{
\stepcounter{instnum}
\path (inst\thepreinst.east)+(#1,0) node[inststyle] (inst\theinstnum)
{\ifpgfumlsdunderline
\underline{#3}
\else
#3
\fi};
\path (inst\theinstnum)+(0,-0.5*\unitfactor) node (#2) {};
\tikzstyle{instcolor#2}=[]
\stepcounter{preinst}
}
% new an instance thread
% Example:
% \newinst[color]{var}{name}{class}
\newcommand{\newthread}[3][gray!30]{
\newinst{#2}{#3}
\stepcounter{threadnum}
\node[below of=inst\theinstnum,node distance=0.8cm] (thread\thethreadnum) {};
\tikzstyle{threadcolor\thethreadnum}=[fill=#1]
\tikzstyle{instcolor#2}=[fill=#1]
}
% draw running (thick) line, should not call directly
\newcommand*{\drawthread}[2]{
\begin{pgfonlayer}{umlsd@threadlayer}
\draw[threadstyle] (#1.west) -- (#1.east) -- (#2.east) -- (#2.west) -- cycle;
\end{pgfonlayer}
}
% a function call
% Example:
% \begin{call}[height]{caller}{function}{callee}{return}
% \end{call}
\newenvironment{call}[5][1]{
\ifthenelse{\equal{#2}{#4}}
{
\begin{callself}[#1]{#2}{#3}{#5}
}
{
\begin{callanother}[#1]{#2}{#3}{#4}{#5}
}
}
{
\ifthenelse{\equal{\f\thecallevel}{\t\thecallevel}}
{
\end{callself}
}
{
\end{callanother}
}
}
% function call to another instance
% interal use only
\newenvironment*{callanother}[5][1]{
\stepcounter{seqlevel}
\stepcounter{callevel} % push
\path
(#2)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (cf\thecallevel) {}
(#4.\threadbias)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (ct\thecallevel) {};
\draw[->,>=triangle 60] ({cf\thecallevel}) -- (ct\thecallevel)
node[midway, above] {#3};
\def\l\thecallevel{#1}
\def\f\thecallevel{#2}
\def\t\thecallevel{#4}
\def\returnvalue{#5}
\tikzstyle{threadstyle}+=[instcolor#2]
}
{
\addtocounter{seqlevel}{\l\thecallevel}
\path
(\f\thecallevel)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (rf\thecallevel) {}
(\t\thecallevel.\threadbias)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (rt\thecallevel) {};
\draw[dashed,->,>=angle 60] ({rt\thecallevel}) -- (rf\thecallevel)
node[midway, above]{\returnvalue};
\drawthread{ct\thecallevel}{rt\thecallevel}
\addtocounter{callevel}{-1} % pop
}
% a function do not need call others
% interal use only
% Example:
% \begin{callself}[height]{caller}{function}{return}
% \end{callself}
\newenvironment*{callself}[4][1]{
\stepcounter{seqlevel}
\stepcounter{callevel} % push
\stepcounter{callselflevel}
\path
(#2)+(\thecallselflevel*0.1-0.1,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (sc\thecallevel) {}
({sc\thecallevel}.east)+(0,-0.33*\unitfactor) node (scb\thecallevel) {};
\draw[->,>=triangle 60] ({sc\thecallevel}.east) -- ++(0.8,0)
node[near start, above right] {#3} -- ++(0,-0.33*\unitfactor)
-- (scb\thecallevel);
\def\l\thecallevel{#1}
\def\f\thecallevel{#2}
\def\t\thecallevel{#2}
\def\returnvalue{#4}
\tikzstyle{threadstyle}+=[instcolor#2]
}{
\addtocounter{seqlevel}{\l\thecallevel}
\path (\f\thecallevel)+(\thecallselflevel*0.1-0.1,-\theseqlevel*\unitfactor-0.33*\unitfactor) node
(sct\thecallevel) {};
\draw[dashed,->,>=angle 60] ({sct\thecallevel}.east) node
(sce\thecallevel) {} -- ++(0.8,0) -- node[midway, right]{\returnvalue} ++(0,-0.33*\unitfactor) -- ++(-0.8,0);
\drawthread{scb\thecallevel}{sce\thecallevel}
\addtocounter{callevel}{-1} % pop
\addtocounter{callselflevel}{-1}
}
% message between threads
% Example:
% \mess[delay]{sender}{message content}{receiver}
\newcommand{\mess}[4][0]{
\stepcounter{seqlevel}
\path
(#2)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (mess from) {};
\addtocounter{seqlevel}{#1}
\path
(#4)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (mess to) {};
\draw[->,>=angle 60] (mess from) -- (mess to) node[midway, above]
{#3};
\node (#3 from) at (mess from) {};
\node (#3 to) at (mess to) {};
}
\newenvironment{messcall}[4][1]{
\stepcounter{seqlevel}
\stepcounter{callevel} % push
\path
(#2)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (cf\thecallevel) {}
(#4.\threadbias)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (ct\thecallevel) {};
\draw[->,>=angle 60] ({cf\thecallevel}) -- (ct\thecallevel)
node[midway, above] {#3};
\def\l\thecallevel{#1}
\def\f\thecallevel{#2}
\def\t\thecallevel{#4}
\tikzstyle{threadstyle}+=[instcolor#2]
}
{
\addtocounter{seqlevel}{\l\thecallevel}
\path
(\f\thecallevel)+(0,-\theseqlevel*\unitfactor-0.7*\unitfactor) node (rf\thecallevel) {}
(\t\thecallevel.\threadbias)+(0,-\theseqlevel*\unitfactor-0.3*\unitfactor) node (rt\thecallevel) {};
\drawthread{ct\thecallevel}{rt\thecallevel}
\addtocounter{callevel}{-1} % pop
}
% In the situation of multi-threads, some objects are called at the
% same time. Currently, we have to adjust the bias of thread line
% manually. Possible parameters are: center, west, east
\newcommand{\setthreadbias}[1]{\global\def\threadbias{#1}}
% This function makes the call earlier.
\newcommand{\prelevel}{\addtocounter{seqlevel}{-1}}
% This function makes the call later.
\newcommand{\postlevel}{\addtocounter{seqlevel}{+1}}
% a block box with caption
% \begin{sdblock}[caption background color]{caption}{comments}
% \end{sdblock}
\newenvironment{sdblock}[3][white]{
\stepcounter{seqlevel}
\stepcounter{blocklevel} % push
\coordinate (blockbeg\theblocklevel) at (0,-\theseqlevel*\unitfactor-\unitfactor);
\stepcounter{seqlevel}
\def\blockcolor\theblocklevel{#1}
\def\blockname\theblocklevel{#2}
\def\blockcomm\theblocklevel{#3}
\begin{pgfinterruptboundingbox}
}{
\coordinate (blockend) at (0,-\theseqlevel*\unitfactor-2*\unitfactor);
\path (current bounding box.east)+(0.2,0) node (boxeast) {}
(current bounding box.west |- {blockbeg\theblocklevel}) + (-0.2,0)
node (nw) {};
\path (boxeast |- blockend) node (se) {};
% % title
\node[blockstyle] (blocktitle) at (nw) {\blockname\theblocklevel};
\path (blocktitle.south east) + (0,0.2) node (set) {}
(blocktitle.south east) + (-0.2,0) node (seb) {}
(blocktitle.north east) + (0.2,0) node (comm) {};
\draw[fill=\blockcolor\theblocklevel] (blocktitle.north west) -- (blocktitle.north east) --
(set.center) -- (seb.center) -- (blocktitle.south west) -- cycle;
\node[blockstyle] (blocktitle) at (nw) {\blockname\theblocklevel};
\node[blockcommentstyle] (blockcomment) at (comm) {\blockcomm\theblocklevel};
\coordinate (se) at (current bounding box.south east);
\end{pgfinterruptboundingbox}
\draw (se) rectangle (nw);
\addtocounter{blocklevel}{-1} % pop
\stepcounter{seqlevel}
}
% the environment of sequence diagram
\newenvironment{sequencediagram}{
% declare layers
\pgfdeclarelayer{umlsd@background}
\pgfdeclarelayer{umlsd@threadlayer}
\pgfsetlayers{umlsd@background,umlsd@threadlayer,main}
\begin{tikzpicture}
\setlength{\unitlength}{1cm}
\tikzstyle{sequence}=[coordinate]
\tikzstyle{inststyle}=[rectangle, draw, anchor=west, minimum
height=0.8cm, minimum width=1.6cm, fill=white,
drop shadow={opacity=1,fill=black}]
\ifpgfumlsdroundedcorners
\tikzstyle{inststyle}+=[rounded corners=3mm]
\fi
\tikzstyle{blockstyle}=[anchor=north west]
\tikzstyle{blockcommentstyle}=[anchor=north west, font=\small]
\tikzstyle{dot}=[inner sep=0pt,fill=black,circle,minimum size=0.2pt]
\global\def\unitfactor{0.6}
\global\def\threadbias{center}
% reset counters
\setcounter{preinst}{0}
\setcounter{instnum}{0}
\setcounter{threadnum}{0}
\setcounter{seqlevel}{0}
\setcounter{callevel}{0}
\setcounter{callselflevel}{0}
\setcounter{blocklevel}{0}
% origin
\node[coordinate] (inst0) {};
}
{
\begin{pgfonlayer}{umlsd@background}
\ifnum\c@instnum > 0
\foreach \t [evaluate=\t] in {1,...,\theinstnum}{
\draw[dotted] (inst\t) -- ++(0,-\theseqlevel*\unitfactor-2.2*\unitfactor);
}
\fi
\ifnum\c@threadnum > 0
\foreach \t [evaluate=\t] in {1,...,\thethreadnum}{
\path (thread\t)+(0,-\theseqlevel*\unitfactor-0.1*\unitfactor) node (threadend) {};
\tikzstyle{threadstyle}+=[threadcolor\t]
\drawthread{thread\t}{threadend}
}
\fi
\end{pgfonlayer}
\end{tikzpicture}}
%%% End of pgf-umlsd.sty
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment