Subversion Repositories Applications.papyrus

Rev

Blame | Last modification | View Log | RSS feed

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.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.forEachReversed(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;
                }
        });
})();

}