diff options
Diffstat (limited to 'js/dojo/dojox/widget/DataPresentation.js')
| -rw-r--r-- | js/dojo/dojox/widget/DataPresentation.js | 902 |
1 files changed, 902 insertions, 0 deletions
diff --git a/js/dojo/dojox/widget/DataPresentation.js b/js/dojo/dojox/widget/DataPresentation.js new file mode 100644 index 0000000..f616445 --- /dev/null +++ b/js/dojo/dojox/widget/DataPresentation.js @@ -0,0 +1,902 @@ +//>>built +// wrapped by build app +define("dojox/widget/DataPresentation", ["dijit","dojo","dojox","dojo/require!dojox/grid/DataGrid,dojox/charting/Chart2D,dojox/charting/widget/Legend,dojox/charting/action2d/Tooltip,dojox/charting/action2d/Highlight,dojo/colors,dojo/data/ItemFileWriteStore"], function(dijit,dojo,dojox){ +dojo.provide("dojox.widget.DataPresentation"); +dojo.experimental("dojox.widget.DataPresentation"); + +dojo.require("dojox.grid.DataGrid"); +dojo.require("dojox.charting.Chart2D"); +dojo.require("dojox.charting.widget.Legend"); +dojo.require("dojox.charting.action2d.Tooltip"); +dojo.require("dojox.charting.action2d.Highlight"); +dojo.require("dojo.colors"); +dojo.require("dojo.data.ItemFileWriteStore"); + +(function(){ + + // sort out the labels for the independent axis of the chart + var getLabels = function(range, labelMod, charttype, domNode){ + + // prepare labels for the independent axis + var labels = []; + // add empty label, hack + labels[0] = {value: 0, text: ''}; + + var nlabels = range.length; + + // auto-set labelMod for horizontal charts if the labels will otherwise collide + if((charttype !== "ClusteredBars") && (charttype !== "StackedBars")){ + var cwid = domNode.offsetWidth; + var tmp = ("" + range[0]).length * range.length * 7; // *assume* 7 pixels width per character ( was 9 ) + + if(labelMod == 1){ + for(var z = 1; z < 500; ++z){ + if((tmp / z) < cwid){ + break; + } + ++labelMod; + } + } + } + + // now set the labels + for(var i = 0; i < nlabels; i++){ + //sparse labels + labels.push({ + value: i + 1, + text: (!labelMod || i % labelMod) ? "" : range[i] + }); + } + + // add empty label again, hack + labels.push({value: nlabels + 1, text:''}); + + return labels; + }; + + // get the configuration of an independent axis for the chart + var getIndependentAxisArgs = function(charttype, labels){ + + var args = { vertical: false, labels: labels, min: 0, max: labels.length-1, majorTickStep: 1, minorTickStep: 1 }; + + // clustered or stacked bars have a vertical independent axis + if((charttype === "ClusteredBars") || (charttype === "StackedBars")){ + args.vertical = true; + } + + // lines, areas and stacked areas don't need the extra slots at each end + if((charttype === "Lines") || (charttype === "Areas") || (charttype === "StackedAreas")){ + args.min++; + args.max--; + } + + return args; + }; + + // get the configuration of a dependent axis for the chart + var getDependentAxisArgs = function(charttype, axistype, minval, maxval){ + + var args = { vertical: true, fixLower: "major", fixUpper: "major", natural: true }; + + // secondary dependent axis is not left-bottom + if(axistype === "secondary"){ + args.leftBottom = false; + } + + // clustered or stacked bars have horizontal dependent axes + if((charttype === "ClusteredBars") || (charttype === "StackedBars")){ + args.vertical = false; + } + + // ensure axis does not "collapse" for flat series + if(minval == maxval){ + args.min = minval - 1; + args.max = maxval + 1; + } + + return args; + }; + + // get the configuration of a plot for the chart + var getPlotArgs = function(charttype, axistype, animate){ + + var args = { type: charttype, hAxis: "independent", vAxis: "dependent-" + axistype, gap: 4, lines: false, areas: false, markers: false }; + + // clustered or stacked bars have horizontal dependent axes + if((charttype === "ClusteredBars") || (charttype === "StackedBars")){ + args.hAxis = args.vAxis; + args.vAxis = "independent"; + } + + // turn on lines for Lines, Areas and StackedAreas + if((charttype === "Lines") || (charttype === "Hybrid-Lines") || (charttype === "Areas") || (charttype === "StackedAreas")){ + args.lines = true; + } + + // turn on areas for Areas and StackedAreas + if((charttype === "Areas") || (charttype === "StackedAreas")){ + args.areas = true; + } + + // turn on markers and shadow for Lines + if(charttype === "Lines"){ + args.markers = true; + } + + // turn on shadow for Hybrid-Lines + // also, Hybrid-Lines is not a true chart type: use Lines for the actual plot + if(charttype === "Hybrid-Lines"){ + args.shadows = {dx: 2, dy: 2, dw: 2}; + args.type = "Lines"; + } + + // also, Hybrid-ClusteredColumns is not a true chart type: use ClusteredColumns for the actual plot + if(charttype === "Hybrid-ClusteredColumns"){ + args.type = "ClusteredColumns"; + } + + // enable animation on the plot if animation is requested + if(animate){ + args.animate = animate; + } + + return args; + }; + + // set up a chart presentation + var setupChart = function(/*DomNode*/domNode, /*Object?*/chart, /*String*/type, /*Boolean*/reverse, /*Object*/animate, /*Integer*/labelMod, /*String*/theme, /*String*/tooltip, /*Object?*/store, /*String?*/query, /*String?*/queryOptions){ + var _chart = chart; + + if(!_chart){ + domNode.innerHTML = ""; // any other content in the node disrupts the chart rendering + _chart = new dojox.charting.Chart2D(domNode); + } + + // set the theme + if(theme){ + + // workaround for a theme bug: its _clone method + // does not transfer the markers, so we repair + // that omission here + // FIXME this should be removed once the theme bug is fixed + theme._clone = function(){ + var result = new dojox.charting.Theme({ + chart: this.chart, + plotarea: this.plotarea, + axis: this.axis, + series: this.series, + marker: this.marker, + antiAlias: this.antiAlias, + assignColors: this.assignColors, + assignMarkers: this.assigneMarkers, + colors: dojo.delegate(this.colors) + }); + + result.markers = this.markers; + result._buildMarkerArray(); + + return result; + }; + + _chart.setTheme(theme); + } + + var range = store.series_data[0].slice(0); + + // reverse the labels if requested + if(reverse){ + range.reverse(); + } + + var labels = getLabels(range, labelMod, type, domNode); + + // collect details of whether primary and/or secondary axes are required + // and what plots we have instantiated using each type of axis + var plots = {}; + + // collect maximum and minimum data values + var maxval = null; + var minval = null; + + var seriestoremove = {}; + for(var sname in _chart.runs){ + seriestoremove[sname] = true; + } + + // set x values & max data value + var nseries = store.series_name.length; + for(var i = 0; i < nseries; i++){ + // only include series with chart=true and with some data values in + if(store.series_chart[i] && (store.series_data[i].length > 0)){ + + var charttype = type; + var axistype = store.series_axis[i]; + + if(charttype == "Hybrid"){ + if(store.series_charttype[i] == 'line'){ + charttype = "Hybrid-Lines"; + }else{ + charttype = "Hybrid-ClusteredColumns"; + } + } + + // ensure we have recorded that we are using this axis type + if(!plots[axistype]){ + plots[axistype] = {}; + } + + // ensure we have the correct type of plot for this series + if(!plots[axistype][charttype]){ + var axisname = axistype + "-" + charttype; + + // create the plot and enable tooltips + _chart.addPlot(axisname, getPlotArgs(charttype, axistype, animate)); + + var tooltipArgs = {}; + if(typeof tooltip == 'string'){ + tooltipArgs.text = function(o){ + var substitutions = [o.element, o.run.name, range[o.index], ((charttype === "ClusteredBars") || (charttype === "StackedBars")) ? o.x : o.y]; + return dojo.replace(tooltip, substitutions); // from Dojo 1.4 onward + //return tooltip.replace(/\{([^\}]+)\}/g, function(_, token){ return dojo.getObject(token, false, substitutions); }); // prior to Dojo 1.4 + } + }else if(typeof tooltip == 'function'){ + tooltipArgs.text = tooltip; + } + new dojox.charting.action2d.Tooltip(_chart, axisname, tooltipArgs); + + // add highlighting, except for lines + if(charttype !== "Lines" && charttype !== "Hybrid-Lines"){ + new dojox.charting.action2d.Highlight(_chart, axisname); + } + + // record that this plot type is now created + plots[axistype][charttype] = true; + } + + // extract the series values + var xvals = []; + var valen = store.series_data[i].length; + for(var j = 0; j < valen; j++){ + var val = store.series_data[i][j]; + xvals.push(val); + if(maxval === null || val > maxval){ + maxval = val; + } + if(minval === null || val < minval){ + minval = val; + } + } + + // reverse the values if requested + if(reverse){ + xvals.reverse(); + } + + var seriesargs = { plot: axistype + "-" + charttype }; + if(store.series_linestyle[i]){ + seriesargs.stroke = { style: store.series_linestyle[i] }; + } + + _chart.addSeries(store.series_name[i], xvals, seriesargs); + delete seriestoremove[store.series_name[i]]; + } + } + + // remove any series that are no longer needed + for(sname in seriestoremove){ + _chart.removeSeries(sname); + } + + // create axes + _chart.addAxis("independent", getIndependentAxisArgs(type, labels)); + _chart.addAxis("dependent-primary", getDependentAxisArgs(type, "primary", minval, maxval)); + _chart.addAxis("dependent-secondary", getDependentAxisArgs(type, "secondary", minval, maxval)); + + return _chart; + }; + + // set up a legend presentation + var setupLegend = function(/*DomNode*/domNode, /*Legend*/legend, /*Chart2D*/chart, /*Boolean*/horizontal){ + // destroy any existing legend and recreate + var _legend = legend; + + if(!_legend){ + _legend = new dojox.charting.widget.Legend({ chart: chart, horizontal: horizontal }, domNode); + }else{ + _legend.refresh(); + } + + return _legend; + }; + + // set up a grid presentation + var setupGrid = function(/*DomNode*/domNode, /*Object?*/grid, /*Object?*/store, /*String?*/query, /*String?*/queryOptions){ + var _grid = grid || new dojox.grid.DataGrid({}, domNode); + _grid.startup(); + _grid.setStore(store, query, queryOptions); + + var structure = []; + for(var ser = 0; ser < store.series_name.length; ser++){ + // only include series with grid=true and with some data values in + if(store.series_grid[ser] && (store.series_data[ser].length > 0)){ + structure.push({ field: "data." + ser, name: store.series_name[ser], width: "auto", formatter: store.series_gridformatter[ser] }); + } + } + + _grid.setStructure(structure); + + return _grid; + }; + + // set up a title presentation + var setupTitle = function(/*DomNode*/domNode, /*object*/store){ + if(store.title){ + domNode.innerHTML = store.title; + } + }; + + // set up a footer presentation + var setupFooter = function(/*DomNode*/domNode, /*object*/store){ + if(store.footer){ + domNode.innerHTML = store.footer; + } + }; + + // obtain a subfield from a field specifier which may contain + // multiple levels (eg, "child.foo[36].manacle") + var getSubfield = function(/*Object*/object, /*String*/field){ + var result = object; + + if(field){ + var fragments = field.split(/[.\[\]]+/); + for(var frag = 0, l = fragments.length; frag < l; frag++){ + if(result){ + result = result[fragments[frag]]; + } + } + } + + return result; + }; + + dojo.declare("dojox.widget.DataPresentation", null, { + // summary: + // + // DataPresentation + // + // A widget that connects to a data store in a simple manner, + // and also provides some additional convenience mechanisms + // for connecting to common data sources without needing to + // explicitly construct a Dojo data store. The widget can then + // present the data in several forms: as a graphical chart, + // as a tabular grid, or as display panels presenting meta-data + // (title, creation information, etc) from the data. The + // widget can also create and manage several of these forms + // in one simple construction. + // + // Note: this is a first experimental draft and any/all details + // are subject to substantial change in later drafts. + // + // example: + // + // var pres = new dojox.data.DataPresentation("myChartNode", { + // type: "chart", + // url: "/data/mydata", + // gridNode: "myGridNode" + // }); + // + // properties: + // + // store: Object + // Dojo data store used to supply data to be presented. This may + // be supplied on construction or created implicitly based on + // other construction parameters ('data', 'url'). + // + // query: String + // Query to apply to the Dojo data store used to supply data to + // be presented. + // + // queryOptions: String + // Query options to apply to the Dojo data store used to supply + // data to be presented. + // + // data: Object + // Data to be presented. If supplied on construction this property + // will override any value supplied for the 'store' property. + // + // url: String + // URL to fetch data from in JSON format. If supplied on + // construction this property will override any values supplied + // for the 'store' and/or 'data' properties. Note that the data + // can also be comment-filtered JSON, although this will trigger + // a warning message in the console unless djConfig.useCommentedJson + // has been set to true. + // + // urlContent: Object + // Content to be passed to the URL when fetching data. If a URL has + // not been supplied, this value is ignored. + // + // urlError: function + // A function to be called if an error is encountered when fetching + // data from the supplied URL. This function will be supplied with + // two parameters exactly as the error function supplied to the + // dojo.xhrGet function. This function may be called multiple times + // if a refresh interval has been supplied. + // + // refreshInterval: Number + // the time interval in milliseconds after which the data supplied + // via the 'data' property or fetched from a URL via the 'url' + // property should be regularly refreshed. This property is + // ignored if neither the 'data' nor 'url' property has been + // supplied. If the refresh interval is zero, no regular refresh is done. + // + // refreshIntervalPending: + // the JavaScript set interval currently in progress, if any + // + // series: Array + // an array of objects describing the data series to be included + // in the data presentation. Each object may contain the + // following fields: + // datapoints: the name of the field from the source data which + // contains an array of the data points for this data series. + // If not supplied, the source data is assumed to be an array + // of data points to be used. + // field: the name of the field within each data point which + // contains the data for this data series. If not supplied, + // each data point is assumed to be the value for the series. + // name: a name for the series, used in the legend and grid headings + // namefield: the name of the field from the source data which + // contains the name the series, used in the legend and grid + // headings. If both name and namefield are supplied, name takes + // precedence. If neither are supplied, a default name is used. + // chart: true if the series should be included in a chart presentation (default: true) + // charttype: the type of presentation of the series in the chart, which can be + // "range", "line", "bar" (default: "bar") + // linestyle: the stroke style for lines (if applicable) (default: "Solid") + // axis: the dependant axis to which the series will be attached in the chart, + // which can be "primary" or "secondary" + // grid: true if the series should be included in a data grid presentation (default: true) + // gridformatter: an optional formatter to use for this series in the data grid + // + // a call-back function may alternatively be supplied. The function takes + // a single parameter, which will be the data (from the 'data' field or + // loaded from the value in the 'url' field), and should return the array + // of objects describing the data series to be included in the data + // presentation. This enables the series structures to be built dynamically + // after data load, and rebuilt if necessary on data refresh. The call-back + // function will be called each time new data is set, loaded or refreshed. + // A call-back function cannot be used if the data is supplied directly + // from a Dojo data store. + // + // type: String + // the type of presentation to be applied at the DOM attach point. + // This can be 'chart', 'legend', 'grid', 'title', 'footer'. The + // default type is 'chart'. + type: "chart", + // + // chartType: String + // the type of chart to display. This can be 'clusteredbars', + // 'areas', 'stackedcolumns', 'stackedbars', 'stackedareas', + // 'lines', 'hybrid'. The default type is 'bar'. + chartType: "clusteredBars", + // + // reverse: Boolean + // true if the chart independant axis should be reversed. + reverse: false, + // + // animate: Object + // if an object is supplied, then the chart bars or columns will animate + // into place. If the object contains a field 'duration' then the value + // supplied is the duration of the animation in milliseconds, otherwise + // a default duration is used. A boolean value true can alternatively be + // supplied to enable animation with the default duration. + // The default is null (no animation). + animate: null, + // + // labelMod: Integer + // the frequency of label annotations to be included on the + // independent axis. 1=every label. 0=no labels. The default is 1. + labelMod: 1, + // + // tooltip: String | Function + // a string pattern defining the tooltip text to be applied to chart + // data points, or a function which takes a single parameter and returns + // the tooltip text to be applied to chart data points. The string pattern + // will have the following substitutions applied: + // {0} - the type of chart element ('bar', 'surface', etc) + // {1} - the name of the data series + // {2} - the independent axis value at the tooltip data point + // {3} - the series value at the tooltip data point point + // The function, if supplied, will receive a single parameter exactly + // as per the dojox.charting.action2D.Tooltip class. The default value + // is to apply the default tooltip as defined by the + // dojox.charting.action2D.Tooltip class. + // + // legendHorizontal: Boolean | Number + // true if the legend should be rendered horizontally, or a number if + // the legend should be rendered as horizontal rows with that number of + // items in each row, or false if the legend should be rendered + // vertically (same as specifying 1). The default is true (legend + // rendered horizontally). + legendHorizontal: true, + // + // theme: String|Theme + // a theme to use for the chart, or the name of a theme. + // + // chartNode: String|DomNode + // an optional DOM node or the id of a DOM node to receive a + // chart presentation of the data. Supply only when a chart is + // required and the type is not 'chart'; when the type is + // 'chart' this property will be set to the widget attach point. + // + // legendNode: String|DomNode + // an optional DOM node or the id of a DOM node to receive a + // chart legend for the data. Supply only when a legend is + // required and the type is not 'legend'; when the type is + // 'legend' this property will be set to the widget attach point. + // + // gridNode: String|DomNode + // an optional DOM node or the id of a DOM node to receive a + // grid presentation of the data. Supply only when a grid is + // required and the type is not 'grid'; when the type is + // 'grid' this property will be set to the widget attach point. + // + // titleNode: String|DomNode + // an optional DOM node or the id of a DOM node to receive a + // title for the data. Supply only when a title is + // required and the type is not 'title'; when the type is + // 'title' this property will be set to the widget attach point. + // + // footerNode: String|DomNode + // an optional DOM node or the id of a DOM node to receive a + // footer presentation of the data. Supply only when a footer is + // required and the type is not 'footer'; when the type is + // 'footer' this property will be set to the widget attach point. + // + // chartWidget: Object + // the chart widget, if any + // + // legendWidget: Object + // the legend widget, if any + // + // gridWidget: Object + // the grid widget, if any + + constructor: function(node, args){ + // summary: + // Set up properties and initialize. + // + // arguments: + // node: DomNode + // The node to attach the data presentation to. + // kwArgs: Object (see above) + + // apply arguments directly + dojo.mixin(this, args); + + // store our DOM attach point + this.domNode = dojo.byId(node); + + // also apply the DOM attach point as the node for the presentation type + this[this.type + "Node"] = this.domNode; + + // load the theme if provided by name + if(typeof this.theme == 'string'){ + this.theme = dojo.getObject(this.theme); + } + + // resolve any the nodes that were supplied as ids + this.chartNode = dojo.byId(this.chartNode); + this.legendNode = dojo.byId(this.legendNode); + this.gridNode = dojo.byId(this.gridNode); + this.titleNode = dojo.byId(this.titleNode); + this.footerNode = dojo.byId(this.footerNode); + + // we used to support a 'legendVertical' so for now + // at least maintain backward compatibility + if(this.legendVertical){ + this.legendHorizontal = !this.legendVertical; + } + + if(this.url){ + this.setURL(null, null, this.refreshInterval); + } + else{ + if(this.data){ + this.setData(null, this.refreshInterval); + } + else{ + this.setStore(); + } + } + }, + + setURL: function(/*String?*/url, /*Object?*/ urlContent, /*Number?*/refreshInterval){ + // summary: + // Sets the URL to fetch data from, with optional content + // supplied with the request, and an optional + // refresh interval in milliseconds (0=no refresh) + + // if a refresh interval is supplied we will start a fresh + // refresh after storing the supplied url + if(refreshInterval){ + this.cancelRefresh(); + } + + this.url = url || this.url; + this.urlContent = urlContent || this.urlContent; + this.refreshInterval = refreshInterval || this.refreshInterval; + + var me = this; + + dojo.xhrGet({ + url: this.url, + content: this.urlContent, + handleAs: 'json-comment-optional', + load: function(response, ioArgs){ + me.setData(response); + }, + error: function(xhr, ioArgs){ + if(me.urlError && (typeof me.urlError == "function")){ + me.urlError(xhr, ioArgs); + } + } + }); + + if(refreshInterval && (this.refreshInterval > 0)){ + this.refreshIntervalPending = setInterval(function(){ + me.setURL(); + }, this.refreshInterval); + } + }, + + setData: function(/*Object?*/data, /*Number?*/refreshInterval){ + // summary: + // Sets the data to be presented, and an optional + // refresh interval in milliseconds (0=no refresh) + + // if a refresh interval is supplied we will start a fresh + // refresh after storing the supplied data reference + if(refreshInterval){ + this.cancelRefresh(); + } + + this.data = data || this.data; + this.refreshInterval = refreshInterval || this.refreshInterval; + + // TODO if no 'series' property was provided, build one intelligently here + // (until that is done, a 'series' property must be supplied) + + var _series = (typeof this.series == 'function') ? this.series(this.data) : this.series; + + var datasets = [], + series_data = [], + series_name = [], + series_chart = [], + series_charttype = [], + series_linestyle = [], + series_axis = [], + series_grid = [], + series_gridformatter = [], + maxlen = 0; + + // identify the dataset arrays in which series values can be found + for(var ser = 0; ser < _series.length; ser++){ + datasets[ser] = getSubfield(this.data, _series[ser].datapoints); + if(datasets[ser] && (datasets[ser].length > maxlen)){ + maxlen = datasets[ser].length; + } + + series_data[ser] = []; + // name can be specified in series structure, or by field in series structure, otherwise use a default + series_name[ser] = _series[ser].name || (_series[ser].namefield ? getSubfield(this.data, _series[ser].namefield) : null) || ("series " + ser); + series_chart[ser] = (_series[ser].chart !== false); + series_charttype[ser] = _series[ser].charttype || "bar"; + series_linestyle[ser] = _series[ser].linestyle; + series_axis[ser] = _series[ser].axis || "primary"; + series_grid[ser] = (_series[ser].grid !== false); + series_gridformatter[ser] = _series[ser].gridformatter; + } + + // create an array of data points by sampling the series + // and an array of series arrays by collecting the series + // each data point has an 'index' item containing a sequence number + // and items named "data.0", "data.1", ... containing the series samples + // and the first data point also has items named "name.0", "name.1", ... containing the series names + // and items named "series.0", "series.1", ... containing arrays with the complete series in + var point, datapoint, datavalue, fdatavalue; + var datapoints = []; + + for(point = 0; point < maxlen; point++){ + datapoint = { index: point }; + for(ser = 0; ser < _series.length; ser++){ + if(datasets[ser] && (datasets[ser].length > point)){ + datavalue = getSubfield(datasets[ser][point], _series[ser].field); + + if(series_chart[ser]){ + // convert the data value to a float if possible + fdatavalue = parseFloat(datavalue); + if(!isNaN(fdatavalue)){ + datavalue = fdatavalue; + } + } + + datapoint["data." + ser] = datavalue; + series_data[ser].push(datavalue); + } + } + datapoints.push(datapoint); + } + + if(maxlen <= 0){ + datapoints.push({index: 0}); + } + + // now build a prepared store from the data points we've constructed + var store = new dojo.data.ItemFileWriteStore({ data: { identifier: 'index', items: datapoints }}); + if(this.data.title){ + store.title = this.data.title; + } + if(this.data.footer){ + store.footer = this.data.footer; + } + + store.series_data = series_data; + store.series_name = series_name; + store.series_chart = series_chart; + store.series_charttype = series_charttype; + store.series_linestyle = series_linestyle; + store.series_axis = series_axis; + store.series_grid = series_grid; + store.series_gridformatter = series_gridformatter; + + this.setPreparedStore(store); + + if(refreshInterval && (this.refreshInterval > 0)){ + var me = this; + this.refreshIntervalPending = setInterval(function(){ + me.setData(); + }, this.refreshInterval); + } + }, + + refresh: function(){ + // summary: + // If a URL or data has been supplied, refreshes the + // presented data from the URL or data. If a refresh + // interval is also set, the periodic refresh is + // restarted. If a URL or data was not supplied, this + // method has no effect. + if(this.url){ + this.setURL(this.url, this.urlContent, this.refreshInterval); + }else if(this.data){ + this.setData(this.data, this.refreshInterval); + } + }, + + cancelRefresh: function(){ + // summary: + // Cancels any and all outstanding data refreshes + if(this.refreshIntervalPending){ + // cancel existing refresh + clearInterval(this.refreshIntervalPending); + this.refreshIntervalPending = undefined; + } + }, + + setStore: function(/*Object?*/store, /*String?*/query, /*Object?*/queryOptions){ + // FIXME build a prepared store properly -- this requires too tight a convention to be followed to be useful + this.setPreparedStore(store, query, queryOptions); + }, + + setPreparedStore: function(/*Object?*/store, /*String?*/query, /*Object?*/queryOptions){ + // summary: + // Sets the store and query. + // + this.preparedstore = store || this.store; + this.query = query || this.query; + this.queryOptions = queryOptions || this.queryOptions; + + if(this.preparedstore){ + if(this.chartNode){ + this.chartWidget = setupChart(this.chartNode, this.chartWidget, this.chartType, this.reverse, this.animate, this.labelMod, this.theme, this.tooltip, this.preparedstore, this.query, this,queryOptions); + this.renderChartWidget(); + } + if(this.legendNode){ + this.legendWidget = setupLegend(this.legendNode, this.legendWidget, this.chartWidget, this.legendHorizontal); + } + if(this.gridNode){ + this.gridWidget = setupGrid(this.gridNode, this.gridWidget, this.preparedstore, this.query, this.queryOptions); + this.renderGridWidget(); + } + if(this.titleNode){ + setupTitle(this.titleNode, this.preparedstore); + } + if(this.footerNode){ + setupFooter(this.footerNode, this.preparedstore); + } + } + }, + + renderChartWidget: function(){ + // summary: + // Renders the chart widget (if any). This method is + // called whenever a chart widget is created or + // configured, and may be connected to. + if(this.chartWidget){ + this.chartWidget.render(); + } + }, + + renderGridWidget: function(){ + // summary: + // Renders the grid widget (if any). This method is + // called whenever a grid widget is created or + // configured, and may be connected to. + if(this.gridWidget){ + this.gridWidget.render(); + } + }, + + getChartWidget: function(){ + // summary: + // Returns the chart widget (if any) created if the type + // is "chart" or the "chartNode" property was supplied. + return this.chartWidget; + }, + + getGridWidget: function(){ + // summary: + // Returns the grid widget (if any) created if the type + // is "grid" or the "gridNode" property was supplied. + return this.gridWidget; + }, + + destroy: function(){ + // summary: + // Destroys the widget and all components and resources. + + // cancel any outstanding refresh requests + this.cancelRefresh(); + + if(this.chartWidget){ + this.chartWidget.destroy(); + delete this.chartWidget; + } + + if(this.legendWidget){ + // no legend.destroy() + delete this.legendWidget; + } + + if(this.gridWidget){ + // no grid.destroy() + delete this.gridWidget; + } + + if(this.chartNode){ + this.chartNode.innerHTML = ""; + } + + if(this.legendNode){ + this.legendNode.innerHTML = ""; + } + + if(this.gridNode){ + this.gridNode.innerHTML = ""; + } + + if(this.titleNode){ + this.titleNode.innerHTML = ""; + } + + if(this.footerNode){ + this.footerNode.innerHTML = ""; + } + } + + }); + +})(); + +}); |
