# Sequence Diagram

      define Complex System as sys
      define User as usr
      define Sequence Diagram as diagram
      define Other Users as usr2
      begin sys, usr, usr2
      sys ~> usr
      note over usr: "Take time to\nunderstand System"
      usr -> *diagram: Create
      usr -> usr2: Inform
      usr2 <-> diagram: Learn & understand
      usr2 -> sys: Use
      terminators box

## Introduction

Want to draw a Sequence Diagram? Go to the online editor.

This library renders sequence diagrams from code. It is open-source (LGPL-3.0), and including it in a website is as simple as adding the script:

    <script src="lib/sequence-diagram-web.min.js"></script>

Or if you are using requirejs:

    requirejs(['lib/sequence-diagram-web.min'], (SequenceDiagram) => {
      SequenceDiagram.convertAll();
    });

Any element with the class `sequence-diagram` will automatically be converted when the page loads:

      A -> B: foo
      B -> A: bar

    <pre class="sequence-diagram">
      A -> B: foo
      B -> A: bar
    </pre>

## Language

### Connection Types

    title Connection Types

    begin Foo, Bar, Baz

    Foo -> Bar: Simple arrow
    Bar --> Baz: Dashed arrow
    Foo <- Bar: Reversed arrow
    Bar <-- Baz: Reversed & dashed
    Foo <-> Bar: Double arrow
    Bar <--> Baz: Double dashed arrow

    # An arrow with no label:
    Foo -> Bar

    Bar ->> Baz: Different arrow
    Foo <<--> Bar: Mix of arrows

    Bar -> Bar: Bar talks to itself

    Foo -> +Bar: Foo asks Bar
    -Bar --> Foo: and Bar replies

    Bar -x Baz: Lost message

    # Arrows leaving on the left and right of the diagram
    [ -> Foo: From the left
    [ <- Foo: To the left
    Foo -> ]: To the right
    Foo <- ]: From the right
    [ ~> ]: Wavy left to right!
    # (etc.)

### Dividers

    title Dividers

    begin Foo, Bar, Baz

    Foo -> +Bar

    divider

    Bar -> +Baz

    divider delay: This takes a while

    -Baz --> Bar

    divider tear with height 20: Lots of stuff happens

    -Bar --> Foo

### Notes & State

    title Note Placements

    note over Foo: Foo says something
    note left of Foo: Stuff
    note right of Bar: More stuff
    note over Foo, Bar: "Foo and Bar
    on multiple lines"
    note between Foo, Bar: Link

    text right: "Comments\nOver here!"

    state over Foo: Foo is ponderous

### Logic

    title At the Bank

    begin Person, ATM, Bank
    Person -> ATM: Request money
    ATM -> Bank: Check funds
    if fraud detected
      Bank -> Police: "Get 'em!"
      Police -> Person: "You're nicked"
      end Police
    else if sufficient funds
      ATM -> Bank: Withdraw funds
      repeat until "all requested money
                    has been handed over"
        ATM -> Person: Dispense note
      end
    else
      ATM -> Person: Error
    end

### Label Templates

    autolabel "[<inc>] <label>"

    begin "Underpants\nGnomes" as A
    A <- ]: Collect underpants
    A <-> ]: ???
    A <- ]: Profit!

### Multiline Text

    title "My Multiline
    Title"

    note over Foo: "Also possible\nwith escapes"

    Foo -> Bar: "Lines of text\non this arrow"

    if "Even multiline\ninside conditions like this"
      Foo -> "Multiline\nagent"
    end

    state over Foo: "Newlines here,
    too!"

### Themes

    theme sketch

    title Mockup

    A thing -> +Another thing: Something happens
    -Another thing --> A thing: With some response
    note right of Another thing: Find out what happens here
    end Another thing

#### Available themes

- basic
- monospace
- chunky
- sketch
- sketch left handed

### Short-Lived Agents

    title "Baz doesn't live long"

    note over Foo, Bar: Using begin / end

    begin Baz
    Bar -> Baz
    Baz -> Foo
    end Baz

    note over Foo, Bar: Using * / !

    # * and ! cause agents to be
    # created and destroyed inline
    Bar -> *Baz: make Baz
    Foo <- !Baz: end Baz

    # Foo and Bar end with black bars
    terminators bar
    # (options are: box, bar, cross, fade, none)

### Agent Aliases

    define My complicated agent name as A
    define "Another agent name,
    and this one's multi-line!" as B

    A -> B: this is much easier
    A <- B: than writing the whole name

### Markdown

    define "Name with
    **bold** and _italic_" as A
    define "Also `code`
    and ~strikeout~" as B

    A -> B: "_**basic markdown
    is supported!**_"

### Alternative Agent Ordering

    define Baz, Foo

    Foo -> Bar
    Bar -> Baz

### Asynchronous Communication

    begin Initiator as I, Receiver as R

    # the '...id' syntax allows connections
    # to span multiple lines

    I -> ...fin1
    ...fin1 -> R: FIN

    # they can even inter-mix!
    R -> ...ack1
    R -> ...fin2
    ...ack1 -> I: ACK
    ...fin2 -> I: FIN

    !I -> ...ack2
    ...ack2 -> !R: ACK

### More

More features are supported. See the online editor’s library and autocomplete features to discover them.

## Browser Support

This has been tested in the latest versions of Google Chrome, Mozilla Firefox, and Apple Safari. Versions of Microsoft Internet Explorer / Edge have not been tested and probably won’t work. Any bugs found in a supported browser should be reported in the Issue Tracker.

## API

For more advanced usage, an API is available:

    var diagram = new SequenceDiagram();
    diagram.set('A -> B\nB -> A');
    document.body.appendChild(diagram.dom());

    // Highlight elements created in line 1 (0-based)
    diagram.setHighlight(1);

### Constructor

    diagram = new SequenceDiagram(code, options);
    diagram = new SequenceDiagram(code);
    diagram = new SequenceDiagram(options);
    diagram = new SequenceDiagram();

Creates a new SequenceDiagram object. Options is an object which can contain:

- `code`: Alternative way of specifying code, instead of using a separate argument.
- `container`: DOM node to append the diagram to (defaults to null).
- `document`: Document object to base the diagram in (defaults to container's document, or `window.document`).
- `textSizerFactory`: Function which returns an object capable of measuring text (defaults to wrapping `getComputedTextLength`).
- `themes`: List of themes to make available to the diagram (defaults to globally registered themes).
- `namespace`: Each diagram on a page must have a unique namespace. By default a unique namespace is generated, but if you want something specific, enter it here.
- `interactive`: If `true`, will automatically call `addInteractivity` when constructing the diagram.

### .clone

    newDiagram = diagram.clone(options);
    newDiagram = diagram.clone();

Creates a copy of the diagram. If options are given, they will override the current diagram’s state (options is passed to the constructor of the new object, so all the same options are available). Note that by default, the `namespace` will not be cloned (a new unique namespace will be generated). Also the `container` will not be cloned; you will need to specify one explicitly or manually attach the new diagram at a later point.

### .set

    diagram.set(code);

Changes the code for the diagram and causes a re-render.

### .process

    processed = diagram.process(code);

Processes the given code but does not render it. Causes no change to the diagram object. This is mostly useful for debounced rendering with immediate error notifications. The resulting object can be passed to `render` at a later point.

### .render

    diagram.render();
    diagram.render(processed);

Forces a re-render of the diagram. Typically this happens automatically. Optionally, the result of an earlier call to `process` can be provided.

### .addTheme

    diagram.addTheme(theme);

Make a new theme available to the diagram. Any unrecognised themes are replaced with the default theme.

The theme API has not been finalised yet, so this method is not typically useful.

### .getThemeNames

    names = diagram.getThemeNames();

Returns a list of names of themes which are available to this diagram. These can be specified in a `theme <name>` line in the code.

### .getThemes

    themes = diagram.getThemes();

Returns a list of themes which are available to this diagram.

### .addInteractivity

      begin A, B
      if bored
        A -> +B
        -B --> A
      end
      if still bored
        A -> +B
        -B --> A
      end

    diagram.addInteractivity();

Makes the rendered diagram interactive. Currently this means adding a click listener to any groups which causes them to collapse / expand. Try clicking on the example to the right.

The example here has CSS styling applied:

    .region.collapsed,
    .region.expanded {
    	cursor: pointer;
    	user-select: none;
    }

    .region.collapsed:hover .outline,
    .region.expanded:hover .outline {
    	fill: rgba(255, 128, 0, 0.5);
    }

It is also possible to enable interactivity using a HTML attribute:

    <pre class="sequence-diagram" data-sd-interactive>
      A -> +B
      if something
        -B --> A
      end
    </pre>

### .getSVGSynchronous

    svgURL = diagram.getSVGSynchronous(options);

Returns a blob URL which contains the SVG code for the current diagram.

The options can include:

- `size`: Object containing optional width, height or zoom to specify in the SVG.

### .getSVG

    diagram.getSVG(options).then(({url, latest}) => { ... });

Asynchronous version of `getSVGSynchronous`. This is provided for compatibility with `getPNG`, which has no synchronous equivalent.

The options can include:

- `size`: Object containing optional width, height or zoom to specify in the SVG.

The callback receives an object containing:

- `url`: The URL of the generated blob.
- `latest`: True if the URL given is still valid; subsequent calls to this method will invalidate previous URLs.

### .getPNG

    diagram.getPNG(options).then(({url, latest}) => { ... });

Generates a PNG image and returns a blob URL.

The options can include:

- `resolution`: Desired pixels-per-unit.
- `size`: Object containing optional width, height or zoom to render the image at (defaults to the unit size of the diagram). The final output will have size `width * resolution` × `height * resolution`.

The callback receives an object containing:

- `url`: The URL of the generated blob.
- `latest`: True if the URL given is still valid; subsequent calls to this method will invalidate previous URLs.

### .getSize

    size = diagram.getSize();

Returns an object containing `width` and `height` properties, corresponding to the size of the diagram in units.

### .setContainer

    diagram.setContainer(node);

Same as calling `node.appendChild(diagram.dom())`.

### .dom

    node = diagram.dom();

Returns the base SVG element which the diagram has been rendered into.

### .setHighlight

    diagram.setHighlight(line);
    diagram.setHighlight();

Marks elements generated by the specified line with a "focus" CSS class, which can be used to style them. Only one line can be highlighted at a time. Calling with no parameter (or `null`) will remove the highlighting.

The outline effect seen in the editor can be achieved by targetting `.focus .outline`. All elements contain an element with the class "outline", which defines a simple shape surrounding the entire element. For example:

    .region.focus .outline {
    	stroke-width: 5px;
    	stroke: rgba(255, 128, 0, 0.5);
    }

### .setCollapsed

    diagram.setCollapsed(line, collapsed, options);
    diagram.setCollapsed(line, collapsed);

Marks the given line as collapsed or non-collapsed. If an element defined at that line can be collapsed, it will be modified during the next render. Returns true if a change occurred, or false if the line already had the requested state.

`line` can also be an array of lines.

By default, calling this method will trigger an automatic render (unless called as a no-op). This can be disabled by passing `{render: false}` in the options argument.

### .isCollapsed

    collapsed = diagram.isCollapsed(line);

Returns true if the given line is marked as collapsed, regardless of whether that line being collapsed has a meaningful impact on the rendered document.

### .collapse

    diagram.collapse(line, options);
    diagram.collapse(line);

Shorthand for `.setCollapsed(line, true, options)`.

### .expand

    diagram.expand(line, options);
    diagram.expand(line);

Shorthand for `.setCollapsed(line, false, options)`.

### .toggleCollapsed

    diagram.toggleCollapsed(line, options);
    diagram.toggleCollapsed(line);

Toggles the given line’s collapsed status by calling `.setCollapsed`.

### .expandAll

    diagram.expandAll(options);
    diagram.expandAll();

Marks all lines as non-collapsed. Returns true if a change occurred, or false if all lines were already non-collapsed.

By default, calling this method will trigger an automatic render (unless called as a no-op). This can be disabled by passing `{render: false}` in the options argument.

### .addEventListener

    diagram.addEventListener(type, callback);

Registers an event listener. The available events are:

- `mouseover`: called when the mouse enters a region of the diagram (e.g. a note).
- `mouseout`: called when the mouse leaves a region of the diagram.
- `click`: called when the user clicks on a region of the diagram.
- `dblclick`: called when the user double-clicks on a region of the diagram.
- `render`: called when the diagram finishes rendering. Receives the sequence diagram object as an argument.

All mouse events are invoked with a single parameter: the element. This object contains:

- `ln`: the line number of the source code which defined the element.
- `type`: a string representing the type of the element.
- Other fields which define the element (exact fields vary by type).

### .removeEventListener

    diagram.removeEventListener(type, callback);

Removes a previously registered event listener.

### .removeAllEventListeners

    diagram.removeAllEventListeners(type);
    diagram.removeAllEventListeners();

Removes all registered event listeners for a given type, or all event listeners for all types.

## Similar Tools

There are quite a lot of sequence diagram drawing tools available. If this one doesn’t fit your needs for whatever reason, you might want to take a look at the alternatives: (but also feel free to raise feature requests in the issue tracker!)

- websequencediagrams.com is a commercial offering which inspired the syntax of this project and many others. It has a wide range of themes but limited functionality. Also offers a hosted image generation service.
- js-sequence-diagrams is a Javascript library which has wider browser support via snap.svg but very limited functionality.
- mermaid is a Javascript library and online editor which can render multiple types of UML diagram, including simple sequence diagrams.
- Scruffy UML is a Python library which can render multiple types of UML diagram, including simple sequence diagrams, from the commandline. Uses yUML syntax rather than the human friendly syntax used by most other projects.
- PlantUML is a Java project and online editor which can render multiple types of UML diagram, including sequence diagrams. Has a good range of features and allows a high degree of customisation (e.g. diagram colours).

## Thanks

Thanks to the other tools mentioned above for inspiring parts of the syntax of this project, and to the Handlee font which is used in the sketch theme.

      theme sketch
      begin User, SequenceDiagram as SD, Parser, Generator, Renderer

      User -> +SD: code

      SD -> +Parser: code
      -Parser --> SD: parsed

      SD -> +Generator: parsed
      -Generator --> SD: generated

      -SD -> +Renderer: generated
      -Renderer -> *DOM: SVG
      User <~> DOM: interaction

      terminators box