Scatter.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  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.plot2d.Scatter"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.charting.plot2d.Scatter"] = true;
  8. dojo.provide("dojox.charting.plot2d.Scatter");
  9. dojo.require("dojox.charting.plot2d.common");
  10. dojo.require("dojox.charting.plot2d.Base");
  11. dojo.require("dojox.lang.utils");
  12. dojo.require("dojox.lang.functional");
  13. dojo.require("dojox.lang.functional.reversed");
  14. dojo.require("dojox.gfx.gradutils");
  15. (function(){
  16. var df = dojox.lang.functional, du = dojox.lang.utils,
  17. dc = dojox.charting.plot2d.common,
  18. purgeGroup = df.lambda("item.purgeGroup()");
  19. dojo.declare("dojox.charting.plot2d.Scatter", dojox.charting.plot2d.Base, {
  20. // summary:
  21. // A plot object representing a typical scatter chart.
  22. defaultParams: {
  23. hAxis: "x", // use a horizontal axis named "x"
  24. vAxis: "y", // use a vertical axis named "y"
  25. shadows: null, // draw shadows
  26. animate: null // animate chart to place
  27. },
  28. optionalParams: {
  29. // theme component
  30. markerStroke: {},
  31. markerOutline: {},
  32. markerShadow: {},
  33. markerFill: {},
  34. markerFont: "",
  35. markerFontColor: ""
  36. },
  37. constructor: function(chart, kwArgs){
  38. // summary:
  39. // Create the scatter plot.
  40. // chart: dojox.charting.Chart2D
  41. // The chart this plot belongs to.
  42. // kwArgs: dojox.charting.plot2d.__DefaultCtorArgs?
  43. // An optional keyword arguments object to help define this plot's parameters.
  44. this.opt = dojo.clone(this.defaultParams);
  45. du.updateWithObject(this.opt, kwArgs);
  46. du.updateWithPattern(this.opt, kwArgs, this.optionalParams);
  47. this.series = [];
  48. this.hAxis = this.opt.hAxis;
  49. this.vAxis = this.opt.vAxis;
  50. this.animate = this.opt.animate;
  51. },
  52. render: function(dim, offsets){
  53. // summary:
  54. // Run the calculations for any axes for this plot.
  55. // dim: Object
  56. // An object in the form of { width, height }
  57. // offsets: Object
  58. // An object of the form { l, r, t, b}.
  59. // returns: dojox.charting.plot2d.Scatter
  60. // A reference to this plot for functional chaining.
  61. if(this.zoom && !this.isDataDirty()){
  62. return this.performZoom(dim, offsets);
  63. }
  64. this.resetEvents();
  65. this.dirty = this.isDirty();
  66. if(this.dirty){
  67. dojo.forEach(this.series, purgeGroup);
  68. this._eventSeries = {};
  69. this.cleanGroup();
  70. var s = this.group;
  71. df.forEachRev(this.series, function(item){ item.cleanGroup(s); });
  72. }
  73. var t = this.chart.theme, events = this.events();
  74. for(var i = this.series.length - 1; i >= 0; --i){
  75. var run = this.series[i];
  76. if(!this.dirty && !run.dirty){
  77. t.skip();
  78. this._reconnectEvents(run.name);
  79. continue;
  80. }
  81. run.cleanGroup();
  82. if(!run.data.length){
  83. run.dirty = false;
  84. t.skip();
  85. continue;
  86. }
  87. var theme = t.next("marker", [this.opt, run]), s = run.group, lpoly,
  88. ht = this._hScaler.scaler.getTransformerFromModel(this._hScaler),
  89. vt = this._vScaler.scaler.getTransformerFromModel(this._vScaler);
  90. if(typeof run.data[0] == "number"){
  91. lpoly = dojo.map(run.data, function(v, i){
  92. return {
  93. x: ht(i + 1) + offsets.l,
  94. y: dim.height - offsets.b - vt(v)
  95. };
  96. }, this);
  97. }else{
  98. lpoly = dojo.map(run.data, function(v, i){
  99. return {
  100. x: ht(v.x) + offsets.l,
  101. y: dim.height - offsets.b - vt(v.y)
  102. };
  103. }, this);
  104. }
  105. var shadowMarkers = new Array(lpoly.length),
  106. frontMarkers = new Array(lpoly.length),
  107. outlineMarkers = new Array(lpoly.length);
  108. dojo.forEach(lpoly, function(c, i){
  109. var finalTheme = typeof run.data[i] == "number" ?
  110. t.post(theme, "marker") :
  111. t.addMixin(theme, "marker", run.data[i], true),
  112. path = "M" + c.x + " " + c.y + " " + finalTheme.symbol;
  113. if(finalTheme.marker.shadow){
  114. shadowMarkers[i] = s.createPath("M" + (c.x + finalTheme.marker.shadow.dx) + " " +
  115. (c.y + finalTheme.marker.shadow.dy) + " " + finalTheme.symbol).
  116. setStroke(finalTheme.marker.shadow).setFill(finalTheme.marker.shadow.color);
  117. if(this.animate){
  118. this._animateScatter(shadowMarkers[i], dim.height - offsets.b);
  119. }
  120. }
  121. if(finalTheme.marker.outline){
  122. var outline = dc.makeStroke(finalTheme.marker.outline);
  123. outline.width = 2 * outline.width + finalTheme.marker.stroke.width;
  124. outlineMarkers[i] = s.createPath(path).setStroke(outline);
  125. if(this.animate){
  126. this._animateScatter(outlineMarkers[i], dim.height - offsets.b);
  127. }
  128. }
  129. var stroke = dc.makeStroke(finalTheme.marker.stroke),
  130. fill = this._plotFill(finalTheme.marker.fill, dim, offsets);
  131. if(fill && (fill.type === "linear" || fill.type == "radial")){
  132. var color = dojox.gfx.gradutils.getColor(fill, {x: c.x, y: c.y});
  133. if(stroke){
  134. stroke.color = color;
  135. }
  136. frontMarkers[i] = s.createPath(path).setStroke(stroke).setFill(color);
  137. }else{
  138. frontMarkers[i] = s.createPath(path).setStroke(stroke).setFill(fill);
  139. }
  140. if(this.animate){
  141. this._animateScatter(frontMarkers[i], dim.height - offsets.b);
  142. }
  143. }, this);
  144. if(frontMarkers.length){
  145. run.dyn.stroke = frontMarkers[frontMarkers.length - 1].getStroke();
  146. run.dyn.fill = frontMarkers[frontMarkers.length - 1].getFill();
  147. }
  148. if(events){
  149. var eventSeries = new Array(frontMarkers.length);
  150. dojo.forEach(frontMarkers, function(s, i){
  151. var o = {
  152. element: "marker",
  153. index: i,
  154. run: run,
  155. shape: s,
  156. outline: outlineMarkers && outlineMarkers[i] || null,
  157. shadow: shadowMarkers && shadowMarkers[i] || null,
  158. cx: lpoly[i].x,
  159. cy: lpoly[i].y
  160. };
  161. if(typeof run.data[0] == "number"){
  162. o.x = i + 1;
  163. o.y = run.data[i];
  164. }else{
  165. o.x = run.data[i].x;
  166. o.y = run.data[i].y;
  167. }
  168. this._connectEvents(o);
  169. eventSeries[i] = o;
  170. }, this);
  171. this._eventSeries[run.name] = eventSeries;
  172. }else{
  173. delete this._eventSeries[run.name];
  174. }
  175. run.dirty = false;
  176. }
  177. this.dirty = false;
  178. return this; // dojox.charting.plot2d.Scatter
  179. },
  180. _animateScatter: function(shape, offset){
  181. dojox.gfx.fx.animateTransform(dojo.delegate({
  182. shape: shape,
  183. duration: 1200,
  184. transform: [
  185. {name: "translate", start: [0, offset], end: [0, 0]},
  186. {name: "scale", start: [0, 0], end: [1, 1]},
  187. {name: "original"}
  188. ]
  189. }, this.animate)).play();
  190. }
  191. });
  192. })();
  193. }