1 if(!dojo._hasResource["dojox.charting.Chart2D"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2 dojo._hasResource["dojox.charting.Chart2D"] = true;
3 dojo.provide("dojox.charting.Chart2D");
5 dojo.require("dojox.gfx");
6 dojo.require("dojox.lang.functional");
7 dojo.require("dojox.lang.functional.fold");
8 dojo.require("dojox.lang.functional.reversed");
10 dojo.require("dojox.charting.Theme");
11 dojo.require("dojox.charting.Series");
13 dojo.require("dojox.charting.axis2d.Default");
15 dojo.require("dojox.charting.plot2d.Default");
16 dojo.require("dojox.charting.plot2d.Lines");
17 dojo.require("dojox.charting.plot2d.Areas");
18 dojo.require("dojox.charting.plot2d.Markers");
19 dojo.require("dojox.charting.plot2d.MarkersOnly");
20 dojo.require("dojox.charting.plot2d.Scatter");
21 dojo.require("dojox.charting.plot2d.Stacked");
22 dojo.require("dojox.charting.plot2d.StackedLines");
23 dojo.require("dojox.charting.plot2d.StackedAreas");
24 dojo.require("dojox.charting.plot2d.Columns");
25 dojo.require("dojox.charting.plot2d.StackedColumns");
26 dojo.require("dojox.charting.plot2d.ClusteredColumns");
27 dojo.require("dojox.charting.plot2d.Bars");
28 dojo.require("dojox.charting.plot2d.StackedBars");
29 dojo.require("dojox.charting.plot2d.ClusteredBars");
30 dojo.require("dojox.charting.plot2d.Grid");
31 dojo.require("dojox.charting.plot2d.Pie");
34 var df = dojox.lang.functional, dc = dojox.charting,
35 clear = df.lambda("item.clear()"),
36 purge = df.lambda("item.purgeGroup()"),
37 destroy = df.lambda("item.destroy()"),
38 makeClean = df.lambda("item.dirty = false"),
39 makeDirty = df.lambda("item.dirty = true");
41 dojo.declare("dojox.charting.Chart2D", null, {
42 constructor: function(node, kwArgs){
43 // initialize parameters
44 if(!kwArgs){ kwArgs = {}; }
45 this.margins = kwArgs.margins ? kwArgs.margins : {l: 10, t: 10, r: 10, b: 10};
46 this.stroke = kwArgs.stroke;
47 this.fill = kwArgs.fill;
49 // default initialization
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
60 this.node = dojo.byId(node);
61 var box = dojo.marginBox(node);
62 this.surface = dojox.gfx.createSurface(this.node, box.w, box.h);
65 dojo.forEach(this.series, destroy);
66 dojo.forEach(this.stack, destroy);
67 df.forIn(this.axes, destroy);
69 getCoords: function(){
71 this.coords = dojo.coords(this.node, true);
75 setTheme: function(theme){
80 addAxis: function(name, kwArgs){
82 if(!kwArgs || !("type" in kwArgs)){
83 axis = new dc.axis2d.Default(this, kwArgs);
85 axis = typeof kwArgs.type == "string" ?
86 new dc.axis2d[kwArgs.type](this, kwArgs) :
87 new kwArgs.type(this, kwArgs);
91 if(name in this.axes){
92 this.axes[name].destroy();
94 this.axes[name] = axis;
98 addPlot: function(name, kwArgs){
100 if(!kwArgs || !("type" in kwArgs)){
101 plot = new dc.plot2d.Default(this, kwArgs);
103 plot = typeof kwArgs.type == "string" ?
104 new dc.plot2d[kwArgs.type](this, kwArgs) :
105 new kwArgs.type(this, kwArgs);
109 if(name in this.plots){
110 this.stack[this.plots[name]].destroy();
111 this.stack[this.plots[name]] = plot;
113 this.plots[name] = this.stack.length;
114 this.stack.push(plot);
119 addSeries: function(name, data, kwArgs){
120 var run = new dc.Series(this, data, kwArgs);
121 if(name in this.runs){
122 this.series[this.runs[name]].destroy();
123 this.series[this.runs[name]] = run;
125 this.runs[name] = this.series.length;
126 this.series.push(run);
130 if(!("ymin" in run) && "min" in run){ run.ymin = run.min; }
131 if(!("ymax" in run) && "max" in run){ run.ymax = run.max; }
134 updateSeries: function(name, data){
135 if(name in this.runs){
136 var run = this.series[this.runs[name]],
137 plot = this.stack[this.plots[run.plot]], axis;
140 // check to see if axes and plot should be updated
142 axis = this.axes[plot.hAxis];
143 if(axis.dependOnData()){
145 // find all plots and mark them dirty
146 dojo.forEach(this.stack, function(p){
147 if(p.hAxis && p.hAxis == plot.hAxis){
156 axis = this.axes[plot.vAxis];
157 if(axis.dependOnData()){
159 // find all plots and mark them dirty
160 dojo.forEach(this.stack, function(p){
161 if(p.vAxis && p.vAxis == plot.vAxis){
172 resize: function(width, height){
174 switch(arguments.length){
176 box = dojo.marginBox(this.node);
182 box = {w: width, h: height};
185 dojo.marginBox(this.node, box);
186 this.surface.setDimensions(box.w, box.h);
189 return this.render();
193 return this.fullRender();
196 // calculate geometry
197 dojo.forEach(this.stack, function(plot){
198 if(plot.dirty || (plot.hAxis && this.axes[plot.hAxis].dirty) ||
199 (plot.vAxis && this.axes[plot.vAxis].dirty)){
200 plot.calculateAxes(this.plotArea);
204 // go over the stack backwards
205 df.forEachRev(this.stack, function(plot){ plot.render(this.dim, this.offsets); }, this);
208 df.forIn(this.axes, function(axis){ axis.render(this.dim, this.offsets); }, this);
212 // BEGIN FOR HTML CANVAS
213 if(this.surface.render){ this.surface.render(); };
214 // END FOR HTML CANVAS
218 fullRender: function(){
222 dojo.forEach(this.stack, clear);
223 dojo.forEach(this.series, purge);
224 df.forIn(this.axes, purge);
225 dojo.forEach(this.stack, purge);
226 this.surface.clear();
228 // rebuild new connections, and add defaults
231 dojo.forEach(this.series, function(run){
232 if(!(run.plot in this.plots)){
233 var plot = new dc.plot2d.Default(this, {});
234 plot.name = run.plot;
235 this.plots[run.plot] = this.stack.length;
236 this.stack.push(plot);
238 this.stack[this.plots[run.plot]].addSeries(run);
241 dojo.forEach(this.stack, function(plot){
243 plot.setAxis(this.axes[plot.hAxis]);
246 plot.setAxis(this.axes[plot.vAxis]);
251 this.theme = new dojox.charting.Theme(dojox.charting._def);
253 var requiredColors = df.foldl(this.stack, "z + plot.getRequiredColors()", 0);
254 this.theme.defineColors({num: requiredColors, cache: false});
256 // calculate geometry
259 var dim = this.dim = this.surface.getDimensions();
260 dim.width = dojox.gfx.normalizedLength(dim.width);
261 dim.height = dojox.gfx.normalizedLength(dim.height);
262 df.forIn(this.axes, clear);
263 dojo.forEach(this.stack, function(plot){ plot.calculateAxes(dim); });
265 // assumption: we don't have stacked axes yet
266 var offsets = this.offsets = {l: 0, r: 0, t: 0, b: 0};
267 df.forIn(this.axes, function(axis){
268 df.forIn(axis.getOffsets(), function(o, i){ offsets[i] += o; });
271 df.forIn(this.margins, function(o, i){ offsets[i] += o; });
273 // 2nd pass with realistic dimensions
274 this.plotArea = {width: dim.width - offsets.l - offsets.r, height: dim.height - offsets.t - offsets.b};
275 df.forIn(this.axes, clear);
276 dojo.forEach(this.stack, function(plot){ plot.calculateAxes(this.plotArea); }, this);
280 // draw a chart background
282 fill = this.fill ? this.fill : (t.chart && t.chart.fill),
283 stroke = this.stroke ? this.stroke : (t.chart && t.chart.stroke);
285 this.surface.createRect({
291 this.surface.createRect({
292 width: dim.width - 1,
293 height: dim.height - 1
294 }).setStroke(stroke);
296 // draw a plot background
297 fill = t.plotarea && t.plotarea.fill;
298 stroke = t.plotarea && t.plotarea.stroke;
300 this.surface.createRect({
301 x: offsets.l, y: offsets.t,
302 width: dim.width - offsets.l - offsets.r,
303 height: dim.height - offsets.t - offsets.b
307 this.surface.createRect({
308 x: offsets.l, y: offsets.t,
309 width: dim.width - offsets.l - offsets.r - 1,
310 height: dim.height - offsets.t - offsets.b - 1
311 }).setStroke(stroke);
314 // go over the stack backwards
315 df.foldr(this.stack, function(z, plot){ return plot.render(dim, offsets), 0; }, 0);
318 df.forIn(this.axes, function(axis){ axis.render(dim, offsets); });
324 _makeClean: function(){
326 dojo.forEach(this.axes, makeClean);
327 dojo.forEach(this.stack, makeClean);
328 dojo.forEach(this.series, makeClean);
331 _makeDirty: function(){
333 dojo.forEach(this.axes, makeDirty);
334 dojo.forEach(this.stack, makeDirty);
335 dojo.forEach(this.series, makeDirty);