if(!dojo._hasResource["dojox.charting.Chart2D"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["dojox.charting.Chart2D"] = true; dojo.provide("dojox.charting.Chart2D"); dojo.require("dojox.gfx"); dojo.require("dojox.lang.functional"); dojo.require("dojox.lang.functional.fold"); dojo.require("dojox.lang.functional.reversed"); dojo.require("dojox.charting.Theme"); dojo.require("dojox.charting.Series"); dojo.require("dojox.charting.axis2d.Default"); dojo.require("dojox.charting.plot2d.Default"); dojo.require("dojox.charting.plot2d.Lines"); dojo.require("dojox.charting.plot2d.Areas"); dojo.require("dojox.charting.plot2d.Markers"); dojo.require("dojox.charting.plot2d.MarkersOnly"); dojo.require("dojox.charting.plot2d.Scatter"); dojo.require("dojox.charting.plot2d.Stacked"); dojo.require("dojox.charting.plot2d.StackedLines"); dojo.require("dojox.charting.plot2d.StackedAreas"); dojo.require("dojox.charting.plot2d.Columns"); dojo.require("dojox.charting.plot2d.StackedColumns"); dojo.require("dojox.charting.plot2d.ClusteredColumns"); dojo.require("dojox.charting.plot2d.Bars"); dojo.require("dojox.charting.plot2d.StackedBars"); dojo.require("dojox.charting.plot2d.ClusteredBars"); dojo.require("dojox.charting.plot2d.Grid"); dojo.require("dojox.charting.plot2d.Pie"); (function(){ var df = dojox.lang.functional, dc = dojox.charting, clear = df.lambda("item.clear()"), purge = df.lambda("item.purgeGroup()"), destroy = df.lambda("item.destroy()"), makeClean = df.lambda("item.dirty = false"), makeDirty = df.lambda("item.dirty = true"); dojo.declare("dojox.charting.Chart2D", null, { constructor: function(node, kwArgs){ // initialize parameters if(!kwArgs){ kwArgs = {}; } this.margins = kwArgs.margins ? kwArgs.margins : {l: 10, t: 10, r: 10, b: 10}; this.stroke = kwArgs.stroke; this.fill = kwArgs.fill; // default initialization this.theme = null; this.axes = {}; // map of axes this.stack = []; // stack of plotters this.plots = {}; // map of plotter indices this.series = []; // stack of data runs this.runs = {}; // map of data run indices this.dirty = true; this.coords = null; // create a surface this.node = dojo.byId(node); var box = dojo.marginBox(node); this.surface = dojox.gfx.createSurface(this.node, box.w, box.h); }, destroy: function(){ dojo.forEach(this.series, destroy); dojo.forEach(this.stack, destroy); df.forIn(this.axes, destroy); }, getCoords: function(){ if(!this.coords){ this.coords = dojo.coords(this.node, true); } return this.coords; }, setTheme: function(theme){ this.theme = theme; this.dirty = true; return this; }, addAxis: function(name, kwArgs){ var axis; if(!kwArgs || !("type" in kwArgs)){ axis = new dc.axis2d.Default(this, kwArgs); }else{ axis = typeof kwArgs.type == "string" ? new dc.axis2d[kwArgs.type](this, kwArgs) : new kwArgs.type(this, kwArgs); } axis.name = name; axis.dirty = true; if(name in this.axes){ this.axes[name].destroy(); } this.axes[name] = axis; this.dirty = true; return this; }, addPlot: function(name, kwArgs){ var plot; if(!kwArgs || !("type" in kwArgs)){ plot = new dc.plot2d.Default(this, kwArgs); }else{ plot = typeof kwArgs.type == "string" ? new dc.plot2d[kwArgs.type](this, kwArgs) : new kwArgs.type(this, kwArgs); } plot.name = name; plot.dirty = true; if(name in this.plots){ this.stack[this.plots[name]].destroy(); this.stack[this.plots[name]] = plot; }else{ this.plots[name] = this.stack.length; this.stack.push(plot); } this.dirty = true; return this; }, addSeries: function(name, data, kwArgs){ var run = new dc.Series(this, data, kwArgs); if(name in this.runs){ this.series[this.runs[name]].destroy(); this.series[this.runs[name]] = run; }else{ this.runs[name] = this.series.length; this.series.push(run); } this.dirty = true; // fix min/max if(!("ymin" in run) && "min" in run){ run.ymin = run.min; } if(!("ymax" in run) && "max" in run){ run.ymax = run.max; } return this; }, updateSeries: function(name, data){ if(name in this.runs){ var run = this.series[this.runs[name]], plot = this.stack[this.plots[run.plot]], axis; run.data = data; run.dirty = true; // check to see if axes and plot should be updated if(plot.hAxis){ axis = this.axes[plot.hAxis]; if(axis.dependOnData()){ axis.dirty = true; // find all plots and mark them dirty dojo.forEach(this.stack, function(p){ if(p.hAxis && p.hAxis == plot.hAxis){ p.dirty = true; } }); } }else{ plot.dirty = true; } if(plot.vAxis){ axis = this.axes[plot.vAxis]; if(axis.dependOnData()){ axis.dirty = true; // find all plots and mark them dirty dojo.forEach(this.stack, function(p){ if(p.vAxis && p.vAxis == plot.vAxis){ p.dirty = true; } }); } }else{ plot.dirty = true; } } return this; }, resize: function(width, height){ var box; switch(arguments.length){ case 0: box = dojo.marginBox(this.node); break; case 1: box = width; break; default: box = {w: width, h: height}; break; } dojo.marginBox(this.node, box); this.surface.setDimensions(box.w, box.h); this.dirty = true; this.coords = null; return this.render(); }, render: function(){ if(this.dirty){ return this.fullRender(); } // calculate geometry dojo.forEach(this.stack, function(plot){ if(plot.dirty || (plot.hAxis && this.axes[plot.hAxis].dirty) || (plot.vAxis && this.axes[plot.vAxis].dirty)){ plot.calculateAxes(this.plotArea); } }, this); // go over the stack backwards df.forEachRev(this.stack, function(plot){ plot.render(this.dim, this.offsets); }, this); // go over axes df.forIn(this.axes, function(axis){ axis.render(this.dim, this.offsets); }, this); this._makeClean(); // BEGIN FOR HTML CANVAS if(this.surface.render){ this.surface.render(); }; // END FOR HTML CANVAS return this; }, fullRender: function(){ this._makeDirty(); // clear old values dojo.forEach(this.stack, clear); dojo.forEach(this.series, purge); df.forIn(this.axes, purge); dojo.forEach(this.stack, purge); this.surface.clear(); // rebuild new connections, and add defaults // assign series dojo.forEach(this.series, function(run){ if(!(run.plot in this.plots)){ var plot = new dc.plot2d.Default(this, {}); plot.name = run.plot; this.plots[run.plot] = this.stack.length; this.stack.push(plot); } this.stack[this.plots[run.plot]].addSeries(run); }, this); // assign axes dojo.forEach(this.stack, function(plot){ if(plot.hAxis){ plot.setAxis(this.axes[plot.hAxis]); } if(plot.vAxis){ plot.setAxis(this.axes[plot.vAxis]); } }, this); // set up a theme if(!this.theme){ this.theme = new dojox.charting.Theme(dojox.charting._def); } var requiredColors = df.foldl(this.stack, "z + plot.getRequiredColors()", 0); this.theme.defineColors({num: requiredColors, cache: false}); // calculate geometry // 1st pass var dim = this.dim = this.surface.getDimensions(); dim.width = dojox.gfx.normalizedLength(dim.width); dim.height = dojox.gfx.normalizedLength(dim.height); df.forIn(this.axes, clear); dojo.forEach(this.stack, function(plot){ plot.calculateAxes(dim); }); // assumption: we don't have stacked axes yet var offsets = this.offsets = {l: 0, r: 0, t: 0, b: 0}; df.forIn(this.axes, function(axis){ df.forIn(axis.getOffsets(), function(o, i){ offsets[i] += o; }); }); // add margins df.forIn(this.margins, function(o, i){ offsets[i] += o; }); // 2nd pass with realistic dimensions this.plotArea = {width: dim.width - offsets.l - offsets.r, height: dim.height - offsets.t - offsets.b}; df.forIn(this.axes, clear); dojo.forEach(this.stack, function(plot){ plot.calculateAxes(this.plotArea); }, this); // generate shapes // draw a chart background var t = this.theme, fill = this.fill ? this.fill : (t.chart && t.chart.fill), stroke = this.stroke ? this.stroke : (t.chart && t.chart.stroke); if(fill){ this.surface.createRect({ width: dim.width, height: dim.height }).setFill(fill); } if(stroke){ this.surface.createRect({ width: dim.width - 1, height: dim.height - 1 }).setStroke(stroke); } // draw a plot background fill = t.plotarea && t.plotarea.fill; stroke = t.plotarea && t.plotarea.stroke; if(fill){ this.surface.createRect({ x: offsets.l, y: offsets.t, width: dim.width - offsets.l - offsets.r, height: dim.height - offsets.t - offsets.b }).setFill(fill); } if(stroke){ this.surface.createRect({ x: offsets.l, y: offsets.t, width: dim.width - offsets.l - offsets.r - 1, height: dim.height - offsets.t - offsets.b - 1 }).setStroke(stroke); } // go over the stack backwards df.foldr(this.stack, function(z, plot){ return plot.render(dim, offsets), 0; }, 0); // go over axes df.forIn(this.axes, function(axis){ axis.render(dim, offsets); }); this._makeClean(); return this; }, _makeClean: function(){ // reset dirty flags dojo.forEach(this.axes, makeClean); dojo.forEach(this.stack, makeClean); dojo.forEach(this.series, makeClean); this.dirty = false; }, _makeDirty: function(){ // reset dirty flags dojo.forEach(this.axes, makeDirty); dojo.forEach(this.stack, makeDirty); dojo.forEach(this.series, makeDirty); this.dirty = true; } }); })(); }