da721b6681b6d15cf2f25b2609eb9f98cb73b252.svn-base 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. if (!dojo._hasResource["dojox.charting.Chart2D"]) { // _hasResource checks added
  2. // by build. Do not use
  3. // _hasResource directly in
  4. // your code.
  5. dojo._hasResource["dojox.charting.Chart2D"] = true;
  6. dojo.provide("dojox.charting.Chart2D");
  7. dojo.require("dojox.gfx");
  8. dojo.require("dojox.lang.functional");
  9. dojo.require("dojox.charting.Theme");
  10. dojo.require("dojox.charting.Series");
  11. dojo.require("dojox.charting.axis2d.Default");
  12. dojo.require("dojox.charting.plot2d.Default");
  13. dojo.require("dojox.charting.plot2d.Lines");
  14. dojo.require("dojox.charting.plot2d.Areas");
  15. dojo.require("dojox.charting.plot2d.Markers");
  16. dojo.require("dojox.charting.plot2d.MarkersOnly");
  17. dojo.require("dojox.charting.plot2d.Scatter");
  18. dojo.require("dojox.charting.plot2d.Stacked");
  19. dojo.require("dojox.charting.plot2d.StackedLines");
  20. dojo.require("dojox.charting.plot2d.StackedAreas");
  21. dojo.require("dojox.charting.plot2d.Columns");
  22. dojo.require("dojox.charting.plot2d.StackedColumns");
  23. dojo.require("dojox.charting.plot2d.ClusteredColumns");
  24. dojo.require("dojox.charting.plot2d.Bars");
  25. dojo.require("dojox.charting.plot2d.StackedBars");
  26. dojo.require("dojox.charting.plot2d.ClusteredBars");
  27. dojo.require("dojox.charting.plot2d.Grid");
  28. dojo.require("dojox.charting.plot2d.Pie");
  29. (function() {
  30. var df = dojox.lang.functional, dc = dojox.charting, clear = df
  31. .lambda("item.clear()"), purge = df.lambda("item.purgeGroup()"), destroy = df
  32. .lambda("item.destroy()"), makeClean = df
  33. .lambda("item.dirty = false"), makeDirty = df
  34. .lambda("item.dirty = true");
  35. dojo.declare("dojox.charting.Chart2D", null, {
  36. constructor : function(node, kwArgs) {
  37. // initialize parameters
  38. if (!kwArgs) {
  39. kwArgs = {};
  40. }
  41. this.margins = kwArgs.margins ? kwArgs.margins : {
  42. l : 10,
  43. t : 10,
  44. r : 10,
  45. b : 10
  46. };
  47. this.stroke = kwArgs.stroke;
  48. this.fill = kwArgs.fill;
  49. // default initialization
  50. this.theme = null;
  51. this.axes = {}; // map of axes
  52. this.stack = []; // stack of plotters
  53. this.plots = {}; // map of plotter indices
  54. this.series = []; // stack of data runs
  55. this.runs = {}; // map of data run indices
  56. this.dirty = true;
  57. this.coords = null;
  58. // create a surface
  59. this.node = dojo.byId(node);
  60. var box = dojo.marginBox(node);
  61. this.surface = dojox.gfx.createSurface(this.node, box.w, box.h);
  62. },
  63. destroy : function() {
  64. dojo.forEach(this.series, destroy);
  65. dojo.forEach(this.stack, destroy);
  66. df.forIn(this.axes, destroy);
  67. },
  68. getCoords : function() {
  69. if (!this.coords) {
  70. this.coords = dojo.coords(this.node, true);
  71. }
  72. return this.coords;
  73. },
  74. setTheme : function(theme) {
  75. this.theme = theme;
  76. this.dirty = true;
  77. return this;
  78. },
  79. addAxis : function(name, kwArgs) {
  80. var axis;
  81. if (!kwArgs || !("type" in kwArgs)) {
  82. axis = new dc.axis2d.Default(this, kwArgs);
  83. } else {
  84. axis = typeof kwArgs.type == "string"
  85. ? new dc.axis2d[kwArgs.type](this, kwArgs)
  86. : new kwArgs.type(this, kwArgs);
  87. }
  88. axis.name = name;
  89. axis.dirty = true;
  90. if (name in this.axes) {
  91. this.axes[name].destroy();
  92. }
  93. this.axes[name] = axis;
  94. this.dirty = true;
  95. return this;
  96. },
  97. addPlot : function(name, kwArgs) {
  98. var plot;
  99. if (!kwArgs || !("type" in kwArgs)) {
  100. plot = new dc.plot2d.Default(this, kwArgs);
  101. } else {
  102. plot = typeof kwArgs.type == "string"
  103. ? new dc.plot2d[kwArgs.type](this, kwArgs)
  104. : new kwArgs.type(this, kwArgs);
  105. }
  106. plot.name = name;
  107. plot.dirty = true;
  108. if (name in this.plots) {
  109. this.stack[this.plots[name]].destroy();
  110. this.stack[this.plots[name]] = plot;
  111. } else {
  112. this.plots[name] = this.stack.length;
  113. this.stack.push(plot);
  114. }
  115. this.dirty = true;
  116. return this;
  117. },
  118. addSeries : function(name, data, kwArgs) {
  119. var run = new dc.Series(this, data, kwArgs);
  120. if (name in this.runs) {
  121. this.series[this.runs[name]].destroy();
  122. this.series[this.runs[name]] = run;
  123. } else {
  124. this.runs[name] = this.series.length;
  125. this.series.push(run);
  126. }
  127. this.dirty = true;
  128. // fix min/max
  129. if (!("ymin" in run) && "min" in run) {
  130. run.ymin = run.min;
  131. }
  132. if (!("ymax" in run) && "max" in run) {
  133. run.ymax = run.max;
  134. }
  135. return this;
  136. },
  137. updateSeries : function(name, data) {
  138. if (name in this.runs) {
  139. var run = this.series[this.runs[name]], plot = this.stack[this.plots[run.plot]], axis;
  140. run.data = data;
  141. run.dirty = true;
  142. // check to see if axes and plot should be updated
  143. if (plot.hAxis) {
  144. axis = this.axes[plot.hAxis];
  145. if (axis.dependOnData()) {
  146. axis.dirty = true;
  147. // find all plots and mark them dirty
  148. dojo.forEach(this.stack, function(p) {
  149. if (p.hAxis && p.hAxis == plot.hAxis) {
  150. p.dirty = true;
  151. }
  152. });
  153. }
  154. } else {
  155. plot.dirty = true;
  156. }
  157. if (plot.vAxis) {
  158. axis = this.axes[plot.vAxis];
  159. if (axis.dependOnData()) {
  160. axis.dirty = true;
  161. // find all plots and mark them dirty
  162. dojo.forEach(this.stack, function(p) {
  163. if (p.vAxis && p.vAxis == plot.vAxis) {
  164. p.dirty = true;
  165. }
  166. });
  167. }
  168. } else {
  169. plot.dirty = true;
  170. }
  171. }
  172. return this;
  173. },
  174. resize : function(width, height) {
  175. var box;
  176. switch (arguments.length) {
  177. case 0 :
  178. box = dojo.marginBox(this.node);
  179. break;
  180. case 1 :
  181. box = width;
  182. break;
  183. default :
  184. box = {
  185. w : width,
  186. h : height
  187. };
  188. break;
  189. }
  190. dojo.marginBox(this.node, box);
  191. this.surface.setDimensions(box.w, box.h);
  192. this.dirty = true;
  193. this.coords = null;
  194. return this.render();
  195. },
  196. render : function() {
  197. if (this.dirty) {
  198. return this.fullRender();
  199. }
  200. // calculate geometry
  201. dojo.forEach(this.stack, function(plot) {
  202. if (plot.dirty
  203. || (plot.hAxis && this.axes[plot.hAxis].dirty)
  204. || (plot.vAxis && this.axes[plot.vAxis].dirty)) {
  205. plot.calculateAxes(this.plotArea);
  206. }
  207. }, this);
  208. // go over the stack backwards
  209. df.forEachReversed(this.stack, function(plot) {
  210. plot.render(this.dim, this.offsets);
  211. }, this);
  212. // go over axes
  213. df.forIn(this.axes, function(axis) {
  214. axis.render(this.dim, this.offsets);
  215. }, this);
  216. this._makeClean();
  217. // BEGIN FOR HTML CANVAS
  218. if (this.surface.render) {
  219. this.surface.render();
  220. };
  221. // END FOR HTML CANVAS
  222. return this;
  223. },
  224. fullRender : function() {
  225. this._makeDirty();
  226. // clear old values
  227. dojo.forEach(this.stack, clear);
  228. dojo.forEach(this.series, purge);
  229. df.forIn(this.axes, purge);
  230. dojo.forEach(this.stack, purge);
  231. this.surface.clear();
  232. // rebuild new connections, and add defaults
  233. // assign series
  234. dojo.forEach(this.series, function(run) {
  235. if (!(run.plot in this.plots)) {
  236. var plot = new dc.plot2d.Default(this, {});
  237. plot.name = run.plot;
  238. this.plots[run.plot] = this.stack.length;
  239. this.stack.push(plot);
  240. }
  241. this.stack[this.plots[run.plot]].addSeries(run);
  242. }, this);
  243. // assign axes
  244. dojo.forEach(this.stack, function(plot) {
  245. if (plot.hAxis) {
  246. plot.setAxis(this.axes[plot.hAxis]);
  247. }
  248. if (plot.vAxis) {
  249. plot.setAxis(this.axes[plot.vAxis]);
  250. }
  251. }, this);
  252. // set up a theme
  253. if (!this.theme) {
  254. this.theme = new dojox.charting.Theme(dojox.charting._def);
  255. }
  256. var requiredColors = df.foldl(this.stack,
  257. "z + plot.getRequiredColors()", 0);
  258. this.theme.defineColors({
  259. num : requiredColors,
  260. cache : false
  261. });
  262. // calculate geometry
  263. // 1st pass
  264. var dim = this.dim = this.surface.getDimensions();
  265. dim.width = dojox.gfx.normalizedLength(dim.width);
  266. dim.height = dojox.gfx.normalizedLength(dim.height);
  267. df.forIn(this.axes, clear);
  268. dojo.forEach(this.stack, function(plot) {
  269. plot.calculateAxes(dim);
  270. });
  271. // assumption: we don't have stacked axes yet
  272. var offsets = this.offsets = {
  273. l : 0,
  274. r : 0,
  275. t : 0,
  276. b : 0
  277. };
  278. df.forIn(this.axes, function(axis) {
  279. df.forIn(axis.getOffsets(), function(o, i) {
  280. offsets[i] += o;
  281. });
  282. });
  283. // add margins
  284. df.forIn(this.margins, function(o, i) {
  285. offsets[i] += o;
  286. });
  287. // 2nd pass with realistic dimensions
  288. this.plotArea = {
  289. width : dim.width - offsets.l - offsets.r,
  290. height : dim.height - offsets.t - offsets.b
  291. };
  292. df.forIn(this.axes, clear);
  293. dojo.forEach(this.stack, function(plot) {
  294. plot.calculateAxes(this.plotArea);
  295. }, this);
  296. // generate shapes
  297. // draw a chart background
  298. var t = this.theme, fill = this.fill
  299. ? this.fill
  300. : (t.chart && t.chart.fill), stroke = this.stroke
  301. ? this.stroke
  302. : (t.chart && t.chart.stroke);
  303. if (fill) {
  304. this.surface.createRect({
  305. width : dim.width,
  306. height : dim.height
  307. }).setFill(fill);
  308. }
  309. if (stroke) {
  310. this.surface.createRect({
  311. width : dim.width - 1,
  312. height : dim.height - 1
  313. }).setStroke(stroke);
  314. }
  315. // draw a plot background
  316. fill = t.plotarea && t.plotarea.fill;
  317. stroke = t.plotarea && t.plotarea.stroke;
  318. if (fill) {
  319. this.surface.createRect({
  320. x : offsets.l,
  321. y : offsets.t,
  322. width : dim.width - offsets.l - offsets.r,
  323. height : dim.height - offsets.t - offsets.b
  324. }).setFill(fill);
  325. }
  326. if (stroke) {
  327. this.surface.createRect({
  328. x : offsets.l,
  329. y : offsets.t,
  330. width : dim.width - offsets.l - offsets.r - 1,
  331. height : dim.height - offsets.t - offsets.b - 1
  332. }).setStroke(stroke);
  333. }
  334. // go over the stack backwards
  335. df.foldr(this.stack, function(z, plot) {
  336. return plot.render(dim, offsets), 0;
  337. }, 0);
  338. // go over axes
  339. df.forIn(this.axes, function(axis) {
  340. axis.render(dim, offsets);
  341. });
  342. this._makeClean();
  343. return this;
  344. },
  345. _makeClean : function() {
  346. // reset dirty flags
  347. dojo.forEach(this.axes, makeClean);
  348. dojo.forEach(this.stack, makeClean);
  349. dojo.forEach(this.series, makeClean);
  350. this.dirty = false;
  351. },
  352. _makeDirty : function() {
  353. // reset dirty flags
  354. dojo.forEach(this.axes, makeDirty);
  355. dojo.forEach(this.stack, makeDirty);
  356. dojo.forEach(this.series, makeDirty);
  357. this.dirty = true;
  358. }
  359. });
  360. })();
  361. }