Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
jeroenvandera
Contributor

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.

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.

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.



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.

3 Comments
Labels in this area