DataSeries.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. define("dojox/charting/DataSeries", ["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/array", "dojo/_base/connect", "dojox/lang/functional"],
  2. function(Lang, declare, ArrayUtil, Hub, df){
  3. return declare("dojox.charting.DataSeries", null, {
  4. constructor: function(store, kwArgs, value){
  5. // summary:
  6. // Series adapter for dojo.data stores.
  7. // store: Object:
  8. // A dojo.data store object.
  9. // kwArgs: Object:
  10. // A store-specific keyword parameters used for fetching items.
  11. // See dojo.data.api.Read.fetch().
  12. // value: Function|Object|String|Null:
  13. // Function, which takes a store, and an object handle, and
  14. // produces an output possibly inspecting the store's item. Or
  15. // a dictionary object, which tells what names to extract from
  16. // an object and how to map them to an output. Or a string, which
  17. // is a numeric field name to use for plotting. If undefined, null
  18. // or empty string (the default), "value" field is extracted.
  19. this.store = store;
  20. this.kwArgs = kwArgs;
  21. if(value){
  22. if(Lang.isFunction(value)){
  23. this.value = value;
  24. }else if(Lang.isObject(value)){
  25. this.value = Lang.hitch(this, "_dictValue",
  26. df.keys(value), value);
  27. }else{
  28. this.value = Lang.hitch(this, "_fieldValue", value);
  29. }
  30. }else{
  31. this.value = Lang.hitch(this, "_defaultValue");
  32. }
  33. this.data = [];
  34. this._events = [];
  35. if(this.store.getFeatures()["dojo.data.api.Notification"]){
  36. this._events.push(
  37. Hub.connect(this.store, "onNew", this, "_onStoreNew"),
  38. Hub.connect(this.store, "onDelete", this, "_onStoreDelete"),
  39. Hub.connect(this.store, "onSet", this, "_onStoreSet")
  40. );
  41. }
  42. this.fetch();
  43. },
  44. destroy: function(){
  45. // summary:
  46. // Clean up before GC.
  47. ArrayUtil.forEach(this._events, Hub.disconnect);
  48. },
  49. setSeriesObject: function(series){
  50. // summary:
  51. // Sets a dojox.charting.Series object we will be working with.
  52. // series: dojox.charting.Series:
  53. // Our interface to the chart.
  54. this.series = series;
  55. },
  56. // value transformers
  57. _dictValue: function(keys, dict, store, item){
  58. var o = {};
  59. ArrayUtil.forEach(keys, function(key){
  60. o[key] = store.getValue(item, dict[key]);
  61. });
  62. return o;
  63. },
  64. _fieldValue: function(field, store, item){
  65. return store.getValue(item, field);
  66. },
  67. _defaultValue: function(store, item){
  68. return store.getValue(item, "value");
  69. },
  70. // store fetch loop
  71. fetch: function(){
  72. // summary:
  73. // Fetches data from the store and updates a chart.
  74. if(!this._inFlight){
  75. this._inFlight = true;
  76. var kwArgs = Lang.delegate(this.kwArgs);
  77. kwArgs.onComplete = Lang.hitch(this, "_onFetchComplete");
  78. kwArgs.onError = Lang.hitch(this, "onFetchError");
  79. this.store.fetch(kwArgs);
  80. }
  81. },
  82. _onFetchComplete: function(items, request){
  83. this.items = items;
  84. this._buildItemMap();
  85. this.data = ArrayUtil.map(this.items, function(item){
  86. return this.value(this.store, item);
  87. }, this);
  88. this._pushDataChanges();
  89. this._inFlight = false;
  90. },
  91. onFetchError: function(errorData, request){
  92. // summary:
  93. // As stub to process fetch errors. Provide so user can attach to
  94. // it with dojo.connect(). See dojo.data.api.Read fetch() for
  95. // details: onError property.
  96. this._inFlight = false;
  97. },
  98. _buildItemMap: function(){
  99. if(this.store.getFeatures()["dojo.data.api.Identity"]){
  100. var itemMap = {};
  101. ArrayUtil.forEach(this.items, function(item, index){
  102. itemMap[this.store.getIdentity(item)] = index;
  103. }, this);
  104. this.itemMap = itemMap;
  105. }
  106. },
  107. _pushDataChanges: function(){
  108. if(this.series){
  109. this.series.chart.updateSeries(this.series.name, this);
  110. this.series.chart.delayedRender();
  111. }
  112. },
  113. // store notification handlers
  114. _onStoreNew: function(){
  115. // the only thing we can do is to re-fetch items
  116. this.fetch();
  117. },
  118. _onStoreDelete: function(item){
  119. // we cannot do anything with deleted item, the only way is to compare
  120. // items for equality
  121. if(this.items){
  122. var flag = ArrayUtil.some(this.items, function(it, index){
  123. if(it === item){
  124. this.items.splice(index, 1);
  125. this._buildItemMap();
  126. this.data.splice(index, 1);
  127. return true;
  128. }
  129. return false;
  130. }, this);
  131. if(flag){
  132. this._pushDataChanges();
  133. }
  134. }
  135. },
  136. _onStoreSet: function(item){
  137. if(this.itemMap){
  138. // we can use our handy item map, if the store supports Identity
  139. var id = this.store.getIdentity(item), index = this.itemMap[id];
  140. if(typeof index == "number"){
  141. this.data[index] = this.value(this.store, this.items[index]);
  142. this._pushDataChanges();
  143. }
  144. }else{
  145. // otherwise we have to rely on item's equality
  146. if(this.items){
  147. var flag = ArrayUtil.some(this.items, function(it, index){
  148. if(it === item){
  149. this.data[index] = this.value(this.store, it);
  150. return true;
  151. }
  152. return false;
  153. }, this);
  154. if(flag){
  155. this._pushDataChanges();
  156. }
  157. }
  158. }
  159. }
  160. });
  161. });