/* * Copyright 2012 OSBI Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Renders a chart for each workspace */ var Chart = Backbone.View.extend({ initialize: function(args) { this.workspace = args.workspace; // Create a unique ID for use as the CSS selector this.id = _.uniqueId("chart_"); $(this.el).attr({ id: this.id }); // Bind table rendering to query result event _.bindAll(this, "render", "receive_data", "process_data", "show", "setOptions"); this.workspace.bind('query:result', this.receive_data); // Add chart button this.add_button(); this.workspace.toolbar.chart = this.show; // Listen to adjust event and rerender chart this.workspace.bind('workspace:adjust', this.render); var chartoptions ="
" + "bar" + "stacked bar" + "line" + "pie" + "heatgrid"; var exportoptions = "Export to: " + "PNG, " + "PDF, " + "TIFF, " + "SVG, " + "JPG" + "
" + "" + "" + "
"; var chartnav = (Settings.PLUGIN) ? chartoptions + "
" : chartoptions + exportoptions + "
"; // Create navigation this.nav = $(chartnav).css({ 'padding-bottom': '10px' }); this.nav.find('a.type').css({ color: '#666', 'margin-right': '5px', 'text-decoration': 'none', 'border': '1px solid #ccc', padding: '5px' }) .click(this.setOptions); this.nav.find('a.export').click(this.exportChart); // Append chart to workspace $(this.workspace.el).find('.workspace_results') .prepend($(this.el).hide()) .prepend(this.nav.hide()); }, add_button: function() { var $chart_button = $('') .css({ 'background-image': "url('js/saiku/plugins/Chart/chart.png')", 'background-repeat':'no-repeat', 'background-position':'50% 50%' }); var $chart_li = $('
  • ').append($chart_button); $(this.workspace.toolbar.el).find("ul").append($chart_li); }, show: function(event, ui) { $(this.workspace.el).find('.workspace_results table').toggle(); $(this.el).toggle(); $(this.nav).toggle(); $(event.target).toggleClass('on'); if ($(event.target).hasClass('on')) { this.process_data({ data: this.workspace.query.result.lastresult() }); this.render(); } }, setOptions: function(event) { var type = $(event.target).attr('href').replace('#', ''); try { this[type](); } catch (e) { } return false; }, exportChart: function(event) { var type = $(event.target).attr('href').replace('#', ''); var svgContent = new XMLSerializer().serializeToString($('svg')[0]); var form = $('#svgChartPseudoForm'); form.find('.type').val(type); form.find('.svg').val(svgContent); form.submit(); return false; }, stackedBar: function() { this.options.stacked = true; this.options.type = "BarChart"; this.render(); }, bar: function() { this.options.stacked = false; this.options.type = "BarChart"; this.render(); }, line: function() { this.options.stacked = false; this.options.type = "LineChart"; this.render(); }, pie: function() { this.options.stacked = false; this.options.type = "PieChart"; this.render(); }, heatgrid: function() { this.options.stacked = false; this.options.type = "HeatGridChart"; this.render(); }, render: function() { if (! $(this.workspace.toolbar.el).find('.chart').hasClass('on')) { return; } var options = _.extend({ canvas: this.id, width: $(this.workspace.el).find('.workspace_results').width() - 40, height: $(this.workspace.el).find('.workspace_results').height() - 40, yAxisSize: 70, orientation: 'vertical', stacked: false, animate: false, showValues: false, legend: true, legendPosition:"top", legendAlign: "right", colors: ["#4bb2c5", "#c5b47f", "#EAA228", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc"], type: 'BarChart' }, this.options); if (options.type == "HeatGridChart") { options = _.extend({ canvas: this.id, width: $(this.workspace.el).find('.workspace_results').width() - 40, height: $(this.workspace.el).find('.workspace_results').height() - 40, animate: false, clickable: false, orientation: "horizontal", showValues: false, showXScale: true, xAxisPosition: "bottom", showYScale: true, panelSizeRatio: 0.8, yAxisPosition: "left", yAxisSize: 150, minColor: "#FFFFFF", maxColor: "green", extensionPoints: { xAxisLabel_textAngle: -(Math.PI / 2), xAxisLabel_textAlign: "right", xAxisLabel_bottom: 10 } }, this.options); } if (this.data.resultset.length > 5 ) { options.extensionPoints = { xAxisLabel_textAngle: -(Math.PI / 2), xAxisLabel_textAlign: "right", xAxisLabel_bottom: 10 }; options.xAxisSize = 100; } this.chart = new pvc[options.type](options); this.chart.setData(this.data, { crosstabMode: true, seriesInRows: false }); try { this.chart.render(); Saiku.i18n.automatic_i18n(); } catch (e) { $(this.el).text("Could not render chart"); } }, receive_data: function(args) { if (! $(this.workspace.toolbar.el).find('.chart').hasClass('on')) { return; } return _.delay(this.process_data, 0, args); }, process_data: function(args) { this.data = {}; this.data.resultset = []; this.data.metadata = []; this.data.height = 0; this.data.width = 0; var cellset = args.data.cellset; if (cellset && cellset.length > 0) { var lowest_level = 0; var data_start = 0; for (var row = 0; data_start == 0 && row < cellset.length; row++) { this.data.metadata = []; for (var field = 0; field < cellset[row].length; field++) { var firstHeader = []; while (cellset[row][field].type == "COLUMN_HEADER" && cellset[row][field].value == "null") { row++; } if (cellset[row][field].type == "ROW_HEADER_HEADER") { while(cellset[row][field].type == "ROW_HEADER_HEADER") { firstHeader.push(cellset[row][field].value); field++; } this.data.metadata.push({ colIndex: 0, colType: "String", colName: firstHeader.join('/') }); lowest_level = field - 1; } if (cellset[row][field].type == "COLUMN_HEADER" && cellset[row][field].value != "null") { var lowest_col_header = 0; var colheader = []; while(lowest_col_header <= row) { colheader.push(cellset[lowest_col_header][field].value); lowest_col_header++; } this.data.metadata.push({ colIndex: field - lowest_level + 1, colType: "Numeric", colName: colheader.join('/') }); data_start = row+1; } } } var labelsSet = {}; for (var row = data_start; row < cellset.length; row++) { if (cellset[row][0].value !== "") { var record = []; this.data.width = cellset[row].length - lowest_level + 1; var label = ""; for (var labelCol = lowest_level; labelCol >= 0; labelCol--) { var lastKnownUpperLevelRow = row; while(cellset[lastKnownUpperLevelRow] && cellset[lastKnownUpperLevelRow][labelCol].value === 'null') { --lastKnownUpperLevelRow; } if(cellset[lastKnownUpperLevelRow]) { if (label == "") { label = cellset[lastKnownUpperLevelRow][labelCol].value; } else { label = cellset[lastKnownUpperLevelRow][labelCol].value + " / " + label; } } } if(label in labelsSet) { labelsSet[label] = labelsSet[label]+1; label = label + ' [' + (labelsSet[label] + 1) + ']'; } else { labelsSet[label] = 0; } record.push(label); for (var col = lowest_level + 1; col < cellset[row].length; col++) { var cell = cellset[row][col]; var value = cell.value || 0; // check if the resultset contains the raw value, if not try to parse the given value var raw = cell.properties.raw; if (raw && raw !== "null") { value = parseFloat(raw); } else if (typeof(cell.value) !== "number" && parseFloat(cell.value.replace(/[^a-zA-Z 0-9.]+/g,''))) { value = parseFloat(cell.value.replace(/[^a-zA-Z 0-9.]+/g,'')); } record.push(value); } this.data.resultset.push(record); } } //makeSureUniqueLabels(this.data.resultset); this.data.height = this.data.resultset.length; this.render(); } else { $(this.el).text("No results"); } } }); /** * Loads CCC and initializes chart plugin */ (function() { // Initialize CCC $.ajax({ url: "js/saiku/plugins/Chart/ccc.js", dataType: "script", cache: true, success: function() { var initPlugin = function(session) { function new_workspace(args) { // Add chart element if (typeof args.workspace.chart == "undefined") { args.workspace.chart = new Chart({ workspace: args.workspace }); } } function clear_workspace(args) { if (typeof args.workspace.chart != "undefined") { $(args.workspace.chart.nav).hide(); $(args.workspace.chart.el).hide(); $(args.workspace.chart.el).parents().find('.workspace_results table').show(); } } // Attach chart to existing tabs for(var i = 0; i < Saiku.tabs._tabs.length; i++) { var tab = Saiku.tabs._tabs[i]; new_workspace({ workspace: tab.content }); }; // Attach chart to future tabs session.bind("workspace:new", new_workspace); session.bind("workspace:clear", clear_workspace); }; if (typeof Saiku.session == "undefined") { Saiku.events.bind('session:new', initPlugin); } else { initPlugin(Saiku.session); } } }); }());