Skip to Content

As you probably have noticed in my blog posts I’ve made quite a lot of SDK extensions in the past year. As I ran into a version I made last year I couldn’t help but notice that I do things now a lot differently than at the first start.

screenshot graphs.png

Why not tell about some of the things  I do now based on lessons I learned .
One of the latest graphs I made is the boxplot chart. This is a chart that does help you to learn more about a population that just an average.  You see how the population is divided into groups, If there is a large spread and if there are single outliers. In the setup you see in the image below, the axes and the labels are turned off, but you are able to toggle this at runtime with script. (in the first screenshot you see an example of all the options turned on.

/wp-content/uploads/2014/10/boxplot_573718.png

So what do I do now what I didn’t do earlier ?

Use JSON as initalization variables :

A declaration of standard variables with getter/setter now looks like this:  


var properties = {
        RandomGraphs: 5,
        showXaxis: true,
        showYaxis: true,
        showLabels: true,
        boxColor: "silver"
    };

With an example getter/setter function for one of the properties :

 this.boxcolor = function(e) { if (e === undefined) {return properties.boxColor;}else{properties.boxColor = e;return this;}};

I find this a lot easier to manage my variables. In the main declaration I have a few standard declarations


var that = this;
 var margin = {left:0, right: 0}
 var properties = {}
 var graph{xAxis:undefined, yAxis:undefined, chartArea: undefined}

The properties are all properties as defined in the contribution.xml, the margins are used for layout purposes, often enough they are being calculated immediately in the afterUpdate function based on the properties settings.

An example is the win/loss chart below. Here you see in one component that the charts are divided over multiple columns. That means a lot of margin and thus the necessity to manage them.


/wp-content/uploads/2014/10/winloss_573746.png


An additional advantage is that when you use these kind of variables the editor offers you input help. If you enter “properties.” The editor will show a menu will all available attributes. Especially handy because JavaScript is a case sensitive language and I am not case sensitive at all!


Use Javascript Beautify

The more you code in JavaScript, the more you appreciate it when the code is (relatively) easy to read. Someone who wades into the JavaScript will be overwhelmed with all the () {} [] signs that pop up all over your code.

Good indentation of the code really helps to keep an overview of your code. However when you are busy tweaking your code you (or at least I ) tend to just write it down and not mind the indentation too much. This is when a site like http://jsbeautifier.org/ comes in. You can copy and paste your code in there and beautify the code. The result you can copy and paste back into your editor.



    function iqr(k) {
      return function(d, i) {
        var q1 = d.quartiles[0],
          q3 = d.quartiles[2],
          iqr = (q3 - q1) * k,
          i = -1,
          j = d.length;
        while (d[++i] < q1 - iqr);
        while (d[--j] > q3 + iqr);
        return [i, j];
      };
    }

In this example you have a function that is part of the boxplot graph. This function will calculate the values at the border of the boxes. With the indentation you have a better view of what is at which level.

.call(mygraph)

In earlier versions when I grouped graphs I used to code directly into the grouping. This As classes grew this caused problems as each time you had not looked at the code for some time you had to spend time to rebuild a mental picture of the code.

This is where .call comes in. At the main group level you only have a reference to a function. This will  allow you to create several parts. You even can create a level of reusability.

In the D3 library one of the main functions is .selectAll. This function will allow you to build elements for each row in your data. You use enter() for adding elements for new rows and update attributes for already existing rows. For completeness sake: you use .exit() to remove all elements that have no row of data anymore.

With .call your code can look like this:

Adding :


                boxes
                .enter()
                    .append("svg")
                    .attr("class", "box")
                    .attr("x", function (d,i) { return i * (margin.graphWidth + margin.graphMargin + margin.graphMargin);})
                    .attr("width", margin.graphWidth + margin.graphMargin + margin.graphMargin).attr("height",margin.graphHeight)
                    .append("g")
                    .attr("transform", "translate(" + margin.graphMargin + "," + margin.Graphtop + ")")
                    .call(boxchart);

Updating:


                boxes
                    .attr("x", function (d,i) { return i * (margin.graphWidth + margin.graphMargin + margin.graphMargin);})
                    .attr("width", margin.graphWidth + margin.graphMargin + margin.graphMargin).attr("height",margin.graphHeight)
                    .select("g")
                    .attr("transform", "translate(" + margin.graphMargin + "," + margin.Graphtop + ")")
                    .call(boxchart.duration(500).width(margin.graphWidth));

Note that calling the chart in the update is done by using the .call method, the chart and  with the changed properties but without passing the data. Thanks to closures (a subject in itself) the function gets the context via the keyword this and inherits the data which it can address. You are able to pass variables to the function by creating getter/setter function inside the boxchart function. Especially if you want to reuse the function elsewhere this is better than using higher level variables as they will not be available at the new location.

Although this doesn’t look ‘easy’ by any means it is a lot shorter. Imagine instead of one .call line here this :


.each(function(d,i) {
d3.select(this).append("p")
.text(d.text);
d3.select(this).append("img")
          .attr("src", d.img);
    });

Where a function can contain hundreds of lines.

Although the earlier versions worked fine I did notice that this way It becomes easier to code. At some point your scripts grow and at that point you want to have structures in place to enable you an overview of the code.

To report this post you need to login first.

3 Comments

You must be Logged on to comment or reply to a post.

  1. Willy Yen

    Hello~~

    Can I try the spot chart you made?

    So far ,design studio do not support the spot chart, but it will be great if I can enhance the chart in the dashboard.

    Thank you!

    Willy

    (0) 

Leave a Reply