Building a UML editor in JavaScript - part 1

This is part 1 of a series exploring how to build a full-pledged UML editor in pure JavaScript. 


Why JavaScript

I really love Python & its wonderful frameworks - they brought me pure joy & satisfaction for the past 6 years.

However, I'm forced to acknowledge that the times they are a-changin: logic moves back to the client-side, leaving the server-side to do almost nothing (just data access, usually). Further more, the server side turned into a series of disporate API's, which the client consumes, provided by different vendors - so now even the data access moves to the client, which talks directly with datastore providers.


The lingua-franca of the client-side, available anywhere there's a browser, is JavaScript. And, when I needed to write some very scalable server-side service, I also found JavaScript (node.js) doing a really great job even there.

With HTML5, there's no limitation to the abilities of JavaScript on the client-side.


In addition, the platform of computing is going thru an even larger change: mobile devices talking with cloud back-ends. I don't know whether the mobile-specific platforms will remain the mobile client-side technology, or the open-stack of the Web will arrive to the client. Time will tell.


The application

So, in this series I will develop an application in pure JavaScript, for Web & Mobile platforms. 

I do design very often, but don't have a UML editor that works for me: either they're not cloud-based & don't support collaboration, or they're too unusable, or just costing too much money.

So, I'll try to develop in this series a simple UML editor, which is

  • Cloud-based
  • Supports real-time collaboration
  • Works well on tablet & mobile
  • Free & open-source


Mock-up of the application:




Regarding the application name: the main consideration for a name should obviously be SEO - how easy it will be to find it in Google. So, given this imperative consideration, I came up with the name: model 


It's going to be pure client-side app - all static files downloaded from CDN to the client The app will consume remote 3rd-party API's, for example, a remote storage for persistence. Using a tool such as PhoneGap, I'll try to make it usable also as a Mobile app. Of course a pure MVC will be enforced: clear separations between data, business logic & presentation .


If you were given the task of writing a UML editor, which languages would you use?



Initial survey


Before starting out I've sent a couple of colleagues a survey, asking them about their activities & needs in respect to UML. The idea is to try understand who will be the 1st users of the editor (except for myself) & how to make it useful for them.

You can see (& fill out) the survey here.



I received some 7 responses, from which I've learnt that:

  •  Usage: A third of the responders use it often (every week). A third uses it once a month or few. Another third don't use UML at all.
  •  Tools: Half of the users use desktop tools (StarUML, Sparx, OpenOffice, Violet). Another hald uses online tools (WebSequenceDiagrams, Google Docs). Many said they also use paper & whiteboard.
  •  Diagram types: Most use Class diagram, Sequence diagram & Use-case. Also: Activity, State, Relationship, Work-flow.
  •  Activities: Almost everyone: Embed diagrams in design documents, Present them in design reviews, Collaborate on them with others. Also: Save them in the repository, Revise them when design changes. 
  •  Problems & needs: People expressed the need for online editor. Another requested feature is reverse engineering from existing source repository                      




Possible frameworks & technologies


I made a check-list of frameworks & technologies that I'd like to use in this app:

  • CoffeeScript - a high-level language that compiles into JavaScript, & abstracts some of the difficult & bad parts of the language
  • BrowserID - an email-based authentication mechanism by Mozilla
  • RemoteStorage - a mechanism to store data from JavaScript on remote providers
  • Datastore providers: IrisCouch
  • Backbone.js - a popular MVC framework for javascript
  • Backbone.dualStorage - for Backbone storage on both local (HTML5) & remote storage
  • Backbone.boilerplate - template utilities for Backbone
  • Underscore.js - clean & feature-rich JavaScript framework
  • d3.js - data-driven visualization framework
  • Bootstrap2 - HTML5 template
  • Uijet - UI widgets framework
  • Faye & Kue- for real-time collaboration
  • Selenium2 - unit-tests framework for JavaScript * Sauce Labs - hosted service for cross-browser testing using Selenium
  • PhoneGap - framework for generatubg mobile editions of a Web app
  • Google Page Speed- for optimizing loading & performance
  • Google AnalyticsProvide the analytics on a client-side app
  • CloudBees - Continuous Integration & Testing
  • ??? - Hosting & continuous deployment



Code hosting & IDE


BitBucket - source hosting
Since I prefer mercurial, I usually host my projects on BitBucket. The source code can be found in:


WebStorm - IDE
This full-pledged JavaScript IDE is based on JetBrains' Java IDE: IntelliJ IDEA. 

The main advantage of using it is the amazing intelligence it has in understanding code, detecting errors & enabling refactoring

I prefer it on any other IDE on this sole ground: especially with dynamic languages, it's crucial to have an editor that understands your code, & can validate it intelligently


WebStorm supports debugging of JavaScript ran on the browser from the IDE & comes with many plugins, such as CSS-X-Fire which enables you to update CSS attributes in your browser & automatically update them in your source files. For example, WebStorm can infer the type of function parameters (which aren't typed of course) & detect when a call passes parameters of a different type!



Debug & inspection


Browsers debug console
All modern browser have an interactive console, crucial for debugging & exploratory development



An online tool to experiment with JavaScript & share it with others                  



This tool by Douglas Corkford (the main guru & reviver of modern JavaScript) to validate the quality & correctness of your JavaScript code






The project can be started with several templates:


 Many nice features for HTML5 support. Comes with Google Analytics code & also script to install Chrome Frame
Service that let's you customize the template, which is based on Boilerplate. Customizing it is a bit annoying - because there are incompatibilities between possible elements, & it takes time to succeed resolving the conflicts. Uses the Modernizr framework for detecting & leveraging HTML5 & CSS3
Best practices template by Twitter. Includes both resources & widgets.      

All of these templates support the infra to make the app responsive - adapt to different devices (Computer, Tablet, Mobile, TV)


I decided to start with Bootstrap2We'd also take stuff from Initializr/Biolerplate, such as: Chrome Frame & Google Analytics





Design & code


The initial version of the product is very simple - it let's you describe classes in text, and draws the corresponding class diagram. Here's the back-of-the-envelope design:


Main page (app.html)

The application has 1 main page, using Bootstrap2 as templae. The code is straight-forward:



    <div class="navbar navbar-fixed-top">
      <div class="navbar-inner">
        <div class="container-fluid">
          <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          <a class="brand" href="#">Model</a>
          <div class="nav-collapse">
            <ul class="nav">
              <li class="active"><a href="#">Home</a></li>
              <li><a href="#about">About</a></li>
              <li><a href="#contact">Contact</a></li>
            <p class="navbar-text pull-right">Logged in as <a href="#">username</a></p>
          </div><!--/.nav-collapse -->

    <div class="container-fluid">
      <div class="row-fluid">
        <div class="span3">
          <div class="well sidebar-nav">
            <ul class="nav nav-list">
              <li class="nav-header">Project 1</li>
              <li class="active"><a href="#">Class Diagram 1</a></li>
              <li><a href="#">Diagram 2</a></li>
              <li><a href="#">Diagram 3</a></li>
              <li><a href="#">Diagram 4</a></li>
              <li class="nav-header">Project 2</li>
              <li><a href="#">Diagram 1</a></li>
              <li><a href="#">Diagram 2</a></li>
              <li><a href="#">Diagram 3</a></li>
              <li><a href="#">Diagram 4</a></li>
              <li><a href="#">Diagram 5</a></li>
              <li><a href="#">Diagram 6</a></li>
              <li class="nav-header">Project 3</li>
              <li><a href="#">Diagram 1</a></li>
              <li><a href="#">Diagram 2</a></li>
              <li><a href="#">Diagram 3</a></li>
          </div><!--/.well -->
        <div class="span9">
          <div class="hero-unit">
            <h2>Class Diagram 1</h2>
            <p>This is the diagram description.</p>

            <ul id="tab" class="nav nav-tabs">
                <li class="active"><a href="#diagram" data-toggle="tab">Diagram</a></li>
                <li class=""><a href="#source" data-toggle="tab">Source</a></li>
            <div id="myTabContent" class="tab-content">
                <div class="tab-pane fade active in" id="diagram">
                    <div id="chart" style="width: 675px; height: 360px;"></div>
                <div class="tab-pane fade" id="source">
                        <textarea id="source_input" rows="20" style="width: 675px; height: 341px;"></textarea>
                        <p class="muted" style="float: right;">
                            For example:<br/><br/>
                            Class1 : BaseClass1<br/>
                            Class2 : BaseClass2<br/>



        <p>(cc) Model UML editor 2012</p>



JavaScript models (model-models.js)

The 1st interesting place is the JavaScript in which the Backbone.js models are defined. There's a simple base class (DiagramElement), a class that extend it (Class) for representing classes, & a collection of classes (ClassDiagram).



var DiagramElement = Backbone.Model.extend({
    defaults: {
        "x": 0,
        "y": 0,
        "width": 40,
        "height": 100

var Class = DiagramElement.extend({
    defaults: {
        "name": "",
        "super_classes": [],
        "public_methods": [],
        "private_methods": []
    get_all_members: function () {
        var result = [];
        var name = this.get('name');
        if (this.get('super_classes').length > 0) {
            name += " : ";
            name += this.get('super_classes').join(",")
        _.each(this.get('public_methods'), function(n) { result.push(n); });
        _.each(this.get('private_methods'), function(n) { result.push(n); });
        return result;

var ClassDiagram = Backbone.Collection.extend({
    model: Class,
    source: "",
    get_classes: function() {
        var result = [];
        _.each(this.models, function(model) {
        return result;

var current_diagram = new ClassDiagram();


JavaScript controllers (model-controllers.js)

The contoller file contains the parser of the text in which you describe classes. The parser goes over the text & creates Backbone models out of it. Then the controller creates the Drawer, that renders the class diagram, & binds it to the add event of the diagram (triggered whenever a new Class is added to the collection).



var SourceParser = {

    parse: function() {
        var previous_source = "",
            current_class = "",
            current_super_classes = [];

        var members_map = {
            "+": [],
            "-": []

        var add_class = function() {
            var cls = new Class({
                "name": current_class,
                "super_classes": _.clone(current_super_classes),
                "public_methods": _.clone(members_map["+"]),
                "private_methods": _.clone(members_map["-"])
            var existing_class = current_diagram.find(function(c) { return c.get('name') ==});
            if (existing_class) {
            else {
            current_class = "";
            current_super_classes = [];
            members_map["+"] = [];
            members_map["-"] = [];

        return function() {
            var source = $("#source_input").val();
            if (source != previous_source) {
                previous_source = source;
                var lines = source.split("\n");
                _.each(lines, function(line) {
                    if (line.trim().length == 0) return;
                    var first_char = line.charAt(0);
                    if (members_map[first_char]) {
                    else {
                        if (current_class != "") {
                        if (line.indexOf(":") >= 0) {
                            var parts = line.split(":");
                            current_class = parts[0].trim();
                            current_super_classes = parts[1].trim().split(",");
                        else {
                            current_class = line;


$(function () {

    var parse = SourceParser.parse();

    $('a[data-toggle="tab"]').on('shown', function (e) {

    current_diagram.on("add", drawer.draw_class, drawer);


JavaScript widgets (model-widgets.js)

The final source file defines the ClassDiagramDrawer, which uses the d3.js library to tramsform the Backbone models into SVG elements. d3.js is a very powerful library, which we'll explore more deeply in following posts. The main idea is to associate a data array with DOM elements, & create DOM elements for new data.


var ClassDiagramDrawer = {
    svg: null,
    current_offset: 0,
    default_class_width: 150,
    default_member_height: 20,
    default_member_spacing: 20,
    class_containers: {},

    init: function() {
        var w = 675,
            h = 360;

        var pack = d3.layout.pack()
            .size([w - 4, h - 4])
            .value(function (d) {
                return d.size;

        this.svg ="#chart").append("svg")
            .attr("width", w)
            .attr("height", h)
            .attr("class", "pack")
            .attr("transform", "translate(2, 2)");        
    draw_class: function(model) {
        var data = model.get_all_members(),
            x = this.current_offset,
            y = 50,
            margin = 10;

        var g = this.svg.append('g')
            .attr("x", x)
            .attr("y", y);
        this.class_containers[model.get('name')] = g;

            .attr("x", x)
            .attr("y", y)
            .attr("width", this.default_class_width)
            .attr("height", data.length * this.default_member_height);

        var that = this;
             .attr("x", x + margin)
             .attr("y", function(d, i) { return y + margin + i * that.default_member_height; })
             .attr("dy", ".35em") // vertical-align: middle

            .attr("x1", x)
            .attr("y1", y + this.default_member_height)
            .attr("x2", x + this.default_class_width)
            .attr("y2", y + this.default_member_height);

        this.current_offset += this.default_class_width + this.default_member_spacing;


var drawer = ClassDiagramDrawer;







Finally, here's how the 1st version looks like:







In the next parts, I'll try to make a real application out of this prototype, & alsp adopt better frameworks & technologies, such as CoffeeScript.




Thank you for your interest!

We will contact you as soon as possible.

Send us a message

Oops, something went wrong
Please try again or contact us by email at