Commits

Chris Leonello  committed 7001cd9

Started putting together unit tests.
got the category axis renderer working.

  • Participants
  • Parent commits cd753af

Comments (0)

Files changed (6)

File jqplot.categoryAxisRenderer.js

 	    }
 	};
     
-    $.jqplot.categoryAxisRenderer = function() {
-        $.jqplot.linearAxisRenderer.call(this);
+    $.jqplot.CategoryAxisRenderer = function() {
+        $.jqplot.LinearAxisRenderer.call(this);
     };
     
-    $.jqplot.categoryAxisRenderer.prototype = new $.jqplot.linearAxisRenderer();
-    $.jqplot.categoryAxisRenderer.prototype.constructor = $.jqplot.categoryAxisRenderer;
+    $.jqplot.CategoryAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
+    $.jqplot.CategoryAxisRenderer.prototype.constructor = $.jqplot.CategoryAxisRenderer;
  
 
-    $.jqplot.categoryAxisRenderer.prototype.setAxis = function(plotHeight, plotWidth) {
+    $.jqplot.CategoryAxisRenderer.prototype.createTicks = function() {
         // we're are operating on an axis here
-        var axis = this;
+        log("in category axis renderer create ticks");
         var ticks = this._ticks;
         var name = this.name;
+        // databounds were set on axis initialization.
         var db = this._dataBounds;
         var dim, interval;
         var min, max;
         var pos1, pos2;
         var tt, i;
+
+        //////////////////////////
+        //////////////////////////
+        // fix me
+        //////////////////////////
+        // if we already have ticks, use them.
+        // ticks must be in order of increasing value.
+        if (ticks.length) {
+            // for (i=0; i<ticks.length; i++){
+            //     var t = ticks[i];
+            //     if (!t.label) t.label = t.value.toString();
+            //     // set iitial css positioning styles for the ticks.
+            //     var pox = i*15+'px';
+            //     switch (name) {
+            //         case 'xaxis':
+            //             t._styles = {position:'absolute', top:'0px', left:pox, paddingTop:'10px'};
+            //             break;
+            //         case 'x2axis':
+            //             t._styles = {position:'absolute', bottom:'0px', left:pox, paddingBottom:'10px'};
+            //             break;
+            //         case 'yaxis':
+            //             t._styles = {position:'absolute', right:'0px', top:pox, paddingRight:'10px'};
+            //             break;
+            //         case 'y2axis':
+            //             t._styles = {position:'absolute', left:'0px', top:pox, paddingLeft:'10px'};
+            //             break;
+            //     }
+            // }
+            // axis.numberTicks = ticks.length;
+            // axis.min = ticks[0].value;
+            // axis.max = ticks[axis.numberTicks-1].value;
+            // axis.tickInterval = (axis.max - axis.min) / (axis.numberTicks - 1);
+        }
+
+        // we don't have any ticks yet, let's make some!
+        else {
+            if (name == 'xaxis' || name == 'x2axis') {
+                dim = this._plotDimensions.width;
+            }
+            else {
+                dim = this._plotDimensions.height;
+            }
         
-        this._canvasHeight = plotHeight;
-        this._canvasWidth = plotWidth;
-        
-        // if tick
-        
-        // Ticks should have been already specified by the user or set by the line renderer.  Since we
-        // don't have access to the series, there's not much to do if we don't already have ticks.
-        if (ticks.length) {
-            this.numberTicks =ticks.length;
-            for (i=0; i<ticks.length; i++){
-                var t = ticks[i];
-                if (!t.label) t.label = this.formatter(this.formatString, t.value.toString());
-                // databounds should have been set to 0, 2*series length in line renderer
-                this.min = db.min;
-                this.max = db.max;
-                // set iitial css positioning styles for the ticks.
-                var pox = i*15+'px';
-                switch (name) {
-                    case 'xaxis':
-                        t._styles = {position:'absolute', top:'0px', left:pox, paddingTop:'10px'};
-                        break;
-                    case 'x2axis':
-                        t._styles = {position:'absolute', bottom:'0px', left:pox, paddingBottom:'10px'};
-                        break;
-                    case 'yaxis':
-                        t._styles = {position:'absolute', right:'0px', top:pox, paddingRight:'10px'};
-                        break;
-                    case 'y2axis':
-                        t._styles = {position:'absolute', left:'0px', top:pox, paddingLeft:'10px'};
-                        break;
+            // find out how many categories are in the lines and collect labels
+            var labels = [];
+            var numcats = 0;
+            var min = 0.5;
+            var max;
+            for (var i=0; i<this._series.length; i++) {
+                var s = this._series[i];
+                log(s);
+                for (var j=0; j<s.data.length; j++) {
+                    var val = String(s.data[j][0]);
+                    log(val);
+                    if ($.inArray(val, labels) == -1) {
+                        numcats += 1;      
+                        labels.push(val);
+                    }
+                    // for category axis, force the x values into category bins.
+                    s.data[j][0] = j+1;
                 }
             }
+        
+            max = numcats + 0.5;
+            this.numberTicks = 2*numcats + 1;
+
+            var range = max - min;
+            this.min = min;
+            this.max = max;
+            var maxVisibleTicks = parseInt(3+dim/50);
+
+
+            this.tickInterval = range / (this.numberTicks-1);
+            for (var i=0; i<this.numberTicks; i++){
+                tt = this.min + i * range / (this.numberTicks-1);
+                var t = new this.tickRenderer(this.tickOptions);
+                // if even tick, it isn't a category, it's a divider
+                if (i/2 == parseInt(i/2)) {
+                    t.showLabel = false;
+                    t.showMark = true;
+                    t.showGridline = true;
+                }
+                else {
+                    t.showLabel = true;
+                    t.label = labels[(i-1)/2];
+                    t.showMark = false;
+                    t.showGridline = false;
+                }
+                if (!this.showTicks) {
+                    t.showLabel = false;
+                    t.showMark = false;
+                }
+                else if (!this.showTickMarks) t.showMark = false;
+                t.setTick(tt, this.name);
+                this._ticks.push(t);
+            }
+            log(this);
         }
-        
-        // we don't have any ticks yet, try to guess based on the bounds.
-        else {
-            // TBD what to do here.
-        }
-        
-        if (name == 'yaxis' || name == 'y2axis') this.ticks.styles.reverse();
     };
     
     

File jqplot.logAxisRenderer.js

             var rmin, rmax;
 
             if (this.tickDistribution == 'even') {                    
-                // for log axes, open up range to get a nice power of axis.renderer.base.
-                rmin = min - min*((this.pad-1)/2);
-                rmax = max + max*((this.pad-1)/2);
+                rmin = (this.min != null) ? this.min : min - min*((this.pad-1)/2);
+                rmax = (this.max != null) ? this.max : max + max*((this.pad-1)/2);
                 this.min = rmin;
                 this.max = rmax;
                 range = this.max - this.min;            
             }
             
             else if (this.tickDistribution == 'power'){
-                
-                // for log axes, open up range to get a nice power of axis.renderer.base.
+                // for power distribution, open up range to get a nice power of axis.renderer.base.
+                // don't respect the user's min/max settings. (fix this).
                 rmin = Math.pow(this.base, Math.ceil(Math.log(min*(2-this.pad))/Math.log(this.base))-1);
                 rmax = Math.pow(this.base, Math.floor(Math.log(max*this.pad)/Math.log(this.base))+1);
                 this.min = rmin;

File jquery.jqplot.js

         var _data, _options;
         
         // check to see if only 2 arguments were specified, what is what.
+        if (data == null) throw "No data specified";
         if (options == null) {
             if (data instanceof Array) {
                 _data = data;
         return this._elem;
     };
     
-    $.jqplot.LinearAxisRenderer.prototype.set = function() {   
+    $.jqplot.LinearAxisRenderer.prototype.set = function() { 
         var dim = 0;
         var temp; 
         if (this.show && this.showTicks) {
             if (this.name == 'xaxis' || this.name == 'x2axis') {
                 for (i=0; i<ticks.length; i++) {
                     var t = ticks[i];
-                    var shim = t.getWidth()/2;
-                    var val = this.u2p(t.value) - shim + 'px';
-                    t._elem.css('left', val);
+                    if (t.show && t.showLabel) {
+                        var shim = t.getWidth()/2;
+                        var val = this.u2p(t.value) - shim + 'px';
+                        t._elem.css('left', val);
+                    }
                 }
             }
             else {
                 for (i=0; i<ticks.length; i++) {
                     var t = ticks[i];
-                    var shim = t.getHeight()/2;
-                    var val = this.u2p(t.value) - shim + 'px';
-                    t._elem.css('top', val);
+                    if (t.show && t.showLabel) {
+                        var shim = t.getHeight()/2;
+                        var val = this.u2p(t.value) - shim + 'px';
+                        t._elem.css('top', val);
+                    }
                 }
             }
-        }    
+        }   
+        log(this); 
     };
 
     // class: $.jqplot.AxisTickRenderer
         // prop: showMark
         // wether or not to show the mark on the axis.
         this.showMark = true;
+        // prop: showGridline
+        // wether or not to draw the gridline on the grid at this tick.
+        this.showGridline = true;
         // prop: isMinorTick
         // if this is a minor tick.
         this.isMinorTick = false;
         
         // prop: show
         // Wether to display the legend on the graph.
-        this.show = true;
+        this.show = false;
         // prop: location
         // Placement of the legend.  one of the compas directions: nw, n, ne, e, se, s, sw, w
         this.location = 'ne';
                 var axis = axes[name];
                 var ticks = axis._ticks;
                 if (axis.show) {
-                    switch (name) {
-                        case 'xaxis':
-                            for (var i=0; i<ticks.length; i++) {
-                                var pos = Math.round(axis.u2p(axis._ticks[i].value)) + 0.5;
-                                drawLine(pos, this._top, pos, this._bottom);
+                    for (var i=0; i<ticks.length; i++) {
+                        var t = axis._ticks[i];
+                        if (t.show && t.showGridline) {
+                            var pos = Math.round(axis.u2p(t.value)) + 0.5;
+                            switch (name) {
+                                case 'xaxis':
+                                    drawLine(pos, this._top, pos, this._bottom);
+                                    break;
+                                case 'yaxis':
+                                    drawLine(this._right, pos, this._left, pos);
+                                    break;
+                                case 'x2axis':
+                                    drawLine(pos, this._bottom, pos, this._top);
+                                    break;
+                                case 'y2axis':
+                                    drawLine(this._left, pos, this._right, pos);
+                                    break;
                             }
-                            break;
-                        case 'yaxis':
-                            for (var i=0; i<ticks.length; i++) {
-                                var pos = Math.round(axis.u2p(axis._ticks[i].value)) + 0.5;
-                                drawLine(this._right, pos, this._left, pos);
-                            }
-                            break;
-                        case 'x2axis':
-                            for (var i=0; i<ticks.length; i++) {
-                                var pos = Math.round(axis.u2p(axis._ticks[i].value)) + 0.5;
-                                drawLine(pos, this._bottom, pos, this._top);
-                            }
-                            break;
-                        case 'y2axis':
-                            for (var i=0; i<ticks.length; i++) {
-                                var pos = Math.round(axis.u2p(axis._ticks[i].value)) + 0.5;
-                                drawLine(this._left, pos, this._right, pos);
-                            }
-                            break;
+                        }
                     }
                 }
             }
                 var s = to.markSize;
                 var m = to.mark;
                 var t = axis._ticks;
-                switch (name) {
-                    case 'xaxis':
-                        for (var i=0; i<t.length; i++) {
-                            var pos = Math.round(axis.u2p(t[i].value)) + 0.5;
-                            var b, e;
-                            switch (m) {
-                                case 'inside':
-                                    b = this._bottom-s;
-                                    e = this._bottom;
-                                    break;
-                                case 'outside':
-                                    b = this._bottom;
-                                    e = this._bottom+s;
-                                    break;
-                                case 'cross':
-                                    b = this._bottom-s;
-                                    e = this._bottom+s;
-                                    break;
-                                default:
-                                    b = this._bottom;
-                                    e = this._bottom+s;
-                                    break;
-                            }
-                            drawLine(pos, b, pos, e);
+                for (var i=0; i<t.length; i++) {
+                    if (t[i].show && t[i].showMark) {
+                        var pos = Math.round(axis.u2p(t[i].value)) + 0.5;
+                        var b, e;
+                        switch (name)     {
+                            case 'xaxis':
+                                switch (m) {
+                                    case 'inside':
+                                        b = this._bottom-s;
+                                        e = this._bottom;
+                                        break;
+                                    case 'outside':
+                                        b = this._bottom;
+                                        e = this._bottom+s;
+                                        break;
+                                    case 'cross':
+                                        b = this._bottom-s;
+                                        e = this._bottom+s;
+                                        break;
+                                    default:
+                                        b = this._bottom;
+                                        e = this._bottom+s;
+                                        break;
+                                }
+                                drawLine(pos, b, pos, e);
+                                break;
+                            case 'yaxis':
+                                switch (m) {
+                                    case 'outside':
+                                        b = this._left-s;
+                                        e = this._left;
+                                        break;
+                                    case 'inside':
+                                        b = this._left;
+                                        e = this._left+s;
+                                        break;
+                                    case 'cross':
+                                        b = this._left-s;
+                                        e = this._left+s;
+                                        break;
+                                    default:
+                                        b = this._left-s;
+                                        e = this._left;
+                                        break;
+                                }
+                                drawLine(b, pos, e, pos);
+                                break;
+                            case 'x2axis':
+                                switch (m) {
+                                    case 'outside':
+                                        b = this._top-s;
+                                        e = this._top;
+                                        break;
+                                    case 'inside':
+                                        b = this._top;
+                                        e = this._top+s;
+                                        break;
+                                    case 'cross':
+                                        b = this._top-s;
+                                        e = this._top+s;
+                                        break;
+                                    default:
+                                        b = this._top-s;
+                                        e = this._top;
+                                        break;
+                                }
+                                drawLine(pos, b, pos, e);
+                                break;
+                            case 'y2axis':
+                                switch (m) {
+                                    case 'inside':
+                                        b = this._right-s;
+                                        e = this._right;
+                                        break;
+                                    case 'outside':
+                                        b = this._right;
+                                        e = this._right+s;
+                                        break;
+                                    case 'cross':
+                                        b = this._right-s;
+                                        e = this._right+s;
+                                        break;
+                                    default:
+                                        b = this._right;
+                                        e = this._right+s;
+                                        break;
+                                }
+                                drawLine(b, pos, e, pos);
+                                break;
                         }
-                        break;
-                    case 'yaxis':
-                        for (var i=0; i<t.length; i++) {
-                            var pos = Math.round(axis.u2p(t[i].value)) + 0.5;
-                            var b, e;
-                            switch (m) {
-                                case 'outside':
-                                    b = this._left-s;
-                                    e = this._left;
-                                    break;
-                                case 'inside':
-                                    b = this._left;
-                                    e = this._left+s;
-                                    break;
-                                case 'cross':
-                                    b = this._left-s;
-                                    e = this._left+s;
-                                    break;
-                                default:
-                                    b = this._left-s;
-                                    e = this._left;
-                                    break;
-                            }
-                            drawLine(b, pos, e, pos);
-                        }
-                        break;
-                    case 'x2axis':
-                        for (var i=0; i<t.length; i++) {
-                            var pos = Math.round(axis.u2p(t[i].value)) + 0.5;
-                            var b, e;
-                            switch (m) {
-                                case 'outside':
-                                    b = this._top-s;
-                                    e = this._top;
-                                    break;
-                                case 'inside':
-                                    b = this._top;
-                                    e = this._top+s;
-                                    break;
-                                case 'cross':
-                                    b = this._top-s;
-                                    e = this._top+s;
-                                    break;
-                                default:
-                                    b = this._top-s;
-                                    e = this._top;
-                                    break;
-                            }
-                            drawLine(pos, b, pos, e);
-                        }
-                        break;
-                    case 'y2axis':
-                        for (var i=0; i<t.length; i++) {
-                            var pos = Math.round(axis.u2p(t[i].value)) + 0.5;
-                            var b, e;
-                            switch (m) {
-                                case 'inside':
-                                    b = this._right-s;
-                                    e = this._right;
-                                    break;
-                                case 'outside':
-                                    b = this._right;
-                                    e = this._right+s;
-                                    break;
-                                case 'cross':
-                                    b = this._right-s;
-                                    e = this._right+s;
-                                    break;
-                                default:
-                                    b = this._right;
-                                    e = this._right+s;
-                                    break;
-                            }
-                            drawLine(b, pos, e, pos);
-                        }
-                        break;
+                    }
                 }
             }
         }
         this.equalYTicks = true;
         // prop: seriesColors
         // default colors for the series.#c29549
-        this.seriesColors = [ "#4bb2c5", "#c5b47f", "#cba02e", "#579575", "#839557", "#958c12", "#953579"];
+        this.seriesColors = [ "#4bb2c5", "#c5b47f", "#EAA228", "#579575", "#839557", "#958c12", "#953579"];
         this._seriesColorsIndex = 0;
         // prop textColor
         // css spec for the css color attribute.  Default for the entire plot.
         this.init = function(target, data, options) {
             this.targetId = target;
             this.target = $('#'+target);
-            if (!this.target) throw "No plot target specified";
+            if (!this.target.get(0)) throw "No plot target specified";
             
             // make sure the target is positioned by some means and set css
             if (this.target.css('position') == 'static') this.target.css('position', 'relative');
             
             for (var i=0; i<this.series.length; i++) {
                 this.series[i]._plotDimensions = this._plotDimensions;
-               this.series[i].init();
+                this.series[i].init();
             }
 
             for (var name in this.axes) {

File samples/dualaxis.png

Added
New image

File unittest.html

+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+   "http://www.w3.org/TR/html4/loose.dtd">
+
+<html lang="en">
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+	<title>unittest</title>
+    <script language="javascript" type="text/javascript" src="../jquery-1.3.2.js"></script>
+	<link rel="stylesheet" href="../../jspec/pkg/jspec.css" type="text/css" media="screen" title="no title" charset="utf-8">
+	<script src="../../jspec/pkg/jspec.js"></script>
+	<script src="../../jspec/pkg/jspec.jquery.js"></script>
+	<script src="jquery.jqplot.js"></script>
+	<script src="jqplot.logAxisRenderer.js"></script>
+	<script>
+    function runSuites() {
+      JSpec.options.profile = true;
+      JSpec
+      .exec('unittest.js')
+      .run()
+      .report()
+    }
+  </script>
+  <style type="text/css">
+  div.jqPLot {
+    position:relative;
+    margin-left: 20px;
+    margin-top: 30px;
+  }
+  </style>
+</head>
+	<body class="jspec" onLoad="runSuites();">
+		<div id="jspec-top"><h2 id="jspec-title">JSpec <em><script>document.write(JSpec.version)</script></em></h2></div>
+		<div id="jspec"></div>
+		<div id="jspec-bottom"></div>
+		
+		<div class="jqPLot" id="chart0"></div>
+		<div class="jqPLot"  id="chart1"></div>
+		<div class="jqPLot"  id="chart2" style="height:300px;width:480px;"></div>
+		<div class="jqPLot"  id="chart3" style="height:300px;width:480px;"></div>
+		<div class="jqPLot"  id="chart4" style="height:300px;width:480px;"></div>
+		<div class="jqPLot"  id="chart5" style="height:300px;width:480px;"></div>
+		<div class="jqPLot"  id="chart6" style="height:300px;width:480px;"></div>
+		<div class="jqPLot"  id="chart7" style="height:300px;width:480px;"></div>
+		<div class="jqPLot"  id="chart8" style="height:300px;width:480px;"></div>
+		<div class="jqPLot"  id="chart9" style="height:300px;width:480px;"></div>
+		<div class="jqPLot"  id="chart10" style="height:300px;width:480px;"></div>
+</body>
+</html>
+
+describe 'jqPlot'
+    describe '.init(target, data, options)'
+        it 'catch no data specified'
+            -{ $.jqplot('chart0', null) }.should.throw_error 'No data specified'
+        end
+
+        it 'catch no plot target specified'
+            -{ $.jqplot('nada', [[1,2,3,4]]) }.should.throw_error 'No plot target specified'
+        end
+
+        it 'catch canvas dimensions <=0'
+            -{ $.jqplot('chart1', [[1,2,3,4]]) }.should.throw_error 'Canvas dimensions <=0'
+        end
+    end
+    
+    describe 'Line options'
+    
+        it 'Multiple mixed data lines'
+            chart = $.jqplot('chart2', [[[1,1],[1.5, 2.25],[2,4],[2.5,6.25],[3,9],[3.5,12.25],[4,16]],[25, 12.5, 6.25, 3.125], [4, 25, 21, 9]], {
+                legend:{show:true},
+                title:'Mixed Data Lines',
+                series:[{label:'Rising line', showLine:false, markerOptions:{style:'square'}}, {label:'Declining line'}, {label:'Zig Zag Line', lineWidth:5, showMarker:false}]
+            })
+            chart.axes.xaxis.should.have_property '_elem'
+            chart.axes.yaxis.should.have_property '_elem'
+            chart.title.should.have_property '_elem'
+            chart.seriesCanvas.should.have_property '_elem'
+            chart.series.should.have_property 'length', 3
+            chart.series[0].markerRenderer.style.should.equal 'square'
+            chart.series[0].showLine.should.be_false
+            chart.series[2].lineWidth.should.equal 5
+            chart.title.text.should.be 'Mixed Data Lines'
+        end
+    end
+    
+    describe 'Axes options' 
+        it 'Secondary log y axis and options'
+            chart = $.jqplot('chart3', [[[1,1],[2,4],[3,9],[4,16]],[25, 12.5, 6.25, 3.125]], {
+                legend:{show:true, location:'e'},
+                title:'Secondary Log Axis',
+                series:[{label:'Rising line'},{yaxis:'y2axis', label:'Declining line'}], 
+                axes:{xaxis:{min:0, max:5}, y2axis:{renderer:$.jqplot.LogAxisRenderer, min:2, max:30}}
+            })
+            chart.axes.xaxis.should.have_property '_elem'
+            chart.axes.yaxis.should.have_property '_elem'
+            chart.axes.y2axis.should.have_property '_elem'
+            chart.title.should.have_property '_elem'
+            chart.seriesCanvas.should.have_property '_elem'
+            chart.axes.y2axis.renderer.constructor.should.be $.jqplot.LogAxisRenderer
+            chart.axes.y2axis.base.should.equal 10
+            chart.legend.location.should.be 'e'
+            chart.title.text.should.be 'Secondary Log Axis'
+            chart.axes.xaxis.min.should.be 0
+            chart.axes.xaxis.max.should.be 5
+        end
+        it 'Secondary log y axis, power distribution'
+            chart = $.jqplot('chart4', [[[1,1],[2,4],[3,9],[4,16]],[25, 12.5, 6.25, 3.125]], {
+                legend:{show:true, location:'e'},
+                title:'Secondary Log Axis, Power Distribution',
+                series:[{label:'Rising line'},{yaxis:'y2axis', label:'Declining line'}], 
+                axes:{xaxis:{min:0, max:5}, y2axis:{tickDistribution:'power', renderer:$.jqplot.LogAxisRenderer, min:2, max:30}}
+            })
+            chart.axes.xaxis.should.have_property '_elem'
+            chart.axes.yaxis.should.have_property '_elem'
+            chart.axes.y2axis.should.have_property '_elem'
+            chart.title.should.have_property '_elem'
+            chart.seriesCanvas.should.have_property '_elem'
+            chart.axes.y2axis.renderer.constructor.should.equal $.jqplot.LogAxisRenderer
+            chart.axes.y2axis.base.should.equal 10
+            chart.legend.location.should.be 'e'
+            chart.title.text.should.be 'Secondary Log Axis, Power Distribution'
+            chart.axes.xaxis.min.should.be 0
+            chart.axes.xaxis.max.should.be 5
+            chart.axes.y2axis.tickDistribution.should.be 'power'
+        end
+    end
+
+end