DataSeries.js 5.0 KB

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