Adding a line to a chart using the advanced area

by aliceoneill » Thu Aug 17, 2017 10:34 am

Hi, I've got a list that contains data on when someone was admitted to hospital and the ward they were admitted to. I'm using columns called MonthAdmitted (which has the month they were admitted e.g. 6) and Ward.

In the aggregation section I've grouped by Ward and set up tmpMonthTotal which is a count of MonthAdmitted.

I've then added some code to the Dashboard Advanced section:
var handlers = {};
handlers.preRender = function (config, logger) {
logger.debug('Configuration: ', config);

var data = config.series[0].data;

config.series.push({
name: 'Total',
type: 'line',
data: data,
field: 'tmpMonthTotal',
categoryField: 'MonthAdmitted',
tooltip: {
visible: true
}
});

window.config = config;
return true;

}

The bar chart looks fine, but I can't get the line that I've added, which I want to display the total admissions for the month, to show up properly on the chart. Please tell me what I'm doing wrong.

"Display each group as a separate series" is ticked, which I think may be an issue, but without it my bar chart doesn't display properly.

Thank you.
Attachments
admissionsbymonth.JPG
admissionsbymonth.JPG (24.99 KiB) Viewed 144 times
User avatar
aliceoneill
 
Posts: 19
Joined: Mon Dec 19, 2016 10:32 am

by Nikita Kurguzov » Mon Aug 21, 2017 4:18 pm

Hello, Alice!
This was quite a complex case, but not impossible. The main difficulty arose from the multiple series used in this graph, while most our examples only used one. But this can be overcome using JavaScript in Dashboard -> Advanced settings:
Ward Line.png
Ward Line.png (45.59 KiB) Viewed 133 times


Here is my code, hope it will work for you, might need slight adjustments first:
Code: Select all
var handlers = {};
handlers.preRender = function (config, logger) {
      var myData = [];
      var map = new Map;

     data.items.forEach(function (el) {
       map.set(el.Month, (map.get(el.Month) ? map.get(el.Month) : 0) + 1);
     });
 
      let keys = Array.from( map.keys() );

     for (var i = 0; i < keys.length; i++){
          var obj = {};
          obj.Month = keys[i];
          obj.value = map.get(keys[i]);
          myData.push(obj);
     }
 
    config.series.push({
        type: 'line',
         data: myData,
         categoryField: 'Month',
         field: 'value',
        name: "Total",
         tooltip: {
       visible: true
   }
    });
 
    logger.debug('Configuration: ', config);
    window.config = config;
 
    return true;
}
User avatar
Nikita Kurguzov
 
Posts: 24
Joined: Fri Jul 14, 2017 1:35 pm

by aliceoneill » Tue Aug 22, 2017 8:38 am

Thank you for replying Nikita. I'm getting an error
09:29:31 ERROR - Pre-rendering failed: TypeError: Object doesn't support property or method 'keys'

when I process - is there something I need to include? Sorry - my javascript skills are limited.
User avatar
aliceoneill
 
Posts: 19
Joined: Mon Dec 19, 2016 10:32 am

by Nikita Kurguzov » Tue Aug 22, 2017 10:48 am

Hello, Alice!
Most likely you are using IE or Edge, maybe an older version of another browser, and they might not support keys - https://developer.mozilla.org/en-US/doc ... bject/keys

Try adding this code before yours, it might solve the issue:
Code: Select all
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
if (!Object.keys) {
  Object.keys = (function() {
    'use strict';
    var hasOwnProperty = Object.prototype.hasOwnProperty,
        hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'),
        dontEnums = [
          'toString',
          'toLocaleString',
          'valueOf',
          'hasOwnProperty',
          'isPrototypeOf',
          'propertyIsEnumerable',
          'constructor'
        ],
        dontEnumsLength = dontEnums.length;

    return function(obj) {
      if (typeof obj !== 'function' && (typeof obj !== 'object' || obj === null)) {
        throw new TypeError('Object.keys called on non-object');
      }

      var result = [], prop, i;

      for (prop in obj) {
        if (hasOwnProperty.call(obj, prop)) {
          result.push(prop);
        }
      }

      if (hasDontEnumBug) {
        for (i = 0; i < dontEnumsLength; i++) {
          if (hasOwnProperty.call(obj, dontEnums[i])) {
            result.push(dontEnums[i]);
          }
        }
      }
      return result;
    };
  }());
}
User avatar
Nikita Kurguzov
 
Posts: 24
Joined: Fri Jul 14, 2017 1:35 pm

by aliceoneill » Tue Aug 22, 2017 1:36 pm

Well, some very strange results - the original code and the new code work in Chrome when I do a preview. However, when I save my work and look at the page it doesn't display the chart at all! Instead it says "An Error has occured during rendering. Please, get more detail in the browser console.". I go back into Plumsail, don't change anything, do a preview and it still works. Very odd.

In IE I still get the same error as before (the one about 'keys') when I try to do a preview, even with the new code. The page displays the bar chart but not the line.
User avatar
aliceoneill
 
Posts: 19
Joined: Mon Dec 19, 2016 10:32 am

by Nikita Kurguzov » Tue Aug 22, 2017 3:49 pm

Hello, Alice!
Regarding the problem in Google Chrome - it's my bad.
What you need to do to make it work is to split code in two parts, one part goes to Data Source and another goes to Dashboard. Here are the screenshots and the code:
DataSource-Line.png
DataSource-Line.png (32.06 KiB) Viewed 126 times

Code: Select all
handlers.aggregationSuccess = function(data, logger) {
  window.myData = [];
  var map = new Map;

  data.items.forEach(function (el) {
    map.set(el.Month, (map.get(el.Month) ? map.get(el.Month) : 0) + 1);
  });
 
  let keys = Array.from( map.keys() );
 
  for (var i = 0; i < keys.length; i++){
    var obj = {};
    obj.Month = keys[i];
    obj.value = map.get(keys[i]);
     
    myData.push(obj);
  }
 
  return true;
}

Dashboard-Line.png
Dashboard-Line.png (16.43 KiB) Viewed 126 times

Code: Select all
var handlers = {};
handlers.preRender = function (config, logger) {
    config.series.push({
        type: 'line',
         data: myData,
         categoryField: 'Month',
         field: 'value',
         name: "Total",
         tooltip: {
     visible: true
   }
    });
 
    logger.debug('Configuration: ', config);
  window.config = config;
 
    return true;
}


P.S. If you need support for Internet Explorer, we can most likely write code for you and post it here tomorrow. For now, this code should work in Google Chrome and other browsers that support keys object.
User avatar
Nikita Kurguzov
 
Posts: 24
Joined: Fri Jul 14, 2017 1:35 pm

by aliceoneill » Thu Aug 24, 2017 7:59 am

Thanks Nikita - that does now work in Chrome. Hooray! But .. yes I do need it to work in IE. Sorry - please can you help?
User avatar
aliceoneill
 
Posts: 19
Joined: Mon Dec 19, 2016 10:32 am

by Nikita Kurguzov » Thu Aug 24, 2017 1:31 pm

Hello, Alice!
Try this code in Data Source -> Advanced:
Code: Select all
handlers.aggregationSuccess = function(data, logger) {
  window.myData = [];
  var monthObj = {};

  data.items.forEach(function (el) {
    if(monthObj[el.Month]){
        monthObj[el.Month] += 1;
    }
    else{
       monthObj[el.Month] = 1;
    }
  });
 
 
  for (var property in monthObj) {
    if (monthObj.hasOwnProperty(property)) {
      var obj = {};
      obj.Month = property;
      obj.value = monthObj[property];
      myData.push(obj);
    }
}
 
  return true;
}
User avatar
Nikita Kurguzov
 
Posts: 24
Joined: Fri Jul 14, 2017 1:35 pm

by aliceoneill » Tue Aug 29, 2017 7:32 am

Hi Nikita, I'm afraid it's still not working. Can I please just check I've done the right thing? The field I'm using is called MonthAdmitted. In Datasource Advanced I've got this:

Code: Select all
handlers.aggregationSuccess = function(data, logger) {
  window.myData = [];
  var monthObj = {};

  data.items.forEach(function (el) {
    if(monthObj[el.MonthAdmitted]){
        monthObj[el.MonthAdmitted] += 1;
    }
    else{
       monthObj[el.MonthAdmitted] = 1;
    }
  });
 
 
  for (var property in monthObj) {
    if (monthObj.hasOwnProperty(property)) {
      var obj = {};
      obj.Month = property;
      obj.value = monthObj[property];
      myData.push(obj);
    }
}
 
  return true;
}

handlers.aggregationError = function(error, logger) {
  return $.Deferred().reject(error);
}

handlers.finish = function(data, logger) {
  logger.debug('Data is processed: ', data);
  return true;
}


And in Dashboard Advanced I have this:
Code: Select all
var handlers = {};
handlers.preRender = function (config, logger) {
 
    config.series.push({
        type: 'line',
         data: myData,
         categoryField: 'MonthAdmitted', //or Month?
         field: 'value',
         //name: "Total",
         tooltip: {
       visible: true
   }
    });
 
    logger.debug('Configuration: ', config);
    window.config = config;
 
    return true;
}
User avatar
aliceoneill
 
Posts: 19
Joined: Mon Dec 19, 2016 10:32 am

by Nikita Kurguzov » Tue Aug 29, 2017 9:46 am

It should work, just tested it once again. Don't worry about Dashboard -> Advanced settings, they are the same for IE and Chrome, so if it works for Chrome then the problem is in Data Source -> Advanced tab.

Most likely the issue is that you didn't change
obj.Month = property;
to
obj.MonthAdmitted = property;

Try this and tell me if it works or not.
User avatar
Nikita Kurguzov
 
Posts: 24
Joined: Fri Jul 14, 2017 1:35 pm

Next

Return to Dashboard Designer for SharePoint 2013

cron