001    /*
002     * Copyright 2007,2008 John C. Gunther
003     * 
004     * Licensed under the Apache License, Version 2.0 (the
005     * "License"); you may not use this file except in compliance
006     * with the License. You may obtain a copy of the License at:
007     * 
008     *  http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing,
011     * software distributed under the License is distributed on an
012     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013     * either express or implied. See the License for the specific
014     * language governing permissions and limitations under the
015     * License.
016     * 
017     */
018    package com.googlecode.gchart.client;
019    
020    import com.google.gwt.i18n.client.DateTimeFormat;
021    import com.google.gwt.i18n.client.NumberFormat;
022    import com.google.gwt.user.client.DOM;
023    import com.google.gwt.user.client.Event;
024    import com.google.gwt.user.client.ui.AbsolutePanel;
025    import com.google.gwt.user.client.ui.Composite;
026    import com.google.gwt.user.client.ui.DockPanel;
027    import com.google.gwt.user.client.ui.Grid;
028    import com.google.gwt.user.client.ui.HasHorizontalAlignment;
029    import com.google.gwt.user.client.ui.HasVerticalAlignment;
030    import com.google.gwt.user.client.ui.HorizontalPanel;
031    import com.google.gwt.user.client.ui.HTML;
032    import com.google.gwt.user.client.ui.Image;
033    import com.google.gwt.user.client.ui.MouseListener;
034    import com.google.gwt.user.client.ui.UIObject;
035    import com.google.gwt.user.client.ui.VerticalPanel;
036    import com.google.gwt.user.client.ui.Widget;
037    
038    import java.util.ArrayList;
039    import java.util.Date;
040    
041    /**
042     * A GChart can represent and display a line chart, a bar chart,
043     * a pie chart, an area chart, or a chart that contains arbitrary
044     * combinations of line, bar, pie, and/or area based curves.
045     * 
046     * <p>
047     * For detailed examples, with screen shots, visit the
048     * <a href="package-summary.html#ChartGallery">
049     * Chart Gallery</a>. 
050     * 
051     * <p>
052     * For detailed instructions on how to integrate Client-side GChart
053     * into your GWT application, see
054     * <a href="package-summary.html#InstallingGChart">
055     * Installing Client-side GChart</a>.
056     * 
057     * <p>
058     * <b>CSS Style Rule</b>
059     * <ul>
060     * .gchart-GChart { the GChart's primary top-level styles }
061     * </ul>
062     *
063     *
064     * It is sometimes more natural to consider certain CSS
065     * attributes as properties of a GChart Java object. So, GChart
066     * supports "CSS convenience methods" that let you (optionally) use
067     * Java to specify GChart CSS attributes such as
068     * <tt>border-color</tt> and <tt>background-color</tt>. See
069     * {@link #USE_CSS USE_CSS} for a detailed description of these
070     * CSS convenience methods--which won't interfere with standard
071     * CSS-based specifications if you never invoke them.
072     *
073     * 
074     **/ 
075    
076    public class GChart extends Composite {
077    
078       
079       /**
080        ** Defines the location of a data point's annotation (text
081        ** label) relative to the location of that point's symbol.
082        ** The default annotation location is {@link
083        ** AnnotationLocation#SOUTH SOUTH}.  The "Field Summary"
084        ** section below lists all available annotation locations.
085        ** 
086        ** <p>
087        ** 
088        ** You can further adjust the position of a point's
089        ** annotation by specifying non-zero positional shifts via
090        ** the <tt>setAnnotationXShift</tt> and
091        ** <tt>setAnnotationYShift</tt> methods.
092        **
093        ** @see Curve.Point#setAnnotationLocation Point.setAnnotationLocation
094        ** @see Curve.Point#setAnnotationXShift Point.setAnnotationXShift
095        ** @see Curve.Point#setAnnotationYShift Point.setAnnotationYShift
096        ** 
097        **/ 
098       public static final class AnnotationLocation {
099          /**
100           ** Specifies that a point's annotation (label) should
101           ** be positioned so as to be centered on the symbol
102           ** used to represent the point.
103           **
104           ** @see Curve.Point#setAnnotationLocation setAnnotationLocation
105           **/
106          public static final AnnotationLocation CENTER =
107            new AnnotationLocation(0,0);
108    
109          private static final AnnotationLocation north =
110             new AnnotationLocation(0,-1);
111          private static final AnnotationLocation west =
112            new AnnotationLocation(-1, 0);
113          private static final AnnotationLocation south =
114              new AnnotationLocation(0, 1);
115          
116          /**
117           ** Specifies that a point's annotation (label) should be
118           ** placed just above, and centered horizontally on,
119           ** vertical bars that grow down from a horizontal
120           ** baseline, and just below, and centered horizontally on,
121           ** vertical bars that grow up from a horizontal baseline.
122           **
123           ** <p>
124           **
125           ** This another name for
126           ** <tt>AnnotationLocation.NORTH</tt>. Its sole purpose is
127           ** to clarify/document the behavior of this location type
128           ** when used in conjunction with curves that employ 
129           ** <tt>VBAR_BASELINE_*</tt> symbol types.
130           **
131           ** @see Curve.Point#setAnnotationLocation setAnnotationLocation
132           ** @see SymbolType#VBAR_BASELINE_CENTER SymbolType.VBAR_BASELINE_CENTER
133           ** 
134           **/
135          public static final AnnotationLocation 
136              CLOSEST_TO_HORIZONTAL_BASELINE = north;
137          
138          /**
139           ** Specifies that a point's annotation (label) should be
140           ** placed just to the right of, and centered vertically
141           ** on, horizontal bars that grow left from a vertical
142           ** baseline, and just to the left of, and centered
143           ** vertically on, horizontal bars that grow right from a
144           ** vertical baseline.
145           **
146           ** <p>
147           **
148           ** This another name for
149           ** <tt>AnnotationLocation.WEST</tt>. Its sole purpose is
150           ** to clarify/document the behavior of this location type
151           ** when used in conjunction with curves that employ the
152           ** <tt>HBAR_BASELINE_*</tt> symbol types.
153           **
154           ** @see Curve.Point#setAnnotationLocation setAnnotationLocation
155           ** @see SymbolType#HBAR_BASELINE_CENTER SymbolType.HBAR_BASELINE_CENTER
156           ** 
157           **/
158           
159          public static final AnnotationLocation 
160             CLOSEST_TO_VERTICAL_BASELINE = west;
161          
162          /**
163           ** Specifies that a point's annotation (label) should
164           ** be positioned just to the right of, and vertically
165           ** centered on, the symbol used to represent the
166           ** point.
167           **
168           ** @see Curve.Point#setAnnotationLocation
169           **/
170          public static final AnnotationLocation EAST =
171             new AnnotationLocation(1, 0);
172    
173          /**
174           ** Specifies that a point's annotation (label) should be
175           ** placed just below, and centered horizontally on,
176           ** vertical bars that grow down from a horizontal
177           ** baseline, and just above, and centered horizontally on,
178           ** vertical bars that grow up from a horizontal baseline.
179           **
180           ** <p>
181           **
182           ** This another name for
183           ** <tt>AnnotationLocation.SOUTH</tt>. Its sole purpose is
184           ** to clarify/document the behavior of this location type
185           ** when used in conjunction with curves that employ
186           ** <tt>VBAR_BASELINE_*</tt> symbol types.
187           **
188           ** @see Curve.Point#setAnnotationLocation setAnnotationLocation
189           ** @see SymbolType#VBAR_BASELINE_CENTER SymbolType.VBAR_BASELINE_CENTER
190           ** 
191           **/
192          public static final AnnotationLocation
193              FARTHEST_FROM_HORIZONTAL_BASELINE = south;
194          
195          /**
196           ** Specifies that a point's annotation (label) should be
197           ** placed just to the left of, and centered vertically on,
198           ** horizontal bars that grow left from a vertical
199           ** baseline, and just to the right of, and centered
200           ** vertically on, horizontal bars that grow right from a
201           ** vertical baseline.
202           **
203           ** <p>
204           **
205           ** This another name for
206           ** <tt>AnnotationLocation.EAST</tt>. Its sole purpose is
207           ** to clarify/document the behavior of this location type
208           ** when used in conjunction with curves that employ the
209           ** <tt>HBAR_BASELINE_*</tt> family of symbol types.
210           **
211           ** @see Curve.Point#setAnnotationLocation setAnnotationLocation
212           ** @see SymbolType#HBAR_BASELINE_CENTER SymbolType.HBAR_BASELINE_CENTER
213           ** 
214           **/
215          public static final AnnotationLocation 
216              FARTHEST_FROM_VERTICAL_BASELINE = EAST;
217          
218    
219          /**
220           ** Specifies that a point's annotation (label) should
221           ** be positioned just inside, and centered on, the
222           ** arc side of a pie slice.
223           ** <p>
224           ** 
225           ** You can move a pie slice's annotation a specific number
226           ** of pixels radially away from (or towards) the pie
227           ** center by passing a positive (or negative) argument to
228           ** the associated <tt>Point</tt>'s
229           ** <tt>setAnnotationXShift</tt> method.
230           ** 
231           ** <p> This is pie-friendly synonym for, and when used
232           ** with non-pie symbol types will behave exactly the same
233           ** as, <tt>AnnotationLocation.NORTH</tt>
234           **      
235           ** @see #OUTSIDE_PIE_ARC OUTSIDE_PIE_ARC
236           ** @see #ON_PIE_ARC ON_PIE_ARC
237           ** @see Curve.Point#setAnnotationLocation setAnnotationLocation
238           ** @see AnnotationLocation#NORTH NORTH
239           **/
240          public static final AnnotationLocation INSIDE_PIE_ARC = north;
241    
242          /**
243           ** Specifies that a point's annotation (label) should
244           ** be positioned just above, and horizontally centered on,
245           ** the symbol used to represent the point.
246           **
247           ** @see Curve.Point#setAnnotationLocation setAnnotationLocation
248           **/
249          public static final AnnotationLocation NORTH = north;
250    
251    
252          /**
253           ** Specifies that a point's annotation (label) should
254           ** be positioned just to the right of and above,
255           ** the symbol used to represent the
256           ** point.
257           **
258           ** @see Curve.Point#setAnnotationLocation
259           **/
260          public static final AnnotationLocation NORTHEAST =
261            new AnnotationLocation(1, -1);
262    
263          /**
264           ** Specifies that a point's annotation (label) should
265           ** be positioned just to the left of and above,
266           ** the symbol used to represent the
267           ** point.
268           **
269           ** @see Curve.Point#setAnnotationLocation
270           **/
271          public static final AnnotationLocation NORTHWEST =
272            new AnnotationLocation(-1, -1);
273    
274          
275          /**
276           ** Specifies that a point's annotation (label) should
277           ** be centered on the center-point of the
278           ** arc side of a pie slice.
279           ** <p>
280           **
281           ** You can move a pie slice's annotation a specific number
282           ** of pixels radially away from (or towards) the pie
283           ** center by passing a positive (or negative) argument to
284           ** the associated <tt>Point</tt>'s
285           ** <tt>setAnnotationXShift</tt> method.
286           ** 
287           **
288           ** 
289           ** <p> This is pie-friendly synonym for, and when used
290           ** with non-pie symbol types will behave exactly the same
291           ** as, <tt>AnnotationLocation.CENTER</tt>
292           **
293           ** @see #OUTSIDE_PIE_ARC OUTSIDE_PIE_ARC
294           ** @see #INSIDE_PIE_ARC INSIDE_PIE_ARC
295           ** @see Curve.Point#setAnnotationLocation setAnnotationLocation
296           ** @see AnnotationLocation#CENTER CENTER
297           ** 
298           **/
299          public static final AnnotationLocation ON_PIE_ARC = CENTER;
300    
301          /**
302           ** Specifies that a point's annotation (label) should
303           ** be positioned just outside, and centered on, the
304           ** arc side of a pie slice.
305           ** <p>
306           ** 
307           ** You can move a pie slice's annotation a specific number
308           ** of pixels radially away from (or towards) the pie
309           ** center by passing a positive (or negative) argument to
310           ** the associated <tt>Point</tt>'s
311           ** <tt>setAnnotationXShift</tt> method.
312           ** 
313           ** <p> This is pie-friendly synonym for, and when used
314           ** with non-pie symbol types will behave exactly the same
315           ** as, <tt>AnnotationLocation.SOUTH</tt>
316           **
317           ** @see #INSIDE_PIE_ARC INSIDE_PIE_ARC
318           ** @see #ON_PIE_ARC ON_PIE_ARC
319           ** @see Curve.Point#setAnnotationLocation setAnnotationLocation
320           ** @see Curve.Point#setAnnotationXShift setAnnotationXShift
321           ** @see AnnotationLocation#SOUTH SOUTH
322           **/
323          public static final AnnotationLocation OUTSIDE_PIE_ARC = south;
324    
325          /**
326           ** Specifies that a point's annotation (label) should
327           ** be positioned just below, and horizontally centered on,
328           ** the symbol used to represent the point.
329           **
330           ** @see Curve.Point#setAnnotationLocation setAnnotationLocation
331           **/
332          public static final AnnotationLocation SOUTH = south;
333    
334          
335          /**
336           ** Specifies that a point's annotation (label) should
337           ** be positioned just to the right of and below,
338           ** the symbol used to represent the
339           ** point.
340           **
341           ** @see Curve.Point#setAnnotationLocation setAnnotationLocation
342           **/
343          public static final AnnotationLocation SOUTHEAST =
344            new AnnotationLocation(1, 1);
345          /**
346           ** Specifies that a point's annotation (label) should
347           ** be positioned just to the left of and below,
348           ** the symbol used to represent the
349           ** point.
350           **
351           ** @see Curve.Point#setAnnotationLocation setAnnotationLocation
352           **/
353          public static final AnnotationLocation SOUTHWEST =
354            new AnnotationLocation(-1, 1);
355    
356          /**
357           ** Specifies that a point's annotation (label) should
358           ** be positioned just to the left of, and vertically
359           ** centered on, the symbol used to represent the
360           ** point.
361           **
362           ** @see Curve.Point#setAnnotationLocation setAnnotationLocation
363           **/
364          public static final AnnotationLocation WEST = west;
365    
366          
367          
368          // these multiply the width and height of the annotation and
369          // the symbol it is attached to in order to define the
370          // center of the annotation (see equations in later code),
371          // and thus the upper left corner anchoring point.
372          private int heightMultiplier;
373          private int widthMultiplier;
374          private AnnotationLocation(int widthMultiplier,
375                                 int heightMultiplier) {
376            validateMultipliers(widthMultiplier, heightMultiplier);
377            this.widthMultiplier = widthMultiplier;
378            this.heightMultiplier = heightMultiplier;
379          }
380          // retrieves a static location given its multipliers
381          private static AnnotationLocation getAnnotationLocation(
382             int widthMultiplier, int heightMultiplier) {
383            final AnnotationLocation[][] locationMap = {
384             {NORTHWEST, NORTH, NORTHEAST},
385             {WEST, CENTER, EAST},
386             {SOUTHWEST, SOUTH, SOUTHEAST}};
387       // assumes both multiplier are -1, 0, or 1   
388            AnnotationLocation result =
389             locationMap[heightMultiplier+1][widthMultiplier+1];
390           return result;                
391          }
392                                                       
393          // Negative width or height "turn the symbol inside-out",
394          // requiring a corresponding "reflection" of annotation
395          // location (only needed for baseline-based bar symbols)
396          static AnnotationLocation transform(AnnotationLocation a,
397                                              int signWidth,
398                                              int signHeight) {
399            AnnotationLocation result = a;
400            if (signWidth < 0 || signHeight < 0) 
401               result = getAnnotationLocation(
402                    signWidth*a.widthMultiplier,
403                    signHeight*a.heightMultiplier);
404    
405            return result;
406          }
407          // These define the alignment of the label within it's
408          // containing 1 x 1 Grid. For example, if this
409          // containing grid is to the left of the labeled
410          // symbol (widthMultiplier==-1) the horizontal
411          // alignment will be ALIGN_RIGHT, so as to bring the
412          // contained label flush against the left edge of the
413          // labeled symbol.
414          HasHorizontalAlignment.HorizontalAlignmentConstant
415                getHorizontalAlignment() {
416             HasHorizontalAlignment.HorizontalAlignmentConstant result;
417             if (widthMultiplier == -1)
418                result = HasHorizontalAlignment.ALIGN_RIGHT;
419             else if (widthMultiplier == 0)
420                result = HasHorizontalAlignment.ALIGN_CENTER;
421             else if (widthMultiplier == 1)
422                result = HasHorizontalAlignment.ALIGN_LEFT;
423             else
424                throw new IllegalStateException(
425                   "Invalid widthMultiplier: " + widthMultiplier +
426                   " 1, 0, or -1 were expected.");
427             return result;
428          }
429    
430          /* Given the x-coordinate at the center of the symbol
431           * that this annotation annotates, the annotation's
432           * width, and the symbol's width, this method returns
433           * the x-coordinate of the upper left corner of
434           * this annotation.
435           */
436          int getUpperLeftX(double x, double w, double symbolW) {
437             int result = (int) Math.round(x +
438               (widthMultiplier * (w + symbolW) - w)/2.);
439             return result;
440          }
441    
442          /* analogous to getUpperLeftX, except for the y-coordinate */
443          int getUpperLeftY(double y, double h, double symbolH) {
444             int result = (int) Math.round(y +
445               (heightMultiplier * (h + symbolH) - h)/2.);
446             return result;
447          }
448          // analogous to getHorizontalAlignment  
449          HasVerticalAlignment.VerticalAlignmentConstant
450                getVerticalAlignment() {
451             HasVerticalAlignment.VerticalAlignmentConstant result;
452             if (heightMultiplier == -1)
453                result = HasVerticalAlignment.ALIGN_BOTTOM;
454             else if (heightMultiplier == 0)
455                result = HasVerticalAlignment.ALIGN_MIDDLE;
456             else if (heightMultiplier == 1)
457                result = HasVerticalAlignment.ALIGN_TOP;
458             else
459                throw new IllegalStateException(
460                   "Invalid heightMultiplier: " + heightMultiplier +
461                   " -1, 0, or 1 were expected.");
462             return result;
463          }
464    
465    
466           /*
467            * This method returns the annotation location whose
468            * "attachment point" keeps the annotation either
469            * completely outside, centered on, or completely inside
470            * (depending on if the heightMultiplier of this annotation
471            * is 1, 0, or -1) the point on the pie's circumference
472            * associated with the given angle.
473            * <p>
474            *
475            * The use of heightMultiplier rather than widthMultiplier
476            * is somewhat arbitrary, but was chosen so that the
477            * NORTH, CENTER, and SOUTH annotation locations have the
478            * same interpretation for a pie slice whose bisecting
479            * radius points due south (due south is the default initial
480            * pie slice orientation) and for a 1px x 1px BOX_CENTER
481            * type symbol positioned at the due south position on the
482            * pie's circumference. As the pie-slice-arc-bisection
483            * point moves clockwise around the pie perimeter, the
484            * attachment point (except for vertically-centered
485            * annotations, which remain centered on the pie arc) also
486            * moves clockwise, but in discrete jumps (e.g. from
487            * NORTH, to NORTHEAST, to EAST, to SOUTHEAST, to SOUTH,
488            * etc. for annotations inside the pie) so the annotation
489            * remains appropriately attached to the center of the
490            * slice's arc as the angle changes.
491            * 
492            */
493         AnnotationLocation decodePieLocation(double thetaMid) {
494            // a sin or cos that is small enough so that the
495            // associated angle is horizontal (for sines) or vertical
496            // (for cosines) enough to warrent use of a "centered"
497            // annotation location.
498           final double LOOKS_VERTICAL_OR_HORIZONTAL_DELTA = 0.1; 
499           double sinTheta = Math.sin(thetaMid); 
500           double cosTheta = Math.cos(thetaMid); 
501           int pieTransformedWidthMultiplier = heightMultiplier *
502              ((cosTheta < -LOOKS_VERTICAL_OR_HORIZONTAL_DELTA)? -1 :
503              ((cosTheta > LOOKS_VERTICAL_OR_HORIZONTAL_DELTA)? 1 : 0));
504           int pieTransformedHeightMultiplier = heightMultiplier *
505              ((sinTheta < -LOOKS_VERTICAL_OR_HORIZONTAL_DELTA)? 1 :
506              ((sinTheta > LOOKS_VERTICAL_OR_HORIZONTAL_DELTA)? -1 : 0));
507                 
508           return getAnnotationLocation(pieTransformedWidthMultiplier,
509                                        pieTransformedHeightMultiplier);
510             
511         }
512          
513       } // end of class AnnotationLocation
514    
515      /**
516       ** Represents an axis of the chart, for example, the x,
517       ** y, or y2 axis. An axis consists of the axis itself,
518       ** along with its tick marks, tick labels and gridlines.
519       **
520       ** @see XAxis XAxis
521       ** @see YAxis YAxis
522       ** @see Y2Axis Y2Axis
523       ** @see #getXAxis getXAxis 
524       ** @see #getYAxis getYAxis
525       ** @see #getY2Axis getY2Axis
526       ** 
527       **
528       **/ 
529      public abstract class Axis {
530         // holds info needed to render a single axis tick
531         private class TickInfo {
532            double position;  // along the tick axis in model units
533            String tickLabel;
534            Widget tickWidget;
535            int widthUpperBound;  // upperbound on size of an enclosing
536            int heightUpperBound; // 1 x 1 grid (used for centering, etc.)
537            TickInfo(double position, String tickLabel, Widget tickWidget,
538                     int widthUpperBound,
539                     int heightUpperBound) {
540               this.position = position;
541               this.tickLabel = tickLabel;
542               this.tickWidget = tickWidget;
543               this.widthUpperBound = widthUpperBound;
544               this.heightUpperBound = heightUpperBound;
545            }
546         } // end of class TickInfo
547         protected class AxisLimits { 
548          double max; double min; // in user-defined model units 
549         }
550         private Widget axisLabel;
551         private boolean hasGridlines = false;
552         private int tickCount = DEFAULT_TICK_COUNT;
553         private ArrayList tickInfo = new ArrayList();
554    // axes auto-scale whenever min or max are NaN.
555         protected double axisMax = Double.NaN;
556         protected double axisMin = Double.NaN;
557    // this symbol facilitates rendering of gridlines & axes
558         protected Symbol gridSymbol;
559         protected String tickLabelFontColor = DEFAULT_TICK_LABEL_FONT_COLOR;
560    // In CSS font-size pixels. These define the height of each
561    // character; our code relies on the rule of thumb that
562    // character width is approximately 3/5th this height to
563    // obtain a reasonably tight upper bound on tick label widths.
564         protected int tickLabelFontSize = DEFAULT_TICK_LABEL_FONTSIZE;
565         protected String tickLabelFontStyle = DEFAULT_TICK_LABEL_FONT_STYLE;
566         protected String tickLabelFontWeight = DEFAULT_TICK_LABEL_FONT_WEIGHT;
567    
568         protected String tickLabelFormat = DEFAULT_TICK_LABEL_FORMAT;
569         protected int tickLabelThickness = GChart.NAI;
570         protected int ticksPerLabel = 1;
571         protected int ticksPerGridline = 1;
572         protected int tickLength = DEFAULT_TICK_LENGTH;
573         
574         // this symbol facilitates rendering of labeled tick-marks
575         protected Symbol tickSymbol;
576         protected int tickThickness = DEFAULT_TICK_THICKNESS;
577         protected WidgetCursor widgetCursor = new WidgetCursor();
578    
579             
580         // is axis itself visible (has no impact ticks or their labels)
581         boolean axisVisible = true;
582         
583         WidgetCursor getWidgetCursor() { return widgetCursor;}
584         /**
585          * Adds a tick on this axis at the specified position.
586          * Note that explicitly adding a single tick via this method
587          * will eliminate any implicitly generated ticks associated with the
588          * <tt>setTickCount</tt> method.
589          * <p>
590          * The label associated with this tick will be generated by
591          * applying the format specified via <tt>setTickLabelFormat</tt>
592          * to the specified position.
593          * <p>
594          * This is a convenience method equivalent to
595          * <tt>addTick(tickPosition, null, GChart.NAI,
596          * GChart.NAI)</tt>. See {@link #addTick(double,String,int,int)
597          * addTick(tickPosition,tickLabel,widthUpperBound,heightUpperBound)}
598          * for details.
599          * 
600          * @param tickPosition the position, in model units,
601          *   along this axis at which this tick is displayed.
602          *   For example, if the axis range goes from 0 to 100,
603          *   a tick at position 50 would appear in the middle of
604          *   the axis.
605          *
606          * @see #clearTicks clearTicks
607          * @see #addTick(double,String) addTick(double,String)
608          * @see #addTick(double,String,int,int) addTick(double,String,int,int)
609          * @see #addTick(double,Widget,int,int) addTick(double,Widget,int,int)
610          * @see #setTickCount setTickCount
611          * @see #setTickLabelFormat setTickLabelFormat
612          * @see #setTickLabelFontStyle setTickLabelFontStyle
613          * @see #setTickLabelFontColor setTickLabelFontColor
614          * @see #setTickLabelFontWeight setTickLabelFontWeight
615          * @see #setTickLabelFontSize setTickLabelFontSize
616          * 
617          */
618         public void addTick(double tickPosition) {
619            addTick(tickPosition, (String) null);  
620         }
621         /**
622          * Adds a tick at the specified position with the specified
623          * label on this axis, whose width and height are within
624          * the specified upper-bounds.
625          * 
626          * <p>
627          * Note that explicitly adding a single tick via this method
628          * will eliminate any auto-generated ticks associated with the
629          * <tt>setTickCount</tt> method. 
630          * 
631          * <p>
632          * Use this method to specify unusually spaced
633          * tick marks with labels that do not directly
634          * reflect the position (for example, for a logarithmic axis,
635          * or for a bar chart with special keyword-type labels, or
636          * a time axis that places date and time on two separate lines).
637          * 
638          * @param tickPosition the position, in model units, along
639          *   this axis at which the tick is displayed.
640          *   For example, if the axis range goes from 0 to 1,
641          *   a tick at position 0.5 would appear in the middle of
642          *   the axis.
643          *   
644          *  @param tickLabel the label for this tick.  HTML is
645          *  supported in tick labels, but it must be prefixed by
646          *  <tt>&lt;html&gt</tt>.  See the {@link
647          *  Curve.Point#setAnnotationText(String,int,int)
648          *  setAnnotationText} method for more information.
649          *
650          *  @param widthUpperBound an upper bound on the width of
651          *  the text or HTML, in pixels. Use <tt>GChart.NAI</tt> to
652          *  get GChart to estimate this width for you. See the
653          *  <tt>setAnnotationText</tt> method for more information.
654          * 
655          *  @param heightUpperBound an upper bound on the height of
656          *  the text or HTML, in pixels. Use <tt>GChart.NAI</tt> to
657          *  get GChart to estimate this height for you. See the
658          *  <tt>setAnnotationText</tt> method for more information.
659          *
660          * @see #clearTicks clearTicks
661          * @see #addTick(double) addTick(double)
662          * @see #addTick(double,String) addTick(double,String)
663          * @see #addTick(double,Widget,int,int) addTick(double,Widget,int,int)
664          * @see #setTickCount setTickCount
665          * @see #setTickLabelFormat setTickLabelFormat
666          * @see #setTickLabelFontSize setTickLabelFontSize
667          * @see #setTickLabelFontStyle setTickLabelFontStyle
668          * @see #setTickLabelFontColor setTickLabelFontColor
669          * @see #setTickLabelFontWeight setTickLabelFontWeight
670          * @see Curve.Point#setAnnotationText(String,int,int)
671          *      setAnnotationText
672          * @see Curve.Point#setAnnotationWidget setAnnotationWidget
673          *      
674          */
675         public void addTick(double tickPosition, String tickLabel,
676                             int widthUpperBound,
677                             int heightUpperBound) {
678           plotPanel.invalidateWidgetsAfterCursor(widgetCursor);
679    // position of plot area can depend on size of tick labels
680           plotPanel.plotAreaNeedsUpdate(); 
681           tickCount = 0; // eliminates any auto-generated ticks   
682           tickInfo.add(new TickInfo(tickPosition, tickLabel, null,
683                                     widthUpperBound,
684                                     heightUpperBound));
685         }
686    
687         /**
688          * Adds a tick at the specified position with the specified
689          * label on this axis.
690          * <p>
691          *
692          * This is a convenience method equivalent to
693          * <tt>addTick(tickPosition, tickLabel, GChart.NAI,
694          * GChart.NAI)</tt>. Most applications can usually just
695          * use this convenience method. See {@link #addTick(double,String,int,int)
696          * addTick(tickPosition,tickLabel,
697          * widthUpperBound,heightUpperBound)} for the fine print.
698          *
699          * @param tickPosition the position, in model units, along
700          *   this axis at which the tick is displayed.
701          *   
702          * @param tickLabel the plain text or
703          * (<tt>&lt;html&gt</tt>-prefixed) HTML defining the tick's
704          * label.
705          *
706          * @see #addTick(double,String,int,int) addTick(double,String,int,int)
707          * @see #addTick(double,Widget) addTick(double,Widget)
708          * 
709          */ 
710         public void addTick(double tickPosition,
711                             String tickLabel) {
712              addTick(tickPosition, tickLabel, GChart.NAI, GChart.NAI);
713         }
714         
715         /**
716          *  Adds a widget-defined tick label at the specified
717          *  position, whose width and height are within
718          *  the specified upper-bounds.
719          * 
720          *
721          *  <p>
722          ** 
723          ** This method is similar to
724          ** <tt>addTick(double,String,int,int)</tt> except that it
725          ** uses a widget, rather than a string, to define the
726          ** tick's label. Although the string-based method is faster
727          ** on first chart rendering, and uses less memory, the
728          ** widget-based method allows you to change the label
729          ** independently of the chart--potentially bypassing (or
730          ** speeding up) expensive chart updates later on.
731          **
732          ** <p>
733          ** 
734          ** You might use a widget-based tick label to pop up a
735          ** dialog that allows the user to edit the parameters
736          ** defining the axis (min, max, etc.) whenever they click
737          ** on one of the tick labels on that axis, to define
738          ** hovertext that appears when the user mouses over
739          ** a tick label, to use images for your tick labels, etc. 
740          **
741          * @param tickPosition the position, in model units, along
742          *   this axis at which the tick is displayed.
743          *   For example, if the axis range goes from 0 to 1,
744          *   a tick at position 0.5 would appear in the middle of
745          *   the axis.
746          *   
747          *  @param tickWidget the label for this tick, as defined
748          *  by any GWT Widget.
749          *
750          *  @param widthUpperBound an upper bound on the width of
751          *  the widget, in pixels. If this and the next
752          *  parameter are omitted, GChart will use
753          *  <tt>DEFAULT_WIDGET_WIDTH_UPPERBOUND</tt>.
754          *  
755          *  @param heightUpperBound an upper bound on the height of
756          *  the widget, in pixels. If this and the previous
757          *  parameter are omitted, GChart will use <tt>
758          *  DEFAULT_WIDGET_HEIGHT_UPPERBOUND</tt>
759          *
760          *  @see #addTick(double,Widget) addTick(double,Widget) 
761          *  @see #addTick(double,String,int,int) addTick(double,String,int,int) 
762          *  @see Curve.Point#setAnnotationWidget setAnnotationWidget
763          *  @see #DEFAULT_WIDGET_WIDTH_UPPERBOUND DEFAULT_WIDGET_WIDTH_UPPERBOUND
764          *  @see #DEFAULT_WIDGET_HEIGHT_UPPERBOUND DEFAULT_WIDGET_HEIGHT_UPPERBOUND
765          **/ 
766         public void addTick(double tickPosition, 
767                             Widget tickWidget,
768                             int widthUpperBound,
769                             int heightUpperBound) {
770           plotPanel.invalidateWidgetsAfterCursor(widgetCursor);
771           plotPanel.plotAreaNeedsUpdate();
772           // accept "Not an Integer" (because text-based addTick does)
773           if (widthUpperBound == GChart.NAI)
774              widthUpperBound = DEFAULT_WIDGET_WIDTH_UPPERBOUND;
775           if (heightUpperBound == GChart.NAI)
776              heightUpperBound = DEFAULT_WIDGET_HEIGHT_UPPERBOUND;
777           tickCount = 0; // eliminates any auto-generated ticks   
778           tickInfo.add(new TickInfo(tickPosition, null, tickWidget,
779                                     widthUpperBound,
780                                     heightUpperBound));
781         }
782    
783         /**
784          *  Adds a Widget-defined tick label at the specified
785          *  position. Convenience method equivalent to
786          *  <tt>addTick(tickPosition, tickWidget,
787          *  DEFAULT_WIDGET_WIDTH_UPPERBOUND,
788          *  DEFAULT_WIDGET_HEIGHT_UPPERBOUND)</tt>.
789          *  
790          * @param tickPosition the position, in model units, along
791          *   this axis at which the tick is displayed.
792          *   For example, if the axis range goes from 0 to 1,
793          *   a tick at position 0.5 would appear in the middle of
794          *   the axis.
795          *   
796          * @param tickWidget the label for this tick, as defined
797          *  by any GWT Widget.
798          *  
799          * @see #addTick(double,Widget,int,int)
800          * addTick(double,Widget,int,int)
801          *  
802          */
803         public void addTick(double tickPosition,
804                             Widget tickWidget) {
805            addTick(tickPosition, tickWidget,
806                    DEFAULT_WIDGET_WIDTH_UPPERBOUND,
807                    DEFAULT_WIDGET_HEIGHT_UPPERBOUND);
808         }
809         /**
810          *
811          * Removes all ticks from this axis. Specifically,
812          * erases any ticks that were explicitly specified via
813          * <tt>addTick</tt>, and also sets the tick count to 0.
814          * <p>
815          * 
816          * @see #setTickCount setTickCount
817          * @see #addTick(double) addTick(double)
818          * @see #addTick(double,String) addTick(double,String)
819          * @see #addTick(double,String,int,int) addTick(double,String,int,int)
820          * @see #addTick(double,Widget) addTick(double,Widget)
821          * @see #addTick(double,Widget,int,int) addTick(double,Widget,int,int)
822          * 
823          */
824         public void clearTicks() {
825            plotPanel.invalidateWidgetsAfterCursor(widgetCursor);
826            plotPanel.plotAreaNeedsUpdate(); 
827            tickCount = 0;
828            tickInfo.clear();
829         }
830         // these are used in formatting tick positions into tick labels:
831         private NumberFormat numberFormat =
832            NumberFormat.getFormat(DEFAULT_TICK_LABEL_FORMAT);
833         private DateTimeFormat dateFormat =
834            DateTimeFormat.getShortDateTimeFormat();
835         private final int NUMBER_FORMAT_TYPE = 0;
836         private final int DATE_FORMAT_TYPE = 1;
837         private final int LOG10INVERSE_FORMAT_TYPE = 2;
838         private final int LOG2INVERSE_FORMAT_TYPE = 3;
839         private int tickLabelFormatType = NUMBER_FORMAT_TYPE;
840         /**
841         * 
842         * Applies this axis' tick label format to format a given value.
843         * 
844         * @return the value formated as per this axis' currently specified 
845         * tick label format.
846         * 
847         * @see  #setTickLabelFormat(String) setTickLabelFormat
848         * 
849         */
850         public String formatNumberAsTickLabel(double value) {
851           String result = null;
852           switch (tickLabelFormatType) {
853             case DATE_FORMAT_TYPE:
854               Date transDate = new Date((long) value);
855               result = dateFormat.format(transDate);
856               break;
857             case LOG10INVERSE_FORMAT_TYPE:
858               value = Math.pow(10., value);
859               result = numberFormat.format(value);
860               break;
861             case LOG2INVERSE_FORMAT_TYPE:
862               value = Math.pow(2., value);
863               result = numberFormat.format(value);
864               break;
865             default:  
866               result = numberFormat.format(value);
867               break;
868           }
869           
870           return result;
871        }
872    
873         /** Returns the previously specified label of this axis.
874          **
875          ** @return the Widget used as the label of this axis
876          **
877          ** @see #setAxisLabel setAxisLabel
878          ** 
879          */
880         public Widget getAxisLabel() {
881           return axisLabel;
882         }
883         
884         /**
885          ** Returns the maximum value displayed on this axis.
886          ** If the explicitly specified maximum value is
887          ** undefined (<tt>Double.NaN</tt>) the maximum value returned
888          ** by this function is calculated as the maximum of
889          ** all of the values either displayed on this axis via
890          ** points on a curve, or explicitly specified via tick
891          ** positions. 
892          **
893          ** @return maximum value visible on this axis, in
894          ** "model units" (arbitrary, application-specific,
895          ** units)
896          **
897          ** @see #setAxisMax setAxisMax
898          ** @see #getDataMin getDataMin
899          ** @see #getDataMax getDataMax
900          **/ 
901         public double getAxisMax() {
902               
903            if (!(axisMax!=axisMax)) { // x!=x is a faster isNaN
904               return axisMax;
905            }
906            else if (tickCount > 0) { 
907              return getDataMax();
908            }
909            else {
910               return Math.max(getDataMax(), getTickMax());           
911            }
912         }
913         /**
914          **
915          ** Returns the minimum value displayed on this axis.
916          ** If the minimum value is undefined (<tt>Double.NaN</tt>) the
917          ** minimum value returned by this function is the
918          ** minimum of all of the values either displayed on
919          ** this axis via points on a curve, or explicitly specified
920          ** via tick positions.
921          **
922          ** @return minimum value visible on this axis, in
923          ** "model units" (arbitrary, application-specific,
924          ** units)
925          **
926          ** @see #setAxisMin setAxisMin
927          **/ 
928         public double getAxisMin() {
929            if (!(axisMin!=axisMin)) { // x!=x is a faster isNaN
930               return axisMin; // explicitly set
931            }
932            else if (tickCount > 0) { 
933               return getDataMin();
934            }
935            else {  
936               return Math.min(getDataMin(), getTickMin());           
937            }
938         }
939    
940       /** Is axis line visible on the chart? Note that
941        ** this property only determines the visibility of the axis line
942        ** itself. It does not control the visibility of the
943        ** tick marks or tick labels along this axis.
944        ** <p>
945        **
946        ** @return true if the axis line is visible, false otherwise.
947        **
948        ** @see #setAxisVisible setAxisVisible
949        ** 
950        **/ 
951         public boolean getAxisVisible() {
952           return axisVisible;
953         }
954    
955    
956         
957         /** Returns the maximum data value associated with values
958         ** represented on this axis. For example, for the left
959         ** y-axis, this would be the largest y-value of all points
960         ** contained in curves that are displayed on the left y-axis.
961         ** 
962         ** @return the maximum value associated with values
963         **   mapped onto this axis.
964         **
965         ** @see #getDataMin getDataMin
966         ** @see #getAxisMax getAxisMax
967         ** @see #getAxisMin getAxisMin
968         ** 
969          */
970        public abstract double getDataMax();
971         /** Returns the minimum data value associated with values
972         ** represented on this axis. For example, for the left
973         ** y-axis, this would be the smallest y-value of all points
974         ** contained in curves that are displayed on the left y-axis.
975         **
976         ** @return the minumum value associated with values
977         **   mapped onto this axis.
978         **
979         ** @see #getDataMax getDataMax
980         ** @see #getAxisMax getAxisMax
981         ** @see #getAxisMin getAxisMax
982         **
983          */
984        public abstract double getDataMin();
985         
986         /** Returns the gridline setting previously made with
987          ** <tt>setHasGridlines</tt>.
988          **
989          ** @return true if gridlines have been enabled, false if not.
990          **
991          ** @see #setHasGridlines setHasGridlines
992          ** 
993          **/
994         public boolean getHasGridlines() {
995            return hasGridlines;
996         }
997         /**
998          ** Returns the number of ticks on this axis.
999          **
1000          ** @return the number of ticks on this axis.
1001          **
1002          ** @see #setTickCount setTickCount
1003          ** @see #addTick(double) addTick(double)
1004          ** @see #addTick(double,String) addTick(double,String)
1005          ** @see #addTick(double,String,int,int) addTick(double,String,int,int)
1006          ** @see #addTick(double,Widget) addTick(double,Widget)
1007          ** @see #addTick(double,Widget,int,int) addTick(double,Widget,int,int)
1008          ** @see #clearTicks clearTicks
1009          ** 
1010          **/
1011         public int getTickCount() {
1012            if (tickCount == 0)
1013               return tickInfo.size();
1014            else
1015               return tickCount;
1016         }
1017         /**
1018          ** Returns the CSS font-weight specification to be used
1019          ** by this axis' tick labels.
1020          **
1021          ** @return font-weight of this axis' tick labels
1022          **
1023          ** @see #setTickLabelFontWeight setTickLabelFontWeight
1024          **/ 
1025         public String getTickLabelFontWeight() {
1026            return tickLabelFontWeight;
1027         }
1028         /**
1029          ** Returns the color of the font used to display the
1030          **    text of the tick labels on this axis.
1031          **   
1032          **   
1033          ** @return CSS color string defining the color of the text of
1034          **    the tick labels for this axis.
1035          **
1036          ** @see #setTickLabelFontColor setTickLabelFontColor
1037          **
1038          ** @see #DEFAULT_TICK_LABEL_FONT_COLOR DEFAULT_TICK_LABEL_FONT_COLOR
1039          **
1040          **
1041          ** 
1042          **/ 
1043         public String getTickLabelFontColor() {
1044            return tickLabelFontColor;
1045         }
1046    
1047         /**
1048          ** Returns the font-style of the font used to render tick
1049          ** labels on this axis (typically either "italic" or
1050          ** "normal") 
1051          **
1052          ** @return the CSS font-style in which tick labels of this axis
1053          **   are rendered.
1054          **
1055          ** @see #setTickLabelFontStyle setTickLabelFontStyle
1056          **/ 
1057         public String getTickLabelFontStyle() {
1058            return tickLabelFontStyle;
1059         }
1060         /** Returns the font size, in pixels, used for tick labels
1061          ** on this axis.
1062          **
1063          ** @return the tick label font size in pixels
1064          **
1065          ** @see #setTickLabelFontSize setTickLabelFontSize
1066          **/ 
1067         public int getTickLabelFontSize() {
1068            return tickLabelFontSize;
1069         }
1070    
1071         /**
1072         ** Returns the tick label numeric format string for this
1073         ** axis.
1074         **
1075         ** @return numeric format used to generate tick labels.
1076         **
1077         ** @see #setTickLabelFormat setTickLabelFormat
1078         ** 
1079         **/ 
1080        public String getTickLabelFormat() {
1081           return tickLabelFormat;
1082        }
1083        /** Returns the thickness of the band adjacent to
1084         ** this axis that GChart will
1085         ** allocate to hold this axis' tick labels.
1086         ** <p>
1087         **
1088         ** @return width of band, in pixels, GChart will reserve
1089         **   for this axis' tick labels.
1090         **   
1091         ** @see #setTickLabelThickness setTickLabelThickness
1092         ** 
1093         **/ 
1094        public int getTickLabelThickness() {
1095          int maxLength = 0;
1096          int result;
1097          if (tickLabelThickness != GChart.NAI)
1098            result = tickLabelThickness;
1099          else { // use an heuristic to estimate thickness            
1100           maybePopulateTicks();
1101           for (int i=0; i < tickInfo.size(); i++) {
1102             String tt = getTickText(i);
1103             if (null != tt)
1104                maxLength = Math.max(maxLength,
1105                                     Annotation.getNumberOfCharsWide(tt));
1106           }
1107           result = (int) Math.round(maxLength * tickLabelFontSize *
1108                    TICK_CHARWIDTH_TO_FONTSIZE_LOWERBOUND);
1109          }
1110          return result;
1111        }
1112    
1113    
1114        /**
1115         ** Returns the ratio of the number of ticks to the number of
1116         ** ticks that have an associated gridline. 
1117         **
1118         ** @return number of ticks per gridline for this axis
1119         **
1120         ** @see #setTicksPerGridline setTicksPerGridline
1121         **
1122         **/
1123        public int getTicksPerGridline() {
1124           return ticksPerGridline;
1125        }
1126        /**
1127         ** Returns the ratio of the number of ticks to the number of
1128         ** labeled ticks. 
1129         **
1130         ** @return number of ticks per label.
1131         **
1132         ** @see #setTicksPerLabel setTicksPerLabel
1133         **
1134         **/
1135        public int getTicksPerLabel() {
1136          return ticksPerLabel;
1137        }
1138    
1139         /**
1140         * Returns the length of ticks for this axis.
1141         *
1142         * @return the length of this axis' ticks, in pixels.
1143         *
1144         * @see #setTickLength setTickLength
1145         */
1146        public int getTickLength() {
1147           return tickLength;
1148        }
1149    
1150        /**
1151         * Returns the thickness of ticks for this axis.
1152         *
1153         * @return the thickness of this axis' ticks, in pixels.
1154         *
1155         * @see #setTickThickness setTickThickness
1156         * @see #getTickLength getTickLength
1157         */
1158        public int getTickThickness() {
1159           return tickThickness;
1160        }
1161    
1162         /**
1163          * Convenience method equivalent to
1164          * <tt>setAxisLabel(new HTML(html))</tt>
1165          *
1166          * @param html HTML text used to define the axis label
1167          * 
1168          * @see #setAxisLabel(Widget) setAxisLabel(Widget)
1169          */
1170          public void setAxisLabel(String html) {
1171           setAxisLabel(new HTML(html));
1172          }
1173    
1174         /** Specifies the label of this axis.
1175          ** <p>
1176          **
1177          ** This label will be positioned just outside of, and
1178          ** centered lengthwise on, the region adjacent to
1179          ** this axis that GChart reserves for this axis' tick labels.
1180          **
1181          ** @param axisLabel a Widget to use as the label of this axis.
1182          **
1183          ** @see #getAxisLabel getAxisLabel
1184          ** @see #setTickLabelThickness setTickLabelThickness
1185          ** 
1186          */
1187         
1188         public void setAxisLabel(Widget axisLabel) {
1189           GChart.this.chartDecorationsChanged = true;
1190           this.axisLabel = axisLabel;
1191         }
1192    
1193         /**
1194          ** Specifies the maximum value visible on this axis.
1195          ** <p>
1196          ** 
1197          ** Points with associated coordinates greater than this
1198          ** value will be clipped unless the chart's
1199          ** <tt>showOffChartPoints</tt> property is <tt>true</tt>.
1200          ** 
1201          ** <p>
1202          ** 
1203          ** If <tt>Double.NaN</tt> is specified, this maximum
1204          ** is auto-determined as described in <tt>getAxisMax</tt>.
1205          ** 
1206          ** <p> <i>Performance tip:</i> Using auto-determined axis
1207          ** limits (via <tt>Double.NaN</tt>) forces GChart to
1208          ** re-render the axis every time you call
1209          ** <tt>GChart.update</tt>.  When your axis limits don't
1210          ** change between updates, these (often expensive)
1211          ** re-renderings can be avoided by using explicitly
1212          ** specified axis limits on every axis.  <p>
1213          **
1214          ** @param max maximum value visible on this axis, in "model units"
1215          ** (arbitrary, application-specific, units) or <tt>Double.NaN</tt>
1216          ** (the default value) to use an auto-determined maximum.
1217          **
1218          ** @see #getAxisMax getAxisMax
1219          ** @see #getDataMin getDataMin
1220          ** @see #getDataMax getDataMax
1221          ** @see GChart#setShowOffChartPoints setShowOffChartPoints
1222          ** 
1223          **/ 
1224         public void setAxisMax(double max) {
1225            plotPanel.invalidateWidgetsAfterCursor(widgetCursor);
1226    // max can change axis label width ==> changes position of plot area
1227            plotPanel.plotAreaNeedsUpdate(); 
1228            this.axisMax = max;
1229         }
1230         /**
1231          ** Specifies the minimum value of this axis.
1232          ** <p>
1233          ** 
1234          ** Points with associated coordinates less than this
1235          ** value will be clipped unless the chart's
1236          ** <tt>showOffChartPoints</tt> property is <tt>true</tt>.
1237          ** <p>
1238          ** 
1239          ** If <tt>Double.NaN</tt> is specified, this minimum
1240          ** is auto-determined as described in <tt>getAxisMin</tt>.
1241          ** 
1242          ** <p> <i>Performance tip:</i> Using auto-determined axis
1243          ** limits (via <tt>Double.NaN</tt>) forces GChart to
1244          ** re-render the axis every time you call
1245          ** <tt>GChart.update</tt>.  When your axis limits don't
1246          ** change between updates, these (often expensive)
1247          ** re-renderings can be avoided by using explicitly
1248          ** specified axis limits on every axis.  <p>
1249          ** 
1250          ** @param min minumum value visible on this axis, in "model units"
1251          ** (arbitrary, application-specific, units), or Double.NaN
1252          ** (the default) to use an auto-determined minimum.
1253          **
1254          ** @see #getAxisMin getAxisMin
1255          ** @see #getDataMin getDataMin
1256          ** @see #getDataMax getDataMax
1257          ** 
1258          **/ 
1259         public void setAxisMin(double min) {
1260            plotPanel.invalidateWidgetsAfterCursor(widgetCursor);
1261    // min can change axis label width ==> changes position of plot area
1262            plotPanel.plotAreaNeedsUpdate(); 
1263            this.axisMin = min;
1264         }
1265    
1266      /**
1267       ** Defines if this axis is visible. Note that
1268       ** this property only defines the visibility of the axis line
1269       ** itself, it does not control the visibility of
1270       ** tick marks or tick labels associated with the axis.
1271       ** 
1272       ** <p>
1273       ** <i>Tip:</i>Tick marks can be made invisible by using
1274       ** <tt>setTickThickness</tt> to set the tick thickness
1275       ** to 0. Tick labels can be made invisible by using
1276       ** <tt>setTickLabelFontColor</tt> to set the tick label
1277       ** color to the chart's background color.
1278       ** <p>
1279       ** 
1280       ** @param axisVisible false to hide axis, true to show it.
1281       **
1282       ** @see #setTickThickness setTickThickness
1283       ** @see #setTickLabelFontColor setTickLabelFontColor
1284       ** @see #getAxisVisible getAxisVisible
1285       **/ 
1286       public void setAxisVisible(boolean axisVisible) {
1287          plotPanel.invalidateWidgetsAfterCursor(widgetCursor);
1288          this.axisVisible = axisVisible;
1289       }
1290       
1291         
1292         /**
1293          ** Specifies if this axis should have gridlines. When an
1294          ** axis has gridlines, tick marks with indexes <tt>0, N,
1295          ** 2*N,...</tt> where <tt>N</tt> is the value of this axis'
1296          ** <tt>ticksPerGridline</tt> property, are in effect
1297          ** extended across the entire chart.
1298          **
1299          ** @param hasGridlines true to display gridlines,
1300          ** false (the default) to not display them.
1301          **
1302          ** @see #getHasGridlines getHasGridlines
1303          ** @see #setTicksPerGridline setTicksPerGridline
1304          ** 
1305          **/ 
1306         public void setHasGridlines(boolean hasGridlines) {
1307            plotPanel.invalidateWidgetsAfterCursor(widgetCursor);
1308            this.hasGridlines = hasGridlines;
1309         }
1310         /** Sets the number of ticks to be placed on this axis. The
1311          ** default tick count is 10. Ticks are always evenly
1312          ** spaced across the entire axis, unless explicitly
1313          ** specified via <tt>addTick</tt>.
1314          ** <p>
1315          ** 
1316          ** Note that setting the tick count overrides (erases)
1317          ** any ticks explicitly specified via <tt>addTick</tt>.
1318          ** 
1319          ** @param tickCount the number of ticks for this axis. 
1320          ** 
1321          ** @see #getTickCount getTickCount
1322          ** @see #addTick(double) addTick(double)
1323          ** @see #addTick(double,String) addTick(double, String)
1324          ** @see #addTick(double,String,int,int) addTick(double,String,int,int)
1325          ** @see #addTick(double,Widget) addTick(double,Widget)
1326          ** @see #addTick(double,Widget,int,int) addTick(double,Widget,int,int)
1327          ** @see #setTickLabelFormat setTickLabelFormat
1328          ** @see #setTickLabelFontSize setTickLabelFontSize
1329          ** @see #setTickLabelFontStyle setTickLabelFontStyle
1330          ** @see #setTickLabelFontColor setTickLabelFontColor
1331          ** @see #setTickLabelFontWeight setTickLabelFontWeight
1332          **
1333          **/
1334         public void setTickCount(int tickCount) {
1335            plotPanel.invalidateWidgetsAfterCursor(widgetCursor);
1336            plotPanel.plotAreaNeedsUpdate(); 
1337            tickInfo.clear();    // eliminate user specified ticks
1338            this.tickCount = tickCount;
1339         }
1340    
1341         
1342         /**
1343          ** Specifies the weight of the font used in this axis' tick