dhis2-devs team mailing list archive
-
dhis2-devs team
-
Mailing list archive
-
Message #27273
[Branch ~dhis2-devs-core/dhis2/trunk] Rev 13550: DV, plugin updated
Merge authors:
Jan Henrik Øverland (janhenrik-overland)
------------------------------------------------------------
revno: 13550 [merge]
committer: Jan Henrik Overland <janhenrik.overland@xxxxxxxxx>
branch nick: dhis2
timestamp: Thu 2014-01-02 20:19:38 +0100
message:
DV, plugin updated
modified:
dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/plugin.js
dhis-2/dhis-web/dhis-web-visualizer/src/main/webapp/dhis-web-visualizer/app/plugin.html
dhis-2/dhis-web/dhis-web-visualizer/src/main/webapp/dhis-web-visualizer/app/scripts/app.js
dhis-2/dhis-web/dhis-web-visualizer/src/main/webapp/dhis-web-visualizer/app/scripts/plugin.js
--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk
Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/plugin.js'
--- dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/plugin.js 2014-01-02 15:36:23 +0000
+++ dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/plugin.js 2014-01-02 18:14:38 +0000
@@ -2697,7 +2697,6 @@
service = ns.core.service,
web = ns.core.web;
-
// mouse events
web.events = web.events || {};
=== modified file 'dhis-2/dhis-web/dhis-web-visualizer/src/main/webapp/dhis-web-visualizer/app/plugin.html'
--- dhis-2/dhis-web/dhis-web-visualizer/src/main/webapp/dhis-web-visualizer/app/plugin.html 2013-10-16 12:10:40 +0000
+++ dhis-2/dhis-web/dhis-web-visualizer/src/main/webapp/dhis-web-visualizer/app/plugin.html 2014-01-02 19:18:40 +0000
@@ -2,35 +2,33 @@
<html>
<head>
<link rel="stylesheet" type="text/css" href="../../dhis-web-commons/javascripts/ext/resources/css/ext-plugin-gray.css" />
-
<script src="../../dhis-web-commons/javascripts/ext/ext-all.js"></script>
- <script src="../../dhis-web-commons/javascripts/simpleRegression.js"></script>
- <script src="../../dhis-web-commons/javascripts/plugin/chart.js"></script>
+ <script src="http://dhis2-cdn.org/v214/plugin/chart.js"></script>
<style type="text/css">
body {font-family: sans-serif; margin: 0 0 0 60px;}
h1 {font-size: 20px; margin: 20px 0;}
- #chart1, #chart2 {width: 1000px; margin-bottom: 50px; height: 300px; border: 2px solid #d1d1d1; border-radius: 1px;}
+ #chart1, #chart2 {width: 90%; margin-bottom: 50px; height: 300px; border: 2px solid #d1d1d1; border-radius: 1px;}
</style>
<script>
Ext.onReady(function() {
var url = 'http://localhost:8080';
- DV.plugin.getChart({
+ DHIS.getChart({
url: url,
el: 'chart1',
- uid: 'j1gNXBgwKVm'
+ uid: 'R0DVGvXDUNP'
});
- DV.plugin.getChart({
+ DHIS.getChart({
url: url,
el: 'chart2',
type: 'column',
columns: [
- {dimension: 'de', items: [{id: 'Uvn6LCg7dVU'}, {id: 'sB79w2hiLp8'}]}
+ {dimension: 'in', items: [{id: 'Uvn6LCg7dVU'}, {id: 'sB79w2hiLp8'}]}
],
rows: [
{dimension: 'pe', items: [{id: 'LAST_3_MONTHS'}]}
@@ -38,7 +36,6 @@
filters: [
{dimension: 'ou', items: [{id: 'USER_ORGUNIT'}]}
],
- showData: true,
targetLineValue: 70,
//baseLineValue: 20,
//showTrendLine: true,
=== modified file 'dhis-2/dhis-web/dhis-web-visualizer/src/main/webapp/dhis-web-visualizer/app/scripts/app.js'
--- dhis-2/dhis-web/dhis-web-visualizer/src/main/webapp/dhis-web-visualizer/app/scripts/app.js 2013-12-31 16:01:52 +0000
+++ dhis-2/dhis-web/dhis-web-visualizer/src/main/webapp/dhis-web-visualizer/app/scripts/app.js 2014-01-02 18:14:38 +0000
@@ -330,7 +330,7 @@
return;
}
- ns.core.web.chart.update(layout, false);
+ ns.core.web.chart.getData(layout, false);
window.hide();
}
@@ -1659,13 +1659,13 @@
layout = api.layout.Layout(layoutConfig);
if (layout) {
- web.chart.update(layout, true);
+ web.chart.getData(layout, true);
}
}
});
};
- web.chart.update = function(layout, isUpdateGui) {
+ web.chart.getData = function(layout, isUpdateGui) {
var xLayout,
paramString;
@@ -1714,42 +1714,55 @@
web.mask.hide(ns.app.centerRegion);
return;
}
-
- // extend response
- xResponse = service.response.getExtendedResponse(xLayout, response);
-
- // references
- ns.app.layout = layout;
- ns.app.xLayout = xLayout;
- ns.app.response = response;
- ns.app.xResponse = xResponse;
+
ns.app.paramString = paramString;
- // create chart
- ns.app.chart = ns.core.web.chart.createChart(ns);
-
- // update viewport
- ns.app.centerRegion.removeAll();
- ns.app.centerRegion.add(ns.app.chart);
-
- // after render
- if (NS.isSessionStorage) {
- web.storage.session.set(layout, 'table');
- }
-
- ns.app.viewport.setGui(layout, xLayout, isUpdateGui);
-
- web.mask.hide(ns.app.centerRegion);
-
- if (NS.isDebug) {
- console.log("core", ns.core);
- console.log("app", ns.app);
- }
+ web.chart.getChart(layout, xLayout, response, isUpdateGui);
}
});
};
+
+ web.chart.getChart = function(layout, xLayout, response, isUpdateGui) {
+ var xResponse,
+ xColAxis,
+ xRowAxis,
+ config;
+
+ if (!xLayout) {
+ xLayout = service.layout.getExtendedLayout(layout);
+ }
+
+ // extend response
+ xResponse = service.response.getExtendedResponse(xLayout, response);
+
+ // references
+ ns.app.layout = layout;
+ ns.app.xLayout = xLayout;
+ ns.app.response = response;
+ ns.app.xResponse = xResponse;
+
+ // create chart
+ ns.app.chart = ns.core.web.chart.createChart(ns);
+
+ // update viewport
+ ns.app.centerRegion.removeAll();
+ ns.app.centerRegion.add(ns.app.chart);
+
+ // after render
+ if (NS.isSessionStorage) {
+ web.storage.session.set(layout, 'table');
+ }
+
+ ns.app.viewport.setGui(layout, xLayout, isUpdateGui);
+
+ web.mask.hide(ns.app.centerRegion);
+
+ if (NS.isDebug) {
+ console.log("core", ns.core);
+ console.log("app", ns.app);
+ }
+ };
}());
-
};
// viewport
@@ -4207,7 +4220,7 @@
return;
}
- ns.core.web.chart.update(layout, false);
+ ns.core.web.chart.getData(layout, false);
};
accordionBody = Ext.create('Ext.panel.Panel', {
@@ -4956,7 +4969,7 @@
layout = ns.core.api.layout.Layout(JSON.parse(sessionStorage.getItem('dhis2'))[session]);
if (layout) {
- ns.core.web.chart.update(layout, true);
+ ns.core.web.chart.getData(layout, true);
}
}
=== modified file 'dhis-2/dhis-web/dhis-web-visualizer/src/main/webapp/dhis-web-visualizer/app/scripts/plugin.js'
--- dhis-2/dhis-web/dhis-web-visualizer/src/main/webapp/dhis-web-visualizer/app/scripts/plugin.js 2013-10-15 17:37:29 +0000
+++ dhis-2/dhis-web/dhis-web-visualizer/src/main/webapp/dhis-web-visualizer/app/scripts/plugin.js 2014-01-02 19:18:40 +0000
@@ -1,12 +1,2560 @@
Ext.onReady(function() {
+ // SIMPLE REGRESSION
+ function SimpleRegression()
+ {
+ var sumX = 0; // Sum of x values
+ var sumY = 0; // Sum of y values
+ var sumXX = 0; // Total variation in x
+ var sumXY = 0; // Sum of products
+ var n = 0; // Number of observations
+ var xbar = 0; // Mean of accumulated x values, used in updating formulas
+ var ybar = 0; // Mean of accumulated y values, used in updating formulas
+
+ this.addData = function( x, y )
+ {
+ if ( n == 0 )
+ {
+ xbar = x;
+ ybar = y;
+ }
+ else
+ {
+ var dx = x - xbar;
+ var dy = y - ybar;
+ sumXX += dx * dx * n / ( n + 1 );
+ sumXY += dx * dy * n / ( n + 1 );
+ xbar += dx / ( n + 1 );
+ ybar += dy / ( n + 1 );
+ }
+
+ sumX += x;
+ sumY += y;
+ n++;
+ };
+
+ this.predict = function( x )
+ {
+ var b1 = this.getSlope();
+
+ return this.getIntercept( b1 ) + b1 * x;
+ };
+
+ this.getSlope = function()
+ {
+ if ( n < 2 )
+ {
+ return Number.NaN;
+ }
+
+ return sumXY / sumXX;
+ };
+
+ this.getIntercept = function( slope )
+ {
+ return ( sumY - slope * sumX ) / n;
+ };
+ }
+
+ // CORE
+
+ // ext config
+ Ext.Ajax.method = 'GET';
+
+ // namespace
+ DV = {};
+
+ DV.instances = [];
+ DV.i18n = {};
+ DV.isDebug = false;
+ DV.isSessionStorage = ('sessionStorage' in window && window['sessionStorage'] !== null);
+
+ DV.getCore = function(init) {
+ var conf = {},
+ api = {},
+ support = {},
+ service = {},
+ web = {},
+ dimConf;
+
+ // conf
+ (function() {
+ conf.finals = {
+ ajax: {
+ path_module: '/dhis-web-visualizer/',
+ path_api: '/api/',
+ path_commons: '/dhis-web-commons-ajax-json/',
+ data_get: 'chartValues.json',
+ indicator_get: 'indicatorGroups/',
+ indicator_getall: 'indicators.json?paging=false&links=false',
+ indicatorgroup_get: 'indicatorGroups.json?paging=false&links=false',
+ dataelement_get: 'dataElementGroups/',
+ dataelement_getall: 'dataElements.json?domainType=aggregate&paging=false&links=false',
+ dataelementgroup_get: 'dataElementGroups.json?paging=false&links=false',
+ dataset_get: 'dataSets.json?paging=false&links=false'
+ },
+ dimension: {
+ data: {
+ value: 'data',
+ name: DV.i18n.data,
+ dimensionName: 'dx',
+ objectName: 'dx'
+ },
+ indicator: {
+ value: 'indicator',
+ name: DV.i18n.indicator,
+ dimensionName: 'dx',
+ objectName: 'in'
+ },
+ dataElement: {
+ value: 'dataelement',
+ name: DV.i18n.data_element,
+ dimensionName: 'dx',
+ objectName: 'de'
+ },
+ operand: {
+ value: 'operand',
+ name: 'Operand',
+ dimensionName: 'dx',
+ objectName: 'dc'
+ },
+ dataSet: {
+ value: 'dataset',
+ name: DV.i18n.dataset,
+ dimensionName: 'dx',
+ objectName: 'ds'
+ },
+ category: {
+ name: DV.i18n.categories,
+ dimensionName: 'co',
+ objectName: 'co',
+ },
+ period: {
+ value: 'period',
+ name: DV.i18n.period,
+ dimensionName: 'pe',
+ objectName: 'pe',
+ },
+ fixedPeriod: {
+ value: 'periods'
+ },
+ relativePeriod: {
+ value: 'relativePeriods'
+ },
+ organisationUnit: {
+ value: 'organisationUnits',
+ name: DV.i18n.organisation_units,
+ dimensionName: 'ou',
+ objectName: 'ou',
+ },
+ dimension: {
+ value: 'dimension'
+ //objectName: 'di'
+ },
+ value: {
+ value: 'value'
+ }
+ },
+ chart: {
+ series: 'series',
+ category: 'category',
+ filter: 'filter',
+ column: 'column',
+ stackedcolumn: 'stackedcolumn',
+ bar: 'bar',
+ stackedbar: 'stackedbar',
+ line: 'line',
+ area: 'area',
+ pie: 'pie',
+ radar: 'radar'
+ },
+ data: {
+ domain: 'domain_',
+ targetLine: 'targetline_',
+ baseLine: 'baseline_',
+ trendLine: 'trendline_'
+ },
+ image: {
+ png: 'png',
+ pdf: 'pdf'
+ },
+ cmd: {
+ init: 'init_',
+ none: 'none_',
+ urlparam: 'id'
+ },
+ root: {
+ id: 'root'
+ }
+ };
+
+ dimConf = conf.finals.dimension;
+
+ dimConf.objectNameMap = {};
+ dimConf.objectNameMap[dimConf.data.objectName] = dimConf.data;
+ dimConf.objectNameMap[dimConf.indicator.objectName] = dimConf.indicator;
+ dimConf.objectNameMap[dimConf.dataElement.objectName] = dimConf.dataElement;
+ dimConf.objectNameMap[dimConf.operand.objectName] = dimConf.operand;
+ dimConf.objectNameMap[dimConf.dataSet.objectName] = dimConf.dataSet;
+ dimConf.objectNameMap[dimConf.category.objectName] = dimConf.category;
+ dimConf.objectNameMap[dimConf.period.objectName] = dimConf.period;
+ dimConf.objectNameMap[dimConf.organisationUnit.objectName] = dimConf.organisationUnit;
+ dimConf.objectNameMap[dimConf.dimension.objectName] = dimConf.dimension;
+
+ conf.period = {
+ periodTypes: [
+ {id: 'Daily', name: DV.i18n.daily},
+ {id: 'Weekly', name: DV.i18n.weekly},
+ {id: 'Monthly', name: DV.i18n.monthly},
+ {id: 'BiMonthly', name: DV.i18n.bimonthly},
+ {id: 'Quarterly', name: DV.i18n.quarterly},
+ {id: 'SixMonthly', name: DV.i18n.sixmonthly},
+ {id: 'Yearly', name: DV.i18n.yearly},
+ {id: 'FinancialOct', name: DV.i18n.financial_oct},
+ {id: 'FinancialJuly', name: DV.i18n.financial_july},
+ {id: 'FinancialApril', name: DV.i18n.financial_april}
+ ]
+ };
+
+ conf.layout = {
+ west_width: 424,
+ west_fieldset_width: 416,
+ west_width_padding: 4,
+ west_fill: 2,
+ west_fill_accordion_indicator: 59,
+ west_fill_accordion_dataelement: 59,
+ west_fill_accordion_dataset: 33,
+ west_fill_accordion_period: 296,
+ west_fill_accordion_organisationunit: 62,
+ west_maxheight_accordion_indicator: 350,
+ west_maxheight_accordion_dataelement: 350,
+ west_maxheight_accordion_dataset: 350,
+ west_maxheight_accordion_period: 513,
+ west_maxheight_accordion_organisationunit: 500,
+ west_maxheight_accordion_group: 350,
+ west_scrollbarheight_accordion_indicator: 300,
+ west_scrollbarheight_accordion_dataelement: 300,
+ west_scrollbarheight_accordion_dataset: 300,
+ west_scrollbarheight_accordion_period: 450,
+ west_scrollbarheight_accordion_organisationunit: 450,
+ west_scrollbarheight_accordion_group: 300,
+ east_tbar_height: 31,
+ east_gridcolumn_height: 30,
+ form_label_width: 55,
+ window_favorite_ypos: 100,
+ window_confirm_width: 250,
+ window_share_width: 500,
+ grid_favorite_width: 420,
+ grid_row_height: 27,
+ treepanel_minheight: 135,
+ treepanel_maxheight: 400,
+ treepanel_fill_default: 310,
+ treepanel_toolbar_menu_width_group: 140,
+ treepanel_toolbar_menu_width_level: 120,
+ multiselect_minheight: 100,
+ multiselect_maxheight: 250,
+ multiselect_fill_default: 345,
+ multiselect_fill_reportingrates: 315
+ };
+
+ conf.chart = {
+ style: {
+ inset: 30,
+ fontFamily: 'Arial,Sans-serif,Lucida Grande,Ubuntu'
+ },
+ theme: {
+ dv1: ['#94ae0a', '#0b3b68', '#a61120', '#ff8809', '#7c7474', '#a61187', '#ffd13e', '#24ad9a', '#a66111', '#414141', '#4500c4', '#1d5700']
+ }
+ };
+
+ conf.status = {
+ icon: {
+ error: 'error_s.png',
+ warning: 'warning.png',
+ ok: 'ok.png'
+ }
+ };
+
+ }());
+
+ // api
+ (function() {
+ api.layout = {};
+
+ api.layout.Record = function(config) {
+ var config = Ext.clone(config);
+
+ // id: string
+
+ return function() {
+ if (!Ext.isObject(config)) {
+ console.log('Record: config is not an object: ' + config);
+ return;
+ }
+
+ if (!Ext.isString(config.id)) {
+ alert('Record: id is not text: ' + config);
+ return;
+ }
+
+ config.id = config.id.replace('.', '-');
+
+ return config;
+ }();
+ };
+
+ api.layout.Dimension = function(config) {
+ var config = Ext.clone(config);
+
+ // dimension: string
+
+ // items: [Record]
+
+ return function() {
+ if (!Ext.isObject(config)) {
+ console.log('Dimension: config is not an object: ' + config);
+ return;
+ }
+
+ if (!Ext.isString(config.dimension)) {
+ console.log('Dimension: name is not a string: ' + config);
+ return;
+ }
+
+ if (config.dimension !== conf.finals.dimension.category.objectName) {
+ var records = [];
+
+ if (!Ext.isArray(config.items)) {
+ console.log('Dimension: items is not an array: ' + config);
+ return;
+ }
+
+ for (var i = 0; i < config.items.length; i++) {
+ records.push(api.layout.Record(config.items[i]));
+ }
+
+ config.items = Ext.Array.clean(records);
+
+ if (!config.items.length) {
+ console.log('Dimension: has no valid items: ' + config);
+ return;
+ }
+ }
+
+ return config;
+ }();
+ };
+
+ api.layout.Layout = function(config) {
+ var config = Ext.clone(config),
+ layout = {},
+ getValidatedDimensionArray,
+ validateSpecialCases;
+
+ // type: string ('column') - 'column', 'stackedcolumn', 'bar', 'stackedbar', 'line', 'area', 'pie'
+
+ // columns: [Dimension]
+
+ // rows: [Dimension]
+
+ // filters: [Dimension]
+
+ // showTrendLine: boolean (false)
+
+ // targetLineValue: number
+
+ // targetLineTitle: string
+
+ // baseLineValue: number
+
+ // baseLineTitle: string
+
+ // showValues: boolean (true)
+
+ // hideLegend: boolean (false)
+
+ // hideTitle: boolean (false)
+
+ // domainAxisTitle: string
+
+ // rangeAxisTitle: string
+
+ // userOrganisationUnit: boolean (false)
+
+ // userOrganisationUnitChildren: boolean (false)
+
+ // parentGraphMap: object
+
+ getValidatedDimensionArray = function(dimensionArray) {
+ var dimensionArray = Ext.clone(dimensionArray);
+
+ if (!(dimensionArray && Ext.isArray(dimensionArray) && dimensionArray.length)) {
+ return;
+ }
+
+ for (var i = 0; i < dimensionArray.length; i++) {
+ dimensionArray[i] = api.layout.Dimension(dimensionArray[i]);
+ }
+
+ dimensionArray = Ext.Array.clean(dimensionArray);
+
+ return dimensionArray.length ? dimensionArray : null;
+ };
+
+ analytical2layout = function(analytical) {
+ var layoutConfig = Ext.clone(analytical),
+ co = dimConf.category.objectName;
+
+ analytical = Ext.clone(analytical);
+
+ layoutConfig.columns = [];
+ layoutConfig.rows = [];
+ layoutConfig.filters = layoutConfig.filters || [];
+
+ // Series
+ if (Ext.isArray(analytical.columns) && analytical.columns.length) {
+ analytical.columns.reverse();
+
+ for (var i = 0, dim; i < analytical.columns.length; i++) {
+ dim = analytical.columns[i];
+
+ if (dim.dimension === co) {
+ continue;
+ }
+
+ if (!layoutConfig.columns.length) {
+ layoutConfig.columns.push(dim);
+ }
+ else {
+
+ // indicators cannot be set as filter
+ if (dim.dimension === dimConf.indicator.objectName) {
+ layoutConfig.filters.push(layoutConfig.columns.pop());
+ layoutConfig.columns = [dim];
+ }
+ else {
+ layoutConfig.filters.push(dim);
+ }
+ }
+ }
+ }
+
+ // Rows
+ if (Ext.isArray(analytical.rows) && analytical.rows.length) {
+ analytical.rows.reverse();
+
+ for (var i = 0, dim; i < analytical.rows.length; i++) {
+ dim = analytical.rows[i];
+
+ if (dim.dimension === co) {
+ continue;
+ }
+
+ if (!layoutConfig.rows.length) {
+ layoutConfig.rows.push(dim);
+ }
+ else {
+
+ // indicators cannot be set as filter
+ if (dim.dimension === dimConf.indicator.objectName) {
+ layoutConfig.filters.push(layoutConfig.rows.pop());
+ layoutConfig.rows = [dim];
+ }
+ else {
+ layoutConfig.filters.push(dim);
+ }
+ }
+ }
+ }
+
+ return layoutConfig;
+ };
+
+ validateSpecialCases = function() {
+ var dimConf = conf.finals.dimension,
+ dimensions,
+ objectNameDimensionMap = {};
+
+ if (!layout) {
+ return;
+ }
+
+ dimensions = Ext.Array.clean([].concat(layout.columns || [], layout.rows || [], layout.filters || []));
+
+ for (var i = 0; i < dimensions.length; i++) {
+ objectNameDimensionMap[dimensions[i].dimension] = dimensions[i];
+ }
+
+ if (layout.filters && layout.filters.length) {
+ for (var i = 0; i < layout.filters.length; i++) {
+
+ // Indicators as filter
+ if (layout.filters[i].dimension === dimConf.indicator.objectName) {
+ web.message.alert(DV.i18n.indicators_cannot_be_specified_as_filter || 'Indicators cannot be specified as filter');
+ return;
+ }
+
+ // Categories as filter
+ if (layout.filters[i].dimension === dimConf.category.objectName) {
+ web.message.alert(DV.i18n.categories_cannot_be_specified_as_filter || 'Categories cannot be specified as filter');
+ return;
+ }
+
+ // Data sets as filter
+ if (layout.filters[i].dimension === dimConf.dataSet.objectName) {
+ web.message.alert(DV.i18n.data_sets_cannot_be_specified_as_filter || 'Data sets cannot be specified as filter');
+ return;
+ }
+ }
+ }
+
+ // dc and in
+ if (objectNameDimensionMap[dimConf.operand.objectName] && objectNameDimensionMap[dimConf.indicator.objectName]) {
+ web.message.alert('Indicators and detailed data elements cannot be specified together');
+ return;
+ }
+
+ // dc and de
+ if (objectNameDimensionMap[dimConf.operand.objectName] && objectNameDimensionMap[dimConf.dataElement.objectName]) {
+ web.message.alert('Detailed data elements and totals cannot be specified together');
+ return;
+ }
+
+ // dc and ds
+ if (objectNameDimensionMap[dimConf.operand.objectName] && objectNameDimensionMap[dimConf.dataSet.objectName]) {
+ web.message.alert('Data sets and detailed data elements cannot be specified together');
+ return;
+ }
+
+ // dc and co
+ if (objectNameDimensionMap[dimConf.operand.objectName] && objectNameDimensionMap[dimConf.category.objectName]) {
+ web.message.alert('Categories and detailed data elements cannot be specified together');
+ return;
+ }
+
+ return true;
+ };
+
+ return function() {
+ var objectNames = [],
+ dimConf = conf.finals.dimension;
+
+ // config must be an object
+ if (!(config && Ext.isObject(config))) {
+ alert('Layout: config is not an object (' + init.el + ')');
+ return;
+ }
+
+ config.columns = getValidatedDimensionArray(config.columns);
+ config.rows = getValidatedDimensionArray(config.rows);
+ config.filters = getValidatedDimensionArray(config.filters);
+
+ // at least one dimension specified as column and row
+ if (!config.columns) {
+ alert('No series items selected');
+ return;
+ }
+
+ if (!config.rows) {
+ alert('No category items selected');
+ return;
+ }
+
+ // get object names
+ for (var i = 0, dims = Ext.Array.clean([].concat(config.columns || [], config.rows || [], config.filters || [])); i < dims.length; i++) {
+
+ // Object names
+ if (api.layout.Dimension(dims[i])) {
+ objectNames.push(dims[i].dimension);
+ }
+ }
+
+ // at least one period
+ if (!Ext.Array.contains(objectNames, dimConf.period.objectName)) {
+ alert('At least one period must be specified as series, category or filter');
+ return;
+ }
+
+ // favorite
+ if (config.id) {
+ layout.id = config.id;
+ }
+
+ if (config.name) {
+ layout.name = config.name;
+ }
+
+ // analytical2layout
+ config = analytical2layout(config);
+
+ // layout
+ layout.type = Ext.isString(config.type) ? config.type.toLowerCase() : conf.finals.chart.column;
+
+ layout.columns = config.columns;
+ layout.rows = config.rows;
+ layout.filters = config.filters;
+
+ // properties
+ layout.showTrendLine = Ext.isBoolean(config.regression) ? config.regression : (Ext.isBoolean(config.showTrendLine) ? config.showTrendLine : false);
+ layout.showValues = Ext.isBoolean(config.showData) ? config.showData : (Ext.isBoolean(config.showValues) ? config.showValues : true);
+
+ layout.hideLegend = Ext.isBoolean(config.hideLegend) ? config.hideLegend : false;
+ layout.hideTitle = Ext.isBoolean(config.hideTitle) ? config.hideTitle : false;
+
+ layout.targetLineValue = Ext.isNumber(config.targetLineValue) ? config.targetLineValue : null;
+ layout.targetLineTitle = Ext.isString(config.targetLineLabel) && !Ext.isEmpty(config.targetLineLabel) ? config.targetLineLabel :
+ (Ext.isString(config.targetLineTitle) && !Ext.isEmpty(config.targetLineTitle) ? config.targetLineTitle : null);
+ layout.baseLineValue = Ext.isNumber(config.baseLineValue) ? config.baseLineValue : null;
+ layout.baseLineTitle = Ext.isString(config.baseLineLabel) && !Ext.isEmpty(config.baseLineLabel) ? config.baseLineLabel :
+ (Ext.isString(config.baseLineTitle) && !Ext.isEmpty(config.baseLineTitle) ? config.baseLineTitle : null);
+
+ layout.title = Ext.isString(config.title) && !Ext.isEmpty(config.title) ? config.title : null;
+ layout.domainAxisTitle = Ext.isString(config.domainAxisLabel) && !Ext.isEmpty(config.domainAxisLabel) ? config.domainAxisLabel :
+ (Ext.isString(config.domainAxisTitle) && !Ext.isEmpty(config.domainAxisTitle) ? config.domainAxisTitle : null);
+ layout.rangeAxisTitle = Ext.isString(config.rangeAxisLabel) && !Ext.isEmpty(config.rangeAxisLabel) ? config.rangeAxisLabel :
+ (Ext.isString(config.rangeAxisTitle) && !Ext.isEmpty(config.rangeAxisTitle) ? config.rangeAxisTitle : null);
+
+ layout.parentGraphMap = Ext.isObject(config.parentGraphMap) ? config.parentGraphMap : null;
+
+ if (!validateSpecialCases()) {
+ return;
+ }
+
+ return layout;
+ }();
+ };
+
+ api.response = {};
+
+ api.response.Header = function(config) {
+ var config = Ext.clone(config);
+
+ // name: string
+
+ // meta: boolean
+
+ return function() {
+ if (!Ext.isObject(config)) {
+ console.log('Header: config is not an object: ' + config);
+ return;
+ }
+
+ if (!Ext.isString(config.name)) {
+ console.log('Header: name is not a string: ' + config);
+ return;
+ }
+
+ if (!Ext.isBoolean(config.meta)) {
+ console.log('Header: meta is not boolean: ' + config);
+ return;
+ }
+
+ return config;
+ }();
+ };
+
+ api.response.Response = function(config) {
+ var config = Ext.clone(config);
+
+ // headers: [Header]
+
+ return function() {
+ if (!(config && Ext.isObject(config))) {
+ console.log('Response: config is not an object');
+ return;
+ }
+
+ if (!(config.headers && Ext.isArray(config.headers))) {
+ console.log('Response: headers is not an array');
+ return;
+ }
+
+ for (var i = 0, header; i < config.headers.length; i++) {
+ config.headers[i] = api.response.Header(config.headers[i]);
+ }
+
+ config.headers = Ext.Array.clean(config.headers);
+
+ if (!config.headers.length) {
+ console.log('Response: no valid headers');
+ return;
+ }
+
+ if (!(Ext.isArray(config.rows) && config.rows.length > 0)) {
+ alert('No values found');
+ return;
+ }
+
+ if (config.headers.length !== config.rows[0].length) {
+ console.log('Response: headers.length !== rows[0].length');
+ }
+
+ return config;
+ }();
+ };
+ }());
+
+ // support
+ (function() {
+
+ // prototype
+ support.prototype = {};
+
+ // array
+ support.prototype.array = {};
+
+ support.prototype.array.getLength = function(array, suppressWarning) {
+ if (!Ext.isArray(array)) {
+ if (!suppressWarning) {
+ console.log('support.prototype.array.getLength: not an array');
+ }
+
+ return null;
+ }
+
+ return array.length;
+ };
+
+ support.prototype.array.sort = function(array, direction, key) {
+ // accepts [number], [string], [{prop: number}], [{prop: string}]
+
+ if (!support.prototype.array.getLength(array)) {
+ return;
+ }
+
+ key = key || 'name';
+
+ array.sort( function(a, b) {
+
+ // if object, get the property values
+ if (Ext.isObject(a) && Ext.isObject(b) && key) {
+ a = a[key];
+ b = b[key];
+ }
+
+ // string
+ if (Ext.isString(a) && Ext.isString(b)) {
+ a = a.toLowerCase();
+ b = b.toLowerCase();
+
+ if (direction === 'DESC') {
+ return a < b ? 1 : (a > b ? -1 : 0);
+ }
+ else {
+ return a < b ? -1 : (a > b ? 1 : 0);
+ }
+ }
+
+ // number
+ else if (Ext.isNumber(a) && Ext.isNumber(b)) {
+ return direction === 'DESC' ? b - a : a - b;
+ }
+
+ return 0;
+ });
+
+ return array;
+ };
+
+ // object
+ support.prototype.object = {};
+
+ support.prototype.object.getLength = function(object, suppressWarning) {
+ if (!Ext.isObject(object)) {
+ if (!suppressWarning) {
+ console.log('support.prototype.object.getLength: not an object');
+ }
+
+ return null;
+ }
+
+ var size = 0;
+
+ for (var key in object) {
+ if (object.hasOwnProperty(key)) {
+ size++;
+ }
+ }
+
+ return size;
+ };
+
+ support.prototype.object.hasObject = function(object, property, value) {
+ if (!support.prototype.object.getLength(object)) {
+ return null;
+ }
+
+ for (var key in object) {
+ var record = object[key];
+
+ if (object.hasOwnProperty(key) && record[property] === value) {
+ return true;
+ }
+ }
+
+ return null;
+ };
+
+ // str
+ support.prototype.str = {};
+
+ support.prototype.str.replaceAll = function(str, find, replace) {
+ return str.replace(new RegExp(find, 'g'), replace);
+ };
+ }());
+
+ // service
+ (function() {
+
+ // layout
+ service.layout = {};
+
+ service.layout.cleanDimensionArray = function(dimensionArray) {
+ if (!support.prototype.array.getLength(dimensionArray)) {
+ return null;
+ }
+
+ var array = [];
+
+ for (var i = 0; i < dimensionArray.length; i++) {
+ array.push(api.layout.Dimension(dimensionArray[i]));
+ }
+
+ array = Ext.Array.clean(array);
+
+ return array.length ? array : null;
+ };
+
+ service.layout.sortDimensionArray = function(dimensionArray, key) {
+ if (!support.prototype.array.getLength(dimensionArray, true)) {
+ return null;
+ }
+
+ // Clean dimension array
+ dimensionArray = service.layout.cleanDimensionArray(dimensionArray);
+
+ if (!dimensionArray) {
+ console.log('service.layout.sortDimensionArray: no valid dimensions');
+ return null;
+ }
+
+ key = key || 'dimensionName';
+
+ // Dimension order
+ Ext.Array.sort(dimensionArray, function(a,b) {
+ if (a[key] < b[key]) {
+ return -1;
+ }
+ if (a[key] > b[key]) {
+ return 1;
+ }
+ return 0;
+ });
+
+ // Sort object items, ids
+ for (var i = 0, items; i < dimensionArray.length; i++) {
+ support.prototype.array.sort(dimensionArray[i].items, 'ASC', 'id');
+
+ if (support.prototype.array.getLength(dimensionArray[i].ids)) {
+ support.prototype.array.sort(dimensionArray[i].ids);
+ }
+ }
+
+ return dimensionArray;
+ };
+
+ service.layout.getObjectNameDimensionMapFromDimensionArray = function(dimensionArray) {
+ var map = {};
+
+ if (!support.prototype.array.getLength(dimensionArray)) {
+ return null;
+ }
+
+ for (var i = 0, dimension; i < dimensionArray.length; i++) {
+ dimension = api.layout.Dimension(dimensionArray[i]);
+
+ if (dimension) {
+ map[dimension.dimension] = dimension;
+ }
+ }
+
+ return support.prototype.object.getLength(map) ? map : null;
+ };
+
+ service.layout.getObjectNameDimensionItemsMapFromDimensionArray = function(dimensionArray) {
+ var map = {};
+
+ if (!support.prototype.array.getLength(dimensionArray)) {
+ return null;
+ }
+
+ for (var i = 0, dimension; i < dimensionArray.length; i++) {
+ dimension = api.layout.Dimension(dimensionArray[i]);
+
+ if (dimension) {
+ map[dimension.dimension] = dimension.items;
+ }
+ }
+
+ return support.prototype.object.getLength(map) ? map : null;
+ };
+
+ service.layout.getExtendedLayout = function(layout) {
+ var layout = Ext.clone(layout),
+ xLayout = {
+ columns: [],
+ rows: [],
+ filters: [],
+
+ columnObjectNames: [],
+ columnDimensionNames: [],
+ columnItems: [],
+ columnIds: [],
+ rowObjectNames: [],
+ rowDimensionNames: [],
+ rowItems: [],
+ rowIds: [],
+
+ // Axis
+ axisDimensions: [],
+ axisObjectNames: [],
+ axisDimensionNames: [],
+
+ // For param string
+ sortedAxisDimensionNames: [],
+
+ // Filter
+ filterDimensions: [],
+ filterObjectNames: [],
+ filterDimensionNames: [],
+ filterItems: [],
+ filterIds: [],
+
+ // For param string
+ sortedFilterDimensions: [],
+
+ // All
+ dimensions: [],
+ objectNames: [],
+ dimensionNames: [],
+
+ // Object name maps
+ objectNameDimensionsMap: {},
+ objectNameItemsMap: {},
+ objectNameIdsMap: {},
+
+ // Dimension name maps
+ dimensionNameDimensionsMap: {},
+ dimensionNameItemsMap: {},
+ dimensionNameIdsMap: {},
+
+ // For param string
+ dimensionNameSortedIdsMap: {}
+ };
+
+ Ext.applyIf(xLayout, layout);
+
+ // Columns, rows, filters
+ if (layout.columns) {
+ for (var i = 0, dim, items, xDim; i < layout.columns.length; i++) {
+ dim = layout.columns[i];
+ items = dim.items;
+ xDim = {};
+
+ xDim.dimension = dim.dimension;
+ xDim.objectName = dim.dimension;
+ xDim.dimensionName = dimConf.objectNameMap[dim.dimension].dimensionName;
+
+ if (items) {
+ xDim.items = items;
+ xDim.ids = [];
+
+ for (var j = 0; j < items.length; j++) {
+ xDim.ids.push(items[j].id);
+ }
+ }
+
+ xLayout.columns.push(xDim);
+
+ xLayout.columnObjectNames.push(xDim.objectName);
+ xLayout.columnDimensionNames.push(xDim.dimensionName);
+ xLayout.columnItems = xLayout.columnItems.concat(xDim.items);
+ xLayout.columnIds = xLayout.columnIds.concat(xDim.ids);
+
+ xLayout.axisDimensions.push(xDim);
+ xLayout.axisObjectNames.push(xDim.objectName);
+ xLayout.axisDimensionNames.push(dimConf.objectNameMap[xDim.objectName].dimensionName);
+
+ xLayout.objectNameDimensionsMap[xDim.objectName] = xDim;
+ xLayout.objectNameItemsMap[xDim.objectName] = xDim.items;
+ xLayout.objectNameIdsMap[xDim.objectName] = xDim.ids;
+ }
+ }
+
+ if (layout.rows) {
+ for (var i = 0, dim, items, xDim; i < layout.rows.length; i++) {
+ dim = layout.rows[i];
+ items = dim.items;
+ xDim = {};
+
+ xDim.dimension = dim.dimension;
+ xDim.objectName = dim.dimension;
+ xDim.dimensionName = dimConf.objectNameMap[dim.dimension].dimensionName;
+
+ if (items) {
+ xDim.items = items;
+ xDim.ids = [];
+
+ for (var j = 0; j < items.length; j++) {
+ xDim.ids.push(items[j].id);
+ }
+ }
+
+ xLayout.rows.push(xDim);
+
+ xLayout.rowObjectNames.push(xDim.objectName);
+ xLayout.rowDimensionNames.push(xDim.dimensionName);
+ xLayout.rowItems = xLayout.rowItems.concat(xDim.items);
+ xLayout.rowIds = xLayout.rowIds.concat(xDim.ids);
+
+ xLayout.axisDimensions.push(xDim);
+ xLayout.axisObjectNames.push(xDim.objectName);
+ xLayout.axisDimensionNames.push(dimConf.objectNameMap[xDim.objectName].dimensionName);
+
+ xLayout.objectNameDimensionsMap[xDim.objectName] = xDim;
+ xLayout.objectNameItemsMap[xDim.objectName] = xDim.items;
+ xLayout.objectNameIdsMap[xDim.objectName] = xDim.ids;
+ }
+ }
+
+ if (layout.filters) {
+ for (var i = 0, dim, items, xDim; i < layout.filters.length; i++) {
+ dim = layout.filters[i];
+ items = dim.items;
+ xDim = {};
+
+ xDim.dimension = dim.dimension;
+ xDim.objectName = dim.dimension;
+ xDim.dimensionName = dimConf.objectNameMap[dim.dimension].dimensionName;
+
+ if (items) {
+ xDim.items = items;
+ xDim.ids = [];
+
+ for (var j = 0; j < items.length; j++) {
+ xDim.ids.push(items[j].id);
+ }
+ }
+
+ xLayout.filters.push(xDim);
+
+ xLayout.filterDimensions.push(xDim);
+ xLayout.filterObjectNames.push(xDim.objectName);
+ xLayout.filterDimensionNames.push(dimConf.objectNameMap[xDim.objectName].dimensionName);
+ xLayout.filterItems = xLayout.filterItems.concat(xDim.items);
+ xLayout.filterIds = xLayout.filterIds.concat(xDim.ids);
+
+ xLayout.objectNameDimensionsMap[xDim.objectName] = xDim;
+ xLayout.objectNameItemsMap[xDim.objectName] = xDim.items;
+ xLayout.objectNameIdsMap[xDim.objectName] = xDim.ids;
+ }
+ }
+
+ // Unique dimension names
+ xLayout.axisDimensionNames = Ext.Array.unique(xLayout.axisDimensionNames);
+ xLayout.filterDimensionNames = Ext.Array.unique(xLayout.filterDimensionNames);
+
+ xLayout.columnDimensionNames = Ext.Array.unique(xLayout.columnDimensionNames);
+ xLayout.rowDimensionNames = Ext.Array.unique(xLayout.rowDimensionNames);
+ xLayout.filterDimensionNames = Ext.Array.unique(xLayout.filterDimensionNames);
+
+ // For param string
+ xLayout.sortedAxisDimensionNames = Ext.clone(xLayout.axisDimensionNames).sort();
+ xLayout.sortedFilterDimensions = service.layout.sortDimensionArray(Ext.clone(xLayout.filterDimensions));
+
+ // All
+ xLayout.dimensions = [].concat(xLayout.axisDimensions, xLayout.filterDimensions);
+ xLayout.objectNames = [].concat(xLayout.axisObjectNames, xLayout.filterObjectNames);
+ xLayout.dimensionNames = [].concat(xLayout.axisDimensionNames, xLayout.filterDimensionNames);
+
+ // Dimension name maps
+ for (var i = 0, dimName; i < xLayout.dimensionNames.length; i++) {
+ dimName = xLayout.dimensionNames[i];
+
+ xLayout.dimensionNameDimensionsMap[dimName] = [];
+ xLayout.dimensionNameItemsMap[dimName] = [];
+ xLayout.dimensionNameIdsMap[dimName] = [];
+ }
+
+ for (var i = 0, xDim; i < xLayout.dimensions.length; i++) {
+ xDim = xLayout.dimensions[i];
+
+ xLayout.dimensionNameDimensionsMap[xDim.dimensionName].push(xDim);
+ xLayout.dimensionNameItemsMap[xDim.dimensionName] = xLayout.dimensionNameItemsMap[xDim.dimensionName].concat(xDim.items);
+ xLayout.dimensionNameIdsMap[xDim.dimensionName] = xLayout.dimensionNameIdsMap[xDim.dimensionName].concat(xDim.ids);
+ }
+
+ // For param string
+ for (var key in xLayout.dimensionNameIdsMap) {
+ if (xLayout.dimensionNameIdsMap.hasOwnProperty(key)) {
+ xLayout.dimensionNameSortedIdsMap[key] = Ext.clone(xLayout.dimensionNameIdsMap[key]).sort();
+ }
+ }
+
+ return xLayout;
+ };
+
+ service.layout.getSyncronizedXLayout = function(xLayout, response) {
+ var dimensions = Ext.Array.clean([].concat(xLayout.columns || [], xLayout.rows || [], xLayout.filters || [])),
+ xOuDimension = xLayout.objectNameDimensionsMap[dimConf.organisationUnit.objectName],
+ isUserOrgunit = xOuDimension && Ext.Array.contains(xOuDimension.ids, 'USER_ORGUNIT'),
+ isUserOrgunitChildren = xOuDimension && Ext.Array.contains(xOuDimension.ids, 'USER_ORGUNIT_CHILDREN'),
+ isUserOrgunitGrandChildren = xOuDimension && Ext.Array.contains(xOuDimension.ids, 'USER_ORGUNIT_GRANDCHILDREN'),
+ isLevel = function() {
+ if (xOuDimension && Ext.isArray(xOuDimension.ids)) {
+ for (var i = 0; i < xOuDimension.ids.length; i++) {
+ if (xOuDimension.ids[i].substr(0,5) === 'LEVEL') {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }(),
+ isGroup = function() {
+ if (xOuDimension && Ext.isArray(xOuDimension.ids)) {
+ for (var i = 0; i < xOuDimension.ids.length; i++) {
+ if (xOuDimension.ids[i].substr(0,8) === 'OU_GROUP') {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }(),
+ ou = dimConf.organisationUnit.objectName,
+ layout;
+
+ // Set items from init/metaData/xLayout
+ for (var i = 0, dim, metaDataDim, items; i < dimensions.length; i++) {
+ dim = dimensions[i];
+ dim.items = [];
+ metaDataDim = response.metaData[dim.objectName];
+
+ // If ou and children
+ if (dim.dimensionName === ou) {
+ if (isUserOrgunit || isUserOrgunitChildren || isUserOrgunitGrandChildren) {
+ var userOu,
+ userOuc,
+ userOugc;
+
+ if (isUserOrgunit) {
+ userOu = [{
+ id: init.user.ou,
+ name: response.metaData.names[init.user.ou]
+ }];
+ }
+ if (isUserOrgunitChildren) {
+ userOuc = [];
+
+ for (var j = 0; j < init.user.ouc.length; j++) {
+ userOuc.push({
+ id: init.user.ouc[j],
+ name: response.metaData.names[init.user.ouc[j]]
+ });
+ }
+
+ support.prototype.array.sort(userOuc);
+ }
+ if (isUserOrgunitGrandChildren) {
+ var userOuOuc = [].concat(init.user.ou, init.user.ouc),
+ responseOu = response.metaData[ou];
+
+ userOugc = [];
+
+ for (var j = 0, id; j < responseOu.length; j++) {
+ id = responseOu[j];
+
+ if (!Ext.Array.contains(userOuOuc, id)) {
+ userOugc.push({
+ id: id,
+ name: response.metaData.names[id]
+ });
+ }
+ }
+
+ support.prototype.array.sort(userOugc);
+ }
+
+ dim.items = [].concat(userOu || [], userOuc || [], userOugc || []);
+ }
+ else if (isLevel || isGroup) {
+ for (var j = 0, responseOu = response.metaData[ou], id; j < responseOu.length; j++) {
+ id = responseOu[j];
+
+ dim.items.push({
+ id: id,
+ name: response.metaData.names[id]
+ });
+ }
+
+ support.prototype.array.sort(dim.items);
+ }
+ else {
+ dim.items = Ext.clone(xLayout.dimensionNameItemsMap[dim.dimensionName]);
+ }
+ }
+ else {
+ // Items: get ids from metadata -> items
+ if (Ext.isArray(metaDataDim) && metaDataDim.length) {
+ var ids = Ext.clone(response.metaData[dim.dimensionName]);
+ for (var j = 0; j < ids.length; j++) {
+ dim.items.push({
+ id: ids[j],
+ name: response.metaData.names[ids[j]]
+ });
+ }
+ }
+ // Items: get items from xLayout
+ else {
+ dim.items = Ext.clone(xLayout.objectNameItemsMap[dim.objectName]);
+ }
+ }
+ }
+
+ // Re-layout
+ layout = api.layout.Layout(xLayout);
+
+ if (layout) {
+ dimensions = Ext.Array.clean([].concat(layout.columns || [], layout.rows || [], layout.filters || []));
+
+ for (var i = 0, idNameMap = response.metaData.names, dimItems; i < dimensions.length; i++) {
+ dimItems = dimensions[i].items;
+
+ if (Ext.isArray(dimItems) && dimItems.length) {
+ for (var j = 0, item; j < dimItems.length; j++) {
+ item = dimItems[j];
+
+ if (Ext.isObject(item) && Ext.isString(idNameMap[item.id]) && !Ext.isString(item.name)) {
+ item.name = idNameMap[item.id] || '';
+ }
+ }
+ }
+ }
+
+ return service.layout.getExtendedLayout(layout);
+ }
+
+ return null;
+ };
+
+ service.layout.layout2plugin = function(layout) {
+ var layout = Ext.clone(layout),
+ dimensions = Ext.Array.clean([].concat(layout.columns || [], layout.rows || [], layout.filters || []));
+
+ if (Ext.isString(layout.id)) {
+ return {id: layout.id};
+ }
+
+ for (var i = 0, dimension, item; i < dimensions.length; i++) {
+ dimension = dimensions[i];
+
+ delete dimension.id;
+ delete dimension.ids;
+ delete dimension.type;
+ delete dimension.dimensionName;
+ delete dimension.objectName;
+
+ for (var j = 0, item; j < dimension.items.length; j++) {
+ item = dimension.items[j];
+
+ delete item.name;
+ delete item.code;
+ delete item.created;
+ delete item.lastUpdated;
+ }
+ }
+
+ if (!layout.showTrendLine) {
+ delete layout.showTrendLine;
+ }
+
+ if (!layout.targetLineValue) {
+ delete layout.targetLineValue;
+ }
+
+ if (!layout.targetLineTitle) {
+ delete layout.targetLineTitle;
+ }
+
+ if (!layout.baseLineValue) {
+ delete layout.baseLineValue;
+ }
+
+ if (!layout.baseLineTitle) {
+ delete layout.baseLineTitle;
+ }
+
+ if (layout.showValues) {
+ delete layout.showValues;
+ }
+
+ if (!layout.hideLegend) {
+ delete layout.hideLegend;
+ }
+
+ if (!layout.hideTitle) {
+ delete layout.hideTitle;
+ }
+
+ if (!layout.title) {
+ delete layout.title;
+ }
+
+ if (!layout.domainAxisTitle) {
+ delete layout.domainAxisTitle;
+ }
+
+ if (!layout.rangeAxisTitle) {
+ delete layout.rangeAxisTitle;
+ }
+
+ if (!layout.sorting) {
+ delete layout.sorting;
+ }
+
+ delete layout.parentGraphMap;
+ delete layout.reportingPeriod;
+ delete layout.organisationUnit;
+ delete layout.parentOrganisationUnit;
+ delete layout.regression;
+ delete layout.cumulative;
+ delete layout.sortOrder;
+ delete layout.topLimit;
+
+ return layout;
+ };
+
+ // response
+ service.response = {};
+
+ service.response.getExtendedResponse = function(xLayout, response) {
+ var ids = [];
+
+ response.nameHeaderMap = {};
+ response.idValueMap = {};
+
+ // extend headers
+ (function() {
+
+ // extend headers: index, ids, size
+ for (var i = 0, header; i < response.headers.length; i++) {
+ header = response.headers[i];
+
+ // index
+ header.index = i;
+
+ if (header.meta) {
+
+ // ids
+ header.ids = Ext.clone(xLayout.dimensionNameIdsMap[header.name]) || [];
+
+ // size
+ header.size = header.ids.length;
+
+ // collect ids, used by extendMetaData
+ ids = ids.concat(header.ids);
+ }
+ }
+
+ // nameHeaderMap (headerName: header)
+ for (var i = 0, header; i < response.headers.length; i++) {
+ header = response.headers[i];
+
+ response.nameHeaderMap[header.name] = header;
+ }
+ }());
+
+ // extend metadata
+ (function() {
+ for (var i = 0, id, splitId ; i < ids.length; i++) {
+ id = ids[i];
+
+ if (id.indexOf('-') !== -1) {
+ splitId = id.split('-');
+ response.metaData.names[id] = response.metaData.names[splitId[0]] + ' ' + response.metaData.names[splitId[1]];
+ }
+ }
+ }());
+
+ // create value id map
+ (function() {
+ var valueHeaderIndex = response.nameHeaderMap[conf.finals.dimension.value.value].index,
+ coHeader = response.nameHeaderMap[conf.finals.dimension.category.dimensionName],
+ dx = dimConf.data.dimensionName,
+ co = dimConf.category.dimensionName,
+ axisDimensionNames = xLayout.axisDimensionNames,
+ idIndexOrder = [];
+
+ // idIndexOrder
+ for (var i = 0; i < axisDimensionNames.length; i++) {
+ idIndexOrder.push(response.nameHeaderMap[axisDimensionNames[i]].index);
+
+ // If co exists in response and is not added in layout, add co after dx
+ if (coHeader && !Ext.Array.contains(axisDimensionNames, co) && axisDimensionNames[i] === dx) {
+ idIndexOrder.push(coHeader.index);
+ }
+ }
+
+ // idValueMap
+ for (var i = 0, row, id; i < response.rows.length; i++) {
+ row = response.rows[i];
+ id = '';
+
+ for (var j = 0; j < idIndexOrder.length; j++) {
+ id += row[idIndexOrder[j]];
+ }
+
+ response.idValueMap[id] = row[valueHeaderIndex];
+ }
+ }());
+
+ return response;
+
+ //response.nameHeaderMap = {};
+ //response.idValueMap = {};
+ //ids = [];
+
+ //var extendHeaders = function() {
+ //// Extend headers: index, items, size
+ //for (var i = 0, header; i < response.headers.length; i++) {
+ //header = response.headers[i];
+
+ //// Index
+ //header.index = i;
+
+ //if (header.meta) {
+
+ //// Items
+ //header.items = Ext.clone(xLayout.dimensionNameIdsMap[header.name]) || [];
+
+ //// Size
+ //header.size = header.items.length;
+
+ //// Collect ids, used by extendMetaData
+ //ids = ids.concat(header.items);
+ //}
+ //}
+
+ //// nameHeaderMap (headerName: header)
+ //for (var i = 0, header; i < response.headers.length; i++) {
+ //header = response.headers[i];
+
+ //response.nameHeaderMap[header.name] = header;
+ //}
+ //}();
+
+ //var extendMetaData = function() {
+ //for (var i = 0, id, splitId ; i < ids.length; i++) {
+ //id = ids[i];
+
+ //if (id.indexOf('-') !== -1) {
+ //splitId = id.split('-');
+ //response.metaData.names[id] = response.metaData.names[splitId[0]] + ' ' + response.metaData.names[splitId[1]];
+ //}
+ //}
+ //}();
+
+ //var createValueIdMap = function() {
+ //var valueHeaderIndex = response.nameHeaderMap[conf.finals.dimension.value.value].index,
+ //coHeader = response.nameHeaderMap[conf.finals.dimension.category.dimensionName],
+ //axisDimensionNames = xLayout.axisDimensionNames,
+ //idIndexOrder = [];
+
+ //// idIndexOrder
+ //for (var i = 0; i < axisDimensionNames.length; i++) {
+ //idIndexOrder.push(response.nameHeaderMap[axisDimensionNames[i]].index);
+
+ //// If co exists in response, add co after dx
+ //if (coHeader && axisDimensionNames[i] === conf.finals.dimension.data.dimensionName) {
+ //idIndexOrder.push(coHeader.index);
+ //}
+ //}
+
+ //// idValueMap
+ //for (var i = 0, row, id; i < response.rows.length; i++) {
+ //row = response.rows[i];
+ //id = '';
+
+ //for (var j = 0; j < idIndexOrder.length; j++) {
+ //id += row[idIndexOrder[j]];
+ //}
+
+ //response.idValueMap[id] = parseFloat(row[valueHeaderIndex]);
+ //}
+ //}();
+
+ //var getMinMax = function() {
+ //var valueIndex = response.nameHeaderMap.value.index,
+ //values = [];
+
+ //for (var i = 0; i < response.rows.length; i++) {
+ //values.push(parseFloat(response.rows[i][valueIndex]));
+ //}
+
+ //response.min = Ext.Array.min(values);
+ //response.max = Ext.Array.max(values);
+ //}();
+
+ //return response;
+ };
+
+ }());
+
+ // web
+ (function() {
+
+ // mask
+ web.mask = {};
+
+ web.mask.show = function(component, message) {
+ if (!Ext.isObject(component)) {
+ console.log('support.gui.mask.show: component not an object');
+ return null;
+ }
+
+ message = message || 'Loading..';
+
+ if (component.mask) {
+ component.mask.destroy();
+ component.mask = null;
+ }
+
+ component.mask = new Ext.create('Ext.LoadMask', component, {
+ shadow: false,
+ message: message,
+ style: 'box-shadow:0',
+ bodyStyle: 'box-shadow:0'
+ });
+
+ component.mask.show();
+ };
+
+ web.mask.hide = function(component) {
+ if (!Ext.isObject(component)) {
+ console.log('support.gui.mask.hide: component not an object');
+ return null;
+ }
+
+ if (component.mask) {
+ component.mask.destroy();
+ component.mask = null;
+ }
+ };
+
+ // message
+ web.message = {};
+
+ web.message.alert = function(message) {
+ console.log(message);
+ };
+
+ // analytics
+ web.analytics = {};
+
+ web.analytics.getParamString = function(xLayout, isSorted) {
+ var axisDimensionNames = isSorted ? xLayout.sortedAxisDimensionNames : xLayout.axisDimensionNames,
+ filterDimensions = isSorted ? xLayout.sortedFilterDimensions : xLayout.filterDimensions,
+ dimensionNameIdsMap = isSorted ? xLayout.dimensionNameSortedIdsMap : xLayout.dimensionNameIdsMap,
+ paramString = '?',
+ addCategoryDimension = false,
+ map = xLayout.dimensionNameItemsMap,
+ dx = dimConf.indicator.dimensionName;
+
+ for (var i = 0, dimName, items; i < axisDimensionNames.length; i++) {
+ dimName = axisDimensionNames[i];
+
+ paramString += 'dimension=' + dimName;
+
+ items = Ext.clone(dimensionNameIdsMap[dimName]);
+
+ if (dimName === dx) {
+ for (var j = 0, index; j < items.length; j++) {
+ index = items[j].indexOf('-');
+
+ if (index > 0) {
+ addCategoryDimension = true;
+ items[j] = items[j].substr(0, index);
+ }
+ }
+
+ items = Ext.Array.unique(items);
+ }
+
+ if (dimName !== dimConf.category.dimensionName) {
+ paramString += ':' + items.join(';');
+ }
+
+ if (i < (axisDimensionNames.length - 1)) {
+ paramString += '&';
+ }
+ }
+
+ if (addCategoryDimension) {
+ paramString += '&dimension=' + conf.finals.dimension.category.dimensionName;
+ }
+
+ if (Ext.isArray(filterDimensions) && filterDimensions.length) {
+ for (var i = 0, dim; i < filterDimensions.length; i++) {
+ dim = filterDimensions[i];
+
+ paramString += '&filter=' + dim.dimensionName + ':' + dim.ids.join(';');
+ }
+ }
+
+ return paramString;
+ };
+
+ web.analytics.validateUrl = function(url) {
+ var msg;
+
+ if (Ext.isIE) {
+ msg = 'Too many items selected (url has ' + url.length + ' characters). Internet Explorer accepts maximum 2048 characters.';
+ }
+ else {
+ var len = url.length > 8000 ? '8000' : (url.length > 4000 ? '4000' : '2000');
+ msg = 'Too many items selected (url has ' + url.length + ' characters). Please reduce to less than ' + len + ' characters.';
+ }
+
+ msg += '\n\n' + 'Hint: A good way to reduce the number of items is to use relative periods and level/group organisation unit selection modes.';
+
+ alert(msg);
+ };
+
+ // chart
+ web.chart = {};
+
+ web.chart.createChart = function(ns) {
+ var xResponse = ns.app.xResponse,
+ xLayout = ns.app.xLayout,
+
+ getSyncronizedXLayout,
+ getExtendedResponse,
+ validateUrl,
+
+ getDefaultStore,
+ getDefaultNumericAxis,
+ getDefaultCategoryAxis,
+ getDefaultSeriesTitle,
+ getDefaultSeries,
+ getDefaultTrendLines,
+ getDefaultTargetLine,
+ getDefaultBaseLine,
+ getDefaultTips,
+ setDefaultTheme,
+ getDefaultLegend,
+ getDefaultChartTitle,
+ getDefaultChartSizeHandler,
+ getDefaultChartTitlePositionHandler,
+ getDefaultChart,
+
+ generator = {};
+
+ getDefaultStore = function() {
+ var pe = conf.finals.dimension.period.dimensionName,
+ columnDimensionName = xLayout.columns[0].dimensionName,
+ rowDimensionName = xLayout.rows[0].dimensionName,
+
+ data = [],
+ columnIds = xLayout.columnIds,
+ rowIds = xLayout.rowIds,
+ trendLineFields = [],
+ targetLineFields = [],
+ baseLineFields = [],
+ store;
+
+ // Data
+ for (var i = 0, obj, category; i < rowIds.length; i++) {
+ obj = {};
+ category = rowIds[i];
+
+ obj[conf.finals.data.domain] = xResponse.metaData.names[category];
+ for (var j = 0, id; j < columnIds.length; j++) {
+ id = support.prototype.str.replaceAll(columnIds[j], '-', '') + support.prototype.str.replaceAll(rowIds[i], '-', '');
+ //id = columnIds[j].replace('-', '') + rowIds[i].replace('-', '');
+
+ obj[columnIds[j]] = parseFloat(xResponse.idValueMap[id]);
+ }
+
+ data.push(obj);
+ }
+
+ // Trend lines
+ if (xLayout.showTrendLine) {
+ for (var i = 0, regression, key; i < columnIds.length; i++) {
+ regression = new SimpleRegression();
+ key = conf.finals.data.trendLine + columnIds[i];
+
+ for (var j = 0; j < data.length; j++) {
+ regression.addData(j, data[j][columnIds[i]]);
+ }
+
+ for (var j = 0; j < data.length; j++) {
+ data[j][key] = parseFloat(regression.predict(j).toFixed(1));
+ }
+
+ trendLineFields.push(key);
+ xResponse.metaData.names[key] = DV.i18n.trend + ' (' + xResponse.metaData.names[columnIds[i]] + ')';
+ }
+ }
+
+ // Target line
+ if (Ext.isNumber(xLayout.targetLineValue) || Ext.isNumber(parseFloat(xLayout.targetLineValue))) {
+ for (var i = 0; i < data.length; i++) {
+ data[i][conf.finals.data.targetLine] = parseFloat(xLayout.targetLineValue);
+ }
+
+ targetLineFields.push(conf.finals.data.targetLine);
+ }
+
+ // Base line
+ if (Ext.isNumber(xLayout.baseLineValue) || Ext.isNumber(parseFloat(xLayout.baseLineValue))) {
+ for (var i = 0; i < data.length; i++) {
+ data[i][conf.finals.data.baseLine] = parseFloat(xLayout.baseLineValue);
+ }
+
+ baseLineFields.push(conf.finals.data.baseLine);
+ }
+
+ store = Ext.create('Ext.data.Store', {
+ fields: function() {
+ var fields = Ext.clone(columnIds);
+ fields.push(conf.finals.data.domain);
+ fields = fields.concat(trendLineFields, targetLineFields, baseLineFields);
+
+ return fields;
+ }(),
+ data: data
+ });
+
+ store.rangeFields = columnIds;
+ store.domainFields = [conf.finals.data.domain];
+ store.trendLineFields = trendLineFields;
+ store.targetLineFields = targetLineFields;
+ store.baseLineFields = baseLineFields;
+ store.numericFields = [].concat(store.rangeFields, store.trendLineFields, store.targetLineFields, store.baseLineFields);
+
+ store.getMaximum = function() {
+ var maximums = [];
+
+ for (var i = 0; i < store.numericFields.length; i++) {
+ maximums.push(store.max(store.numericFields[i]));
+ }
+
+ return Ext.Array.max(maximums);
+ };
+
+ store.getMinimum = function() {
+ var minimums = [];
+
+ for (var i = 0; i < store.numericFields.length; i++) {
+ minimums.push(store.max(store.numericFields[i]));
+ }
+
+ return Ext.Array.min(minimums);
+ };
+
+ store.getMaximumSum = function() {
+ var sums = [],
+ recordSum = 0;
+
+ store.each(function(record) {
+ recordSum = 0;
+
+ for (var i = 0; i < store.rangeFields.length; i++) {
+ recordSum += record.data[store.rangeFields[i]];
+ }
+
+ sums.push(recordSum);
+ });
+
+ return Ext.Array.max(sums);
+ };
+
+ if (DV.isDebug) {
+ console.log("data", data);
+ console.log("rangeFields", store.rangeFields);
+ console.log("domainFields", store.domainFields);
+ console.log("trendLineFields", store.trendLineFields);
+ console.log("targetLineFields", store.targetLineFields);
+ console.log("baseLineFields", store.baseLineFields);
+ }
+
+ return store;
+ };
+
+ getDefaultNumericAxis = function(store) {
+ var typeConf = conf.finals.chart,
+ minimum = store.getMinimum(),
+ maximum,
+ axis;
+
+ // Set maximum if stacked + extra line
+ if ((xLayout.type === typeConf.stackedcolumn || xLayout.type === typeConf.stackedbar) &&
+ (xLayout.showTrendLine || xLayout.targetLineValue || xLayout.baseLineValue)) {
+ var a = [store.getMaximum(), store.getMaximumSum()];
+ maximum = Math.ceil(Ext.Array.max(a) * 1.1);
+ maximum = Math.floor(maximum / 10) * 10;
+ }
+
+ axis = {
+ type: 'Numeric',
+ position: 'left',
+ fields: store.numericFields,
+ minimum: minimum < 0 ? minimum : 0,
+ label: {
+ renderer: Ext.util.Format.numberRenderer('0,0')
+ },
+ grid: {
+ odd: {
+ opacity: 1,
+ stroke: '#aaa',
+ 'stroke-width': 0.1
+ },
+ even: {
+ opacity: 1,
+ stroke: '#aaa',
+ 'stroke-width': 0.1
+ }
+ }
+ };
+
+ if (maximum) {
+ axis.maximum = maximum;
+ }
+
+ if (xLayout.rangeAxisTitle) {
+ axis.title = xLayout.rangeAxisTitle;
+ }
+
+ return axis;
+ };
+
+ getDefaultCategoryAxis = function(store) {
+ var axis = {
+ type: 'Category',
+ position: 'bottom',
+ fields: store.domainFields,
+ label: {
+ rotate: {
+ degrees: 330
+ }
+ }
+ };
+
+ if (xLayout.domainAxisTitle) {
+ axis.title = xLayout.domainAxisTitle;
+ }
+
+ return axis;
+ };
+
+ getDefaultSeriesTitle = function(store) {
+ var a = [];
+
+ for (var i = 0, id, ids; i < store.rangeFields.length; i++) {
+ id = store.rangeFields[i];
+ a.push(xResponse.metaData.names[id]);
+ }
+
+ return a;
+ };
+
+ getDefaultSeries = function(store) {
+ var main = {
+ type: 'column',
+ axis: 'left',
+ xField: store.domainFields,
+ yField: store.rangeFields,
+ style: {
+ opacity: 0.8,
+ lineWidth: 3
+ },
+ markerConfig: {
+ type: 'circle',
+ radius: 4
+ },
+ tips: getDefaultTips(),
+ title: getDefaultSeriesTitle(store)
+ };
+
+ if (xLayout.showValues) {
+ main.label = {
+ display: 'outside',
+ 'text-anchor': 'middle',
+ field: store.rangeFields,
+ font: conf.chart.style.fontFamily
+ };
+ }
+
+ return main;
+ };
+
+ getDefaultTrendLines = function(store) {
+ var a = [];
+
+ for (var i = 0; i < store.trendLineFields.length; i++) {
+ a.push({
+ type: 'line',
+ axis: 'left',
+ xField: store.domainFields,
+ yField: store.trendLineFields[i],
+ style: {
+ opacity: 0.8,
+ lineWidth: 3,
+ 'stroke-dasharray': 8
+ },
+ markerConfig: {
+ type: 'circle',
+ radius: 0
+ },
+ title: xResponse.metaData.names[store.trendLineFields[i]]
+ });
+ }
+
+ return a;
+ };
+
+ getDefaultTargetLine = function(store) {
+ return {
+ type: 'line',
+ axis: 'left',
+ xField: store.domainFields,
+ yField: store.targetLineFields,
+ style: {
+ opacity: 1,
+ lineWidth: 2,
+ 'stroke-width': 1,
+ stroke: '#041423'
+ },
+ showMarkers: false,
+ title: (Ext.isString(xLayout.targetLineTitle) ? xLayout.targetLineTitle : DV.i18n.target) + ' (' + xLayout.targetLineValue + ')'
+ };
+ };
+
+ getDefaultBaseLine = function(store) {
+ return {
+ type: 'line',
+ axis: 'left',
+ xField: store.domainFields,
+ yField: store.baseLineFields,
+ style: {
+ opacity: 1,
+ lineWidth: 2,
+ 'stroke-width': 1,
+ stroke: '#041423'
+ },
+ showMarkers: false,
+ title: (Ext.isString(xLayout.baseLineTitle) ? xLayout.baseLineTitle : DV.i18n.base) + ' (' + xLayout.baseLineValue + ')'
+ };
+ };
+
+ getDefaultTips = function() {
+ return {
+ trackMouse: true,
+ cls: 'dv-chart-tips',
+ renderer: function(si, item) {
+ this.update('<div style="text-align:center"><div style="font-size:17px; font-weight:bold">' + item.value[1] + '</div><div style="font-size:10px">' + si.data[conf.finals.data.domain] + '</div></div>');
+ }
+ };
+ };
+
+ setDefaultTheme = function(store) {
+ var colors = conf.chart.theme.dv1.slice(0, store.rangeFields.length);
+
+ if (xLayout.targetLineValue || xLayout.baseLineValue) {
+ colors.push('#051a2e');
+ }
+
+ if (xLayout.targetLineValue) {
+ colors.push('#051a2e');
+ }
+
+ if (xLayout.baseLineValue) {
+ colors.push('#051a2e');
+ }
+
+ Ext.chart.theme.dv1 = Ext.extend(Ext.chart.theme.Base, {
+ constructor: function(config) {
+ Ext.chart.theme.Base.prototype.constructor.call(this, Ext.apply({
+ seriesThemes: colors,
+ colors: colors
+ }, config));
+ }
+ });
+ };
+
+ getDefaultLegend = function(store) {
+ var itemLength = 30,
+ charLength = 7,
+ numberOfItems,
+ numberOfChars = 0,
+ str = '',
+ width,
+ isVertical = false,
+ position = 'top',
+ padding = 0;
+
+ if (xLayout.type === conf.finals.chart.pie) {
+ numberOfItems = store.getCount();
+ store.each(function(r) {
+ str += r.data[store.domainFields[0]];
+ });
+ }
+ else {
+ numberOfItems = store.rangeFields.length;
+
+ for (var i = 0, name, ids; i < store.rangeFields.length; i++) {
+ if (store.rangeFields[i].indexOf('-') !== -1) {
+ ids = store.rangeFields[i].split('-');
+ name = xResponse.metaData.names[ids[0]] + ' ' + xResponse.metaData.names[ids[1]];
+ }
+ else {
+ name = xResponse.metaData.names[store.rangeFields[i]];
+ }
+
+ str += name;
+ }
+ }
+
+ numberOfChars = str.length;
+
+ width = (numberOfItems * itemLength) + (numberOfChars * charLength);
+
+ if (width > ns.app.centerRegion.getWidth() - 50) {
+ isVertical = true;
+ position = 'right';
+ }
+
+ if (position === 'right') {
+ padding = 5;
+ }
+
+ return Ext.create('Ext.chart.Legend', {
+ position: position,
+ isVertical: isVertical,
+ labelFont: '13px ' + conf.chart.style.fontFamily,
+ boxStroke: '#ffffff',
+ boxStrokeWidth: 0,
+ padding: padding
+ });
+ };
+
+ getDefaultChartTitle = function(store) {
+ var ids = xLayout.filterIds,
+ a = [],
+ text = '',
+ fontSize;
+
+ if (xLayout.type === conf.finals.chart.pie) {
+ ids = ids.concat(xLayout.columnIds);
+ }
+
+ if (Ext.isArray(ids) && ids.length) {
+ for (var i = 0; i < ids.length; i++) {
+ text += xResponse.metaData.names[ids[i]];
+ text += i < ids.length - 1 ? ', ' : '';
+ }
+ }
+
+ if (xLayout.title) {
+ text = xLayout.title;
+ }
+
+ fontSize = (ns.app.centerRegion.getWidth() / text.length) < 11.6 ? 13 : 18;
+
+ return Ext.create('Ext.draw.Sprite', {
+ type: 'text',
+ text: text,
+ font: 'bold ' + fontSize + 'px ' + conf.chart.style.fontFamily,
+ fill: '#111',
+ height: 20,
+ y: 20
+ });
+ };
+
+ getDefaultChartSizeHandler = function() {
+ return function() {
+ this.animate = false;
+ this.setWidth(ns.app.centerRegion.getWidth() - 15);
+ this.setHeight(ns.app.centerRegion.getHeight() - 40);
+ this.animate = true;
+ };
+ };
+
+ getDefaultChartTitlePositionHandler = function() {
+ return function() {
+ if (this.items) {
+ var title = this.items[0],
+ legend = this.legend,
+ legendCenterX,
+ titleX;
+
+ if (this.legend.position === 'top') {
+ legendCenterX = legend.x + (legend.width / 2);
+ titleX = legendCenterX - (title.el.getWidth() / 2);
+ }
+ else {
+ var legendWidth = legend ? legend.width : 0;
+ titleX = (this.width / 2) - (title.el.getWidth() / 2);
+ }
+
+ title.setAttributes({
+ x: titleX
+ }, true);
+ }
+ };
+ };
+
+ getDefaultChart = function(store, axes, series, theme) {
+ var chart,
+ config = {
+ //renderTo: init.el,
+ store: store,
+ axes: axes,
+ series: series,
+ animate: true,
+ shadow: false,
+ insetPadding: 35,
+ width: ns.app.centerRegion.getWidth() - 15,
+ height: ns.app.centerRegion.getHeight() - 40,
+ theme: theme || 'dv1'
+ };
+
+ // Legend
+ if (!xLayout.hideLegend) {
+ config.legend = getDefaultLegend(store);
+
+ if (config.legend.position === 'right') {
+ config.insetPadding = 40;
+ }
+ }
+
+ // Title
+ if (!xLayout.hideTitle) {
+ config.items = [getDefaultChartTitle(store)];
+ }
+ else {
+ config.insetPadding = 10;
+ }
+
+ chart = Ext.create('Ext.chart.Chart', config);
+
+ chart.setChartSize = getDefaultChartSizeHandler();
+ chart.setTitlePosition = getDefaultChartTitlePositionHandler();
+
+ chart.onViewportResize = function() {
+ chart.setChartSize();
+ chart.redraw();
+ chart.setTitlePosition();
+ };
+
+ chart.on('afterrender', function() {
+ chart.setTitlePosition();
+ });
+
+ return chart;
+ };
+
+ generator.column = function() {
+ var store = getDefaultStore(),
+ numericAxis = getDefaultNumericAxis(store),
+ categoryAxis = getDefaultCategoryAxis(store),
+ axes = [numericAxis, categoryAxis],
+ series = [getDefaultSeries(store)];
+
+ // Options
+ if (xLayout.showTrendLine) {
+ series = getDefaultTrendLines(store).concat(series);
+ }
+
+ if (xLayout.targetLineValue) {
+ series.push(getDefaultTargetLine(store));
+ }
+
+ if (xLayout.baseLineValue) {
+ series.push(getDefaultBaseLine(store));
+ }
+
+ // Theme
+ setDefaultTheme(store);
+
+ return getDefaultChart(store, axes, series);
+ };
+
+ generator.stackedcolumn = function() {
+ var chart = this.column();
+
+ for (var i = 0, item; i < chart.series.items.length; i++) {
+ item = chart.series.items[i];
+
+ if (item.type === conf.finals.chart.column) {
+ item.stacked = true;
+ }
+ }
+
+ return chart;
+ };
+
+ generator.bar = function() {
+ var store = getDefaultStore(),
+ numericAxis = getDefaultNumericAxis(store),
+ categoryAxis = getDefaultCategoryAxis(store),
+ axes,
+ series = getDefaultSeries(store),
+ trendLines,
+ targetLine,
+ baseLine,
+ chart;
+
+ // Axes
+ numericAxis.position = 'bottom';
+ categoryAxis.position = 'left';
+ axes = [numericAxis, categoryAxis];
+
+ // Series
+ series.type = 'bar';
+ series.axis = 'bottom';
+
+ // Options
+ if (xLayout.showValues) {
+ series.label = {
+ display: 'outside',
+ 'text-anchor': 'middle',
+ field: store.rangeFields
+ };
+ }
+
+ series = [series];
+
+ if (xLayout.showTrendLine) {
+ trendLines = getDefaultTrendLines(store);
+
+ for (var i = 0; i < trendLines.length; i++) {
+ trendLines[i].axis = 'bottom';
+ trendLines[i].xField = store.trendLineFields[i];
+ trendLines[i].yField = store.domainFields;
+ }
+
+ series = trendLines.concat(series);
+ }
+
+ if (xLayout.targetLineValue) {
+ targetLine = getDefaultTargetLine(store);
+ targetLine.axis = 'bottom';
+ targetLine.xField = store.targetLineFields;
+ targetLine.yField = store.domainFields;
+
+ series.push(targetLine);
+ }
+
+ if (xLayout.baseLineValue) {
+ baseLine = getDefaultBaseLine(store);
+ baseLine.axis = 'bottom';
+ baseLine.xField = store.baseLineFields;
+ baseLine.yField = store.domainFields;
+
+ series.push(baseLine);
+ }
+
+ // Theme
+ setDefaultTheme(store);
+
+ return getDefaultChart(store, axes, series);
+ };
+
+ generator.stackedbar = function() {
+ var chart = this.bar();
+
+ for (var i = 0, item; i < chart.series.items.length; i++) {
+ item = chart.series.items[i];
+
+ if (item.type === conf.finals.chart.bar) {
+ item.stacked = true;
+ }
+ }
+
+ return chart;
+ };
+
+ generator.line = function() {
+ var store = getDefaultStore(),
+ numericAxis = getDefaultNumericAxis(store),
+ categoryAxis = getDefaultCategoryAxis(store),
+ axes = [numericAxis, categoryAxis],
+ series = [],
+ colors = conf.chart.theme.dv1.slice(0, store.rangeFields.length),
+ seriesTitles = getDefaultSeriesTitle(store);
+
+ // Series
+ for (var i = 0, line; i < store.rangeFields.length; i++) {
+ line = {
+ type: 'line',
+ axis: 'left',
+ xField: store.domainFields,
+ yField: store.rangeFields[i],
+ style: {
+ opacity: 0.8,
+ lineWidth: 3
+ },
+ markerConfig: {
+ type: 'circle',
+ radius: 4
+ },
+ tips: getDefaultTips(),
+ title: seriesTitles[i]
+ };
+
+ //if (xLayout.showValues) {
+ //line.label = {
+ //display: 'over',
+ //field: store.rangeFields[i]
+ //};
+ //}
+
+ series.push(line);
+ }
+
+ // Options, theme colors
+ if (xLayout.showTrendLine) {
+ series = getDefaultTrendLines(store).concat(series);
+
+ colors = colors.concat(colors);
+ }
+
+ if (xLayout.targetLineValue) {
+ series.push(getDefaultTargetLine(store));
+
+ colors.push('#051a2e');
+ }
+
+ if (xLayout.baseLineValue) {
+ series.push(getDefaultBaseLine(store));
+
+ colors.push('#051a2e');
+ }
+
+ // Theme
+ Ext.chart.theme.dv1 = Ext.extend(Ext.chart.theme.Base, {
+ constructor: function(config) {
+ Ext.chart.theme.Base.prototype.constructor.call(this, Ext.apply({
+ seriesThemes: colors,
+ colors: colors
+ }, config));
+ }
+ });
+
+ return getDefaultChart(store, axes, series);
+ };
+
+ generator.area = function() {
+ var store = getDefaultStore(),
+ numericAxis = getDefaultNumericAxis(store),
+ categoryAxis = getDefaultCategoryAxis(store),
+ axes = [numericAxis, categoryAxis],
+ series = getDefaultSeries(store);
+
+ series.type = 'area';
+ series.style.opacity = 0.7;
+ series.style.lineWidth = 0;
+ delete series.label;
+ delete series.tips;
+ series = [series];
+
+ // Options
+ if (xLayout.showTrendLine) {
+ series = getDefaultTrendLines(store).concat(series);
+ }
+
+ if (xLayout.targetLineValue) {
+ series.push(getDefaultTargetLine(store));
+ }
+
+ if (xLayout.baseLineValue) {
+ series.push(getDefaultBaseLine(store));
+ }
+
+ // Theme
+ setDefaultTheme(store);
+
+ return getDefaultChart(store, axes, series);
+ };
+
+ generator.pie = function() {
+ var store = getDefaultStore(),
+ series,
+ colors,
+ chart,
+ label = {
+ field: conf.finals.data.domain
+ };
+
+ // Label
+ if (xLayout.showValues) {
+ label.display = 'middle';
+ label.contrast = true;
+ label.font = '14px ' + conf.chart.style.fontFamily;
+ label.renderer = function(value) {
+ var record = store.getAt(store.findExact(conf.finals.data.domain, value));
+ return record.data[store.rangeFields[0]];
+ };
+ }
+
+ // Series
+ series = [{
+ type: 'pie',
+ field: store.rangeFields[0],
+ donut: 7,
+ showInLegend: true,
+ highlight: {
+ segment: {
+ margin: 5
+ }
+ },
+ label: label,
+ style: {
+ opacity: 0.8,
+ stroke: '#555'
+ },
+ tips: {
+ trackMouse: true,
+ cls: 'dv-chart-tips',
+ renderer: function(item) {
+ this.update('<div style="text-align:center"><div style="font-size:17px; font-weight:bold">' + item.data[store.rangeFields[0]] + '</div><div style="font-size:10px">' + item.data[conf.finals.data.domain] + '</div></div>');
+ }
+ }
+ }];
+
+ // Theme
+ colors = conf.chart.theme.dv1.slice(0, xResponse.nameHeaderMap[xLayout.rowDimensionNames[0]].ids.length);
+
+ Ext.chart.theme.dv1 = Ext.extend(Ext.chart.theme.Base, {
+ constructor: function(config) {
+ Ext.chart.theme.Base.prototype.constructor.call(this, Ext.apply({
+ seriesThemes: colors,
+ colors: colors
+ }, config));
+ }
+ });
+
+ // Chart
+ chart = getDefaultChart(store, null, series);
+ //chart.legend.position = 'right';
+ //chart.legend.isVertical = true;
+ chart.insetPadding = 40;
+ chart.shadow = true;
+
+ return chart;
+ };
+
+ generator.radar = function() {
+ var store = getDefaultStore(),
+ axes = [],
+ series = [],
+ seriesTitles = getDefaultSeriesTitle(store),
+ chart;
+
+ // Axes
+ axes.push({
+ type: 'Radial',
+ position: 'radial',
+ label: {
+ display: true
+ }
+ });
+
+ // Series
+ for (var i = 0, obj; i < store.rangeFields.length; i++) {
+ obj = {
+ showInLegend: true,
+ type: 'radar',
+ xField: store.domainFields,
+ yField: store.rangeFields[i],
+ style: {
+ opacity: 0.5
+ },
+ tips: getDefaultTips(),
+ title: seriesTitles[i]
+ };
+
+ if (xLayout.showValues) {
+ obj.label = {
+ display: 'over',
+ field: store.rangeFields[i]
+ };
+ }
+
+ series.push(obj);
+ }
+
+ chart = getDefaultChart(store, axes, series, 'Category2');
+
+ chart.insetPadding = 40;
+ chart.height = ns.app.centerRegion.getHeight() - 80;
+
+ chart.setChartSize = function() {
+ this.animate = false;
+ this.setWidth(ns.app.centerRegion.getWidth());
+ this.setHeight(ns.app.centerRegion.getHeight() - 80);
+ this.animate = true;
+ };
+
+ return chart;
+ };
+
+ // initialize
+ return generator[xLayout.type]();
+ };
+
+ }());
+
+ // extend init
+ (function() {
+
+ // sort and extend dynamic dimensions
+ if (Ext.isArray(init.dimensions)) {
+ support.prototype.array.sort(init.dimensions);
+
+ for (var i = 0, dim; i < init.dimensions.length; i++) {
+ dim = init.dimensions[i];
+ dim.dimensionName = dim.id;
+ dim.objectName = conf.finals.dimension.dimension.objectName;
+ conf.finals.dimension.objectNameMap[dim.id] = dim;
+ }
+ }
+
+ // sort ouc
+ support.prototype.array.sort(init.user.ouc);
+ }());
+
+ // instance
+ return {
+ conf: conf,
+ api: api,
+ support: support,
+ service: service,
+ web: web,
+ init: init
+ };
+ };
+
// chart tips css
- var css = '.dv-chart-tips { border-radius: 2px; padding: 0px 3px 1px; border: 2px solid #777; background-color: #f1f1f1; } \n';
- css += '.dv-chart-tips .x-tip-body { background-color: #f1f1f1; font-size: 13px; font-weight: normal; color: #444; -webkit-text-stroke: 0; } \n';
+ var css = '.dv-chart-tips { border-radius: 2px; padding: 0px 3px 1px; border: 2px solid #000; background-color: #000; } \n';
+ css += '.dv-chart-tips .x-tip-body { background-color: #000; font-size: 13px; font-weight: normal; color: #fff; -webkit-text-stroke: 0; } \n';
css += '.dv-chart-tips .x-tip-body div { font-family: arial,sans-serif,ubuntu,consolas !important; } \n';
// load mask css
- css += '.x-mask-msg { padding: 0; \n border: 0 none; background-image: none; background-color: transparent; } \n';
+ css += '.x-mask-msg { padding: 0; \n border: 0 none; background-image: none; background-color: transparent; } \n';
css += '.x-mask-msg div { background-position: 11px center; } \n';
css += '.x-mask-msg .x-mask-loading { border: 0 none; \n background-color: #000; color: #fff; border-radius: 2px; padding: 12px 14px 12px 30px; opacity: 0.65; } \n';
@@ -19,32 +2567,37 @@
trend: 'Trend'
};
- // plugin
DV.plugin = {};
- var init = {},
+ var init = {
+ user: {}
+ },
configs = [],
- isInitialized = false,
+ isInitStarted = false,
+ isInitComplete = false,
getInit,
execute;
- getInit = function(config) {
- var requests = [],
+ getInit = function(url) {
+ var isInit = false,
+ requests = [],
callbacks = 0,
fn;
- init.user = {};
-
fn = function() {
if (++callbacks === requests.length) {
+ isInitComplete = true;
+
for (var i = 0; i < configs.length; i++) {
execute(configs[i]);
}
+
+ configs = [];
}
};
requests.push({
- url: config.url + '/api/system/context.jsonp',
+ url: url + '/api/system/context.jsonp',
success: function(r) {
init.contextPath = r.contextPath;
fn();
@@ -52,7 +2605,7 @@
});
requests.push({
- url: config.url + '/api/organisationUnits.jsonp?userOnly=true&viewClass=detailed&links=false',
+ url: url + '/api/organisationUnits.jsonp?userOnly=true&viewClass=detailed&links=false',
success: function(r) {
var ou = r.organisationUnits[0];
init.user.ou = ou.id;
@@ -62,7 +2615,7 @@
});
requests.push({
- url: config.url + '/api/mapLegendSets.jsonp?viewClass=detailed&links=false&paging=false',
+ url: url + '/api/mapLegendSets.jsonp?viewClass=detailed&links=false&paging=false',
success: function(r) {
init.legendSets = r.mapLegendSets;
fn();
@@ -70,7 +2623,7 @@
});
requests.push({
- url: config.url + '/api/dimensions.jsonp?links=false&paging=false',
+ url: url + '/api/dimensions.jsonp?links=false&paging=false',
success: function(r) {
init.dimensions = r.dimensions;
fn();
@@ -87,7 +2640,10 @@
extendInstance,
createViewport,
initialize,
- dv;
+ ns = {
+ core: {},
+ app: {}
+ };
validateConfig = function(config) {
if (!Ext.isObject(config)) {
@@ -105,15 +2661,120 @@
return true;
};
- extendInstance = function(dv) {
- var util = dv.util || {},
- init = dv.init || {};
-
- init.el = config.el;
+ extendInstance = function(ns) {
+ var init = ns.core.init,
+ api = ns.core.api,
+ support = ns.core.support,
+ service = ns.core.service,
+ web = ns.core.web;
+
+ init.el = config.el;
+
+ web.chart = web.chart || {};
+
+ web.chart.loadChart = function(id) {
+ if (!Ext.isString(id)) {
+ alert('Invalid chart id');
+ return;
+ }
+
+ Ext.data.JsonP.request({
+ url: init.contextPath + '/api/charts/' + id + '.jsonp?viewClass=dimensional&links=false',
+ failure: function(r) {
+ window.open(init.contextPath + '/api/charts/' + id + '.json?viewClass=dimensional&links=false', '_blank');
+ },
+ success: function(r) {
+ var layout = api.layout.Layout(r);
+
+ if (layout) {
+ web.chart.getData(layout, true);
+ }
+ }
+ });
+ };
+
+ web.chart.getData = function(layout, isUpdateGui) {
+ var xLayout,
+ paramString;
+
+ if (!layout) {
+ return;
+ }
+
+ xLayout = service.layout.getExtendedLayout(layout);
+ paramString = web.analytics.getParamString(xLayout, true);
+
+ // show mask
+ web.mask.show(ns.app.centerRegion);
+
+ Ext.data.JsonP.request({
+ url: init.contextPath + '/api/analytics.jsonp' + paramString,
+ timeout: 60000,
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Accepts': 'application/json'
+ },
+ disableCaching: false,
+ failure: function(r) {
+ web.mask.hide(ns.app.centerRegion);
+
+ window.open(init.contextPath + '/api/analytics.json' + paramString, '_blank');
+ },
+ success: function(r) {
+ var response = api.response.Response(r);
+
+ if (!response) {
+ web.mask.hide(ns.app.centerRegion);
+ return;
+ }
+
+ // sync xLayout with response
+ xLayout = service.layout.getSyncronizedXLayout(xLayout, response);
+
+ if (!xLayout) {
+ web.mask.hide(ns.app.centerRegion);
+ return;
+ }
+
+ ns.app.paramString = paramString;
+
+ web.chart.getChart(layout, xLayout, response, isUpdateGui);
+ }
+ });
+ };
+
+ web.chart.getChart = function(layout, xLayout, response, isUpdateGui) {
+ var xResponse,
+ xColAxis,
+ xRowAxis,
+ config;
+
+ if (!xLayout) {
+ xLayout = service.layout.getExtendedLayout(layout);
+ }
+
+ // extend response
+ xResponse = service.response.getExtendedResponse(xLayout, response);
+
+ // references
+ ns.app.layout = layout;
+ ns.app.xLayout = xLayout;
+ ns.app.response = response;
+ ns.app.xResponse = xResponse;
+
+ // create chart
+ ns.app.chart = ns.core.web.chart.createChart(ns);
+
+ // update viewport
+ ns.app.centerRegion.removeAll();
+ ns.app.centerRegion.add(ns.app.chart);
+
+ web.mask.hide(ns.app.centerRegion);
+ };
};
- createViewport = function() {
- var el = Ext.get(dv.init.el),
+ createViewport = function() {
+ var el = Ext.get(ns.core.init.el),
setFavorite,
centerRegion,
elBorderW = parseInt(el.getStyle('border-left-width')) + parseInt(el.getStyle('border-right-width')),
@@ -123,10 +2784,6 @@
width = el.getWidth() - elBorderW - elPaddingW,
height = el.getHeight() - elBorderH - elPaddingH;
- setFavorite = function(layout) {
- dv.engine.createChart(layout, dv);
- };
-
centerRegion = Ext.create('Ext.panel.Panel', {
renderTo: el,
bodyStyle: 'border: 0 none',
@@ -136,7 +2793,6 @@
});
return {
- setFavorite: setFavorite,
centerRegion: centerRegion
};
};
@@ -146,23 +2802,23 @@
return;
}
- dv = DV.core.getInstance(Ext.clone(init));
- extendInstance(dv);
+ ns.core = DV.getCore(Ext.clone(init));
+ extendInstance(ns);
- dv.isPlugin = true;
- dv.viewport = createViewport();
+ ns.app.viewport = createViewport();
+ ns.app.centerRegion = ns.app.viewport.centerRegion;
if (config.id) {
- dv.engine.loadChart(config.id, dv);
+ ns.core.web.chart.loadChart(config.id);
}
else {
- layout = dv.api.layout.Layout(config);
+ layout = ns.core.api.layout.Layout(config);
if (!layout) {
return;
}
- dv.engine.createChart(layout, dv);
+ ns.core.web.chart.getData(layout);
}
}();
};
@@ -172,11 +2828,19 @@
config.url = config.url.substr(0, config.url.length - 1);
}
- configs.push(config);
+ if (isInitComplete) {
+ execute(config);
+ }
+ else {
+ configs.push(config);
- if (!isInitialized) {
- isInitialized = true;
- getInit(config);
+ if (!isInitStarted) {
+ isInitStarted = true;
+ getInit(config.url);
+ }
}
};
+
+ DHIS = Ext.isObject(window['DHIS']) ? DHIS : {};
+ DHIS.getChart = DV.plugin.getChart;
});