DotNetCurry Logo

Creating Graphics Using SVG and AngularJS

Posted by: Gil Fink , on 11/24/2015, in Category AngularJS
Views: 18699
Abstract: Learn to create interesting biological models and graphics using SVG and AngularJS

A couple of months ago I started working with a startup called Genome Compiler that specializes in software platform to accelerate Genome and DNA design. Their main product was created using Flash and they wanted me to help them to create a new Genome viewer using plain web technologies. They wanted to visualize plasmids, which are small DNA molecules represented as a circle with annotations. They also wanted to visualize sequences, which are the primary structure of a biological molecule written in A, T, G and C characters. To create such visualization we needed the ability to create graphics inside the browser.

 

For more than four months I’ve been helping Genome Compiler to create their viewer using both Scalable Vector Graphics (SVG) and AngularJS. During the time, I learned how to combine SVG and AngularJS together to create biological models and other graphics. In this article I’ll explore what SVG is. Then, I’ll explain how SVG can be used in AngularJS applications. Towards the end of the article, you will see a simple application that combines both SVG and AngularJS.

Note: The article won’t cover the project that I’m doing for Genome Compiler due to the fact that it’s too huge to be covered in an article (or even in a book).

Disclaimer: This article assumes that you have basic knowledge of AngularJS. If you are not familiar with AngularJS, I encourage you to stop reading and start learning about this framework today.

Editorial Note: You can learn more about AngularJS using our tutorials at http://www.dotnetcurry.com/tutorials/angularjs

This article is published from the DNC Magazine for .NET Developers and Architects. Download this magazine from here [Zip PDF] or Subscribe to this magazine for FREE and download all previous and current editions

SVG in a Nutshell

SVG is an XML-based graphics model that you can use in your front-end. As opposed to other new HTML5 graphics models (such as canvas and WebGL), SVG version 1.0 was made a W3C recommendation in 2001. The SVG developers’ adoption was very small due to the popularity of plugins such as Flash, Java and Silverlight, and the lack of browser support. In 2011, W3C introduced the second edition of SVG, version 1.1, and SVG gained a lot of attention as an alternative graphics model, besides the Canvas pixel graphics model.

SVG is all about vector graphics. With SVG you can create and draw two-dimensional vector graphics using HTML elements. These HTML elements are specific to SVG, but they are part of the Document Object Model (DOM) and can be hosted in web pages. The vector graphics can be scaled without loss of image quality. This means that the graphics will look the same in different screens and resolutions. This makes SVG a very good candidate to develop graphics for applications that can be run on different screens (mobile, tablets, desktop or even wide screens). Some prominent areas where Vector graphics are used are in CAD programs, designing animations and presentations, designing graphics that are printed on high-res printers and so on.

The fact that SVG elements are HTML elements makes SVG a very interesting graphics model. You can get full support for DOM access on SVG elements. You can use scripts, CSS style and other web tools to shape your graphics and manipulate it. As opposed to Canvas, which doesn’t include state, SVG is part of the DOM and therefore you have the elements and their state for your own usage. This makes SVG a very powerful model. There is one notable caveat though – drawing a lot of shapes can result in performance decrease.

When you use SVG, you define the graphics within your HTML using the SVG tag. For example, the following code snippet declares an SVG element:

<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
</svg>

It is an HTML element and can be embedded inside your web page as any other HTML element. If not stated, the width of the SVG element will be 300 pixels and its height 150 pixels.

Note: Pay attention to the SVG XML namespace which is different from regular HTML. We will use this information later on when we will use SVG with AngularJS.

Using Shapes

SVG includes a lot of built-in shape elements that can be embedded inside the SVG tag. Each shape has its own set of attributes that helps to create the shapes appearance. For example, the following code snippet shows how to create two rectangles with different colors using the RECT element:

<svg width="400" height="200" version="1.1" xmlns="http://www.w3.org/2000/svg">
    <rect fill="red" x="20" y="20" width="100" height="75" />
    <rect fill="blue" x="50" y="50" width="100" height="75" />
</svg>

The output of running this piece of SVG will be as shown here:

two-rectangles

Figure 1: Two rectangles drawn by SVG

Here are a couple of points to note in the snippet:

1. The last rectangle will appear on top of the first rectangle. SVG behavior is to put the last declared elements on top of previously declared elements, if there are shapes that overlap.

2. In order to create a rectangle, you have to indicate its left-top point using the x and y attributes and its width and height. The default values for these attributes are all set to 0 and if you don’t set them, the rectangle will not be drawn on the SVG surface.

There are other shapes that you can use such as circles, ellipsis, polygons, polylines, lines, paths, text and more. It is up to you to learn to draw these shapes and a good reference for the same can be found in the Mozilla Developer Network (MDN) - https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Basic_Shapes.

Other than attributes, shapes can also include styling using style attributes such as stroke or fill. Stroke accepts a color to create the shape border and Fill accepts a color to fill the entire shape. You can also set styles using regular CSS but not all CSS styles can be applied on SVG elements. For example, styles such as display or visibility can be used with SVG elements but margin or padding has no meaning in SVG. The following example shows a rectangle with some inline styles:

<rect x="200" y="100" width="600" height="300" style="fill: yellow; stroke: blue; stroke-width: 2"/>

As you can see in the code snippet, the rectangle will be filled with yellow color, will have a blue border, with a border width of 2 pixels.

You can group shapes using the g element. The g element is a container for other shapes. If you apply style to a g element, that style will be applied to all its child elements. When you create SVG, it is very common to group some elements inside a g container. For example the following snippet shows you the same two rectangles from Figure 1 but grouped inside a g element:

<svg width="400" height="200" version="1.1" xmlns="http://www.w3.org/2000/svg">
    <g>
        <rect fill="red" x="20" y="20" width="100" height="75" />
        <rect fill="blue" x="50" y="50" width="100" height="75" />
    </g>
</svg>

Using SVG Definitions

SVG includes a defs element which can be used to define special graphical SVG elements such as gradients, filters or patterns. When you want to use a special SVG element, you first define it inside the defs element and later on, you can use it in your SVG. Make sure you specify an id for your special element, so that you can use it later.

The next snippet shows how to define a linear gradient:

<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
   <defs>
      <linearGradient id="lg1">
         <stop offset="40%" stop-color="yellow" />
         <stop offset="60%" stop-color="green" />
         <stop offset="80%" stop-color="blue" />
      </linearGradient>
   </defs>
   <rect fill="url(#lg1)" x="50" y="50" width="100" height="100"/>
</svg>

And the output of running this SVG will be:

gradient

Figure 2: Gradient inside a rectangle

A couple of things to notice about the snippet:

1. I defined the gradient using the linearGradient element. There are other elements that you can use to define other graphical aspects. Each element has its own attributes and sub elements, so it’s up to you to learn them.

2. The gradient has an id which is later on used in the rectangle using the url(#nameOfSVGElement) syntax.

Note: The article doesn’t cover all the possible SVG element definitions.

Now that we are familiar with SVG it is time to move on and see how SVG and AngularJS work together.

SVG + AngularJS = Red heart

You can combine SVG and AngularJS and it is very straight forward. Since SVG elements are part of the DOM, you can add them into view templates both as static graphics, and also as dynamic graphics. The first option is very simple and you just embed static SVG inside the HTML. The second option has a few caveats that you need to know in order to be on the safer side.

The first caveat is dynamic attributes and data binding. Since SVG has its own XML definition, it doesn’t understand AngularJS expressions. That means that if you will try to use SVG attributes with data binding expressions (curly brackets), you will get an error. The work around is to prefix all the dynamic attributes with ng-attr - and then set the binding expression. You can find a reference about ng-attr- prefix in the AngularJS website under the topic “ngAttr attribute bindings” using the following link: https://docs.angularjs.org/guide/directive .The following example shows you how to use the ng-attr and define databinding expressions:

<rect ng-attr-x="{{xAxis}}" ng-attr-y="{{yAxis}}" ng-attr-height="{{rectHeight}}" ng-attr-width="{{rectWidth}}"></rect>

In the example, you can see that all the rectangle attributes are set to some scope properties.

The second caveat is related to directives. Since the SVG XML definitions are different from HTML, directives that generate SVG elements need to declare that they generate SVG. That means that in the Directive Definition Object (DDO) that you return to define the directive, you will need to set the templateNamespace property to 'svg'. For example, the following snippet shows a simple directive DDO that declares that it generates SVG:

(function () {
    'use strict';
    angular.
        module("svgDemo").
        directive("ngRect", ngRect);
    ngRect.$inject = [];
    function ngRect() {
        return {
            restrict: 'E',
            templateUrl: <rect x="50" y="50" width="100" height="100"></rect>',
            templateNamespace: 'svg'
        };
    }
}());

Now that we know how to combine SVG and AngularJS, it is time to see some code in action.

 

Building a Simple App with SVG and AngularJS

The application that we are going to build will generate a rectangle and you will be able to change its width and height, using data binding:

angular-svg-app

Figure 3: Application using SVG and Angular

We will first start by defining a rectangle directive that will resemble some of the code snippets that you saw earlier:

(function () {
    'use strict';
    angular.
        module("svgDemo").
        directive("ngRect", ngRect);
    ngRect.$inject = [];
    function ngRect() {
        return {
            restrict: 'E',
            replace: true,
            scope: {
                xAxis: '=',
                yAxis: '=',
                rectHeight: '=',
                rectWidth: '='
            },
            templateUrl: 'app/common/templates/rectTemplate.html',
            templateNamespace: 'svg'
        };
    }
}());

The directive will include an isolated scope that can accept the x, y, width and height of the rectangle. It also declares that it generates SVG and that it loads a template. Here is the template code:

<rect ng-attr-x="{{xAxis}}" ng-attr-y="{{yAxis}}" ng-attr-height="{{rectHeight}}" ng-attr-width="{{rectWidth}}"></rect>

Now that we have our rectangle directive, we will define a directive that will hold our entire demo:

(function () {
    'use strict';
    angular.
        module("svgDemo").
        directive("ngDemo", ngSvgDemo);
    ngSvgDemo.$inject = [];
    function ngSvgDemo() {
        return {
            restrict: 'E',
            templateUrl: 'app/common/templates/demoTemplate.html',
            controller: 'demoController',
            controllerAs: 'demo'
        };
    }
}());

The main thing in the directive is the controller that it will use, and the template that it will load. So let’s see both of them. We will start with the controller:

(function () {
    'use strict';
    angular.
        module("svgDemo").
        controller("demoController", demoController);
    demoController.$inject = [];
    function demoController() {
        var demo = this;
        function init() {
            demo.xAxis = 0;
            demo.yAxis = 0;
            demo.rectHeight = 50;
            demo.rectWidth = 50;
        }

        init();
    }
}());

In the controller, we define the properties that will be used later for data binding. Now we can look at the template itself:

<div>
    <div>
        <svg height="300" width="300">
            <ng-rect x-axis="demo.xAxis" y-axis="demo.yAxis" rect-height="demo.rectHeight" rect-width="demo.rectWidth"></ng-rect>
        </svg>
    </div>
    <div>
        <label>Set Rectangle Width: </label><input type="text" ng-model="demo.rectHeight" /></br></br>
        <label>Set Rectangle Height: </label><input type="text" ng-model="demo.rectWidth" />
    </div>
</div>

Please observe the usage of ng-rect directive that we have created, and the binding of its attributes to the controller attributes. Also, we have bound the textboxes to the relevant properties using ng-model directive. That is all.

Now we can create the main web page and the svgDemo module. Here is how the main web page will look like:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>SVG & Angular</title>
    <link href="styles/main.css" rel="stylesheet"/>
</head>
<body>
    <div ng-app="svgDemo">
        <section class="body-content">
            <ng-demo></ng-demo>
        </section>
    </div>
    <script src="app/vendor/angular/angular.min.js"></script>
    <script src="app/app.js"></script>
    <script src="app/common/controllers/demoController.js"></script>
    <script src="app/common/directives/ngDemoDirective.js"></script>
    <script src="app/common/directives/ngRectDirective.js"></script>
</body>
</html>

And here is how the svgDemo module will be defined:

(function () {
    var app = angular.module('svgDemo', []);
}());

This is a very simple application but it shows you how to combine both SVG and AngularJS and to create dynamic graphics in your applications. You can also use common SVG generator libraries such as Raphael or d3.js inside your directives but the idea was to show you how to do raw SVG graphics before you jump into a library.

Summary

SVG is a very powerful graphics model that can be used in the browser. It generates graphics that looks good and scales well across different screens and resolutions. It also includes variety of elements that can help you shape your graphics easier. As you saw in the article, combining SVG and AngularJS to generate some sophisticated graphics is not so hard. As I wrote in the introduction, I was able to generate very interesting biological models using SVG and AngularJS and this should encourage you to try and create your own models.

Download the entire source code of this article (Github)

Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+
Further Reading - Articles You May Like!
Author
Gil Fink is a web development expert, ASP.Net/IIS Micrsoft MVP and the founder of sparXys. He conducts lectures and workshops for individuals and enterprises who want to specialize in infrastructure and web development. He is also co-author of several Microsoft Official Courses (MOCs) and training kits, co-author of “Pro Single Page Application Development” book (Apress) and the founder of Front-End.IL Meetup. You can get more information about Gil in his website gilfink.net


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!