During February Bob Balfe has been blogging 28 days of Dojo. To tie in with that I’ve decided now is a good time to blog about a couple of charting enhancements I included in my Lotusphere session with Dave Leedy, XPages: Enter The Dojo.

The first is new functionality available with Dojo 1.5.0 to add gradients to your charts. First of all, Dojo 1.5.0 is not installed by default with Domino 8.5.2, so it will require an install on the server and (if you’re using your charts for XPages in Notes Client) also on the clients. The other implication is that the Domino server, by default, uses the highest numbered version of Dojo. So if you were to rename the dojo-1.1.1 folder that comes with the 8.5.0 install to dojo-1.6.1, that folder would then be the Dojo version in use on the server. You can downgrade the Dojo version by modifying the xsp.properties file on the server (or client for XPiNC), but this will affect all applications on the server. You cannot override the Dojo version for an application or an XPage by changing the xsp.properties file in your application or changing the djConfig parameter in an xp:head tag. You will find those have no effect. This is because the XSP Command Manager needs to load Dojo files automatically for any XPage for standard client functionality like partial refreshes etc. In my experience, even if you set dojoParseOnLoad to “false” for the XPage and all custom controls, the xspClientDojo javascript file is still loaded, and the version used for that is the Dojo version used for all Dojo files.

Having said that, Jeremy Hodge pointed out on the XPages forum that you should be able to put all the Dojo files in an nsf and use that. But that would certainly be a lot of work. So currently, if you want to use gradients, you will need to create a dojo-1.5.0 folder, install all the Dojo sub-folders and the ibm sub-folder. But this will, officially, be unsupported. Alternatively, you can wait for 8.5.3 which will probably ship with Dojo 1.5.0.

Once you have Dojo 1.5.0 accessible for your XPages, there are two Dojo modules to include to implement gradients. These are dojox.gfx.gradutils and dojox.charting.Theme. dojox.gfx.gradutils adds in the gradients functionality itself, whereas dojox.charting.Theme is used as a holder for your settings. Why can’t you use one of the in-built themes? Because your new theme specifies the fill types and “from” and “to” colours, which are not included in the default themes. My recommendation for getting the colours you want is to implement the standard theme that has the colours you want, then to use something to get a screenshot and identify the colours – I used Snag-it. Once you’ve got the colours, you can build up your own theme. So the format is:

  1. var myTheme = new dojox.charting.Theme({
  2.     seriesThemes: [
  3.         {
  4.             fill:{
  5.                 type: “linear”, space:“shape”, x1: 0, y1: 100, x2: 100, y2: 0,
  6.                 colors:[{offset:0, color:“white”},{offset:1, color:“#57808f”}]
  7.             }
  8.         },
  9.         {
  10.             fill:{
  11.                 type: “linear”, space:“shape”, x1: 100, y1: 100, x2: 100, y2: 100,
  12.                 colors:[{offset:0, color:“white”},{offset:1, color:“#558f7f”}]
  13.             }
  14.         },
  15.         {
  16.             fill:{
  17.                 type: “linear”, space:“shape”, x1: 0, y1: 0, x2: 0, y2: 0,
  18.                 colors:[{offset:0, color:“white”},{offset:1, color:“#508567”}]
  19.             }
  20.         }
  21.     ]
  22. });

For a pie chart the first line has no effect whatsoever. The gradient will always move from the centre of the pie chart to the outside. The first offset is the colour you get in the middle, the second offset is the colour you will get on the outside.

For other types of chart, you get more control over your gradients. Th e first option is type – radial or linear. These do what they say on the tin. If you use radial the colours radiate from the centre to the edge of the shape, linear moves from one side to another. The best option for the space parameter is shape: the gradient is relative to the shape of each element in your series – a bar for a bar chart, a column for a column chart etc. The x and y parameters then manage how your gradients extend – the x parameters handle the colour gradients from right to left on your shape, the y parameters handle the colour gradients from top to bottom. So in the option above the second and third fills will actually have no gradient – the second will just be offset:1, the third just offset:0. This means you can manipulate colours quite flexibly. Bear in mind though that the layout of your gradient will have an impact on the colour shown in the icon on your legend.

You then implement your theme in exactly the same way as you would otherwise, with chart.setTheme(myTheme);

The second element of my session at Lotusphere was the Legend. One of the limitations of the out-of-the-box legend is that it can only be horizontal or vertical, so only a row of labels or a column or labels. This means it takes up quite a lot of screen real estate. As part of the preparation I decided to have a go at extending the out-of-the-box module. I knew the legend was implemented as an html table, so in theory it was just a case of allowing the user to select the number of columns, set a default just in case, and add the necessary opening and closing tr tags. The whole thing took less than half an hour. While presenting the session I was also a little irked by the icons being middle-aligned in the table if the label wrapped onto two lines. So the following morning I added options to set class attributes for the icon and label cells. The first took a bit of investigation, about five and a half minutes. Testing took a bit longer, mainly because I was passing a variable instead of the class name as a string. Adding the icon cell class took – from start of development to completion of testing – 2 minutes 45 seconds. For someone who is not a javascript expert, this just shows how flexible Dojo is.

So the finished module is:

  1. dojo.provide(“uk.co.intec.widget.Legend”);
  2. dojo.require(“dojox.charting.widget.Legend”);
  3. dojo.provide(“uk.co.intec.widget.Legend”);
  4. dojo.require(“dojox.charting.widget.Legend”);
  5. dojo.declare(“uk.co.intec.widget.Legend”,dojox.charting.widget.Legend, {
  6.     // extends refresh in dojox.charting.widget.Legend
  7.     columns: 1,
  8.     tdTextStyleClass: “”,
  9.     tdIconStyleClass: “”,
  10.     _colCount: 0,
  11.     // extends _addLabel in dojox.charting.widget.Legend
  12.     _addLabel: function(dyn, label){
  13.         // create necessary elements
  14.         var icon = dojo.doc.createElement(“td”),
  15.             text = dojo.doc.createElement(“td”),
  16.             div  = dojo.doc.createElement(“div”);
  17.         dojo.addClass(icon, “dojoxLegendIcon”);
  18.         dojo.addClass(text, “dojoxLegendText”);
  19.         // Extended PW Add class attributes for icon and label cells
  20.         dojo.addClass(icon, this.tdIconStyleClass);
  21.         dojo.addClass(text, this.tdTextStyleClass);
  22.         // End of extension by PW
  23.         div.style.width  = this.swatchSize + “px”;
  24.         div.style.height = this.swatchSize + “px”;
  25.         icon.appendChild(div);
  26.        
  27.         // create a skeleton
  28.         if(this.horizontal){
  29.             // horizontal
  30.             this._tr.appendChild(icon);
  31.             this._tr.appendChild(text);
  32.         }else{
  33.             // vertical.
  34.             // Extended PW Add a new row for first element, or if we’ve reached
  35.             // the last column the user wants
  36.             if (this._colCount == 0 || this._colCount == this.columns) {
  37.                 this._tr = dojo.doc.createElement(“tr”);
  38.                 this.legendBody.appendChild(this._tr);
  39.                 this._colCount = 1;
  40.             } else {
  41.                 this._colCount += 1;
  42.             }
  43.             // End of extension by PW
  44.             this._tr.appendChild(icon);
  45.             this._tr.appendChild(text);
  46.         }
  47.        
  48.         // populate the skeleton
  49.         this._makeIcon(div, dyn);
  50.         text.innerHTML = String(label);
  51.     }
  52. })

For the classes I add two new string attributes, tdIconStyleClass and tdTextStyleClass. These should be class names as strings and are be default blank strings. I added two lines to add the _addLabel function to add the classes to the relevant cells. The biggest challenge I had was I was expecting an html template rather than dojo.doc.createElement blocks, so it took me a while to spot that.

For the multi-column functionality I add two new attributes: columns is an integer for the number of columns to show, _colCount is an internal variable to manage when to start a new row. It expects that the horizontal dojo attribute be set to false, i.e. that your legend be vertical. Then I have just added an additional if statement. So if _colCount is 0 (the first iteration) or _colCount has reached the number of columns the developer specified, we create a new tr tag and reset _colCount to 1 – if we reset it to 0 on the next iteration it would start another table row, which we don’t want. Otherwise we just increment the _colCount attribute. As you can see it’s a very simple extension to the Dojo module. This can be saved to the server (and clients for XPiNC) or saved as a File Resource in your application. A File Resource is the easiest option because it behaves consitently between client and browser – a Javascript Library means you need to remove the “.js” suffix for web, but leave it on for client.

From looking at support tickets for Dojo 1.6.0, it looks like the Legend functionality is changing a little, so the module may not be applicable for that release. But Dojo 1.6.0 has not yet been released let alone included in the Domino install, so we have some time yet.

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.