define("dojox/charting/DataSeries", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/array", "dojo/_base/connect", "dojox/lang/functional"], function(Lang, declare, ArrayUtil, connect, df){ return declare("dojox.charting.DataSeries", null, { constructor: function(store, kwArgs, value){ // summary: // Series adapter for dojo.data stores. // store: Object // A dojo.data store object. // kwArgs: Object // A store-specific keyword parameters used for fetching items. // See dojo/data/api/Read.fetch(). // value: Function|Object|String // Function, which takes a store, and an object handle, and // produces an output possibly inspecting the store's item. Or // a dictionary object, which tells what names to extract from // an object and how to map them to an output. Or a string, which // is a numeric field name to use for plotting. If undefined, null // or empty string (the default), "value" field is extracted. this.store = store; this.kwArgs = kwArgs; if(value){ if(Lang.isFunction(value)){ this.value = value; }else if(Lang.isObject(value)){ this.value = Lang.hitch(this, "_dictValue", df.keys(value), value); }else{ this.value = Lang.hitch(this, "_fieldValue", value); } }else{ this.value = Lang.hitch(this, "_defaultValue"); } this.data = []; this._events = []; if(this.store.getFeatures()["dojo.data.api.Notification"]){ this._events.push( connect.connect(this.store, "onNew", this, "_onStoreNew"), connect.connect(this.store, "onDelete", this, "_onStoreDelete"), connect.connect(this.store, "onSet", this, "_onStoreSet") ); } this._initialRendering = true; this.fetch(); }, destroy: function(){ // summary: // Clean up before GC. ArrayUtil.forEach(this._events, connect.disconnect); }, setSeriesObject: function(series){ // summary: // Sets a dojox.charting.Series object we will be working with. // series: dojox.charting.Series // Our interface to the chart. this.series = series; }, // value transformers _dictValue: function(keys, dict, store, item){ var o = {}; ArrayUtil.forEach(keys, function(key){ o[key] = store.getValue(item, dict[key]); }); return o; }, _fieldValue: function(field, store, item){ return store.getValue(item, field); }, _defaultValue: function(store, item){ return store.getValue(item, "value"); }, // store fetch loop fetch: function(){ // summary: // Fetches data from the store and updates a chart. if(!this._inFlight){ this._inFlight = true; var kwArgs = Lang.delegate(this.kwArgs); kwArgs.onComplete = Lang.hitch(this, "_onFetchComplete"); kwArgs.onError = Lang.hitch(this, "onFetchError"); this.store.fetch(kwArgs); } }, _onFetchComplete: function(items, request){ this.items = items; this._buildItemMap(); this.data = ArrayUtil.map(this.items, function(item){ return this.value(this.store, item); }, this); this._pushDataChanges(); this._inFlight = false; }, onFetchError: function(errorData, request){ // summary: // As stub to process fetch errors. Provide so user can attach to // it with dojo.connect(). See dojo/data/api/Read fetch() for // details: onError property. this._inFlight = false; }, _buildItemMap: function(){ if(this.store.getFeatures()["dojo.data.api.Identity"]){ var itemMap = {}; ArrayUtil.forEach(this.items, function(item, index){ itemMap[this.store.getIdentity(item)] = index; }, this); this.itemMap = itemMap; } }, _pushDataChanges: function(){ if(this.series){ this.series.chart.updateSeries(this.series.name, this, this._initialRendering); this._initialRendering = false; this.series.chart.delayedRender(); } }, // store notification handlers _onStoreNew: function(){ // the only thing we can do is to re-fetch items this.fetch(); }, _onStoreDelete: function(item){ // we cannot do anything with deleted item, the only way is to compare // items for equality if(this.items){ var flag = ArrayUtil.some(this.items, function(it, index){ if(it === item){ this.items.splice(index, 1); this._buildItemMap(); this.data.splice(index, 1); return true; } return false; }, this); if(flag){ this._pushDataChanges(); } } }, _onStoreSet: function(item){ if(this.itemMap){ // we can use our handy item map, if the store supports Identity var id = this.store.getIdentity(item), index = this.itemMap[id]; if(typeof index == "number"){ this.data[index] = this.value(this.store, this.items[index]); this._pushDataChanges(); } }else{ // otherwise we have to rely on item's equality if(this.items){ var flag = ArrayUtil.some(this.items, function(it, index){ if(it === item){ this.data[index] = this.value(this.store, it); return true; } return false; }, this); if(flag){ this._pushDataChanges(); } } } } }); });