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