Introduction
This article is to demonstrate how one can write an MVVM based HTML5/SVG app with the help of KnockoutJS library.
SVG which stands for Scalable Vector Graphics is a specification of an XML-based file format that makes it possible to represent 2D graphic information in a compact and portable form. The SVG specification is an open standard that has been under development by the World Wide Web Consortium (W3C) since 1999.
SVG is supported by the latest version of all
modern browsers including IE9 and beyond.
The Model-View-ViewModel (MVVM) is an architectural pattern used in software engineering that originated from Microsoft as a specialization of the presentation model design pattern introduced by Martin Fowler It is an excellent design pattern used to facilitate a clear separation of concern between View (presentation/graphics) with the Model (data/business logic).
One can write an excellent SVG based web application with a conventional JavaScript and HTML5. However, often the dilemmas of writing a conventional application without MVVM pattern is that, one might end up with a monolithic code that entangles the presentation layer with the model layer. This results in a code that is hard to maintain.
There are few excellent MVVM enabler open-source libraries and one excellent library is KnockoutJS by Steven Sanderson. In short, KnockoutJS is a javascript library that can help one facilitates an MVVM design pattern through declarative data binding, automatic UI refresh, dependency tracking, and templating.
In the following sections, I am going to show you how you can write a simple MVVM-based HTML/SVG application with KnockoutJS. I am going to call it a Kids Drawing app.
Background
For those new to MVVM pattern, I suggest to read some literature about MVVM pattern. A good one to start is an MSDN article by Josh Smith - The Apps with MVVM design pattern.
I would also suggest for those who are curious about the differences between MVVM, MVC, and MVP to read an excellent article by Joel Wenzel dissecting the differences between MVVM vs MVP vs MVC.
Furthermore, I am going to assume that before you come here reading this article, you must have some interest in SVG/HTML5 and so I assume that you have at least some basic working knowledge of SVG. At the very least you are familiar with what it can do and how you can draw a simple primitive like rectangle, circle, and line. There are plenty of articles, books, tutorials and SVG libraries that you can consult out there. Wikipedia and W3School is a good start for this. If you want to know what SVG is capable of, one of my favorite JS SVG libraries that you should check out is RaphaelJS.
Moreover, SVG Essentials from O'Reilly by David Eisenberg is a good book that is very straight to the bone.
One last thing you should do is to check the KnockoutJS (a.k.a KO) and read its excellent documentation that comes with some systematic examples that are very easy to follow. It will be difficult to follow my article unless you have the basic working knowledge of KO. My KidsDrawing app use heavily the <... data-bind="..." /> property of KO and the templating flow control construct such as foreach and if. So, it is a strong pre-requisite that you are familiar with the KO for you to be able to comprehend the examples and the concepts presented and discussed in this article.
I found that initially it will be a steep learning curve to understand the library, but once you master it you will find it is extremely powerful and easy to use. It took me about 2 days to learn the examples and understand the concepts. If you are a Silverlight veteran, I would imagine that you can skip all this and you will still be fine. I suggest you to check out the excellent tutorials provided in http://learn.knockoutjs.com, and an excellent introduction to KO/MVVM video tutorial by John Papa - "Building HTML5 and Javascript Apps with MVVM and Knockout".
Kids Drawing App
Before even we get started with the code, let me introduce the app that we are going to write. The Kids Drawing is an app that any kid (I would imagine starting from 2 year old) can use to draw and color Rectangle, Circle and Triangle. It is an HTML/SVG based application that works in any modern browsers that support SVG.
The live demo url for PC: KidsDrawing LiveDemo. The IPad version: KidsDrawing IPad LiveDemo.
Writing the KidsDrawing Code
Just as with any SVG HTML app, you would start with the following skeleton. The code snippet below will give you an html page with a red rectangle drawing at screen position x=100, y=100 and width=200; height=200.
<html>
<head>
<title>Kids Drawing</title>
<body>
<div>
<svg xmlns="http://www.w3.org/2000/svg">
<rect fill="red" x="100" y="100" width="200" height="200" />
</svg>
</div>
</body>
Next you want to setup the drawing layout of the KidsDrawing which consists of Palettes panel on the left hand side and the Shapes panel
on the right hand side and the Drawing panel in the center. Moreover there is a Heading section for the title.
We will do this by first creating a list of primitives that we are going to use later by creating <svg> defs for the Palettes and Shapes panel.
<defs>
<!--
<rect id="square" width="100" height="50"></rect>
<polygon id="triangle" points="50,0 100,50 0,50"></polygon>
<circle id="circle" r="25"></circle>
<!--
<rect id="drawingbox" width="500" height="500" fill="azure" stroke="lightgray" transform="translate(120,100)"></rect>
</defs>
Now that we have the primitives defined, in the next snippet we will use these primitives and build our Palettes panel and we are going to create the Palettes panel dynamically by using the KO directive.
To do so we first need to define our ViewModel and binds the ViewModel to the SVG View layer with KO. The idea is that we are going to define the list of our palettes in the ViewModel and let the KO does its magic taking care the View layer by drawing the respective SVG primitives and create the binding through observable objects defined in the ViewModel such that when the ViewModel initialized and/or changed, the changes to the View layer will be taken care of automatically without any extra code.
I should mention that this is the kind of thing that the KO and MVVM pattern helps to simplify things.
In this case, we want to define the palettes as an observableArray.
If you are new to KO, you can check here and here for what the observable
is, how and why it is useful. Also check out the differences between observable and observableArray.
One is for a single item and the latter is for a collection of items (array).
<script type="text/javascript">
var ViewModel = function () {
this.palletes = ko.observableArray([
{ fill: "lightblue", y: 0 },
{ fill: "orange", y: 80 },
{ fill: "purple", y: 160 },
{ fill: "gray", y: 240 },
{ fill: "lightgreen", y: 320 },
{ fill: "red", y: 400 }
]);
}
ko.applyBindings(new ViewModel());
</script>>
Next, after we created the binding, we need to define the View that we create and target the binding for. For this, the KO has the templating directives such as foreach where we can dynamically iterate through an observable objects and duplicates a section of markup for each entry in an array, and binds each copy of that markup to the corresponding array item. This is a handy directive for rendering lists or tables.
The following SVG snippet draws the Drawing panel, the Palettes panel by iterating each palette we created in ViewModel and also listen to any changes made to the ViewModel.palettes observableArray. Thereby, if we add/remove item(s) from
the ViewModel.palettes, the View will be updated automatically through the bindings that we have created before.
There are several things worth pointing out here. The first one is how we bind the 'fill' property of the palette object we created in the ViewModel by using the data-bind directive. What that means is that on iterating each palette object, the KO foreach will generate a new <use> markup and is going to set the style:fill attribute of the <use> to the value of the fill of the palette object that we are iterating. In addition we also bind the y-coordinate attribute of the <use> to the y value of the palette object. This is how we layout the Palette panel horizontally. Furthermore, to make the palette panel reacts to the mousedown event we bind it to a ViewModel.changeColor() function that takes the 'fill' value as the parameter. Note that this is how we enable each palette button in the Palette panel to change the color of the shape that we are drawing on the Drawing panel.
(More on binding to the mouse event can be found here and here. It should also answers your curiosity about what the $root is and what the $data means).
<use xlink:href="#drawingbox"></use>
<!--
<g transform="translate(50, 100)">
<use xlink:href="#circle" data-bind="style:{fill:fill},attr:{y:y},
event:{mousedown:$root.changeColor.bind($data,fill)}"></use>
</g>
<!--
<!--
<g transform="translate(650,180)">
<!--
<use xlink:href="#square" class="shape" transform="translate(0,0)"
data-bind="event:{mousedown:$root.changeShape.bind($data,shape)}"></use>
<!--
<!--
<use xlink:href="#triangle" class="shape" transform="translate(0,100)"
data-bind="event:{mousedown:$root.changeShape.bind($data,shape)}"></use>
<!--
<!--
<use xlink:href="#circle" class="shape" transform="translate(50,250)"
data-bind="event:{mousedown:$root.changeShape.bind($data,shape)}"></use>
<!--
</g>
<!--
Now you got the idea and once you put things together with few little extra code to glue it together - Voila!!! you have some interactive MVVM based SVG/HTML5 app, KidsDrawing, that is very interactive only with a little amount of code. All this is possible because KnockoutJS has already done a lot of work for you by providing the MVVM building blocks (Data-binding and Templating) that allows you to separate the View from Model through ModelView.
You can view the live demo and check the complete code from the following links: PC version and IPad version.
Summary
In summary, SVG is a gift for comp graphics enthusiasts (well it is for me). It is very easy to use and yet powerful enough to do complex things. They have made it so easy and accessible such that virtually anyone who knows HTML and XML suddenly knows how to do very rich graphics manipulation on browser. Moreover, it is fantastics that it runs on all modern browsers.
KnockoutJS is an excellent data-binding and templating library that helps one to facilitate the MVVM design pattern into their HTML5 app.
Without KnockoutJS it would take extra mileage to be able to write an MVVM based app on HTML5/Javascript. It has an excellent documentation and a great set of functionalities (to name a few such as Templating, Data-Binding, Auto UI refresh, etc) that can help anyone to write a powerful app.
MVVM is a good design pattern that allows good separation of concern between View and Model through ViewModel and uses Data-Binding, Template, Commands as the building block. It takes an extra effort to build the right building block but once you have the building blocks (such as provided by KO), writing a clean, robust and very maintainable code is very easy to do.
History
- V1.0: a KidsDrawing app with 6 color palletes and 3 shapes to draw.