Commits

Chris Leonello committed 542542b

Add tickInterval and numberTicks handling to auto tick generation of dateAxisRenderer.
It will not garauntee a given interval or number of ticks, but will try to honor users wishes while still making nice ticks.
Updated example.

Comments (0)

Files changed (2)

examples/dateAxisRenderer.html

   <script language="javascript" type="text/javascript" src="../src/jquery.jqplot.js"></script>
   <script language="javascript" type="text/javascript" src="../src/plugins/jqplot.dateAxisRenderer.js"></script>
   <script language="javascript" type="text/javascript" src="../src/plugins/jqplot.categoryAxisRenderer.js"></script>
+  <script language="javascript" type="text/javascript" src="../src/plugins/jqplot.canvasTextRenderer.js"></script>
+  <script language="javascript" type="text/javascript" src="../src/plugins/jqplot.canvasAxisTickRenderer.js"></script>
   <script language="javascript" type="text/javascript" src="../src/plugins/jqplot.ohlcRenderer.js"></script>
   <script language="javascript" type="text/javascript" src="../src/plugins/jqplot.highlighter.js"></script>
-<!--  <script language="javascript" type="text/javascript" src="../src/plugins/jqplot.cursor.js"></script>
 -->
 
   <!-- END: load jqplot -->
-<script language="javascript" type="text/javascript">
-  
-$(document).ready(function(){
-      $.jqplot.config.enablePlugins = true;
-    
+<script type="text/javascript">
     var ohlc = [['07/06/09', 138.7, 139.68, 135.18, 135.4],
     ['06/29/09', 143.46, 144.66, 139.79, 140.02],
     ['06/22/09', 140.67, 143.56, 132.88, 142.44],
     ['09/15/08', 147.69, 120.68, 140.91],
     ['09/08/08', 164.89, 146, 148.94]
     ];
-       
+</script>
 
-    var ticks = ['08/01/08', '12/01/08', '04/01/09', '08/01/09'];
+<script class="code" type="text/javascript">
+$(document).ready(function(){
+    title: "CandleStick Chart",
+    // Globally enable plugins like cursor and highlighter
+    $.jqplot.config.enablePlugins = true;
 
-	$.jsDate.config.defaultCentury = 2000;
+    // for 2 digit years, set the default centry to 2000.
+    $.jsDate.config.defaultCentury = 2000;
     
     plot1 = $.jqplot('chart1',[ohlc],{
-      title: 'Default Pad',
-      axesDefaults:{},
-      axes: {
+        axes: {
           xaxis: {
               renderer:$.jqplot.DateAxisRenderer,
-              tickOptions:{formatString:'%Y.%m.%d'}, 
-              autoscale: true
           },
           yaxis: {
-              tickOptions:{formatString:'%.2f'}
+              tickOptions:{prefix: '$'}
           }
-      },
-      series: [{renderer:$.jqplot.OHLCRenderer, rendererOptions:{candleStick:true}}],
-      cursor:{
-          zoom:true,
-          tooltipOffset: 10,
-          tooltipLocation: 'nw'
-      },
-      highlighter: {
-          showMarker:false,
-          tooltipAxes: 'xy',
-          yvalues: 4,
-          formatString:'<table class="jqplot-highlighter"><tr><td>date:</td><td>%s</td></tr><tr><td>open:</td><td>%s</td></tr><tr><td>hi:</td><td>%s</td></tr><tr><td>low:</td><td>%s</td></tr><tr><td>close:</td><td>%s</td></tr></table>'
-      }
+        },
+        series: [
+            {
+                renderer:$.jqplot.OHLCRenderer, 
+                rendererOptions:{ 
+                    candleStick:true 
+                }
+            }
+        ],
+        highlighter: {
+            showMarker:false,
+            tooltipAxes: 'xy',
+            yvalues: 4,
+            formatString:'<table class="jqplot-highlighter"> \
+                <tr><td>date:</td><td>%s</td></tr> \
+                <tr><td>open:</td><td>%s</td></tr> \
+                <tr><td>hi:</td><td>%s</td></tr> \
+                <tr><td>low:</td><td>%s</td></tr> \
+                <tr><td>close:</td><td>%s</td></tr> \
+            </table>'
+        }
     });
+});
+</script>
+
+<script class="code" type="text/javascript">
+$(document).ready(function(){
         
     plot2 = $.jqplot('chart2',[ohlc],{
-      title: 'Pad = 1.02',
-      axesDefaults:{},
-      axes: {
-          xaxis: {
-              renderer:$.jqplot.DateAxisRenderer,
-              tickOptions:{formatString:'%Y.%m.%d'},
-              autoscale: true,
-              pad: 1.02
-          },
-          yaxis: {
-              tickOptions:{formatString:'%.2f'}
-          }
-      },
-      series: [{renderer:$.jqplot.OHLCRenderer, rendererOptions:{candleStick:true}}],
-      cursor:{
-          zoom:true,
-          tooltipOffset: 10,
-          tooltipLocation: 'nw'
-      },
-      highlighter: {
-          showMarker:false,
-          tooltipAxes: 'xy',
-          yvalues: 4,
-          formatString:'<table class="jqplot-highlighter"><tr><td>date:</td><td>%s</td></tr><tr><td>open:</td><td>%s</td></tr><tr><td>hi:</td><td>%s</td></tr><tr><td>low:</td><td>%s</td></tr><tr><td>close:</td><td>%s</td></tr></table>'
-      }
+        title: 'OHLC chart',
+        axes: {
+            xaxis: {
+                renderer:$.jqplot.DateAxisRenderer,
+                tickRenderer: $.jqplot.CanvasAxisTickRenderer,
+                tickOptions: {
+                    angle: -30
+                }
+            },
+            yaxis: {
+                tickOptions:{formatString:'%.2f'}
+            }
+        },
+        series: [
+            {
+                renderer:$.jqplot.OHLCRenderer
+            }
+        ],
+        highlighter: {
+            showMarker:false,
+            tooltipAxes: 'xy',
+            yvalues: 4,
+            formatString:'<table class="jqplot-highlighter"> \
+                <tr><td>date:</td><td>%s</td></tr> \
+                <tr><td>open:</td><td>%s</td></tr> \
+                <tr><td>hi:</td><td>%s</td></tr> \
+                <tr><td>low:</td><td>%s</td></tr> \
+                <tr><td>close:</td><td>%s</td></tr> \
+            </table>'
+        }
     });
+});
+</script>
+
+<script class="code" type="text/javascript">
+$(document).ready(function(){
         
     plot3 = $.jqplot('chart3',[ohlc],{
-      title: 'Pad = 2.02',
-      axesDefaults:{},
-      axes: {
-          xaxis: {
-              renderer:$.jqplot.DateAxisRenderer,
-              tickOptions:{formatString:'%Y.%m.%d'},
-              autoscale: true,
-              pad: 2.02
-          },
-          yaxis: {
-              tickOptions:{formatString:'%.2f'}
-          }
-      },
-      series: [{renderer:$.jqplot.OHLCRenderer, rendererOptions:{candleStick:true}}],
-      cursor:{
-          zoom:true,
-          tooltipOffset: 10,
-          tooltipLocation: 'nw'
-      },
-      highlighter: {
-          showMarker:false,
-          tooltipAxes: 'xy',
-          yvalues: 4,
-          formatString:'<table class="jqplot-highlighter"><tr><td>date:</td><td>%s</td></tr><tr><td>open:</td><td>%s</td></tr><tr><td>hi:</td><td>%s</td></tr><tr><td>low:</td><td>%s</td></tr><tr><td>close:</td><td>%s</td></tr></table>'
-      }
+        title: 'Pad = 2.02',
+        axesDefaults:{},
+        axes: {
+            xaxis: {
+                renderer:$.jqplot.DateAxisRenderer,
+                tickRenderer: $.jqplot.CanvasAxisTickRenderer,
+                numberTicks: 7,
+                tickOptions: {
+                    angle: -30
+                }
+            },
+            yaxis: {
+                tickOptions:{formatString:'%.2f'}
+            }
+        },
+        series: [
+            {
+                renderer:$.jqplot.OHLCRenderer, 
+                rendererOptions:{ 
+                    candleStick:true 
+                }
+            }
+        ],
+        highlighter: {
+            showMarker:false,
+            tooltipAxes: 'xy',
+            yvalues: 4,
+            formatString:'<table class="jqplot-highlighter"> \
+                <tr><td>date:</td><td>%s</td></tr> \
+                <tr><td>open:</td><td>%s</td></tr> \
+                <tr><td>hi:</td><td>%s</td></tr> \
+                <tr><td>low:</td><td>%s</td></tr> \
+                <tr><td>close:</td><td>%s</td></tr> \
+            </table>'
+        }
     });
-    
 });
-
-
 </script>
+<script type="text/javascript" src="example.js"></script>
 
   </head>
   <body>

src/plugins/jqplot.dateAxisRenderer.js

         min = ((this.min != null) ? new $.jsDate(this.min).getTime() : db.min);
         max = ((this.max != null) ? new $.jsDate(this.max).getTime() : db.max);
 
-        // padding: min = min(2-padmin);
-
         // see if we're zooming.  if we are, don't use the min and max we're given,
         // but compute some nice ones.  They will be reset later.
 
         else if (this.min == null && this.max == null) {
             var opts = $.extend(true, {}, this.tickOptions, {name: this.name, value: null});
             // want to find a nice interval 
-            if (!this.tickInterval) {
+            var nttarget,
+                titarget;
+
+            // if no tickInterval or numberTicks options specified,  make a good guess.
+            if (!this.tickInterval && !this.numberTicks) {
                 var tdim = Math.max(dim, threshold+1);
-                var nttarget =  Math.ceil((tdim-threshold)/75 + 1);
-                var titarget = (max - min) / (nttarget - 1);
+                // how many ticks to put on the axis?
+                // date labels tend to be long.  If ticks not rotated,
+                // don't use too many and have a high spacing factor.
+                // If we are rotating ticks, use a lower factor.
+                var spacingFactor = 115;
+                if (this.tickRenderer === $.jqplot.CanvasAxisTickRenderer && this.tickOptions.angle) {
+                    spacingFactor = 115 - 40 * Math.abs(Math.sin(this.tickOptions.angle/180*Math.PI));
+                }
+                nttarget =  Math.ceil((tdim-threshold)/spacingFactor + 1);
+                titarget = (max - min) / (nttarget - 1);
+            }
 
-                // If we can use an interval of 2 weeks or less, pick best one
-                if (titarget <= niceIntervals[niceIntervals.length-1] * 1.5) {
-                    var ret = bestDateInterval(min, max, titarget);
-                    var tempti = ret[0];
-                    this._autoFormatString = ret[1];
+            // If tickInterval is specified, we'll try to honor it.
+            // Not gauranteed to get this interval, but we'll get as close as
+            // we can.
+            // tickInterval will be used before numberTicks, that is if
+            // both are specified, numberTicks will be ignored.
+            else if (this.tickInterval) {
+                titarget = this.tickInterval;
+            }
 
-                    min = Math.floor(min/tempti) * tempti;
-                    min = new $.jsDate(min);
-                    min = min.getTime() + min.getUtcOffset();
+            // if numberTicks specified, try to honor it.
+            // Not gauranteed, but will try to get close.
+            else if (this.numberTicks) {
+                nttarget = this.numberTicks;
+                titarget = (max - min) / (nttarget - 1);
+            }
 
-                    nttarget = Math.ceil((max - min) / tempti) + 1;
-                    this.min = min;
-                    this.max = min + (nttarget - 1) * tempti;
+            // If we can use an interval of 2 weeks or less, pick best one
+            if (titarget <= niceIntervals[niceIntervals.length-1] * 1.5) {
+                var ret = bestDateInterval(min, max, titarget);
+                var tempti = ret[0];
+                this._autoFormatString = ret[1];
 
-                    // if max is less than max, add an interval
-                    if (this.max < max) {
-                        this.max += tempti;
-                        nttarget += 1;
+                min = Math.floor(min/tempti) * tempti;
+                min = new $.jsDate(min);
+                min = min.getTime() + min.getUtcOffset();
+
+                nttarget = Math.ceil((max - min) / tempti) + 1;
+                this.min = min;
+                this.max = min + (nttarget - 1) * tempti;
+
+                // if max is less than max, add an interval
+                if (this.max < max) {
+                    this.max += tempti;
+                    nttarget += 1;
+                }
+                this.tickInterval = tempti;
+                this.numberTicks = nttarget;
+
+                for (var i=0; i<nttarget; i++) {
+                    opts.value = this.min + i * tempti;
+                    t = new this.tickRenderer(opts);
+                    
+                    if (this._overrideFormatString && this._autoFormatString != '') {
+                        t.formatString = this._autoFormatString;
                     }
-                    this.tickInterval = tempti;
-                    this.numberTicks = nttarget;
-
-                    for (var i=0; i<nttarget; i++) {
-                        opts.value = this.min + i * tempti;
-                        t = new this.tickRenderer(opts);
-                        
-                        if (this._overrideFormatString && this._autoFormatString != '') {
-                            t.formatString = this._autoFormatString;
-                        }
-                        if (!this.showTicks) {
-                            t.showLabel = false;
-                            t.showMark = false;
-                        }
-                        else if (!this.showTickMarks) {
-                            t.showMark = false;
-                        }
-                        this._ticks.push(t);
+                    if (!this.showTicks) {
+                        t.showLabel = false;
+                        t.showMark = false;
                     }
-
-                    insetMult = this.tickInterval;
+                    else if (!this.showTickMarks) {
+                        t.showMark = false;
+                    }
+                    this._ticks.push(t);
                 }
 
-                // should we use a monthly interval?
-                else if (titarget <= 9 * month) {
+                insetMult = this.tickInterval;
+            }
 
-                    this._autoFormatString = '%v';
+            // should we use a monthly interval?
+            else if (titarget <= 9 * month) {
 
-                    // how many months in an interval?
-                    var intv = Math.round(titarget/month);
-                    if (intv < 1) {
-                        intv = 1;
-                    }
-                    else if (intv > 6) {
-                        intv = 6;
-                    }
+                this._autoFormatString = '%v';
 
-                    // figure out the starting month and ending month.
-                    var mstart = new $.jsDate(min).setDate(1).setHours(0,0,0,0);
-                    var mend = new $.jsDate(max).add(1, 'month').setDate(1).setHours(0,0,0,0);
-
-                    var nmonths = mend.diff(mstart, 'month');
-
-                    nttarget = Math.ceil(nmonths/intv) + 1;
-
-                    this.min = mstart.getTime();
-                    this.max = mstart.clone().add((nttarget - 1) * intv, 'month').getTime();
-                    this.numberTicks = nttarget;
-
-                    for (var i=0; i<nttarget; i++) {
-                        if (i === 0) {
-                            opts.value = mstart.getTime();
-                        }
-                        else {
-                            opts.value = mstart.add(intv, 'month').getTime();
-                        }
-                        t = new this.tickRenderer(opts);
-                        
-                        if (this._overrideFormatString && this._autoFormatString != '') {
-                            t.formatString = this._autoFormatString;
-                        }
-                        if (!this.showTicks) {
-                            t.showLabel = false;
-                            t.showMark = false;
-                        }
-                        else if (!this.showTickMarks) {
-                            t.showMark = false;
-                        }
-                        this._ticks.push(t);
-                    }
-
-                    insetMult = intv * month;
+                // how many months in an interval?
+                var intv = Math.round(titarget/month);
+                if (intv < 1) {
+                    intv = 1;
+                }
+                else if (intv > 6) {
+                    intv = 6;
                 }
 
-                // use yearly intervals
-                else {
+                // figure out the starting month and ending month.
+                var mstart = new $.jsDate(min).setDate(1).setHours(0,0,0,0);
+                var mend = new $.jsDate(max).add(1, 'month').setDate(1).setHours(0,0,0,0);
 
-                    this._autoFormatString = '%v';
+                var nmonths = mend.diff(mstart, 'month');
 
-                    // how many months in an interval?
-                    var intv = Math.round(titarget/year);
-                    if (intv < 1) {
-                        intv = 1;
+                nttarget = Math.ceil(nmonths/intv) + 1;
+
+                this.min = mstart.getTime();
+                this.max = mstart.clone().add((nttarget - 1) * intv, 'month').getTime();
+                this.numberTicks = nttarget;
+
+                for (var i=0; i<nttarget; i++) {
+                    if (i === 0) {
+                        opts.value = mstart.getTime();
                     }
-
-                    // figure out the starting and ending years.
-                    var mstart = new $.jsDate(min).setMonth(0, 1).setHours(0,0,0,0);
-                    var mend = new $.jsDate(max).add(1, 'year').setMonth(0, 1).setHours(0,0,0,0);
-
-                    var nyears = mend.diff(mstart, 'year');
-
-                    nttarget = Math.ceil(nyears/intv) + 1;
-
-                    this.min = mstart.getTime();
-                    this.max = mstart.clone().add((nttarget - 1) * intv, 'year').getTime();
-                    this.numberTicks = nttarget;
-
-                    for (var i=0; i<nttarget; i++) {
-                        if (i === 0) {
-                            opts.value = mstart.getTime();
-                        }
-                        else {
-                            opts.value = mstart.add(intv, 'year').getTime();
-                        }
-                        t = new this.tickRenderer(opts);
-                        
-                        if (this._overrideFormatString && this._autoFormatString != '') {
-                            t.formatString = this._autoFormatString;
-                        }
-                        if (!this.showTicks) {
-                            t.showLabel = false;
-                            t.showMark = false;
-                        }
-                        else if (!this.showTickMarks) {
-                            t.showMark = false;
-                        }
-                        this._ticks.push(t);
+                    else {
+                        opts.value = mstart.add(intv, 'month').getTime();
                     }
-
-                    insetMult = intv * year;
+                    t = new this.tickRenderer(opts);
+                    
+                    if (this._overrideFormatString && this._autoFormatString != '') {
+                        t.formatString = this._autoFormatString;
+                    }
+                    if (!this.showTicks) {
+                        t.showLabel = false;
+                        t.showMark = false;
+                    }
+                    else if (!this.showTickMarks) {
+                        t.showMark = false;
+                    }
+                    this._ticks.push(t);
                 }
 
+                insetMult = intv * month;
             }
 
-            // else tickInterval specified by user
+            // use yearly intervals
             else {
-                
+
+                this._autoFormatString = '%v';
+
+                // how many years in an interval?
+                var intv = Math.round(titarget/year);
+                if (intv < 1) {
+                    intv = 1;
+                }
+
+                // figure out the starting and ending years.
+                var mstart = new $.jsDate(min).setMonth(0, 1).setHours(0,0,0,0);
+                var mend = new $.jsDate(max).add(1, 'year').setMonth(0, 1).setHours(0,0,0,0);
+
+                var nyears = mend.diff(mstart, 'year');
+
+                nttarget = Math.ceil(nyears/intv) + 1;
+
+                this.min = mstart.getTime();
+                this.max = mstart.clone().add((nttarget - 1) * intv, 'year').getTime();
+                this.numberTicks = nttarget;
+
+                for (var i=0; i<nttarget; i++) {
+                    if (i === 0) {
+                        opts.value = mstart.getTime();
+                    }
+                    else {
+                        opts.value = mstart.add(intv, 'year').getTime();
+                    }
+                    t = new this.tickRenderer(opts);
+                    
+                    if (this._overrideFormatString && this._autoFormatString != '') {
+                        t.formatString = this._autoFormatString;
+                    }
+                    if (!this.showTicks) {
+                        t.showLabel = false;
+                        t.showMark = false;
+                    }
+                    else if (!this.showTickMarks) {
+                        t.showMark = false;
+                    }
+                    this._ticks.push(t);
+                }
+
+                insetMult = intv * year;
             }
         }