View Javadoc

1   /*
2    * Copyright (c) 2006 Stiftung Deutsches Elektronen-Synchroton,
3    * Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY.
4    *
5    * THIS SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "../AS IS" BASIS.
6    * WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
7    * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR PARTICULAR PURPOSE AND
8    * NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
9    * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
10   * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
11   * THE USE OR OTHER DEALINGS IN THE SOFTWARE. SHOULD THE SOFTWARE PROVE DEFECTIVE
12   * IN ANY RESPECT, THE USER ASSUMES THE COST OF ANY NECESSARY SERVICING, REPAIR OR
13   * CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.
14   * NO USE OF ANY SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
15   * DESY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
16   * OR MODIFICATIONS.
17   * THE FULL LICENSE SPECIFYING FOR THE SOFTWARE THE REDISTRIBUTION, MODIFICATION,
18   * USAGE AND OTHER RIGHTS AND OBLIGATIONS IS INCLUDED WITH THE DISTRIBUTION OF THIS
19   * PROJECT IN THE FILE LICENSE.HTML. IF THE LICENSE IS NOT INCLUDED YOU MAY FIND A COPY
20   * AT HTTP://WWW.DESY.DE/LEGAL/LICENSE.HTM
21   */
22  
23  package de.desy.acop.chart;
24  
25  import java.awt.BasicStroke;
26  import java.awt.Color;
27  import java.awt.FontMetrics;
28  import java.awt.Rectangle;
29  import java.awt.geom.AffineTransform;
30  import java.text.DecimalFormat;
31  import java.util.Date;
32  
33  public class AcopScale
34  {
35    private static int longTick = 4, shortTick = 2;
36    protected static int gridLineMode = AcopConst.PS_DOT;
37    protected static int gridLineWidth = 1;
38    protected static java.awt.Color gridLineColor = Color.cyan;
39    protected static BasicStroke gridStroke = AcopConst.createStroke(gridLineWidth, gridLineMode);
40    private double Rfirst, Rlast, Rinc;
41    private short Nteile, Ntick;
42    private double Rtick;
43    private double Rmin, Rmax;
44    // flags set by property
45    protected boolean bestScale, grid, ticktext;
46    protected int ticks, fineTicks, xtime, log;
47    protected java.lang.String AxisLabel = "";
48    protected java.awt.Color tickLabelForeColor;
49    private boolean xAxis; // x or y axis
50    protected int time_scale;
51    protected boolean leftBottom; // where to put ticks, or right_top?
52    // for x-axis: Bottom ot Top side of Histogram
53    // for y-axis: Left ot Right side of Histogram
54    protected boolean leftBottLabel; // where to put Label
55    protected Rectangle labelRect; // where to put label
56    protected Rectangle ticksRect; // tick drawing rectangle
57    protected double tick_min, tick_max; // ticks area
58    protected double min, max, dispSize; // data (user) display area after
59                                          // scaling
60    protected double usermin, usermax, userSize; // user input value(property min
61                                                  // and max)
62    private DecimalFormat tickFormat = new DecimalFormat("#####.###");
63    private FontMetrics fMetrix;
64    private Acop acop;
65    private AcopFrame aFrame;
66    protected boolean OnFlag;
67    public AcopScale(Acop acop, boolean xax)
68    {
69      this.acop = acop;
70      this.aFrame = acop.aFrame;
71      xAxis = xax;
72    }
73    protected int getScreenPosition(double userPosition)
74    {
75      double tmp;
76      if (xAxis)
77      {
78        if (xtime != 0)
79          tmp = (userPosition - min) / dispSize;
80        else
81          tmp = ((log != 0 ? (Math.log(userPosition) / Math.log(10) + 0.01) : userPosition) - tick_min)
82              / (tick_max - tick_min);
83        // add left to fix markercursor x poition jump, 2009
84        tmp = tmp * aFrame.dxwidth + aFrame.histRect.x + aFrame.xleft ;
85      }
86      else
87        tmp = aFrame.histRect.height
88            * (1 - ((log != 0 ? (Math.log(userPosition) / Math.log(10) + 0.01) : userPosition) - min)
89                / dispSize) + aFrame.histRect.y;
90      return (int) tmp;
91    }
92    protected double getUserPosition(int screenPosition)
93    {
94      double tmp;
95      if (xAxis)
96      {
97        tmp = (screenPosition - aFrame.xleft) / aFrame.dxwidth;
98        if (xtime != 0)
99          tmp = tmp * dispSize + min;
100       else
101         tmp = tmp * (tick_max - tick_min) + tick_min;
102     }
103     else
104       tmp = (screenPosition - aFrame.histRect.y) / aFrame.histRect.width * dispSize + min;
105     if (log != 0) tmp = Math.pow(10.0, tmp);
106     return tmp;
107   }
108   protected double getMin()
109   {
110     return log != 0 ? Math.pow(10.0, min) : min;
111   }
112   protected double getMax()
113   {
114     return log != 0 ? Math.pow(10.0, max) : max;
115   }
116   protected void setDispscale(double low, double high) // set scaled size
117   {
118     min = low;
119     max = high;
120     dispSize = max - min;
121   }
122   protected void setscale()
123   {
124     setDispscale(usermin, usermax);
125   }
126   protected void setUserscale(double low, double high) // set scaled size
127   {
128     usermin = low;
129     usermax = high;
130     userSize = usermax - usermin;
131   }
132   protected boolean isOriginMaxMin()
133   {
134     if (Math.abs(min - usermin) < AcopConst.zero_check && Math.abs(max - usermax) < AcopConst.zero_check)
135       return true;
136     else
137       return false;
138   }
139   private void logRound()
140   {
141     int i1, i2;
142     int zero_flag = 0;
143     double tmpmin, tmpmax;
144     tmpmin = Rmin;
145     tmpmax = Rmax;
146     if (Rmin < AcopConst.zero_check)
147     { /* check zero */
148       Rmin = 0.1; // 10 to -1
149       zero_flag = 1;
150     }
151     if (Rmax < AcopConst.zero_check)
152     {
153       Rmax = 10.0; // 10 to 1
154       zero_flag += 2;
155     }
156     if (zero_flag == 1)
157     { /* make new boundary */
158       if (Rmax < Rmin * 5.0) if (Rmax * 0.01 > tmpmin) Rmin = Rmax * 0.01;
159     }
160     else if ((zero_flag == 0 && Rmax < Rmin * 5.0) || zero_flag == 2)
161       if (Rmin * 100.0 < tmpmax) Rmax = Rmin * 100.0;
162     if (Rmin < tmpmin && (zero_flag & 0x1) == 0) Rmin = tmpmin; /* check limit */
163     if (Rmax > tmpmax && (zero_flag & 0x2) == 0) Rmax = tmpmax;
164     i1 = Rmin >= 1.0 ? (int) (Math.log(Rmin) / Math.log(10) + 0.01)
165         : (int) (Math.log(Rmin) / Math.log(10) - 0.99);
166     i2 = Rmax > 1.0 ? (int) (Math.log(Rmax) / Math.log(10) + 0.99)
167         : (int) (Math.log(Rmax) / Math.log(10) - 0.01);
168     if (i1 == i2) i1--;
169     Rfirst = i1;
170     Rlast = i2;
171     Rinc = 1;
172     Nteile = (short) (i2 - i1 + 1);
173     Rtick = 2; // take log10
174     Ntick = 5;
175   }
176   private void lineRound()
177   {
178     double del, dl, f, dlm, fdl;
179     int ideca;
180     del = Rmax - Rmin;
181     if (Math.abs(del) < AcopConst.zero_check)
182     { /* ??????? */
183       Rfirst = Rmin;
184       Rinc = 1.0;
185       Rlast = Rmax;
186       Nteile = 2;
187       Ntick = 1;
188       Rtick = 0.5;
189     }
190     else
191     {
192       if (del < 0.0)
193       { /* revers it */
194         dlm = Rmin;
195         Rmin = Rmax;
196         Rmax = dlm;
197         del = Math.abs(del);
198       }
199       dl = Math.log(del) / Math.log(10);
200       dlm = Math.abs(Rmin) > Math.abs(Rmax) ? Math.log(Math.abs(Rmin)) / Math.log(10) : Math.log(Math
201           .abs(Rmax))
202           / Math.log(10);
203       if (Rmin < 0.0 && Rmax > 0.0) dl = dlm;
204       dlm = (double) ((int) (dlm));
205       fdl = (double) ((int) (dl));
206       f = Math.abs(dl - fdl);
207       if (fdl > 0.0)
208       {
209         if (fdl > dlm + 2.0)
210         {
211           fdl = dlm + 1.0;
212           f = 0.0;
213         }
214       }
215       else
216       {
217         if (fdl < dlm - 2.0)
218         {
219           fdl = dlm - 3.0;
220           f = 0.0;
221         }
222       }
223       Rinc = 1.0;
224       if (del > 1.0)
225       {
226         Rinc = Math.pow(10.0, fdl);
227         if (fdl < 10) Rinc = (double) Math.round(Rinc);
228         // sca[index].Rinc = (double) round ( pow (10.0, fdl) );
229         if (f <= 0.31)
230           Rinc /= 5.0;
231         else if (f <= 0.71) Rinc /= 2.0;
232       }
233       else
234       {
235         fdl -= 1.0;
236         Rinc = Math.pow(10.0, fdl);
237         if (f > 0.69)
238           Rinc /= 5.0;
239         else if (f > 0.29) Rinc /= 2.0;
240       }
241       Rfirst = Rmin >= 0.0 ? ((int) (Rmin / Rinc)) * Rinc : ((int) (Rmin / Rinc - 0.99)) * Rinc;
242       Rlast = Rmax >= 0.0 ? ((int) (Rmax / Rinc + 0.99)) * Rinc : ((int) (Rmax / Rinc)) * Rinc;
243       Nteile = (short) (Math.round((Rlast - Rfirst) / Rinc + 1.0));
244       ideca = (int) (Math.log(Math.abs(Rinc)) / Math.log(10));
245       if (ideca < 0) ideca--;
246       Rtick = Math.pow(10.0, (double) ideca);
247       Ntick = (short) (Math.round(Rinc / Rtick) - 1);
248       if (Ntick < 1) Ntick = 1; // for loop to wotk!!!???
249     }
250     ideca = ticks; // user defines ticks!!
251     if (ideca < 0)
252       return;
253     else if (ideca == 0) ideca = 1;
254     del = bestScale ? (Rlast - Rfirst) : (Rmax - Rmin);
255     Nteile = (short) (ideca + 1);
256     Rinc = del / ideca;
257     ideca = fineTicks;
258     Ntick = (short) (ideca <= 1 ? 1 : ideca);
259     Rtick = Rinc / Ntick;
260   }
261   protected void scaleToGrid()
262   {
263     int xstep, i;
264     if (xtime != 0) // convert to time tick
265     {
266       if (min < 0) min = 0; // time cannt be < 0!
267       if (max - min < 1) max = min + 1; // one second is minimal
268       dispSize = max - min;
269       xstep = (int) dispSize;
270       for (i = 0; i < AcopConst.N_TIME; i++)
271       {
272         if (xstep > AcopConst.timeMax[i] * AcopConst.timeScale[i]) continue;
273         time_scale = i;
274         break;
275       }
276       if ( i == AcopConst.N_TIME ) i = AcopConst.N_TIME - 1;  // 2007 hwu
277       if (aFrame.leftTimeLabel == true)
278       {
279         tick_min = 0;
280         tick_max = dispSize / AcopConst.timeScale[i];
281       }
282       else
283       {
284         tick_min = -dispSize / AcopConst.timeScale[i];
285         tick_max = 0;
286       }
287     }
288     else
289     {
290       tick_min = min;
291       tick_max = max;
292     }
293   }
294   protected void xyscale(boolean setYaxis)
295   {
296     if (OnFlag == false) return;
297     if (xAxis == false)
298     {
299       tick_min = min;
300       tick_max = max;
301     }
302     Rmin = tick_min;
303     Rmax = tick_max;
304     if (log != 0)
305       logRound();
306     else
307       lineRound();
308     if (bestScale || log != 0)
309     {
310       tick_min = Rfirst;
311       tick_max = Rlast;
312       if (xtime != 0)
313       {
314         if (aFrame.leftTimeLabel)
315         {
316           min = min + (log != 0 ? Math.pow(10.0, tick_min) : tick_min) * AcopConst.timeScale[time_scale]; // back
317                                                                                                           // to
318                                                                                                           // normal
319                                                                                                           // units
320           max = ((log != 0 ? Math.pow(10.0, tick_max) : tick_max) - (log != 0 ? Math.pow(10.0, tick_min)
321               : tick_min))
322               * AcopConst.timeScale[time_scale] + min;
323         }
324         else
325         {
326           max = max + (log != 0 ? Math.pow(10.0, tick_max) : tick_max) * AcopConst.timeScale[time_scale]; // back
327                                                                                                           // to
328                                                                                                           // normal
329                                                                                                           // units
330           min = max
331               - ((log != 0 ? Math.pow(10.0, tick_max) : tick_max) - (log != 0 ? Math.pow(10.0, tick_min)
332                   : tick_min)) * AcopConst.timeScale[time_scale];
333         }
334         if (log != 0)
335         {
336           min = Math.log(AcopConst.log_check(min)) / Math.log(10);
337           max = Math.log(AcopConst.log_check(max)) / Math.log(10);
338         }
339       }
340       else
341       {
342         min = tick_min;
343         max = tick_max;
344       }
345       dispSize = max - min;
346       if (xAxis == false && setYaxis && log == 0)
347       {
348         usermin = min;
349         usermax = max;
350         userSize = usermax - usermin;
351       }
352     }
353   }
354   protected void drawGrid(java.awt.Graphics2D a)
355   {
356     boolean tickflag;
357     int wx, wy, k, m;
358     double tmp;
359     AcopHisto hist;
360     if (!grid) return;
361     a.setColor(gridLineColor);
362     a.setStroke(gridStroke);
363     tmp = tick_max - tick_min;
364     tickflag = (Nteile <= 2 && log != 0) ? true : false;
365     wy = xAxis ? aFrame.dxwidth : aFrame.histRect.height;
366 //    for (int i = (tickflag ? 1 : 0); i < (tickflag ? Ntick : Nteile); i++)
367     for (int i = 0; i < (tickflag ? (Ntick+1) : Nteile); i++)
368     {
369       if ( i == 0 && tickflag ) wx = xAxis ? 0 : wy;
370       else if (xAxis)
371         wx = (int) (wy * (tickflag ? Math.log(Rtick * i) / Math.log(10) : (Rinc * i)) / tmp + 0.01);
372       else
373         wx = (int) (wy * (1-(tickflag ? Math.log(Rtick * i) / Math.log(10) : (Rinc * i)) / tmp) + 0.01);
374       if (wx > wy || wx < 0) continue;
375       // fix y grid diplay problem, 2009
376       if (xAxis) wx += aFrame.xleft;
377       // if ( wx >= wy || wx == 0 ) continue;
378       if (xAxis)
379       {
380         hist = acop.histo[acop.m_histstart];
381         if (aFrame.drawFlag == false || hist.xlabON == 0 || log != 0 || xtime != 0)
382           a.drawLine(wx, 0, wx, aFrame.histRect.height);
383         else
384         {
385           for (k = 0, m = hist.wrapindex; k < hist.npoints; k++, m++)
386           {
387             if (m >= hist.npoints) m = 0;
388             if (wx <= hist.ix[m]) break;
389           }
390           if (k == hist.npoints) break;
391           if (hist.ix[m] <= aFrame.xright && hist.ix[m] > 1) // within
392                                                               // histogram
393           {
394             wx = hist.ix[m];
395             a.drawLine(wx, 0, wx, aFrame.histRect.height);
396           }
397         }
398       }
399       else
400         a.drawLine(0, wx, aFrame.histRect.width, wx);
401     }
402   }
403   private void convert(java.lang.String string, double w, int[] format)
404   {
405     /*
406      * char s_format [10] ; int i, j, k ; s_format [0] ='%' ; if ( format[2] )
407      * sprintf ( &s_format[1], ".%de", format[1]) ; else sprintf (&s_format[1],
408      * ".%df", format[1]) ; sprintf ( string, s_format, w) ; if ( format[2] ) //
409      * delete unneccesary + & 0 { for ( i = 0; string [i++] != 'e'; ) ; k = i-1 ;
410      * j = string [i++] == '+' ? i : i+1 ; // store copy position while ( string
411      * [i] == '0' && string [i] != 0 ) i++ ; if ( string [i] == 0 ) { string
412      * [j=k] = 0 ; // no exp format[2] = 0 ; } else { // copy rest significant
413      * digits do { string[j++] = string[i++] ; } while ( string[i-1] != 0 ) ;
414      * j-- ; } } else for (j = 0 ; string[j] ; j++ ); format[3] = j; // length
415      * of the string
416      */
417   }
418   private void g_stellen(double wert, int[] format)
419   {
420     double z;
421     int stellen = 5; // default effective # of digits
422     format[1] = 1; // hinter der komma
423     format[2] = 0; // exp format
424     format[4] = 0; // exp format digits after e;
425     z = Math.abs(wert) > AcopConst.zero_check ? // make z = etwas * 1.0e3
426         wert / Math.pow(10., (double) (int) (Math.log(Math.abs(wert)) / Math.log(10.) * 1.001)) * 1.0e3 : 0.0;
427     z = Math.abs(z);
428     wert = Math.abs(wert);
429     z = wert < 1.0 ? z * 10.0 + 0.05 : z + 0.05; // make etwas=x.xxx
430     while (z - (int) z < 0.1 && stellen > 1) // get effective digits
431     {
432       stellen--;
433       z /= 10.0;
434     }
435     if (wert >= 100000.0 || (wert > AcopConst.zero_check && wert < 0.001))
436     {
437       format[2] = 2; // { mit Exponent }
438       if (wert >= 1.0E10)
439         format[2] = 3;
440       else if (wert <= 1.0E-10) format[2] = 4;
441       z = wert * 1.0001; // avoid 10e+-xx problems 2005-Feb
442       format[4] = (int) (Math.log(z) / Math.log(10.));
443       // format[4] = (int)(Math.log(wert)/Math.log(10.));
444       if (format[4] < 0) format[4]--; // digits after exponential
445     }
446     format[0] = 1; // vor der komma
447     if (wert >= 0.001 && wert < .999)
448     {
449       format[0] = 0;
450       if (wert < 0.00999)
451       {
452         if (stellen > 3)
453           stellen = 3;
454         else
455           stellen += 2;
456       }
457       else if (wert < 0.0999)
458       {
459         if (stellen > 4)
460           stellen = 2;
461         else
462           stellen++;
463       }
464     }
465     if (wert >= 10.0 && wert < 100.0)
466       format[0] = 2;
467     else if (wert >= 100.0 && wert < 1000.0)
468       format[0] = 3;
469     else if (wert >= 1000.0 && wert < 10000.0)
470       format[0] = 4;
471     else if (wert >= 10000.0 && wert < 100000.0) format[0] = 5;
472     format[1] = stellen - format[0];
473     if (format[1] < 0) format[1] = 0;
474   }
475   protected void drawLabel(java.awt.Graphics2D a)
476   {
477     int wz, hei;
478     if (AxisLabel.length() == 0) return;
479     Rectangle Cliprect = a.getClipBounds();
480     if (Cliprect != null && Cliprect.intersects(labelRect) == false) return;
481     fMetrix = a.getFontMetrics();
482     a.clipRect(labelRect.x, labelRect.y, labelRect.width, labelRect.height);
483     AffineTransform oldTransform = a.getTransform();
484     if (xAxis)
485     {
486       a.translate(labelRect.x, labelRect.y);
487       hei = fMetrix.getAscent();
488       wz = leftBottLabel ? (5 + hei * 2) : (labelRect.height - 4 - hei);
489       a.drawString(AxisLabel, (labelRect.width - fMetrix.stringWidth(AxisLabel)) / 2, wz);
490     }
491     else
492     {
493       hei = (fMetrix.getDescent() + fMetrix.getAscent()) / 2;
494       if (leftBottLabel == true)
495         a.translate(hei + 5, (labelRect.height + fMetrix.stringWidth(AxisLabel)) / 2);
496       else
497         a.translate(labelRect.x + labelRect.width - hei,
498             (labelRect.height + fMetrix.stringWidth(AxisLabel)) / 2);
499       a.rotate(-Math.PI / 2);
500       a.drawString(AxisLabel, 0, 0);
501     }
502     a.setTransform(oldTransform);
503     a.setClip(Cliprect);
504   }
505   protected void drawTicks(java.awt.Graphics2D a, AcopHisto pHisto)
506   {
507     int wx, wy, wz, lastright, k, m, xpos = 0, xtp, ytp;
508     double tmp;
509     int strformat[] = {0, 0, 0, 0, 0}; // vor, hinter, texp, lang, exp-digits;
510     java.lang.String str = "erty";
511     int siz, hei, tlen, strmaxlen;
512     Rectangle txtRect = new Rectangle();
513     Date date = new Date();
514     if ((xAxis ? ticksRect.height : ticksRect.width) < 1) return;
515     Rectangle Cliprect = a.getClipBounds();
516     if (Cliprect != null && Cliprect.intersects(ticksRect) == false) return;
517     a.setFont(aFrame.frameFont);
518     a.setColor(aFrame.frameForeColor);
519     fMetrix = a.getFontMetrics();
520     strmaxlen = 0;
521     if (xAxis)
522     {
523       a.clipRect(ticksRect.x, ticksRect.y - 1, ticksRect.width + 1, ticksRect.height + 4);
524       a.translate(aFrame.histRect.x + aFrame.xleft, ticksRect.y - 1);
525       hei = fMetrix.getAscent();
526       txtRect.y = leftBottom ? 4 : 0;
527       txtRect.height = ticksRect.height - 4;
528       wy = aFrame.dxwidth;
529       lastright = -100000;
530     }
531     else
532     {
533       a.clipRect(ticksRect.x - 2, ticksRect.y, ticksRect.width + 3, ticksRect.height);
534       a.translate(ticksRect.x, aFrame.histRect.y);
535       txtRect.x = 0;
536       txtRect.width = ticksRect.width - 4;
537       hei = (fMetrix.getDescent() + fMetrix.getAscent()) / 2;
538       wy = aFrame.histRect.height;
539       lastright = 100000;
540     }
541     if (ticks != 0)
542       for (int i = 0; i < Nteile; i++)
543         for (int j = 0; j < Ntick; j++)
544         {
545           tmp = Rtick * j; // linear scale
546           if (j > 0 && log != 0) tmp = Math.log(tmp) / Math.log(10.); // log
547                                                                       // scale
548           tmp += Rinc * i;
549           if (xAxis)
550           {
551             wx = (int) (wy * tmp / (tick_max - tick_min));
552             if (wx > wy) continue;
553           }
554           else
555           {
556             wx = (int) (wy * (1 - tmp / (tick_max - tick_min)));
557             if (wx < 0) continue;
558           }
559           if (j == 0) // convert to string
560           {
561             tmp += tick_min;
562            if ( xtime != 0 && aFrame.absTimeDisplay )
563            {
564              date.setTime( (long)( ((aFrame.leftTimeLabel ? getMin() : getMax()) + tmp * AcopConst.timeScale[time_scale] ) * 1000) );
565               if (time_scale < 1)
566               {
567                 if ( Nteile / (tick_max - tick_min) >= 2 )
568                 {
569                   String tstr = "." + date.getTime();
570                   int len = tstr.length();
571                   str = date.toString().substring(14, 19) + "." + tstr.substring(len-3, len);
572                 }
573                 else
574                   str = date.toString().substring(14, 19);
575               }
576               else if (time_scale < 2)
577               {
578                 if ( Nteile / (tick_max - tick_min) >= 2 )
579                   str = date.toString().substring(11, 19);
580                 else
581                   str = date.toString().substring(11, 16);
582               }
583               else if (time_scale < 3)
584               {
585                 if ( (tick_max - tick_min) > 24 )
586                   str = date.toString().substring(4, 10) + "/" +  date.toString().substring(11, 13) + "h";                  
587                 else
588                   str = date.toString().substring(11, 16);
589               }
590               else if (time_scale < 4)
591               {
592                 if ( Nteile / (tick_max - tick_min) >= 2 )
593                   str = date.toString().substring(4, 10) + "/" +  date.toString().substring(11, 13) + "h";
594                 else
595                   str = date.toString().substring(4, 10);
596               }
597               else if (time_scale < 5)
598               {
599                 if ( (tick_max - tick_min) > 12 )
600                 {
601                   str = "-" + (date.getYear() + 1900);
602                   str = date.toString().substring(4, 11) +  str.substring(3,5) + "'";                
603                 }
604                 else
605                   str = date.toString().substring(4, 10);
606               }
607               else
608               {
609                 str = "-" + (date.getYear() + 1900);
610                 str = date.toString().substring(4, 8) +  str.substring(3,5) + "'";
611               }
612            }
613            else
614            {
615             if (log != 0)
616               tmp = Math.pow(10., tmp);
617             else if (Math.abs(tmp) < (Rlast - Rfirst) * 1.0e-7) tmp = 0.0; // avoid
618                                                                             // 0.1e-9
619             str = tickFormat.format(tmp);
620             g_stellen(tmp, strformat);
621             str = strformat[4] == 0 ? tickFormat.format(tmp) : tickFormat.format(tmp
622                 / Math.pow(10., (double) strformat[4]))
623                 + "e" + strformat[4];
624             // convert (str, tmp, strformat) ;
625             // texp = g_stellen (tmp, &vor, &hinter);
626             // lang = convert (str, tmp, hinter, &texp ) ;                      
627            }
628           }
629           if (xAxis) // output tick and text for x
630           {
631             if (aFrame.drawFlag == false || pHisto.xlabON == 0 || log != 0 || xtime != 0)
632             {
633               wz = leftBottom ? 0 : ticksRect.height - 1;
634               a.drawLine(wx, wz, wx, wz + (j == 0 ? longTick : shortTick));
635               if (ticktext && j == 0)
636               {
637                 siz = fMetrix.stringWidth(str);
638                 if ((txtRect.x = wx - siz / 2) >= lastright)
639                 {
640                   wz = leftBottom ? (4 + hei) : (txtRect.height);
641                   txtRect.width = siz;
642                   if (tickLabelForeColor != aFrame.frameForeColor) a.setColor(tickLabelForeColor);
643                   a.drawString(str, txtRect.x, wz);
644                   lastright = wx + siz;
645                   if (tickLabelForeColor != aFrame.frameForeColor) a.setColor(aFrame.frameForeColor);
646                 }
647               }
648             }
649             // else if ( j == 0 )
650             else
651             {
652               for (k = 0, m = pHisto.wrapindex; k < pHisto.npoints; k++, m++)
653               {
654                 if (m >= pHisto.npoints) m = 0;
655                 xpos = pHisto.ix[m] - aFrame.xleft;
656                 if (wx <= xpos) break;
657               }
658               if (xpos <= aFrame.xright) // within histogram
659               {
660                 if (m == pHisto.npoints) m--;
661                 wz = leftBottom ? 0 : ticksRect.height - 1;
662                 a.drawLine(xpos, wz, xpos, wz + (j == 0 ? longTick : shortTick));
663                 if (tickLabelForeColor != aFrame.frameForeColor) a.setColor(tickLabelForeColor);
664                 if (ticktext && pHisto.xlabON != 0 && m < pHisto.xlabLength)
665                 {
666                   if (pHisto.xlab[m] == null) pHisto.xlab[m] = "#"+m;
667                   siz = fMetrix.stringWidth(pHisto.xlab[m]);
668                   if (acop.xlabelRotation == 0)
669                   {
670                     if (j == 0 && (txtRect.x = xpos - siz / 2) >= lastright)
671                     {
672                       wz = leftBottom ? (4 + hei) : (txtRect.height);
673                       txtRect.width = siz;
674                       a.drawString(pHisto.xlab[m], txtRect.x, wz);
675                       lastright = xpos + siz;
676                     }
677                   }
678                   else
679                   {
680                     AffineTransform oldTransform = a.getTransform();
681                     xtp = xpos;
682                     ytp = 4;
683                     if (acop.xlabelAxis == 1) // 90 dwegree
684                     {
685                       xtp += hei / 2;
686                       ytp += siz;
687                     }
688                     else if (acop.xlabelAxis == 2) // 180 dwegree
689                     {
690                       xtp += siz / 2;
691                       ytp += hei / 2;
692                     }
693                     else if (acop.xlabelAxis == 3) // -90 dwegree
694                     {
695                       // ytp += 4 ;
696                     }
697                     else if (acop.xlabelQudrant == 4)
698                     {
699                       xtp += (int) (hei / 2 * acop.xlabelsin);
700                       ytp += (int) (hei * acop.xlabelcos);
701                     }
702                     else if (acop.xlabelQudrant == 2)
703                     {
704                       xtp -= (int) (siz * acop.xlabelcos);
705                       ytp += (int) (siz * acop.xlabelsin);
706                     }
707                     else if (acop.xlabelQudrant == 1)
708                     {
709                       xtp -= (int) (siz * acop.xlabelcos - hei / 2 * acop.xlabelsin);
710                       ytp += (int) (siz * acop.xlabelsin + hei * acop.xlabelcos);
711                       // xtp -= (int)(hei * de.desy.acop.chart.xlabelsin - siz *
712                       // de.desy.acop.chart.xlabelcos) ;
713                       // ytp += (int)(hei * de.desy.acop.chart.xlabelcos + siz *
714                       // de.desy.acop.chart.xlabelsin) ;
715                     }
716                     a.translate(xtp, ytp);
717                     a.rotate(-acop.xlabelRotateGrad);
718                     a.drawString(pHisto.xlab[m], 0, 0);
719                     a.setTransform(oldTransform);
720                   }
721                 }
722                 if (tickLabelForeColor != aFrame.frameForeColor) a.setColor(aFrame.frameForeColor);
723               }
724             }
725           }
726           else if (ticksRect.width > 3) // y axis
727           {
728             wz = leftBottom ? ticksRect.width + 1 : 2;
729             a.drawLine(wz, wx, wz - (j == 0 ? longTick : shortTick), wx);
730             if (ticktext && j == 0 && ticksRect.width > 4)
731             {
732               siz = fMetrix.stringWidth(str);
733               if (siz > strmaxlen) strmaxlen = siz;
734               if ((txtRect.y = wx + hei / 2) <= lastright)
735               {
736                 wz = leftBottom ? ticksRect.width - 5 - siz : 5;
737                 txtRect.height = hei;
738                 if (tickLabelForeColor != aFrame.frameForeColor) a.setColor(tickLabelForeColor);
739                 a.drawString(str, wz, txtRect.y);
740                 lastright = txtRect.y - hei * 3 / 2;
741                 if (tickLabelForeColor != aFrame.frameForeColor) a.setColor(aFrame.frameForeColor);
742               }
743             }
744           }
745         }
746     if (tickLabelForeColor != aFrame.frameForeColor) a.setColor(tickLabelForeColor);
747     if (xAxis) // x label and time label
748     {
749       wz = leftBottom ? (5 + hei * 2) : (ticksRect.height - 4 - hei);
750       // if ( AxisLabel.length() != 0 && leftBottom == leftBottLabel )
751       // a.drawString(AxisLabel, (aFrame.dxwidth -
752       // fMetrix.stringWidth(AxisLabel))/2, wz );
753       if (ticktext && xtime != 0 && ticks != 0)
754       {
755         if (aFrame.leftTimeLabel)
756           date.setTime((long) getMin() * 1000);
757         else
758           date.setTime((long) getMax() * 1000);
759         siz = fMetrix.stringWidth(date.toString());
760         if ( aFrame.absTimeDisplay )
761         {
762           str = (long)((getMax() - getMin())/AcopConst.timeScale[time_scale] + 0.45) + " " + AcopConst.timeStr[time_scale];
763           tlen = fMetrix.stringWidth(str);
764         }
765         else
766           tlen = fMetrix.stringWidth(AcopConst.timeStr[time_scale]);
767         if (aFrame.leftTimeLabel)
768         {
769           // a.drawString(date.toString(), -siz/4, 5+hei*2);
770           a.drawString(date.toString(), -siz / 4, wz);
771           if ( aFrame.absTimeDisplay )
772             a.drawString(str, aFrame.dxwidth - tlen * 8 / 15, wz);  // 2009-12 it was 1/2
773           else
774           a.drawString(AcopConst.timeStr[time_scale], aFrame.dxwidth - tlen * 8 / 15, wz); // 2009-12 it was 1/2
775         }
776         else
777         {
778           a.drawString(date.toString(), aFrame.dxwidth - siz * 4 / 5, wz);  // 2009-9 it was 3/4
779           if ( aFrame.absTimeDisplay )
780             a.drawString(str, - tlen / 2, wz);
781           else
782           a.drawString(AcopConst.timeStr[time_scale], -tlen / 2, wz);
783         }
784       }
785     }
786     // else if ( AxisLabel.length() != 0 && leftBottom == leftBottLabel ) // y
787     // label
788     else if (false) // y label
789     {
790       AffineTransform oldTransform = a.getTransform();
791       if (leftBottLabel == true)
792       {
793         if (ticksRect.width >= hei + 4)
794         {
795           // a.translate(hei+5,
796           // ticksRect.height/2+fMetrix.stringWidth(AxisLabel)/2);
797           a.translate(hei + 5, ticksRect.height / 2);
798           a.rotate(-Math.PI / 2);
799           a.drawString(AxisLabel, 0, 0);
800         }
801       }
802       else if (acop.yAxisRect.width != 0)
803       {
804         a.translate(acop.yAxisRect.width - hei, acop.yAxisRect.height / 2);
805         // a.translate(de.desy.acop.chart.yAxisRect.x+de.desy.acop.chart.yAxisRect.width/2,
806         // de.desy.acop.chart.yAxisRect.height/2);
807         a.rotate(-Math.PI / 2);
808         a.drawString(AxisLabel, 0, 0);
809       }
810       a.transform(oldTransform);
811       /*
812        * pdc->SelectObject(&y_font); pdc->SetTextAlign( TA_CENTER | TA_TOP); if (
813        * !m_leftYLabel ) { if ( fRight > 0 ) { pdc->SetWindowExt (fRight, -dy);
814        * pdc->SetViewportExt (yAxisRect.right - yAxisRect.left, dy);
815        * pdc->SetViewportOrg (yAxisRect.left, histRect.bottom-1); //
816        * pdc->GetTextMetrics(&tm); // pdc->ExtTextOut((100-tm.tmHeight)/2,
817        * 0,ETO_CLIPPED, &txtRect, m_yAxisLabel,NULL); pdc->TextOut(2, -dy/2,
818        * m_yAxisLabel); } } else if ( fLeft >= strmaxlen + 4 + tm.tmHeight) { //
819        * pdc->GetTextMetrics(&tm); // pdc->ExtTextOut((100-tm.tmHeight)/2,
820        * 0,ETO_CLIPPED, &txtRect, m_yAxisLabel,NULL); strmaxlen =
821        * fLeft-strmaxlen-4-tm.tmHeight-2; pdc->TextOut( strmaxlen < 0 ? 0 :
822        * strmaxlen, -dy/2, m_yAxisLabel); }
823        */
824     }
825     if (xAxis)
826       a.translate(-aFrame.histRect.x - aFrame.xleft, -ticksRect.y + 1);
827     else
828       a.translate(-ticksRect.x, -aFrame.histRect.y);
829     a.setClip(Cliprect);
830     drawLabel(a);
831     if (tickLabelForeColor != aFrame.frameForeColor) a.setColor(aFrame.frameForeColor);
832   }
833 }