1 /*********************************************************************************
2 * SugarCRM Community Edition is a customer relationship management program developed by
3 * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU Affero General Public License version 3 as published by the
7 * Free Software Foundation with the addition of the following permission added
8 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
9 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
10 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
17 * You should have received a copy of the GNU Affero General Public License along with
18 * this program; if not, see http://www.gnu.org/licenses or write to the Free
19 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
23 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
25 * The interactive user interfaces in modified source and object code versions
26 * of this program must display Appropriate Legal Notices, as required under
27 * Section 5 of the GNU Affero General Public License version 3.
29 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
30 * these Appropriate Legal Notices must retain the display of the "Powered by
31 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
32 * technical reasons, the Appropriate Legal Notices must display the words
33 * "Powered by SugarCRM".
34 ********************************************************************************/
39 function loadSugarChart (chartId,jsonFilename,css,chartConfig) {
42 if(document.getElementById(chartId) == null) {
46 var labelType, useGradients, nativeTextSupport, animate;
48 var ua = navigator.userAgent,
49 typeOfCanvas = typeof HTMLCanvasElement,
50 nativeCanvasSupport = (typeOfCanvas == 'object' || typeOfCanvas == 'function'),
51 textSupport = nativeCanvasSupport
52 && (typeof document.createElement('canvas').getContext('2d').fillText == 'function');
54 nativeTextSupport = labelType == 'Native';
55 useGradients = nativeCanvasSupport;
60 switch(chartConfig["chartType"]) {
62 var handleFailure = function(o){
64 if(o.responseText !== undefined){
68 var handleSuccess = function(o){
70 if(o.responseText !== undefined && o.responseText != "No Data"){
71 var json = eval('('+o.responseText+')');
73 var properties = $jit.util.splat(json.properties)[0];
74 var marginBottom = (chartConfig["orientation"] == 'vertical' && json.values.length > 8) ? 20*4 : 20;
76 // Bug #49732 : Bars in charts overlapping
77 // if to many data to display fix canvas width and set up width to container to allow overflow
78 if ( chartConfig["orientation"] == 'vertical' )
80 function fixChartContainer(event, itemsCount)
82 var region = YAHOO.util.Dom.getRegion('content');
83 if ( region && region.width )
85 // one bar needs about 40 px to correct display data and labels
86 var realWidth = itemsCount * 40;
87 if ( realWidth > region.width )
89 var chartCanvas = YAHOO.util.Dom.getElementsByClassName('chartCanvas', 'div');
90 var chartContainer = YAHOO.util.Dom.getElementsByClassName('chartContainer', 'div');
91 if ( chartContainer.length > 0 && chartCanvas.length > 0 )
93 chartContainer = YAHOO.util.Dom.get(chartContainer[0])
94 YAHOO.util.Dom.setStyle(chartContainer, 'width', region.width+'px')
95 chartCanvas = YAHOO.util.Dom.get(chartCanvas[0]);
96 YAHOO.util.Dom.setStyle(chartCanvas, 'width', realWidth+'px');
99 YAHOO.util.Event.addListener(window, "resize", fixChartContainer, json.values.length);
105 fixChartContainer(null, json.values.length);
109 var barChart = new $jit.BarChart({
110 //id of the visualization container
112 //whether to add animations
114 nodeCount: json.values.length,
115 renderBackground: chartConfig['imageExportType'] == "jpg" ? true: false,
116 backgroundColor: 'rgb(255,255,255)',
117 colorStop1: 'rgba(255,255,255,.8)',
118 colorStop2: 'rgba(255,255,255,0)',
123 //horizontal or vertical barcharts
124 orientation: chartConfig["orientation"],
127 text: properties['title'],
133 text: properties['subtitle'],
140 color: css["gridLineColor"]
143 barsOffset: (chartConfig["orientation"] == "vertical") ? 30 : 20,
144 //visualization offset
152 text: (chartConfig["scroll"] && SUGAR.util.isTouchScreen()) ? "Use two fingers to scroll" : "",
157 onClick: function(node) {
158 if(!node || SUGAR.util.isTouchScreen()) return;
159 if(node.link == 'undefined' || node.link == '') return;
160 window.location.href=node.link;
163 //labels offset position
166 type: useGradients? chartConfig["barType"]+':gradient' : chartConfig["barType"],
167 //whether to show the aggregation of the values
169 //whether to show the labels for the bars
173 type: labelType, //Native or HTML
175 family: css["font-family"],
182 onShow: function(tip, elem) {
183 if(elem.link != 'undefined' && elem.link != '') {
184 drillDown = (SUGAR.util.isTouchScreen()) ? "<br><a href='"+ elem.link +"'>Click to drilldown</a>" : "<br>Click to drilldown";
189 if(elem.valuelabel != 'undefined' && elem.valuelabel != undefined && elem.valuelabel != '') {
190 value = "elem.valuelabel";
192 value = "elem.value";
194 eval("tip.innerHTML = '<b>' + elem."+chartConfig["tip"]+" + '</b>: ' + "+value+" + ' - ' + elem.percentage + '%' + drillDown");
199 barChart.loadJSON(json);
205 var list = $jit.id('id-list'),
206 button = $jit.id('update'),
207 orn = $jit.id('switch-orientation');
208 //update json on click 'Update Data'
209 $jit.util.addEvent(button, 'click', function() {
210 var util = $jit.util;
211 if(util.hasClass(button, 'gray')) return;
212 util.removeClass(button, 'white');
213 util.addClass(button, 'gray');
214 barChart.updateJSON(json2);
217 //dynamically add legend to list
218 var list = $jit.id('legend'+chartId);
219 var legend = barChart.getLegend(),
220 cols = (typeof SUGAR == 'undefined' || typeof SUGAR.mySugar == 'undefined') ? 8 : 4,
221 rows = Math.ceil(legend["name"].length/cols),
222 table = "<table cellpadding='0' cellspacing='0' align='left'>";
224 for(i=0;i<rows;i++) {
226 for(td=0;td<cols;td++) {
228 table += '<td width=\'16\' valign=\'top\'>';
229 if(legend["name"][j] != undefined) {
230 table += '<div class=\'query-color\' style=\'background-color:'
231 + legend["color"][j] +'\'> </div>';
235 table += '<td class=\'label\' valign=\'top\'>';
236 if(legend["name"][j] != undefined) {
237 table += legend["name"][j];
247 list.innerHTML = table;
250 //save canvas to image for pdf consumption
251 $jit.util.saveImageTest(chartId,jsonFilename,chartConfig["imageExportType"]);
253 trackWindowResize(barChart, chartId, json);
259 success:handleSuccess,
260 failure:handleFailure,
261 argument: { foo:'foo', bar:''}
264 var request = YAHOO.util.Connect.asyncRequest('GET', jsonFilename + "?r=" + new Date().getTime(), callback);
268 var handleFailure = function(o){
270 if(o.responseText !== undefined){
274 var handleSuccess = function(o){
276 if(o.responseText !== undefined && o.responseText != "No Data"){
277 var json = eval('('+o.responseText+')');
279 var properties = $jit.util.splat(json.properties)[0];
281 var lineChart = new $jit.LineChart({
282 //id of the visualization container
284 //whether to add animations
286 renderBackground: chartConfig['imageExportType'] == "jpg" ? true: false,
287 backgroundColor: 'rgb(255,255,255)',
288 colorStop1: 'rgba(255,255,255,.8)',
289 colorStop2: 'rgba(255,255,255,0)',
290 selectOnHover: false,
292 text: properties['title'],
298 text: properties['subtitle'],
305 color: css["gridLineColor"]
307 //visualization offset
316 onClick: function(node) {
317 if(!node || SUGAR.util.isTouchScreen()) return;
318 if(node.link == 'undefined' || node.link == '') return;
319 window.location.href=node.link;
322 //labels offset position
325 type: useGradients? chartConfig["lineType"]+':gradient' : chartConfig["lineType"],
326 //whether to show the aggregation of the values
328 //whether to show the labels for the bars
332 type: labelType, //Native or HTML
334 family: css["font-family"],
341 onShow: function(tip, elem) {
342 if(elem.link != 'undefined' && elem.link != '') {
343 drillDown = (SUGAR.util.isTouchScreen()) ? "<br><a href='"+ elem.link +"'>Click to drilldown</a>" : "<br>Click to drilldown";
348 if(elem.valuelabel != 'undefined' && elem.valuelabel != undefined && elem.valuelabel != '') {
349 var value = "elem.valuelabel";
351 var value = "elem.value";
355 eval("var name = elem."+chartConfig["tip"]+";");
356 var content = '<table>';
358 for(var i=0; i<name.length; i++) {
359 content += '<tr><td><b>' + name[i] + '</b>:</td><td> ' + elem.value[i] + ' - ' + elem.percentage[i] + '%' + '</td></tr>';
361 content += '</table>';
362 tip.innerHTML = content;
364 eval("tip.innerHTML = '<b>' + elem."+chartConfig["tip"]+" + '</b>: ' + "+value+" + ' - ' + elem.percentage + '%' + drillDown");
370 lineChart.loadJSON(json);
374 var list = $jit.id('id-list'),
375 button = $jit.id('update'),
376 orn = $jit.id('switch-orientation');
377 //update json on click 'Update Data'
378 $jit.util.addEvent(button, 'click', function() {
379 var util = $jit.util;
380 if(util.hasClass(button, 'gray')) return;
381 util.removeClass(button, 'white');
382 util.addClass(button, 'gray');
383 barChart.updateJSON(json2);
386 //dynamically add legend to list
387 var list = $jit.id('legend'+chartId);
388 var legend = lineChart.getLegend(),
389 cols = (typeof SUGAR == 'undefined' || typeof SUGAR.mySugar == 'undefined') ? 8 : 4,
390 rows = Math.ceil(legend["name"].length/cols),
391 table = "<table cellpadding='0' cellspacing='0' align='left'>";
393 for(i=0;i<rows;i++) {
395 for(td=0;td<cols;td++) {
397 table += '<td width=\'16\' valign=\'top\'>';
398 if(legend["name"][j] != undefined) {
399 table += '<div class=\'query-color\' style=\'background-color:'
400 + legend["color"][j] +'\'> </div>';
404 table += '<td class=\'label\' valign=\'top\'>';
405 if(legend["name"][j] != undefined) {
406 table += legend["name"][j];
416 list.innerHTML = table;
419 //save canvas to image for pdf consumption
420 $jit.util.saveImageTest(chartId,jsonFilename,chartConfig["imageExportType"]);
422 trackWindowResize(lineChart, chartId, json);
428 success:handleSuccess,
429 failure:handleFailure,
430 argument: { foo:'foo', bar:''}
433 var request = YAHOO.util.Connect.asyncRequest('GET', jsonFilename + "?r=" + new Date().getTime(), callback);
439 var handleFailure = function(o){
441 if(o.responseText !== undefined){
445 var handleSuccess = function(o){
447 if(o.responseText !== undefined){
448 var json = eval('('+o.responseText+')');
449 var properties = $jit.util.splat(json.properties)[0];
452 var pieChart = new $jit.PieChart({
453 //id of the visualization container
455 //whether to add animations
457 renderBackground: chartConfig['imageExportType'] == "jpg" ? true: false,
458 backgroundColor: 'rgb(255,255,255)',
459 colorStop1: 'rgba(255,255,255,.8)',
460 colorStop2: 'rgba(255,255,255,0)',
461 labelType: properties['labels'],
468 type: useGradients? chartConfig["pieType"]+':gradient' : chartConfig["pieType"],
469 //whether to show the labels for the slices
472 text: properties['title'],
478 text: properties['subtitle'],
491 onClick: function(node) {
492 if(!node || SUGAR.util.isTouchScreen()) return;
493 if(node.link == 'undefined' || node.link == '') return;
494 window.location.href=node.link;
499 type: labelType, //Native or HTML
501 family: css["font-family"],
507 onShow: function(tip, elem) {
508 if(elem.link != 'undefined' && elem.link != '') {
509 drillDown = (SUGAR.util.isTouchScreen()) ? "<br><a href='"+ elem.link +"'>Click to drilldown</a>" : "<br>Click to drilldown";
514 if(elem.valuelabel != 'undefined' && elem.valuelabel != undefined && elem.valuelabel != '') {
515 value = "elem.valuelabel";
517 value = "elem.value";
519 eval("tip.innerHTML = '<b>' + elem.label + '</b>: ' + "+ value +" + ' - ' + elem.percentage + '%' + drillDown");
524 pieChart.loadJSON(json);
526 //dynamically add legend to list
527 var list = $jit.id('legend'+chartId);
528 var legend = pieChart.getLegend(),
529 cols = (typeof SUGAR == 'undefined' || typeof SUGAR.mySugar == 'undefined') ? 8 : 4,
530 rows = Math.ceil(legend["name"].length/cols);
531 table = "<table cellpadding='0' cellspacing='0' align='left'>";
533 for(i=0;i<rows;i++) {
535 for(td=0;td<cols;td++) {
537 table += '<td width=\'16\' valign=\'top\'>';
538 if(legend["name"][j] != undefined) {
539 table += '<div class=\'query-color\' style=\'background-color:'
540 + legend["color"][j] +'\'> </div>';
544 table += '<td class=\'label\' valign=\'top\'>';
545 if(legend["name"][j] != undefined) {
546 table += legend["name"][j];
556 list.innerHTML = table;
559 //save canvas to image for pdf consumption
560 $jit.util.saveImageTest(chartId,jsonFilename,chartConfig["imageExportType"]);
562 trackWindowResize(pieChart, chartId, json);
568 success:handleSuccess,
569 failure:handleFailure,
570 argument: { foo:'foo', bar:''}
573 var request = YAHOO.util.Connect.asyncRequest('GET', jsonFilename + "?r=" + new Date().getTime(), callback);
580 var handleFailure = function(o){
582 if(o.responseText !== undefined){
586 var handleSuccess = function(o){
588 if(o.responseText !== undefined && o.responseText != "No Data"){
589 var json = eval('('+o.responseText+')');
591 var properties = $jit.util.splat(json.properties)[0];
594 var funnelChart = new $jit.FunnelChart({
595 //id of the visualization container
597 //whether to add animations
599 renderBackground: chartConfig['imageExportType'] == "jpg" ? true: false,
600 backgroundColor: 'rgb(255,255,255)',
601 colorStop1: 'rgba(255,255,255,.8)',
602 colorStop2: 'rgba(255,255,255,0)',
603 //orientation setting should not be changed
604 orientation: "vertical",
607 text: properties['title'],
613 text: properties['subtitle'],
620 //visualization offset
629 onClick: function(node) {
630 if(!node || SUGAR.util.isTouchScreen()) return;
631 if(node.link == 'undefined' || node.link == '') return;
632 window.location.href=node.link;
635 //labels offset position
638 type: useGradients? chartConfig["funnelType"]+':gradient' : chartConfig["funnelType"],
639 //whether to show the aggregation of the values
641 //whether to show the labels for the bars
645 type: labelType, //Native or HTML
647 family: css["font-family"],
654 onShow: function(tip, elem) {
655 if(elem.link != 'undefined' && elem.link != '') {
656 drillDown = (SUGAR.util.isTouchScreen()) ? "<br><a href='"+ elem.link +"'>Click to drilldown</a>" : "<br>Click to drilldown";
661 if(elem.valuelabel != 'undefined' && elem.valuelabel != undefined && elem.valuelabel != '') {
662 value = "elem.valuelabel";
664 value = "elem.value";
666 eval("tip.innerHTML = '<b>' + elem."+chartConfig["tip"]+" + '</b>: ' + "+value+" + ' - ' + elem.percentage + '%' + drillDown");
671 funnelChart.loadJSON(json);
675 var list = $jit.id('id-list'),
676 button = $jit.id('update'),
677 orn = $jit.id('switch-orientation');
678 //update json on click 'Update Data'
679 $jit.util.addEvent(button, 'click', function() {
680 var util = $jit.util;
681 if(util.hasClass(button, 'gray')) return;
682 util.removeClass(button, 'white');
683 util.addClass(button, 'gray');
684 barChart.updateJSON(json2);
687 //dynamically add legend to list
688 var list = $jit.id('legend'+chartId);
689 var legend = funnelChart.getLegend(),
690 cols = (typeof SUGAR == 'undefined' || typeof SUGAR.mySugar == 'undefined') ? 8 : 4,
691 rows = Math.ceil(legend["name"].length/cols);
692 table = "<table cellpadding='0' cellspacing='0' align='left'>";
694 for(i=0;i<rows;i++) {
696 for(td=0;td<cols;td++) {
698 table += '<td width=\'16\' valign=\'top\'>';
699 if(legend["name"][j] != undefined) {
700 table += '<div class=\'query-color\' style=\'background-color:'
701 + legend["color"][j] +'\'> </div>';
705 table += '<td class=\'label\' valign=\'top\'>';
706 if(legend["name"][j] != undefined) {
707 table += legend["name"][j];
717 list.innerHTML = table;
719 //save canvas to image for pdf consumption
720 $jit.util.saveImageTest(chartId,jsonFilename,chartConfig["imageExportType"]);
722 trackWindowResize(funnelChart, chartId, json);
728 success:handleSuccess,
729 failure:handleFailure,
730 argument: { foo:'foo', bar:''}
733 var request = YAHOO.util.Connect.asyncRequest('GET', jsonFilename + "?r=" + new Date().getTime(), callback);
740 var handleFailure = function(o){
742 if(o.responseText !== undefined){
746 var handleSuccess = function(o){
748 if(o.responseText !== undefined){
749 var json = eval('('+o.responseText+')');
750 var properties = $jit.util.splat(json.properties)[0];
753 var gaugeChart = new $jit.GaugeChart({
754 //id of the visualization container
756 //whether to add animations
758 renderBackground: chartConfig['imageExportType'] == "jpg" ? true: false,
759 backgroundColor: 'rgb(255,255,255)',
760 colorStop1: 'rgba(255,255,255,.8)',
761 colorStop2: 'rgba(255,255,255,0)',
762 labelType: properties['labels'],
765 text: properties['title'],
771 text: properties['subtitle'],
779 backgroundColor: '#aaaaaa',
780 borderColor: '#999999',
781 needleColor: 'rgba(255,0,0,.8)',
783 positionFontSize: 24,
787 type: useGradients? chartConfig["gaugeType"]+':gradient' : chartConfig["gaugeType"],
788 //whether to show the labels for the slices
792 onClick: function(node) {
793 if(!node || SUGAR.util.isTouchScreen()) return;
794 if(node.link == 'undefined' || node.link == '') return;
795 window.location.href=node.link;
800 type: labelType, //Native or HTML
802 family: css["font-family"],
808 onShow: function(tip, elem) {
809 if(elem.link != 'undefined' && elem.link != '') {
810 drillDown = (SUGAR.util.isTouchScreen()) ? "<br><a href='"+ elem.link +"'>Click to drilldown</a>" : "<br>Click to drilldown";
814 if(elem.valuelabel != 'undefined' && elem.valuelabel != undefined && elem.valuelabel != '') {
815 value = "elem.valuelabel";
817 value = "elem.value";
819 eval("tip.innerHTML = '<b>' + elem.label + '</b>: ' + "+ value +" + drillDown");
824 gaugeChart.loadJSON(json);
827 var list = $jit.id('legend'+chartId);
828 var legend = gaugeChart.getLegend(),
829 cols = (typeof SUGAR == 'undefined' || typeof SUGAR.mySugar == 'undefined') ? 8 : 4,
830 rows = Math.ceil(legend["name"].length/cols);
831 table = "<table cellpadding='0' cellspacing='0' align='left'>";
833 for(i=0;i<rows;i++) {
835 for(td=0;td<cols;td++) {
837 table += '<td width=\'16\' valign=\'top\'>';
838 if(legend["name"][j] != undefined) {
839 table += '<div class=\'query-color\' style=\'background-color:'
840 + legend["color"][j] +'\'> </div>';
844 table += '<td class=\'label\' valign=\'top\'>';
845 if(legend["name"][j] != undefined) {
846 table += legend["name"][j];
856 list.innerHTML = table;
859 //save canvas to image for pdf consumption
860 $jit.util.saveImageTest(chartId,jsonFilename,chartConfig["imageExportType"]);
862 trackWindowResize(gaugeChart, chartId, json);
868 success:handleSuccess,
869 failure:handleFailure,
870 argument: { foo:'foo', bar:''}
873 var request = YAHOO.util.Connect.asyncRequest('GET', jsonFilename + "?r=" + new Date().getTime(), callback);
879 function trackWindowResize(chart, chartId, json)
881 var origWindowWidth = document.documentElement.scrollWidth,
882 container = document.getElementById(chartId),
883 widget = document.getElementById(chartId + "-canvaswidget");
887 // refresh graph on window resize
888 YAHOO.util.Event.addListener(window, "resize", function()
892 clearTimeout(timeout);
895 timeout = setTimeout(function()
897 var newWindowWidth = document.documentElement.scrollWidth;
899 // if window width has changed during resize
900 if (newWindowWidth != origWindowWidth)
902 // hide widget in order to let it's container have
903 // width corresponding to current window size,
905 widget.style.display = "none";
907 // add one more timeout in order to let all widgets
909 setTimeout(function()
911 // measure container width
912 var width = container.offsetWidth;
914 // display widget before resize, otherwise
915 // it will be rendered incorrectly in IE
916 widget.style.display = "";
918 chart.resizeGraph(json, width);
919 origWindowWidth = newWindowWidth;