123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676 |
- /**
- * Chart type enumerations
- */
- var ChartType = {
- LINE : 'line',
- SPLINE : 'spline',
- AREA : 'area',
- BAR : 'bar',
- COLUMN : 'column',
- PIE : 'pie',
- TIMELINE: 'timeline',
- SCATTER: 'scatter'
- };
- /**
- * Column type enumeration
- */
- var ColumnType = {
- STRING : 'string',
- NUMBER : 'number',
- BOOLEAN : 'boolean',
- DATE : 'date'
- };
- /**
- * Abstract chart factory which defines the contract for chart factories
- */
- var ChartFactory = function () {
- };
- ChartFactory.prototype = {
- createChart : function (type, options) {
- throw new Error('createChart must be implemented by a subclass');
- }
- };
- /**
- * Abstract chart which defines the contract for charts
- *
- * @param elementId
- * id of the div element the chart is drawn in
- */
- var Chart = function (elementId) {
- this.elementId = elementId;
- };
- Chart.prototype = {
- draw : function (data, options) {
- throw new Error('draw must be implemented by a subclass');
- },
- redraw : function (options) {
- throw new Error('redraw must be implemented by a subclass');
- },
- destroy : function () {
- throw new Error('destroy must be implemented by a subclass');
- },
- toImageString : function () {
- throw new Error('toImageString must be implemented by a subclass');
- }
- };
- /**
- * Abstract representation of charts that operates on DataTable where,<br />
- * <ul>
- * <li>First column provides index to the data.</li>
- * <li>Each subsequent columns are of type
- * <code>ColumnType.NUMBER<code> and represents a data series.</li>
- * </ul>
- * Line chart, area chart, bar chart, column chart are typical examples.
- *
- * @param elementId
- * id of the div element the chart is drawn in
- */
- var BaseChart = function (elementId) {
- Chart.call(this, elementId);
- };
- BaseChart.prototype = new Chart();
- BaseChart.prototype.constructor = BaseChart;
- BaseChart.prototype.validateColumns = function (dataTable) {
- var columns = dataTable.getColumns();
- if (columns.length < 2) {
- throw new Error('Minimum of two columns are required for this chart');
- }
- for (var i = 1; i < columns.length; i++) {
- if (columns[i].type !== ColumnType.NUMBER) {
- throw new Error('Column ' + (i + 1) + ' should be of type \'Number\'');
- }
- }
- return true;
- };
- /**
- * Abstract pie chart
- *
- * @param elementId
- * id of the div element the chart is drawn in
- */
- var PieChart = function (elementId) {
- BaseChart.call(this, elementId);
- };
- PieChart.prototype = new BaseChart();
- PieChart.prototype.constructor = PieChart;
- PieChart.prototype.validateColumns = function (dataTable) {
- var columns = dataTable.getColumns();
- if (columns.length > 2) {
- throw new Error('Pie charts can draw only one series');
- }
- return BaseChart.prototype.validateColumns.call(this, dataTable);
- };
- /**
- * Abstract timeline chart
- *
- * @param elementId
- * id of the div element the chart is drawn in
- */
- var TimelineChart = function (elementId) {
- BaseChart.call(this, elementId);
- };
- TimelineChart.prototype = new BaseChart();
- TimelineChart.prototype.constructor = TimelineChart;
- TimelineChart.prototype.validateColumns = function (dataTable) {
- var result = BaseChart.prototype.validateColumns.call(this, dataTable);
- if (result) {
- var columns = dataTable.getColumns();
- if (columns[0].type !== ColumnType.DATE) {
- throw new Error('First column of timeline chart need to be a date column');
- }
- }
- return result;
- };
- /**
- * Abstract scatter chart
- *
- * @param elementId
- * id of the div element the chart is drawn in
- */
- var ScatterChart = function (elementId) {
- BaseChart.call(this, elementId);
- };
- ScatterChart.prototype = new BaseChart();
- ScatterChart.prototype.constructor = ScatterChart;
- ScatterChart.prototype.validateColumns = function (dataTable) {
- var result = BaseChart.prototype.validateColumns.call(this, dataTable);
- if (result) {
- var columns = dataTable.getColumns();
- if (columns[0].type !== ColumnType.NUMBER) {
- throw new Error('First column of scatter chart need to be a numeric column');
- }
- }
- return result;
- };
- /**
- * The data table contains column information and data for the chart.
- */
- var DataTable = function () {
- var columns = [];
- var data = null;
- this.addColumn = function (type, name) {
- columns.push({
- 'type' : type,
- 'name' : name
- });
- };
- this.getColumns = function () {
- return columns;
- };
- this.setData = function (rows) {
- data = rows;
- fillMissingValues();
- };
- this.getData = function () {
- return data;
- };
- var fillMissingValues = function () {
- if (columns.length === 0) {
- throw new Error('Set columns first');
- }
- var row;
- for (var i = 0; i < data.length; i++) {
- row = data[i];
- if (row.length > columns.length) {
- row.splice(columns.length - 1, row.length - columns.length);
- } else if (row.length < columns.length) {
- for (var j = row.length; j < columns.length; j++) {
- row.push(null);
- }
- }
- }
- };
- };
- /** *****************************************************************************
- * JQPlot specific code
- ******************************************************************************/
- /**
- * Abstract JQplot chart
- *
- * @param elementId
- * id of the div element the chart is drawn in
- */
- var JQPlotChart = function (elementId) {
- Chart.call(this, elementId);
- this.plot = null;
- this.validator = null;
- };
- JQPlotChart.prototype = new Chart();
- JQPlotChart.prototype.constructor = JQPlotChart;
- JQPlotChart.prototype.draw = function (data, options) {
- if (this.validator.validateColumns(data)) {
- this.plot = $.jqplot(this.elementId, this.prepareData(data), this
- .populateOptions(data, options));
- }
- };
- JQPlotChart.prototype.destroy = function () {
- if (this.plot !== null) {
- this.plot.destroy();
- }
- };
- JQPlotChart.prototype.redraw = function (options) {
- if (this.plot !== null) {
- this.plot.replot(options);
- }
- };
- JQPlotChart.prototype.toImageString = function (options) {
- if (this.plot !== null) {
- return $('#' + this.elementId).jqplotToImageStr({});
- }
- };
- JQPlotChart.prototype.populateOptions = function (dataTable, options) {
- throw new Error('populateOptions must be implemented by a subclass');
- };
- JQPlotChart.prototype.prepareData = function (dataTable) {
- throw new Error('prepareData must be implemented by a subclass');
- };
- /**
- * JQPlot line chart
- *
- * @param elementId
- * id of the div element the chart is drawn in
- */
- var JQPlotLineChart = function (elementId) {
- JQPlotChart.call(this, elementId);
- this.validator = BaseChart.prototype;
- };
- JQPlotLineChart.prototype = new JQPlotChart();
- JQPlotLineChart.prototype.constructor = JQPlotLineChart;
- JQPlotLineChart.prototype.populateOptions = function (dataTable, options) {
- var columns = dataTable.getColumns();
- var optional = {
- axes : {
- xaxis : {
- label : columns[0].name,
- renderer : $.jqplot.CategoryAxisRenderer,
- ticks : []
- },
- yaxis : {
- label : (columns.length === 2 ? columns[1].name : 'Values'),
- labelRenderer : $.jqplot.CanvasAxisLabelRenderer
- }
- },
- highlighter: {
- show: true,
- tooltipAxes: 'y',
- formatString:'%d'
- },
- series : []
- };
- $.extend(true, optional, options);
- if (optional.series.length === 0) {
- for (var i = 1; i < columns.length; i++) {
- optional.series.push({
- label : columns[i].name.toString()
- });
- }
- }
- if (optional.axes.xaxis.ticks.length === 0) {
- var data = dataTable.getData();
- for (var j = 0; j < data.length; j++) {
- optional.axes.xaxis.ticks.push(data[j][0].toString());
- }
- }
- return optional;
- };
- JQPlotLineChart.prototype.prepareData = function (dataTable) {
- var data = dataTable.getData();
- var row;
- var retData = [];
- var retRow;
- for (var i = 0; i < data.length; i++) {
- row = data[i];
- for (var j = 1; j < row.length; j++) {
- retRow = retData[j - 1];
- if (retRow === undefined) {
- retRow = [];
- retData[j - 1] = retRow;
- }
- retRow.push(row[j]);
- }
- }
- return retData;
- };
- /**
- * JQPlot spline chart
- *
- * @param elementId
- * id of the div element the chart is drawn in
- */
- var JQPlotSplineChart = function (elementId) {
- JQPlotLineChart.call(this, elementId);
- };
- JQPlotSplineChart.prototype = new JQPlotLineChart();
- JQPlotSplineChart.prototype.constructor = JQPlotSplineChart;
- JQPlotSplineChart.prototype.populateOptions = function (dataTable, options) {
- var optional = {};
- var opt = JQPlotLineChart.prototype.populateOptions.call(this, dataTable,
- options);
- var compulsory = {
- seriesDefaults : {
- rendererOptions : {
- smooth : true
- }
- }
- };
- $.extend(true, optional, opt, compulsory);
- return optional;
- };
- /**
- * JQPlot scatter chart
- *
- * @param elementId
- * id of the div element the chart is drawn in
- */
- var JQPlotScatterChart = function (elementId) {
- JQPlotChart.call(this, elementId);
- this.validator = ScatterChart.prototype;
- };
- JQPlotScatterChart.prototype = new JQPlotChart();
- JQPlotScatterChart.prototype.constructor = JQPlotScatterChart;
- JQPlotScatterChart.prototype.populateOptions = function (dataTable, options) {
- var columns = dataTable.getColumns();
- var optional = {
- axes : {
- xaxis : {
- label : columns[0].name
- },
- yaxis : {
- label : (columns.length === 2 ? columns[1].name : 'Values'),
- labelRenderer : $.jqplot.CanvasAxisLabelRenderer
- }
- },
- highlighter: {
- show: true,
- tooltipAxes: 'xy',
- formatString:'%d, %d'
- },
- series : []
- };
- for (var i = 1; i < columns.length; i++) {
- optional.series.push({
- label : columns[i].name.toString()
- });
- }
- var compulsory = {
- seriesDefaults : {
- showLine: false,
- markerOptions: {
- size: 7,
- style: 'x'
- }
- }
- };
- $.extend(true, optional, options, compulsory);
- return optional;
- };
- JQPlotScatterChart.prototype.prepareData = function (dataTable) {
- var data = dataTable.getData();
- var row;
- var retData = [];
- var retRow;
- for (var i = 0; i < data.length; i++) {
- row = data[i];
- if (row[0]) {
- for (var j = 1; j < row.length; j++) {
- retRow = retData[j - 1];
- if (retRow === undefined) {
- retRow = [];
- retData[j - 1] = retRow;
- }
- retRow.push([row[0], row[j]]);
- }
- }
- }
- return retData;
- };
- /**
- * JQPlot timeline chart
- *
- * @param elementId
- * id of the div element the chart is drawn in
- */
- var JQPlotTimelineChart = function (elementId) {
- JQPlotLineChart.call(this, elementId);
- this.validator = TimelineChart.prototype;
- };
- JQPlotTimelineChart.prototype = new JQPlotLineChart();
- JQPlotTimelineChart.prototype.constructor = JQPlotTimelineChart;
- JQPlotTimelineChart.prototype.populateOptions = function (dataTable, options) {
- var optional = {
- axes : {
- xaxis : {
- tickOptions : {
- formatString: '%b %#d, %y'
- }
- }
- }
- };
- var opt = JQPlotLineChart.prototype.populateOptions.call(this, dataTable, options);
- var compulsory = {
- axes : {
- xaxis : {
- renderer : $.jqplot.DateAxisRenderer
- }
- }
- };
- $.extend(true, optional, opt, compulsory);
- return optional;
- };
- JQPlotTimelineChart.prototype.prepareData = function (dataTable) {
- var data = dataTable.getData();
- var row;
- var d;
- var retData = [];
- var retRow;
- for (var i = 0; i < data.length; i++) {
- row = data[i];
- d = row[0];
- for (var j = 1; j < row.length; j++) {
- retRow = retData[j - 1];
- if (retRow === undefined) {
- retRow = [];
- retData[j - 1] = retRow;
- }
- if (d !== null) {
- retRow.push([d.getTime(), row[j]]);
- }
- }
- }
- return retData;
- };
- /**
- * JQPlot area chart
- *
- * @param elementId
- * id of the div element the chart is drawn in
- */
- var JQPlotAreaChart = function (elementId) {
- JQPlotLineChart.call(this, elementId);
- };
- JQPlotAreaChart.prototype = new JQPlotLineChart();
- JQPlotAreaChart.prototype.constructor = JQPlotAreaChart;
- JQPlotAreaChart.prototype.populateOptions = function (dataTable, options) {
- var optional = {
- seriesDefaults : {
- fillToZero : true
- }
- };
- var opt = JQPlotLineChart.prototype.populateOptions.call(this, dataTable,
- options);
- var compulsory = {
- seriesDefaults : {
- fill : true
- }
- };
- $.extend(true, optional, opt, compulsory);
- return optional;
- };
- /**
- * JQPlot column chart
- *
- * @param elementId
- * id of the div element the chart is drawn in
- */
- var JQPlotColumnChart = function (elementId) {
- JQPlotLineChart.call(this, elementId);
- };
- JQPlotColumnChart.prototype = new JQPlotLineChart();
- JQPlotColumnChart.prototype.constructor = JQPlotColumnChart;
- JQPlotColumnChart.prototype.populateOptions = function (dataTable, options) {
- var optional = {
- seriesDefaults : {
- fillToZero : true
- }
- };
- var opt = JQPlotLineChart.prototype.populateOptions.call(this, dataTable,
- options);
- var compulsory = {
- seriesDefaults : {
- renderer : $.jqplot.BarRenderer
- }
- };
- $.extend(true, optional, opt, compulsory);
- return optional;
- };
- /**
- * JQPlot bar chart
- *
- * @param elementId
- * id of the div element the chart is drawn in
- */
- var JQPlotBarChart = function (elementId) {
- JQPlotLineChart.call(this, elementId);
- };
- JQPlotBarChart.prototype = new JQPlotLineChart();
- JQPlotBarChart.prototype.constructor = JQPlotBarChart;
- JQPlotBarChart.prototype.populateOptions = function (dataTable, options) {
- var columns = dataTable.getColumns();
- var optional = {
- axes : {
- yaxis : {
- label : columns[0].name,
- labelRenderer : $.jqplot.CanvasAxisLabelRenderer,
- renderer : $.jqplot.CategoryAxisRenderer,
- ticks : []
- },
- xaxis : {
- label : (columns.length === 2 ? columns[1].name : 'Values'),
- labelRenderer : $.jqplot.CanvasAxisLabelRenderer
- }
- },
- highlighter: {
- show: true,
- tooltipAxes: 'x',
- formatString:'%d'
- },
- series : [],
- seriesDefaults : {
- fillToZero : true
- }
- };
- var compulsory = {
- seriesDefaults : {
- renderer : $.jqplot.BarRenderer,
- rendererOptions : {
- barDirection : 'horizontal'
- }
- }
- };
- $.extend(true, optional, options, compulsory);
- if (optional.axes.yaxis.ticks.length === 0) {
- var data = dataTable.getData();
- for (var i = 0; i < data.length; i++) {
- optional.axes.yaxis.ticks.push(data[i][0].toString());
- }
- }
- if (optional.series.length === 0) {
- for (var j = 1; j < columns.length; j++) {
- optional.series.push({
- label : columns[j].name.toString()
- });
- }
- }
- return optional;
- };
- /**
- * JQPlot pie chart
- *
- * @param elementId
- * id of the div element the chart is drawn in
- */
- var JQPlotPieChart = function (elementId) {
- JQPlotChart.call(this, elementId);
- this.validator = PieChart.prototype;
- };
- JQPlotPieChart.prototype = new JQPlotChart();
- JQPlotPieChart.prototype.constructor = JQPlotPieChart;
- JQPlotPieChart.prototype.populateOptions = function (dataTable, options) {
- var optional = {
- highlighter: {
- show: true,
- tooltipAxes: 'xy',
- formatString:'%s, %d',
- useAxesFormatters: false
- },
- legend: {
- renderer: $.jqplot.EnhancedPieLegendRenderer,
- },
- };
- var compulsory = {
- seriesDefaults : {
- shadow: false,
- renderer : $.jqplot.PieRenderer,
- rendererOptions: { sliceMargin: 1, showDataLabels: true }
- }
- };
- $.extend(true, optional, options, compulsory);
- return optional;
- };
- JQPlotPieChart.prototype.prepareData = function (dataTable) {
- var data = dataTable.getData();
- var row;
- var retData = [];
- for (var i = 0; i < data.length; i++) {
- row = data[i];
- retData.push([row[0], row[1]]);
- }
- return [retData];
- };
- /**
- * Chart factory that returns JQPlotCharts
- */
- var JQPlotChartFactory = function () {
- };
- JQPlotChartFactory.prototype = new ChartFactory();
- JQPlotChartFactory.prototype.createChart = function (type, elementId) {
- var chart = null;
- switch (type) {
- case ChartType.LINE:
- chart = new JQPlotLineChart(elementId);
- break;
- case ChartType.SPLINE:
- chart = new JQPlotSplineChart(elementId);
- break;
- case ChartType.TIMELINE:
- chart = new JQPlotTimelineChart(elementId);
- break;
- case ChartType.AREA:
- chart = new JQPlotAreaChart(elementId);
- break;
- case ChartType.BAR:
- chart = new JQPlotBarChart(elementId);
- break;
- case ChartType.COLUMN:
- chart = new JQPlotColumnChart(elementId);
- break;
- case ChartType.PIE:
- chart = new JQPlotPieChart(elementId);
- break;
- case ChartType.SCATTER:
- chart = new JQPlotScatterChart(elementId);
- break;
- }
- return chart;
- };
|