Fix #7123 - getting abra ready to test
[Pman.Xtuple] / Pman.Xtuple.DashboardRender.js
1  
2 Pman.Xtuple.DashboardRender = {
3  
4     offices : {
5         hk : 'Hong Kong',
6         sg : 'Singapore',
7          my: 'Malaysia',
8         au: 'Australia',
9         'au-0': 'Australia Online',
10         'au-1': 'Australia Trade',
11         cn: 'China',  
12         all: 'Group'
13     },
14     currency : false,
15     
16     templates  : {
17        
18         summary : '',
19         totals : '',
20         
21         salestrend : '',
22         percountry : '',
23         revenuebycustomer : '',
24         profitbycustomer : '',
25         perbrand : '',
26         perproduct : '',
27         slowmoving : ''
28         
29     },
30    
31     state : false,
32     
33     default_state  :
34     {
35         'perday-type'    : 'voice',
36         'perday-vtype'   : 'value',
37         'perday-date'   : (new Date()).format('Y') +'' // 2001 2001Q1 200012 W2012-01-01
38         
39     },
40     
41     filterCfg  :{
42         titles : {
43             /*
44             'country':  "Filter by Country",
45             'language':     "Filter by Language",
46             'mediatype':    "Filter by Media Type",
47             //'publication':     "Filter by Publication",
48             'tonality':    "Filter by Tonality",
49             'keywords':     "Filter by Voice"
50             */
51         }
52      
53     },
54     papers : false,
55     paper : false,
56     
57     initPaper : function(rg)
58     {
59         this.papers = this.papers || {};
60         this.paper=  false;
61         
62         var ge = rg.select('.report-graph',true).first();
63         if (!ge) {
64             Roo.log("NO report-graph  ("+ this.view +") found - skipping");
65             return false;
66         }
67         Roo.log("init paper?");
68         Roo.log(ge);
69         this.dash = Pman.Tab.XtupleDashboard;
70            
71         this.paper = Raphael(ge.dom);
72         var sz = ge.getSize();
73         this.paper.setSize(sz.width,sz.height);
74         this.papers[this.view] = this.paper;
75         
76         return true;
77      
78     },
79     resize : function(w,h)
80     {
81         //this.initPaper();
82         //this.paper.setSize(width,400);
83          
84     },
85     
86     view : 'summary',
87     
88     // top level load ....
89     load: function()
90     {
91         
92         Pman.Tab.XtupleDashboard.panel.el.mask("Loading");
93         // if no combined - only show current..
94         var cdb = baseURL.split('/').pop().split('.').shift();
95         
96         
97         if (!Pman.hasPerm('Xtuple.AccountsCombined', 'S') || cdb !='hk'){ //|| window.location.host == 'localhost') {
98             var offices = {};
99             
100             offices[ cdb ] = this.offices[cdb];
101             this.offices = offices;
102         }
103         
104         
105         this.dash = Pman.Tab.XtupleDashboard;
106         this.tree = Pman.Tab.XtupleDashboard.tree.tree;
107         this.treeroot = this.tree.getRootNode();
108         //var sn =   this.dash.tpanel.tree.getSelectionModel().getSelectedNode();
109         this.view = 'summary';
110         
111         //if(sn) {
112         //    this.view = sn.attributes.id.toLowerCase();
113         //    
114         //}
115         if (!this.state) {
116             this.state = Roo.apply({}, this.default_state);
117         }
118         
119         this.updateStateFromTree();
120         
121         // build a list of views to fetch,
122         this.views = [];
123         for (var i in this.templates) {
124             if (i == 'summary') {
125                 continue;
126             }
127             for (k in this.offices) {
128                 if(k == 'au' && i == 'totals'){
129                     this.views.push(i + '-' + k + '-0');
130                     this.views.push(i + '-' + k + '-1');
131                     continue;
132                 }
133                 this.views.push(i + '-' + k);
134             }
135         }
136         
137         this.papers = {}; // reset papers..
138        
139         this.templates.summary.overwrite( this.templateEl(),   {
140             dates : this.buildDates() ,
141             curdates : this.parseDate()
142         }  );
143         
144         // resize height for Month..
145         var dt = this.parseDate();
146         if (dt.type == 'M') {
147             this.templateEl().select('.report-group-perday',true).setStyle('height', '530px');
148             this.templateEl().select('.report-graph-perday',true).setStyle('height', '300px');
149         }
150           
151         
152         //this.dash.viewPanel.el.mask("Loading");
153         this.data = {};
154         this.loadNextView();
155     },
156     
157     data : {},
158     
159     
160     parseDate : function()
161     {
162         // formats :
163         // 2012
164          var ret = {
165             type : '', 
166             year : '',
167             quarter : '',
168             month : '',
169             week:  '',
170             day : '',
171             breadcrumb : ''
172         }
173         
174         ret.type = this.dash.viewType.getValue();
175         
176         var df = Date.parseDate(this.dash.mfrom.getValue(),'Y-m-d');
177         var dt = Date.parseDate(this.dash.mto.getValue(),'Y-m-d');
178         var dp = Date.parseDate(this.dash.daypick.getValue(),'Y-m-d');
179         
180       
181         // year
182         switch(ret.type) {
183             case 'Y':
184             
185                 //ret.year = this.state['perday-date'] *1;
186                 ret.date = df;
187                 ret.dateto =  df.add(Date.YEAR, 1);
188                 ret.breadcrumb =  df.format('F Y') + ' to ' + ret.dateto.format('F Y');
189                 return ret;
190             case 'H':
191                 ret.date = df;
192                 ret.dateto =  df.add(Date.MONTH, 6);
193                 ret.breadcrumb =  df.format('F Y') + ' to ' + ret.dateto.format('F Y');
194                 return ret;
195             
196             case 'Q':
197         
198                 ret.date = df;
199                 ret.dateto =  df.add(Date.MONTH, 3);
200                 ret.breadcrumb =  df.format('F Y') + ' to ' + ret.dateto.format('F Y');
201                 return ret;
202             case 'M':
203         
204                 ret.date = df;
205                 ret.dateto =  df.add(Date.MONTH, 1);
206                 ret.breadcrumb =  df.format('F Y');
207                 return ret;
208             
209           
210             case 'R':
211                 ret.date = df;
212                 ret.dateto =  dt;
213                 ret.breadcrumb =  df.format('F Y') + ' to ' + ret.dateto.format('F Y');
214                 return ret;
215         }
216         return false;
217     },
218     
219     buildDates : function()
220     {
221         var dt = this.parseDate();
222         var ret = {
223             yprev : dt.year - 1,
224             ycur : dt.year,
225             ynext : 0,
226             quarters : [],
227             months : []
228         };
229         
230         if (dt.date.add(Date.YEAR, 1) <= (new Date())) {
231             ret.ynext = dt.year +1;
232         }
233          // quaters..
234         for (var i =0; i < 2; i++) {
235             // is it greater than now..
236             var qs = new Date(dt.year, i * 6, 1);
237             if (qs <= new Date()) {
238                 ret.quarters.push({
239                     qtitle : 'H' + (i+1),
240                     qlink : dt.year + 'H' + (i+1)
241                 });
242             }
243             
244         }
245         
246         
247         // quaters..
248         for (var i =0; i < 4; i++) {
249             // is it greater than now..
250             var qs = new Date(dt.year, i * 3, 1);
251             if (qs <= new Date()) {
252                 ret.quarters.push({
253                     qtitle : 'Q' + (i+1),
254                     qlink : dt.year + 'Q' + (i+1)
255                 });
256             }
257             
258         }
259         // months..
260         for (var i =0; i < 12; i++) {
261             // is it greater than now..
262             var qs = new Date(dt.year, i , 1);
263             if (qs <= new Date()) {
264                 ret.months.push({
265                     mtitle : qs.format('M')[0],
266                     mlink : dt.year + 'M' + (i+1)
267                 });
268             }
269         }
270         
271         return ret;
272         
273         //if ()
274         //ret.ynext 
275         
276         
277         
278     },
279     
280     
281     
282     
283     loadNextView : function()
284     {
285         if (!this.views.length || !this.dash.panel.active) {
286             //this.dash.viewPanel.el.unmask();
287             //this.showFilters();
288             //this.boldSelected();
289             Pman.Tab.XtupleDashboard.panel.el.unmask();
290             return false;
291         }
292         
293         this.view = this.views.shift();
294         //Roo.log(this.view);
295         var rg = this.view == Roo.select('.report-group-' + this.view,true).first();
296         
297         // no hiding in this version??
298         // also need to hide all the share of voices???
299         
300         
301         var _this = this;
302         
303         // not handled yet..
304         //if (['keywords'].indexOf(this.view) > -1) {
305         //    this.loadNextView();
306         //    return false;
307         //}
308         var dt = this.parseDate();
309         
310         var view = this.view.toUpperCase();
311         
312         var ext = view.split('-');
313         view = ext[0];
314         var office = ext[1];
315 //        var ext = view.match(/\-[A-Z]+$/i);
316 //        view = view.replace(/\-[A-Z]+$/, '');
317 //        var office = ext[0].substr(1);
318         var url = office == 'HK' ? baseURL+'/Roo/Dragon_report'  : baseURL+'/Xtuple/Roo/Dragon_report';
319         
320         
321         if(dt.type == 'M' && view == 'SALESTREND') {
322             // it should just mask that entry?
323             Roo.log("skip sales trend");
324             //dash.viewPanel.el.mask("No data available");
325             _this.loadNextView();
326             return false;
327         }
328         
329         
330         var country = this.dash.countryCombo.getValue();
331         
332         if (view == 'PERCOUNTRY' && country.length) {
333             Roo.log("skip per country");
334             //dash.viewPanel.el.mask("No data available");
335             _this.loadNextView();
336             return false;
337         }
338         
339         
340         if ( office == 'ALL') {
341             
342              
343             var rg =   Roo.select('.report-group-' + this.view ,true).first();
344             if (!rg) {
345                 _this.loadNextView();
346                 Roo.log("missing : .report-group-" + this.view);
347                 return false;
348                 
349             }
350             var res = (view == 'TOTALS') ?  { data : [  {} ] } :
351                         { data : [  ] }; // use data from totals.
352             
353             var map = {};
354             
355             for(var k in this.offices) {
356                 var dk = view.toLowerCase()+'-' +k;
357                 
358                 if (typeof(this.data[dk]) == 'undefined') {
359                     Roo.log('skip combined - missing data :'+dk);
360                     continue;
361                 }
362                 
363                 if (view == 'TOTALS') {
364                     //Roo.log("combined : " + view + " " + dk);
365                     //Roo.log(this.data[dk]);
366                     
367                     var dv = this.data[dk][0];
368                     
369                     for (var kk in dv) {
370                         res.data[0][kk] = typeof(res.data[0][kk]) == 'undefined' ?  0 : res.data[0][kk] ;
371                         var n = dv[kk] *1;
372                         if (isNaN(n)) {
373                             res.data[0][kk]  = dv[kk] ;
374                         } else {
375                             res.data[0][kk]  += n;
376                         }
377                         
378                         
379                     }
380                     
381                     
382                 } else {
383                    // Roo.log('combined non-totals : DATA');
384                     // add the rows for each country together..
385                     
386                     // australia double reports...
387                     var unsplit_country = dk.replace(/-[0-9]+$/,'');
388                     if (dk != unsplit_country && typeof(this.data[unsplit_country]) != 'undefined') {
389                         continue;
390                     }
391                     
392                     var dv = this.data[dk];
393                    // Roo.log(dv);
394                     Roo.each(dv, function (dvr) {
395                         dvr.qtysold *= 1;
396                         dvr.rvalue *= 1;
397                        
398                         if (typeof (map[dvr.rkey] ) == 'undefined') {
399                              
400                             map[dvr.rkey] = Roo.apply({}, dvr);
401                             map[dvr.rkey].percent = '';
402                             res.data.push(map[dvr.rkey]);
403                             return;
404                         }
405                         map[dvr.rkey].qtysold +=   dvr.qtysold ;
406                         map[dvr.rkey].rvalue +=   dvr.rvalue ;
407                         
408                         
409                     });
410                        
411                     
412                     
413                 }
414                
415             }
416             Roo.log("MAP for combined");
417             Roo.log(map);
418             if (view != 'TOTALS') {
419                 //_this.data[_this.view] = res.data.slice(0); // copy..
420                 
421                 // percents are borked..
422                 res.data.sort(function(a,b) {
423                     //Roo.log(a.rvalue +' ?= ' + b.rvalue);
424                     if (a.rvalue == b.rvalue) {
425                         return 0;
426                     }
427                     return a.rvalue > b.rvalue ? -1 : 1;
428                     
429                 });
430                 
431                 
432                //Roo.log(res);
433                 var meth = 'render' + _this.view.toUpperCase().split('-').shift();
434                 
435                 if (typeof(_this[meth]) == 'undefined') {
436                     if (res.data.length) {
437                         _this.renderDefault( res, _this.view.toLowerCase())
438                     }
439                     
440                     
441                     
442                 } else {
443                      
444                     _this[meth]( res , _this.view.toLowerCase());
445                 }
446              
447             }  else {
448                 res.office = this.offices[office.toLowerCase()];
449                 if (res.data.length) {
450                     this.templates[view.toLowerCase()].overwrite( rg,  res);
451                 }
452                 //Roo.log(res);
453                 
454             
455             }
456            
457             
458             
459           
460              
461             
462             //dash.viewPanel.el.mask("No data available");
463             _this.loadNextView();
464             return false;
465         }
466         
467         var p = {
468             'query[report]' : view,
469             'query[dateFrom]' : dt.date.format('Y-m-d'),
470             'query[dateUpto]' : dt.dateto.format('Y-m-d'),
471             'query[country]' : country,
472             'query[showExtra]' : 0,
473             'query[notmg]' : 0,
474             '_roo_office' : office.toLowerCase(),
475             limit : 999//,
476             //_columns : 'rkey,rvalue,rkid,radvalue,rcirculation,rcountry,rkiso'
477         };
478         // combined all in HKD..
479         if (Pman.hasPerm('Xtuple.AccountsCombined', 'S') && baseURL.match(/hk\.php$/)) {
480             p['query[currency]'] = 'HKD';
481         }
482         
483         if(ext[2]){
484             p['query[showExtra]'] = 1;
485             p['query[notmg]'] = ext[2];
486         }
487
488         new Pman.Request({
489             timeout: 600000,    // 10 mins ?!
490             url: url,
491             method: 'GET',
492             params: p,
493             
494             failure : function() {
495                 _this.loadNextView();
496                 
497             },
498             success: function(res)
499             {
500                 if(!res.data.length) {
501                     // it should just mask that entry?
502                     Roo.log("NO DATA?");
503                     //dash.viewPanel.el.mask("No data available");
504                     _this.loadNextView();
505                     return;
506                 }
507                 
508                 
509                 //_this.dash.viewPanel.el.unmask();
510                 //_this.initPaper();
511                 //var sz = this.dash.viewPanel.el.getSize()
512                        // h = sz.height - 20;
513                 //_this.width = sz.width;
514                 //_this.paper.setSize(sz.width, 400);
515                 //_this.paper.clear();
516                  
517                 _this.data[_this.view] = res.data.slice(0); 
518                 
519                 var meth = 'render' + _this.view.toUpperCase().split('-').shift();
520                 
521                 if (typeof(_this[meth]) == 'undefined') {
522                     _this.renderDefault( res, _this.view.toLowerCase())
523                     
524                     
525                 } else {
526                      
527                     _this[meth]( res , _this.view.toLowerCase());
528                 }
529                 _this.loadNextView(); 
530                 
531  
532             }
533         });
534         return false;
535     },
536
537     currentColor : function()
538     {
539         var dash = Pman.Tab.XtupleDashboard;
540         
541         var clr = dash.themeCombo.getValue();
542         var clname = dash.themeCombo.el.dom.value;
543         
544         if(!clr) {
545             clr = dash.themeCombo.store.getAt(0).data.themeData;
546             clname = dash.themeCombo.store.getAt(0).data.name;
547         }
548         
549         if(clname.indexOf('Spectral') != 0) {
550             clr = clr.slice(0);
551             clr.reverse();
552             clr.pop();
553             clr.pop();
554         }
555         return clr;
556     },
557     
558     
559     colorthemes : function() {
560         //  too damn lazy to write
561         //  something elegant here
562         var map = [];
563         map['RdYlGn'] = 'Red Yellow Green';
564         map['RdYlBu'] = 'Red Yellow Blue';
565         map['YlOrBr'] = 'Yellow Orange Brown';
566         map['YlOrRd'] = 'Yellow Orange Red';
567         map['PuBuGn'] = 'Purple Blue Green';
568         map['YlGnBu'] = 'Yellow Green Blue';
569
570         var arr = [];
571         Roo.each(colorbrewer, function(cb, i) {
572             for(var j in cb) {
573                 if(j.length > 4) {
574                     for(var k in cb[j]) {
575                         if(k > 8) {
576                             var cn = (map[j] != undefined) ? map[j] : j;
577                             arr.push([cn+' - '+(k-8), cb[j][k]]);
578                         }
579                     }
580                 }
581             }
582         });
583         return arr;
584     },
585     
586     mediamap : false,
587     
588     renderDefault : function(res, tmplname)
589     {
590        // var view = this.view.replace(/\-[A-Z]+$/i, '');
591         
592         var ext = this.view.split('-');
593         var view = ext[0];
594         var office = ext[1];
595         
596         var rg =   Roo.select('.report-group-' + this.view ,true).first();
597         if (!rg) {
598             Roo.log("missing : .report-group-" + this.view);
599             return;
600             
601         }
602         
603 //        var ext = this.view.match(/\-[A-Z]+$/i);
604 //        var office = ext[0].substr(1);
605         
606         
607         //res.dates =  this.buildDates();
608         //res.curdates = this.parseDate();
609         res.office = this.offices[office];
610         if (typeof(res.data[0].currency) != 'undefined') {
611             Roo.log("Got currency:" +  res.data[0].currency)
612             this.currency = res.data[0].currency;
613         }
614         Roo.log("Setting currency to " + this.currency)
615         res.currency = this.currency;
616         
617         if (typeof(res.data[0].total_type) != 'undefined') {
618             res.total_type = res.data[0].total_type;
619         }
620         
621         var dash = Pman.Tab.XtupleDashboard;
622         
623         var clr = this.currentColor();
624         var data = [],
625                 l = [],
626                 n = res.data.length,
627                 per = 1.0 / Math.min(n, 10), // use 10 colours..
628                 colours = [];
629
630       
631         var total = 0.0;
632         var resdata = [];
633         
634         Roo.each(res.data, function(r,i) {
635             if (this.state[this.view] &&
636                 this.state[this.view].length &&
637                 this.state[this.view].split(',').indexOf(r.rkid) < 0)
638             {
639                     return;
640             }
641             
642             
643             data.push(r.rvalue * 1);
644             total+=r.rvalue * 1.0 ;
645             
646             
647             l.push(' %% - ' + r.rkey ); //+ ' (' + r.rvalue + ')');
648             colours.push(clr[i % clr.length]);
649             resdata.push(r);
650         }, this);
651         
652         res.data = resdata;
653         //Roo.log("total:" + total);
654         
655         Roo.each(res.data, function(r,i) {
656             // the type of r.rvalue is string;
657             r.percent =  ((parseInt(r.rvalue) *1.0/ total) * 100.0).toFixed() + '%';
658         })
659         
660         this.templates[view].overwrite( rg,  res);
661         
662          if (!this.initPaper(rg)) {
663             Roo.log("no paper found for " + this.view);
664             return;
665          }          
666         
667         /*
668         var sdata = data.length > 20 ? data.slice(0,20) : data;
669         dash.bar = this.paper.hbarchart(
670             400,
671             10,
672             500,
673             350,
674             sdata ,
675             { 
676                 type :   'sharp' ,
677                 colors : colours
678             }
679         );
680         */
681         //dash.bar.label(l,true);
682         dash.pie = this.paper.piechart(
683             (this.paper.height - 70) / 2,
684             this.paper.height  / 2 ,
685             (this.paper.height / 2) - 60,
686             data ,
687             { 
688                 cut: 10,
689                 colors :  colours,
690                 legend: l,
691                 legendpos: "east"
692             }
693         );
694         dash.pie.hover(
695             // in?
696             function() {
697             
698                 this.sector.stop();
699                 this.sector.scale(1.1, 1.1, this.cx, this.cy);
700
701                 if (this.label) {
702                     this.label[0].stop();
703                     this.label[0].attr({ r: 7.5 });
704                     this.label[1].attr({ "font-weight": 800 });
705                 }
706             },
707             // out..?
708             function () {
709                 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
710
711                 if (this.label) {
712                     this.label[0].animate({ r: 5 }, 500, "bounce");
713                     this.label[1].attr({ "font-weight": 400 });
714                 }
715             
716             
717         })
718         /*
719         var mx = 43;
720         if (tmplname == 'publication') {
721             mx = 10;
722         }
723         
724         if (tmplname == 'country') {
725             mx = 10;
726         }
727         
728         res.data = res.data.splice(0,mx);
729         if (tmplname !== false) {
730             this.templates[tmplname].overwrite(
731                 this.templateEl().select('.report-data-' + this.view,true).first(),
732                 res
733             );
734         }
735         */
736         //this.templates[tmplname].overwrite( this.templateEl(),   res  );
737         
738     },
739      
740     renderSALESTREND : function(res)
741     {
742          var view = this.view.replace(/\-[A-Z]+$/i, '');
743        
744         var rg =   Roo.select('.report-group-' + this.view ,true).first();
745         if (!rg) {
746             Roo.log("missing : .report-group-" + this.view);
747             return;
748             
749         }
750         Roo.log("do template");
751         var ext = this.view.match(/\-[A-Z]+$/i);
752         
753         var office = ext[0].substr(1);
754     
755         res.office = this.offices[office];
756         
757          if (typeof(res.data[0].currency) != 'undefined') {
758             this.currency = res.data[0].currency;
759         }
760         res.currency = this.currency;
761         
762         
763         
764         Roo.each(res.data, function(r, i) {
765
766             r.rmonth = Date.parseDate(r.rkey, 'Y-m-d').format('M Y');
767             r.shortMonth = Date.parseDate(r.rkey, 'Y-m-d').format('My');
768         });
769         // fill in dates..
770         
771         var dt = this.parseDate();
772         // range is more than a year, then do not show last..
773         var showlast =  (dt.dateto > dt.date.add(Date.YEAR, 1)) ? false : true; 
774         
775         this.templates[view].overwrite( rg,  res);
776         Roo.log("done template"); 
777         var dash = Pman.Tab.XtupleDashboard;
778         
779         var clr = this.currentColor();
780         var qty = [  [], [] ],
781                 date = [],
782                 colors = [],
783                 xpos = 75,
784                 ypos = 5;
785           
786         var fc = (res.data[0].rkid +'')[0];
787         
788       
789         var xlabels  = [];
790         var dates = [];
791         // fill data..
792         for (var i = 0; i < res.data.length; i++) {
793             xlabels[i] = res.data[i].shortMonth;
794             qty[1][i] = 0; // make sure previous year is filled out.
795             dates[i] = i;
796              
797         }
798         // fill in the extra data points.
799         
800          
801         // fc can be 'W' or 'M'
802              
803         var k =  'rvalue'  ;
804          var colors = [];
805          var adata = {
806             rvaluetotal: 0,
807             radvaluetotal : 0,
808             rcirculationtotal : 0
809           };
810         var pydata = [];
811         Roo.each(res.data, function(r, i) {
812             
813             var off = r.rkid ;
814             
815             // depending on type of view:
816             // YEARLY - 0000M1
817             // QUARTER --0000M1
818             // anything else... -> nolink...
819             
820             //res.data.rklink = 'nolink';
821             if (r.rkiso) {
822                 var d= Date.parseDate(r.rkey, 'Y-m-d');
823                 r.rklink = d.format('Y')+'M'+d.format('m');
824             }
825             
826             
827               
828             //qty[i]  =  [ r.sales  * 1,  r.salespy  * 1 ];
829             if (r.sales * 1) {
830                 qty[ 0][i] =   r.sales  * 1
831                 
832             }
833             if (showlast && r.salespy *1) {
834                 qty[1][i] =   r.salespy  * 1 ;
835                 
836             }
837             //xlabels[i]  = r.rkey;
838             // not sure if this is needed...
839             colors.push(clr[i%clr.length]);
840             
841             adata.salestotal        += (r.sales *1);
842              
843            
844             
845         });
846         // fill in any empty holes in the original data.
847         for(var i = 0; i < qty[0].length;i++) {
848             qty[0][i] = typeof(qty[0][i] ) == 'undefined' ? 0 : qty[0][i] ;
849         }
850         
851         
852         
853        //Roo.apply(res, adata);
854         
855         // will not work yet..
856         if (this.state['perday-vtype'] == 'cumulative') {
857             var cum = 0;
858
859             for (var i = 0 ; i < last+1;i++) {
860                 cum += qty[i];
861                 qty[i] = cum;
862             }
863             
864             
865         }
866          
867         var xdata = qty; //qty.length > 20 ? qty.slice(0, 20) : qty;
868         var ydata = dates; //date.length > 20 ? date.slice(0, 20) : date;
869
870         Roo.log(xdata);
871         Roo.log(ydata);
872         Roo.log(colors);
873         Roo.log(xlabels);
874         //return;
875         if (xdata.length < 2) {
876             //dash.viewPanel.el.mask("Not enough data");
877             rg.dom.innerHTML = "not big enough range";
878             return;
879         }
880      
881         
882          if (!this.initPaper(rg)) {
883             Roo.log("no paper found for " + this.view);
884             return;
885          }
886         var       w = this.paper.width - 90,
887                 h = this.paper.height - 25;
888
889          
890         Roo.log("Draw linechart");
891         this.line = this.paper.linechart(
892             xpos,
893             ypos,
894             w,
895             h,
896              ydata ,
897             xdata,
898             {
899                 'colors' : colors,
900                 'axis' : '0 0 1 1',
901                 'symbol' : 'circle',
902                 'shade' : '0.2',
903                 z : xdata.length -1,
904                 axisxlabels : xlabels,
905                 axisxstep : xlabels.length -1,
906                 axisxorientation : 3,
907                 ymin : 0
908                 
909             }
910         );
911
912
913         this.line.labels = this.paper.set();
914         
915         Roo.log("Set labels");
916
917         var qtyLbl = this.paper.text(
918                 0,
919                 (h/2+ypos),
920                 'Sales')
921                 .attr({
922                     fill : '#000',
923                     'text-anchor' :
924                     'start',
925                     font : '10px Arial',
926                     transform: 'r270'
927                 });
928         
929         this.line.labels.push(qtyLbl);
930     /*
931         var timeLbl = dash.paper.text(
932                     ((w/2)+xpos+40),
933                     (h+20+45),
934                     'Date'
935                 ).attr({
936                         fill : '#000',
937                         'text-anchor' : 'start',
938                         font : '18px Arial'
939                 });
940         
941         this.line.labels.push(timeLbl);
942     */
943         var snum = xdata.length -1;
944         Roo.log("Draw grid labels");
945         this.paper.drawGrid(
946                 xpos + 8, //+(snum/2) ,
947                 ypos + 8, //+(snum/2)  ,
948                 w - 16 ,
949                 h  - 16,
950                 snum,
951                 snum,
952              //   'rgba(192,192,192,0.2)'
953                 '#ccc'
954             );
955      //   Roo.log(res.data);
956          
957         
958         //this.templates.perday.overwrite( this.templateEl(),   res  );
959
960         
961     },
962     _template_el : false,
963     templateEl  : function ()
964     {
965         if (this._template_el) {
966             return this._template_el;
967         }
968         
969         var dash = Pman.Tab.XtupleDashboard;
970         this._template_el =  dash.viewPanel.el.createChild( '<div></div' );
971         this._template_el.on('click', this.handleClick, this);
972         return this._template_el ;
973     },
974     handleClick : function(a,b)
975     {
976         Roo.log(a);
977         Roo.log(b);
978         if (typeof(b.href) != 'string') {
979             return true;
980         }
981         var href= b.href.replace(/^[^#]*#/, '');
982         var parts = href.split('-');
983         var _t = this;
984         if ((!parts[0].length) || typeof(_t['handleClick' + parts[0]]) == 'undefined') {
985             Roo.log("No handler for " + parts[0] + ' (' + b.href +')');
986             return true;
987         }
988         Roo.log(parts);
989         var type = parts.shift();
990         _t['handleClick' + type](parts);
991         
992         return true;
993         
994         
995     },
996   
997     handleClickperday: function(parts)
998     {
999         var old = this.state['perday-' + parts[0]] ;
1000         this.state['perday-' + parts[0]] = parts[1];
1001         if (old == parts[1]) {
1002             return;
1003             
1004         }
1005         this.load();
1006     },
1007     
1008     updateStateFromTree : function() {
1009         
1010         return;
1011         
1012         var ids = this.tree.getChecked('id');
1013         Roo.each([
1014                 'mediatype'    ,
1015                 'country'      ,
1016                 'language'     ,
1017             //    'publication' , 
1018                  'keywords'     ,
1019                 'tonality'
1020             ],
1021             function(i) {
1022                 this.state[i] = '';
1023             },
1024             this
1025         );
1026         
1027         Roo.each(ids, function(i) {
1028             var ar = i.split('-');
1029             var l = ar.shift();
1030             var r = ar.join('-');
1031             var old = this.state[l].length ? this.state[l].split(',') : [];
1032             old.push(r);
1033             this.state[l] = old.join(',');
1034             
1035         }, this);
1036         
1037     },
1038      
1039     /*boldSelected: function()
1040     {
1041         _this = this;
1042         Roo.log(this.state);
1043         Pman.Clipping.DashboardRender.templateEl().select('a.report-select',true).each(
1044             function(e) {
1045                 //Roo.log(e.dom);
1046                 var href = e.dom.href.replace(/^[^#]*#/, '');
1047                 var parts = href.split('-');
1048                 switch(parts[0]) {
1049                     
1050                     case 'perday':
1051                         var state = _this.state['perday-'+parts[1]];
1052                         Roo.log("CHECK " + parts[2] + '?=' + state);
1053                         if (parts[2] == state) {
1054                             e.addClass('report-selected');
1055                         }
1056                         break;
1057                     
1058                       
1059                     case 'mediatype':
1060                     case 'country':
1061                     case 'language':                        
1062                         var k = parts.shift();
1063                         var v = parts.join('-');
1064                         var state = _this.state[k].split(',');
1065                         //Roo.log(JSON.stringify(state) + ' ?= ' + parts[1]);
1066                         if (state.indexOf(v) > -1) {
1067                             e.addClass('report-selected-on');
1068                         }
1069                         break;
1070                      
1071                     
1072                     default:
1073                         Roo.log("no style handler for " + parts[0]);
1074                         break;
1075                     
1076                  
1077                 }
1078                 
1079                 
1080             }
1081         );
1082         
1083         
1084     },
1085     */
1086     handleClickdownloadpdf: function(parts)
1087     {
1088         this.downloadSvg(this.papers[parts[0]],'application/pdf');
1089     },
1090     handleClickdownload: function(parts)
1091     {
1092         this.downloadSvg(this.papers[parts[0]],'image/jpeg');
1093     },
1094     downloadSvg : function(paper, to)
1095     {
1096         
1097         new Pman.Download({
1098             method : 'POST',
1099             
1100             url : baseURL + '/Core/Images',
1101             params : {
1102                 as : to,
1103                 mimetype  : 'image/svg',
1104                 data : paper.toSVG() ,
1105                 width : paper.width * 2  ,
1106                 height: paper.height * 2 
1107                 
1108             }
1109         });
1110         
1111         
1112         
1113         
1114     },
1115     replaceSvgAll: function(acb)
1116     {
1117         var q = [];
1118         for (var i in this.papers) {
1119             q.push(i);
1120         }
1121         var _t = this;
1122         var cb = function()
1123         {
1124             if (!q.length) {
1125                 if (acb) {
1126                     acb();
1127                 }
1128                 return;
1129             }
1130             var p = q.pop();
1131             
1132             _t.replaceSvg(_t.papers[p], p, cb);
1133             
1134             
1135         }
1136         
1137         cb();
1138     },
1139      
1140      
1141     replaceSvg: function(paper ,view, cb )
1142     {
1143         var _t = this;
1144         new Pman.Request({
1145             method : 'POST',
1146             
1147             url : baseURL + '/Core/Images',
1148             params : {
1149                 as : 'image/jpeg',
1150                 mimetype  : 'image/svg',
1151                 data : paper.toSVG(),
1152                 as_data : 1,
1153                 width : paper.width ,
1154                 height: paper.height 
1155             },
1156             success: function(data){
1157                 //Roo.log(data);
1158                 var g = Roo.get(_t.clonedBase).select('.report-graph-' + view, true).first();
1159                 if (g) {
1160                     g.dom.innerHTML = '<img src="' + 'data:image/jpeg;base64,' +data.data + '">';
1161                 }
1162                 if (cb) {
1163                     cb();
1164                 }
1165                 
1166             }
1167         });
1168         
1169         
1170         
1171         
1172     },
1173     
1174     clonedBase : false,
1175     
1176     downloadDoc : function()
1177     { 
1178     
1179         var _t = this;
1180         Roo.MessageBox.alert("Notice", "Creating Graphs");
1181         
1182         var tp = _t.templateEl();
1183            
1184         // copy and rmeove stufff.
1185         var cp = document.importNode(tp.dom,true);
1186         
1187         
1188         cp.removeAttribute('id');
1189         this.clonedBase= cp;
1190         // remove the top level style..
1191         Roo.get(cp).select('style',true).remove();
1192         
1193         // remove hidden stuff..
1194         
1195         Roo.get(cp).select('.report-no-print',true).remove();
1196         
1197         //this.printReplace(cp); -- this does not appear to work.
1198         //Roo.log(cp);
1199         
1200         this.replaceSvgAll(function() {
1201             
1202           
1203             //Roo.log(cp.innerHTML);
1204            
1205            
1206             var html = '<HTML>' +
1207                 '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />' +
1208                 '<BODY><div style="font-family:sans-serif;font-size:10pt">' + cp.innerHTML + '</div></BODY></HTML>';
1209            
1210             new Pman.Download({
1211                 method : 'POST',
1212                 
1213                 url : baseURL + '/Core/Images',
1214                 params : {
1215                    // as : 'application/msword',
1216                     as : 'application/rtf',
1217                     mimetype  : 'text/html',
1218                     data : html
1219                     
1220                 }
1221                 
1222             });
1223             
1224             Roo.MessageBox.alert("Notice", "Download will start shortly");
1225             
1226             
1227         });
1228         /// downloading dialog.?
1229     
1230     },
1231     
1232     
1233     printReplace : function(cp)
1234     {
1235         Roo.log('print replace');
1236         var st = document.styleSheets;
1237         Roo.log('n sheets' + st.length);
1238         
1239         for (var i = 0;i < st.length; i++) {
1240             try {
1241                 Roo.log(st[i].media[0] );
1242                 if (st[i].media[0] != 'print') {
1243                     continue;
1244                 }
1245             } catch(e) {
1246                 Roo.log(e);
1247                 continue;
1248             }
1249             var rules = st[i].rules; // or cssRules?
1250             
1251             for (var j = 0; j < rules.length; j++) {
1252                 var rule = rules[j];
1253                 var sel = rule.selectorText;
1254                 var val = rule.style.cssText;
1255                 Roo.log("SEL : "+ sel + " => " + val);
1256                 
1257                 Roo.get(cp).select(sel,true).each(function(el) {
1258                     el.dom.setAttribute('style',  val);
1259                     
1260                 });
1261                 
1262                 
1263                 
1264             }
1265             
1266             
1267         }
1268         
1269         
1270     } /*,
1271     
1272     
1273     showFilters : function()
1274     {
1275       
1276         // build filters from array
1277         
1278         while( this.treeroot.firstChild){
1279             this.treeroot.removeChild( this.treeroot.firstChild);
1280         }
1281         //this.treeroot = this.tree.getRootNode();
1282         this.treeroot.childrenRendered = true;
1283         
1284         
1285         var filters = [];
1286         for (var box in this.filterCfg.titles) {
1287             
1288             
1289             
1290             
1291             
1292             var filter = {
1293                 name : this.filterCfg.titles[box],
1294                 options : []
1295             };
1296             if (!this.data[box]) {
1297                 continue;
1298             }
1299             var gnode = false;
1300             if (box != 'keywords') {
1301                 Roo.log("Add to root");
1302                 
1303                 gnode = this.treeroot.appendChild( new Roo.tree.TreeNode({
1304                     id : 'box',
1305                     text : this.filterCfg.titles[box],
1306                     is_leaf : false,
1307                     expanded: true
1308                 }));
1309             }    
1310             
1311             var kword_ar = [];
1312             var kword_nodes = {};
1313             Roo.each(this.data[box], function(e) {
1314                 
1315                 
1316                 
1317                 
1318                 if (box == 'keywords') {
1319                     if (typeof(kword_nodes[e.parent_id]) == 'undefined') {
1320                         
1321                         kword_nodes[e.parent_id] = this.treeroot.appendChild(new Roo.tree.TreeNode({
1322                             text: e.parent_id_keyword ,
1323                             id : box +'-'+ e.parent_id,
1324                             is_leaf : false,
1325                             checked : this.state[box].split(',').indexOf(e.parent_id) > -1 ? true : false,
1326                             expanded: true
1327                         }));
1328                         
1329                     }
1330                     kword_nodes[e.parent_id].appendChild(new Roo.tree.TreeNode({
1331                         text: e.rkey + ' (' + e.rvalue + ')',
1332                         id : box +'-'+ e.rkid,
1333                         is_leaf : true,
1334                         checked : this.state[box].split(',').indexOf(e.rkid) > -1 ? true : false
1335                     }));
1336                     
1337                     
1338                     // need to add child data on?
1339                     return;  
1340                 }
1341                 
1342                 filter.options.push({
1343                     text: (e.rkey && e.rkey.length ? e.rkey : (e.rkid  +' (Untitled)'))   + '(' + e.rvalue + ')',
1344                     id : box +'-'+ e.rkid,
1345                     is_leaf : true,
1346                     checked : this.state[box].split(',').indexOf(e.rkid) > -1 ?  true : false
1347                 });
1348                
1349                 
1350             }, this);
1351             
1352             
1353             
1354             filter.options.sort( function(r1, r2){
1355                 var st = Roo.data.SortTypes.asUCString;
1356                 var v1 = st(r1.text), v2 = st(r2.text);
1357                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
1358             });
1359             Roo.each(filter.options, function (n) {
1360                 
1361                 gnode.appendChild(new Roo.tree.TreeNode( n));
1362                 
1363             });
1364             
1365             
1366             filters.push(filter);
1367             
1368         }
1369         
1370         
1371         
1372         
1373         
1374         
1375         //this.templates.filters.overwrite(
1376         //    this.templateEl().select('.report-filters', true).first(),
1377         //    { filters : filters }
1378         //);
1379        
1380         
1381         
1382     }
1383     */
1384 };
1385 // load all the templates.
1386 for (var i in Pman.Xtuple.DashboardRender.templates) {
1387      Pman.Xtuple.DashboardRender.templates[i] =  new Roo.DomTemplate({
1388                 url : rootURL + '/Pman/Xtuple/domtemplates/' + i +'.html'
1389                  
1390         });
1391 }
1392
1393
1394