SVG Text Element

 

We can easily add text element in the SVG with help of text element and by default browser put the text coordinate of x, y to zero, the text will appear on the top left of the browser and we may not be able to see the text.

<svg height="30" width="200">
  <text x="0" y="15" fill="red">SVG Text Here</text>
  Sorry, your browser does not support inline SVG.
</svg>

What we are learning here

  1. SVG text element attribute.
  2. Positioning our text element in SVG
  3. Use of tspan in text
var dataArray = [5,11,18];

var svg = d3.select("body").append("svg").attr("height","100%").attr("width","100%");
var newX = 400;

				
svg.append("text")
	.attr("x", newX)
	.attr("y", 150)
	.attr("fill","none")
	.attr("stroke","blue")
	.attr("stroke-width","2")
	.attr("text-anchor","start")
	.attr("dominant-baseline","middle")
	.attr("font-size","30")
	.text("start text anchor here");

svg.append("text")
	.attr("x", newX)
	.attr("y", 180)
	.attr("fill","blue")
	.attr("stroke","none")
	.attr("text-anchor","middle")
	.attr("dominant-baseline","middle")
	.attr("font-size","30")
	.text("text anchor midddle here");

svg.append("text")
	.attr("x", newX)
	.attr("y", 210)
	.attr("stroke","blue")
	.attr("fill","none")
	.attr("text-anchor","end")
	.attr("dominant-baseline","middle")
	.attr("font-size","30")
	.text("Text Anchor end here");
	
svg.append("line")
	.attr("x1",newX)
	.attr("y1","150")
	.attr("x2",newX)
	.attr("y2","210");

We can add the text in SVG as svg.append(“text”).text(“Hello World”).  In above code all word begins at the newx that is 400px, we will change the alignment of each word and we want to line up text item in the exact center of another element say a rectangle.  In D3 we can’t do adding text to another svg shape and can’t apply alignment to the middle, start, and end.  In other words, we can’t  add text to a rectangle, circle or any other SVG element. What we can do is add one element one top of another and position them in a similar way.

Screen shot of our above code

As text is aligned default by the browser at the bottom left of text element or item.  In above picture, we can see black line start at the bottom of word start and similar end at the bottom of a word end. By default, our text is aligned vertically by the browser at the bottom of the text. We can change the vertical alignment with two attributes in D3.  But alignmentBaseLine is not working properly in the Firefox and we can use dominantBaseLine to change the vertical alignment in D3.  We can see the second picture where the line had stay in the same position it was before but the text had shifted down.

Text alignment in the SVG

We can align our text position in SVG with help of two Attribute.

Text-anchor – To align text horizontal as star, middle, and end.
Dominant-box – To align text in vertical.

 

In the second example below we can see that we can align the text on top of any other SVG element, by positioning the same location of text coordinate with another element. We can easily change the horizontal alignment of text by using text attribute called anchor-text to the middle as shown below.

 

Adding new line in SVG Text

In our first example, we had added 3 texts manually. In the HTML we write a paragraph and we can put a break or new line character into the paragraph. We can’t add a new line to text in D3, we can only achieve this with help of tspan in D3.

var svg = d3.select("body").append("svg").attr("height","100%").attr("width","100%");
var newX = 400;
var textArray = ['start','middle','end'];
				
svg.append("text").selectAll("tspan")
	.data(textArray)
	.enter().append("tspan")
	.attr("x", newX)
	.attr("y", function(d,i){return 150 + (i*30); })
	.attr("fill","none")
	.attr("stroke","blue")
	.attr("stroke-width","2")
	.attr("text-anchor","start")
	.attr("dominant-baseline","middle")
	.attr("font-size","30")
	.text(function(d){ return d; });

In above code, we are creating a text element with three tspan an element inside the text element inSVG. At the last a highlight line code, we are dynamically creating text with help of text array data.

D3js resources and Book

D3 Example code

D3 Sample example
https://github.com/d3/d3/wiki/tutorials

D3 advanced example – http://dimplejs.org/advanced_examples_index.html

 

D3 Generator graph: http://d3pie.org/#generator

D3 js Core

The D3 Stands for Data-Driven Documents and is a javaScript library.
The D3js version 4 is modular based and released in June 2016. The version 3 and 4 are not compatible. We can’t create d3 graphic without the SVG element. The SVG scalable vector graphic, HTML 5 directly allow us to add SVG into the web page. D3js need the HTML5.

  • D3.js we can animate graphic, play graphic like the movie, interact with the graphic.
  • We can add <svg> </svg> element in html page and svg element is block level element or think it as blank canvas.
  • The SVG is always the first and the largest element in any D3 graphics, we can’t put have graphic without SVG content to put it in.
  • We can’t put DIV and P HTML element in the SVG, as SVG is not a normal HTML element, the SVG is a graphical element and it can only content graphical items such as a rectangle, line, circle and the SVG can also contain text too not within the paragraph element.

Note: A lot of CSS work on the HTML element doesn’t apply to SVG element. In CSS we use color for the style but the SVG element we can use fill to apply color in the shape.

Here we will draw the basic shape in d3.js  add the following code in shape.js

var dataArray = [5,11,18];

var svg = d3.select("body").append("svg").attr("height","100%").attr("width","100%");

svg.selectAll("rect")
      .data(dataArray)
      .enter().append("rect")
                .attr("height",function(d,i){ return d*15; })
                .attr("width","50")
                .attr("fill","pink")
                .attr("x",function(d,i){ return 60*i; })
                .attr("y",function(d,i){ return 300-(d*15); });

var newX = 300;
svg.selectAll("circle.first")
      .data(dataArray)
      .enter().append("circle")
                .attr("class","first")
                .attr("cx",function(d,i){ newX+=(d*3)+(i*20); return newX; })
                .attr("cy","100")
                .attr("r",function(d){ return d*3; });

var newX = 600;
svg.selectAll("ellipse")
      .data(dataArray)
      .enter().append("ellipse")
                .attr("class","second")
                .attr("cx",function(d,i){ newX+=(d*3)+(i*20); return newX; })
                .attr("cy","100")
                .attr("rx",function(d){ return d*3; })
                .attr("ry","30");

var newX = 900;
svg.selectAll("line")
      .data(dataArray)
      .enter().append("line")
                .attr("x1",newX)
                .attr("stroke-width","2")
                .attr("y1",function(d,i){ return 80+(i*20); })
                .attr("x2",function(d){ return newX+(d*15); })
                .attr("y2",function(d,i){ return 80+(i*20); });

In the first highlight line,  js code tells the browser to look in SVG element to find any rectangle inside the SVG element. If it finds any rectangle, then it returns selection which is an array of the rectangle element. If it doesn’t find any it returns empty selection. In our case, we don’t have any rectangle yet in the SVG element so all the 3 elements will be put at the end of the selection.

Note: In our code above d stand as fred I guess if I’m not wrong and i stand for an index of dataArray.

In the second highlight  svg.selectAll(“rect”).data(dataArray), here we are binding our data array or data to selection and binding does in order as in our example we have any rectangle yet in the SVG element so all the 3 data element will put at the end of the selection.

We can have to case based on the number of data binding element and number of the rectangle in the SVG element.
Case 1: 
If we have less graphic element then the data bind element. Suppose we have 2 rectangles in the SVG element and 3 elements in the data binding an array. When joining the data element, d3 put any leftover data or missing element into the end of the selection.

Case 2: 
In the second case, we have a more graphic element and less number of the data elements to bind. Suppose we have 4 rectangles and our data element have only 3 elements to bind. Then d3 will link first three to the rectangle and put the final rectangle into the exit selection. Instead of end.append we could have exit.remove in such case, end of selection we would be empty and running anything after the dot append would have no effect at all.

Mandatory attribute for the Shape

  1. Rectangle: We have four mandatory attributes as x,y, width, and height.
  2. Ellipse: We have four mandatory attributes as cx,cy, rx, ry. c stand for the center.
  3. Circle: We have 3 mandatory attributes as cx,cy and radius.
  4. Line: We have 4 mandatory attributes as x1,y1, x2, y2.

Adding the different way of styling the line:

When working on the line, sometimes we may not see the line in the browser, even we have added line code. The first thing we have to check DOM element of line in the browser, if so then we may not add style to the line. By default in D3js shape are filled with black color and given the stroke of nothing. As most shapes like ellipses and circle show up in the browser, is no border but fill with black color. But for fill online make no sense at all and will not display in the browser.

Three way of adding style for the line.

1. Setting an attribute
svg.selectAll(“line”).data(dataArray).enter().append(“line”).attr(“stroke”, “blue”).attr(“stroke-width”, “2”)

2. Dot style
svg.selectAll(“line”).data(dataArray).enter().append(“line”).style(“stroke”, “green”)

3. Adding style to CSS
svg.selectAll(“line”).data(dataArray).enter().append(“line”) and add following css style of line in style.css
line{
stroke:red;
}

Note: Styling the graphic in the D3 have different precedence as follows style has the highest precedence and then CSS and the attribute has the least attribute.  We have to use CSS styling for the graphic element in D3js as much as possible.  As of css, we can easily manage the style declare in one place and can reduce the file size as style is applied in another file.

D3 Arc Generator

In D3 provide lots of shape generators, arc generator is the most common generator. The D3 arc generator is a lot more versatile than the simple svg: circle. We can use D3 arc generator to create the circle, the annulus (donut), circle sector and annulus sector.

Syntax:
d3.arc
– create a new arc generator.

D3 important function

In D3 scale play important role in visualization for encoding, map abstract data to visual representation

Some of the important D3 function

  1. d3.scaleThreshold()
  2. d3.scaleOrdinal()

scaleThreshold maps continuous numeric input to discrete values defined by the range. n-1 domain split points are specified where n is the number of range values.

In the following example we split the domain at,

0

 

50

 and 

100
  • u < 0 is mapped to ‘#ccc’
  • 0 ≤ u < 50 to ‘lightblue’
  • 50 ≤ u < 100 to ‘orange’
  • u ≥ 100 to ‘#ccc’

where u is the input value.

2. d3.scaleOrdinal() :  

An ordinal scale’s values must be coercible to a string, and the stringified version of the domain value uniquely identifies the corresponding range value.
So, as an example, a domain of an ordinal scale may contain names, like so:

var ordinalScale = d3.scale.ordinal()
.domain(['Alice', 'Bob'])
.range([0, 100]);

ordinalScale('Alice'); // 0
ordinalScale('Bob'); // 100

3. d3.scaleLinear() – Quan­ti­ta­tive scale

Quan­ti­ta­tive scale func­tions are those that trans­late one numeric value into another numeric value using dif­fer­ent types of equa­tions such as lin­ear, log­a­rith­mic etc.

For exam­ple the lin­ear quan­ti­ta­tive scale con­verts a num­ber into another num­ber lin­early and can be defined as follows:

var y = d3.scaleLinear() .domain([0, 170]) .range([height,0]);

Where both domain and range value are numeric and continue from max to min or min to max value.

 

 

Introduction to Dimple JS

The Dimple.js is an object-oriented API for business analytics powered by d3.js. The aim of the dimple is to open up the power and flexibility of d3 to analysts. It aims to give a gentle learning curve and minimal code to achieve something productive.

Creating First Dimple example to understand the code.

<script src="http://d3js.org/d3.v4.min.js"></script>
  <script src="http://dimplejs.org/dist/dimple.v2.3.0.min.js"></script>
</head>
<body>
  <script type="text/javascript">
    var svg = dimple.newSvg("body", 800, 600);
    var data = [
      { "Word":"Hello", "Awesomeness":2000 },
      { "Word":"World", "Awesomeness":3000 }
    ];
    var chart = new dimple.chart(svg, data);
    chart.addCategoryAxis("x", "Word");
    chart.addMeasureAxis("y", "Awesomeness");
    chart.addSeries(null, dimple.plot.bar);
    chart.draw();
  </script>
</body>

Screenshot of first above code

In the addSeries method, we have none, we can also specify the column name instead of null. The second argument dimple.plot.bar, we can other dimple plot option as

  1. dimple.plot.area
  2. dimple.plot.bar
  3. dimple.plot.bubble
  4. dimple.plot.line

In the second example, we will use the addSeries method, with the first argument with column name instead of null.

  <script src="http://d3js.org/d3.v4.min.js"></script>
  <script src="http://dimplejs.org/dist/dimple.v2.3.0.min.js"></script>
</head>
<body>
  <script type="text/javascript">
	// Draw bars for region sales volume stacked by brand
	
	var svg = dimple.newSvg("body", 600, 400);
	var data = [
		{ "Brand":"Coolio", "Region":"Hipsville", "Sales Volume":1000 },
		{ "Brand":"Uncoolio", "Region":"Hipsville", "Sales Volume":500 },
		{ "Brand":"Coolio", "Region":"Dullsville", "Sales Volume":100 },
		{ "Brand":"Uncoolio", "Region":"Dullsville", "Sales Volume":2000 }
	];
	var myChart = new dimple.chart(svg, data);
	myChart.addCategoryAxis("x", "Region");
	myChart.addMeasureAxis("y", "Sales Volume");
	myChart.addSeries("Brand", dimple.plot.bar);
	myChart.draw();
  </script>
</body>
</html>

myChart.addSeries(“Brand”, dimple.plot.bar); We can see in the graph that the brand value of same location or x-axes are added to single bar.


	

Understanding D3 selections

The D3 selection plays important role in our D3 visualization project. Selections allow us to select an element on the page. Once an element is selected, we can perform powerful data-driven transformation of the document object model (DOM): set attributes, styles, properties, HTML or text content, and more.

The D3 has its own selection API, as standard W3C selection have the limitation when it comes to visualization. When selecting multiple elements in W3C we have to use a loop to iterate the multiple selections and we can easily handle with the D3 section.

Selecting a single element and selecting all paragraph element
D3 have two selection function, d3.select, and d3.selectAll. The d3.select will select the first match element and d3.selectall will return an array of array of selected DOM element.

<!DOCTYPE html>
<html> ...
    <script type="text/javascript" src="node_modules/d3/build/d3.js"></script>
</head>
<body>
<p>D3 Selection</p>
<p id="target"></p> 

<script type="text/javascript">
    d3.select("p#target") 
        .text("Hello world!"); 
	
	d3.selectAll("p")
    .attr("class", "graf")
    .style("color", "red");
</script>

</body>
</html>

In above example, we are first selecting first p element with id as the target and second code we are selecting all p element in the page with D3 select. All the D3 selections support a set of standard modifier functions. The text function in above code is one of example.

 

Adding style to selected element
The style() function allows us to set the CSS style on the selected element.

var div = d3.selectAll("div")
    .style("color","white")
    .style("background","blue");

In D3 version 4 doesn’t support styles and attrs, not style and attr as before. The code below will generate an error in D4 version 4.

var div = d3.selectAll("div")
    .attrs({ "title": "Hello, world!", "name" : "greeter" })
    .styles({ "color": "red", "background" : "green" });

The function chaining is the common pattern in the Javascript. Function chaining is a technique that can be used to simplify code in scenarios that involve calling multiple functions on the same object consecutively.

var body = d3.select("body");
body.append("section")
	.attr("id", "main")
	.append("div")
		.attr("class", "box brown")
	.append("p")
		.text("Chaining all over here");

 

Adding and remove class to selected element
In D3 selection.classed function allows us to add and remove CSS classes on the selected element as follow.

	
	d3.select("p").classed("pAll", "true");
	d3.select("p").classed("pAll", function(){ false; });

We can use attr function to apply two class box and content to all div in our page.

    d3.selectAll("div") 
        .attr("class", "box content"); 

 

Setting or Modifying an Attribute
The selection.attr function allows us to set or update a given attribute on the selected element.

	d3.selectAll('rect').attr('width', 10)

 

Adding text to content of the element
The selection.text function allows us to access and set the text content of the selected element.

 d3.select("p#target") 
        .text("Hello world!");
d3.select("p").text(function(){
			return Date();
		});

 

Iterating through D3 a selection:

We can easily iterate in D3 multiple selections. The each function takes an iterator function as the parameter. The each function takes two optional parameter d and i and one more hidden parameter passed in as this reference, which points to the current DOM element object. Where i represent index number of current element object being iterated through.

<div></div>
<div></div>
<div></div>
<div></div>

<script type="text/javascript">
    d3.selectAll("div") 
            .attr("class", "black box") 
            .each(function (d, i) {
                d3.select(this).append("h1").text(i);
            });
</script>

 

Selecting subselection
Scope selection, some time we have to select all elements of a particular tag within particular section element.We can achieve subselection in the number of ways.

d3.selectAll('tbody tr:last-child').remove()

Here in above code, we are removing the last row in the table.

  1. Child Combinator: The child combinator offers a more strict way to achieve a parent-child relationship between two elements. We can define child with character  > separating between parent and child selector as follow parent > child
    <section class="section1">
        <div><p>Section one here</p></div>
    </section>
    <section id="section2">
    </section>
    <section><p>sub selection</section>
    
    <script type="text/javascript">
        d3.select(".section1 > div") 
                .style("color", "red");
    </script>
  2. Descendant combinator: The descendant combinator provides the loose parent-child relationship between two selection. The relationship can be a parent to child, or grandchild or greater grandchild. Example
    d3.select("#section p).style("color", "blue");
  3. The D3 nested subselection: We can also select parent element along with it sub-element.
    d3.select("#section2") 
            .style("font-size", "2em") 
            .select("div") 
            .attr("class", "blue box");

Selecting and manipulating table elements

The D3 allows us to easily select table element. We can select all table row and all column at once. We can apply D3 function and style easily to selected element. In the example below, we are applying D3 to table column and row.

The D3 selection has node() function that returns an array containing the selected element node.

<body>
<table class="table">
    <thead><tr>
        <th>S No</th>
        <th>Name</th>
        <th>Credit</th>
    </tr>
    </thead>
    <tbody>
    <tr>
        <td></td>
        <td>Arun</td>
        <td>300</td>
    </tr>
    <tr>
        <td></td>
        <td>Mickey</td>
        <td>5450</td>
    </tr>
    <tr>
        <td></td>
        <td>Zack</td>
        <td>8900</td>
    </tr>
    </tbody>
</table>

<script type="text/javascript">
    var trSelection = d3.selectAll("tr");

//Select the first row in table as table header
    var headerElement = trSelection.nodes()[0]; 
	console.log("node 0" + headerElement);
	
    console.log("headerElement is an instance of DOM Element: " 
        + (headerElement instanceof Element));

    d3.select(headerElement).attr("class", "table-header"); 
    console.log("d3.select(headerElement) is an instanceof of d3.selection: " 
        + (d3.select(headerElement) instanceof d3.selection));
	
	// selection on column
	 d3.selectAll("td").filter(":first-child")
						.style("color", "yellow")
						.text(function (d,i){ return ++i; });
	d3.selectAll('table').selectAll('td:nth-child(2)')
						.style("color", "blue");
	
	d3.selectAll('table').selectAll('td:last-child')
						.style("color", "red");
	
	//selection on row
    var rows = trSelection.nodes();
    d3.select(rows[1]).attr("class", "table-row-odd");
    d3.select(rows[2]).attr("class", "table-row-even");
    d3.select(rows[3]).attr("class", "table-row-odd"); 
</script>

</body>
</html>

 

In the second example, we are applying some custom function on table element in D3.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">

    <title>Functional Javascript</title>
    <link rel="stylesheet" type="text/css" href="css/style.css"/>
    <script type="text/javascript" src="node_modules/d3/build/d3.js"></script>
	 <style type="text/css">
<style>
      h1 {
        font: 16px sans-serif;
        font-weight: bold;
        text-decoration: underline;
      }
      
      div {
        height: 17px;
      }
      div.container {
        float: left;
        width: 50%;
      }
      div.negative {
        float: right;
        background-color: brown;
      }
      div.positive {
        background-color: steelblue;
      }
      
      table {
        font: 14px sans-serif;
        vertical-align: middle;
        text-align: left;
        border-collapse: collapse;
      }
      
      td,th {
        padding-top: 2px;
        padding-bottom: 2px;
      }
      
      tr.even {
        background-color: #fff3f3; 
      }
      
      td.chart {
        background-color: white; 
      }
     
      th {
        padding-left: 10px;
      }
      
      th.total {
        text-align: right;
      }
      
      td.data {
        padding-left: 10px;

      }
      td.value {
        text-align: right;
      }
      
    </style>
    </style>
</head>

 <body>
  <h1>Language know</h1>
    <script>
      var chartWidth = "100px",
          percent = d3.format(".2%");

      var data = [
        ["Javascript", 0.0050],
        ["C", 0.80],
        ["C++", -0.70],
        ["Java", 0.4],
        ["C#", 0.47]
      ];
      
      var total = d3.sum(data, function(d, i) { return d[1]; });
      
      // Sort the data in descending order
      data.sort(function(a, b) {return d3.descending(a[1], b[1])});
      
      // Setup the scale for the values for display, use abs max as max value
      var x = d3.scaleLinear()
          .domain([0, d3.max(data, function(d) { return Math.abs(d[1]); })])
          .range(["0%", "100%"]);
	
      var table = d3.select("body").append("table");
      
      // Create a table with rows and bind a data row to each table row
      var tr = table.selectAll("tr.data")
          .data(data)
          .enter()
          .append("tr")
          .attr("class", "datarow");
      
      // Set the class to even columns
      d3.selectAll(".datarow").filter(":nth-child(even)").attr("class", "datarow even")
      
      // Add the name to first column 
      tr.append("td").attr("class", "data name")
          .text(function(d) { return d[0] });
          
      // Add class name for second column
      tr.append("td").attr("class", "data value")
          .text(function(d) { return percent(d[1]) })

      // Create a column at the beginning of the table for the chart
      var chart = tr.append("td").attr("class", "chart").attr("width", chartWidth);
      
      // Create the div structure of the chart
      chart.append("div").attr("class", "container").append("div").attr("class", "negative");
      chart.append("div").attr("class", "container").append("div").attr("class", "positive");

      // Creates the negative div bar
      tr.select("div.negative")
        .style("width", "0%")
        .transition()
        .duration(500)
          .style("width", function(d) { return d[1] > 0 ? "0%" : x(Math.abs(d[1]));});

      // Creates the positive div bar
      tr.select("div.positive")
        .style("width", "0%")
        .transition()
        .duration(500)
          .style("width", function(d) { return d[1] > 0 ? x(d[1]) : "0%"; });
    </script>
  </body>
</html>