1 /* ============================================================
2  * JRobin : Pure java implementation of RRDTool's functionality
3  * ============================================================
4  *
5  * Project Info:  http://www.jrobin.org
6  * Project Lead:  Sasa Markovic (saxon@jrobin.org)
7  *
8  * Developers:    Sasa Markovic (saxon@jrobin.org)
9  *
10  *
11  * (C) Copyright 2003-2005, by Sasa Markovic.
12  *
13  * This library is free software; you can redistribute it and/or modify it under the terms
14  * of the GNU Lesser General Public License as published by the Free Software Foundation;
15  * either version 2.1 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
18  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19  * See the GNU Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public License along with this
22  * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
23  * Boston, MA 02111-1307, USA.
24  */

25 package org.jrobin.graph;
26
27 import org.jrobin.core.Util;
28
29 import java.awt.*;
30
31 class ValueAxis implements RrdGraphConstants {
32     private static final YLab[] ylab = {
33         new YLab(0.1, 1, 2, 5, 10),
34         new YLab(0.2, 1, 5, 10, 20),
35         new YLab(0.5, 1, 2, 4, 10),
36         new YLab(1.0, 1, 2, 5, 10),
37         new YLab(2.0, 1, 5, 10, 20),
38         new YLab(5.0, 1, 2, 4, 10),
39         new YLab(10.0, 1, 2, 5, 10),
40         new YLab(20.0, 1, 5, 10, 20),
41         new YLab(50.0, 1, 2, 4, 10),
42         new YLab(100.0, 1, 2, 5, 10),
43         new YLab(200.0, 1, 5, 10, 20),
44         new YLab(500.0, 1, 2, 4, 10),
45         new YLab(1000.0, 1, 2, 5, 10),
46         new YLab(2000.0, 1, 5, 10, 20),
47         new YLab(5000.0, 1, 2, 4, 10),
48         new YLab(10000.0, 1, 2, 5, 10),
49         new YLab(20000.0, 1, 5, 10, 20),
50         new YLab(50000.0, 1, 2, 4, 10),
51         new YLab(100000.0, 1, 2, 5, 10),
52         new YLab(0.0, 0, 0, 0, 0)
53     };
54
55     private RrdGraph rrdGraph;
56     private ImageParameters im;
57     private ImageWorker worker;
58     private RrdGraphDef gdef;
59
60     ValueAxis(RrdGraph rrdGraph) {
61         this.rrdGraph = rrdGraph;
62         this.im = rrdGraph.im;
63         this.gdef = rrdGraph.gdef;
64         this.worker = rrdGraph.worker;
65     }
66
67     boolean draw() {
68         Font font = gdef.smallFont;
69         Paint gridColor = gdef.colors[COLOR_GRID];
70         Paint mGridColor = gdef.colors[COLOR_MGRID];
71         Paint fontColor = gdef.colors[COLOR_FONT];
72         int fontHeight = (int) Math.ceil(rrdGraph.getSmallFontHeight());
73         int labelOffset = (int) (worker.getFontAscent(font) / 2);
74         int labfact = 2, gridind = -1;
75         double range = im.maxval - im.minval;
76         double scaledrange = range / im.magfact;
77         double gridstep;
78         if (Double.isNaN(scaledrange)) {
79             return false;
80         }
81         int pixel = 1;
82         String labfmt = null;
83         if (Double.isNaN(im.ygridstep)) {
84             if (gdef.altYGrid) {
85                 /* find the value with max number of digits. Get number of digits */
86                 int decimals = (int) Math.ceil(Math.log10(Math.max(Math.abs(im.maxval),
87                         Math.abs(im.minval))));
88                 if (decimals <= 0) /* everything is small. make place for zero */ {
89                     decimals = 1;
90                 }
91                 int fractionals = (int) Math.floor(Math.log10(range));
92                 if (fractionals < 0) /* small amplitude. */ {
93                     labfmt = Util.sprintf("%%%d.%df", decimals - fractionals + 1, -fractionals + 1);
94                 }
95                 else {
96                     labfmt = Util.sprintf("%%%d.1f", decimals + 1);
97                 }
98                 gridstep = Math.pow(10, fractionals);
99                 if (gridstep == 0) /* range is one -> 0.1 is reasonable scale */ {
100                     gridstep = 0.1;
101                 }
102                 /* should have at least 5 lines but no more then 15 */
103                 if (range / gridstep < 5) {
104                     gridstep /= 10;
105                 }
106                 if (range / gridstep > 15) {
107                     gridstep *= 10;
108                 }
109                 if (range / gridstep > 5) {
110                     labfact = 1;
111                     if (range / gridstep > 8) {
112                         labfact = 2;
113                     }
114                 }
115                 else {
116                     gridstep /= 5;
117                     labfact = 5;
118                 }
119             }
120             else {
121                 for (int i = 0; ylab[i].grid > 0; i++) {
122                     pixel = (int) (im.ysize / (scaledrange / ylab[i].grid));
123                     if (gridind == -1 && pixel > 5) {
124                         gridind = i;
125                         break;
126                     }
127                 }
128                 for (int i = 0; i < 4; i++) {
129                     if (pixel * ylab[gridind].lfac[i] >= 2 * fontHeight) {
130                         labfact = ylab[gridind].lfac[i];
131                         break;
132                     }
133                 }
134                 gridstep = ylab[gridind].grid * im.magfact;
135             }
136         }
137         else {
138             gridstep = im.ygridstep;
139             labfact = im.ylabfact;
140         }
141         int x0 = im.xorigin, x1 = x0 + im.xsize;
142         int sgrid = (int) (im.minval / gridstep - 1);
143         int egrid = (int) (im.maxval / gridstep + 1);
144         double scaledstep = gridstep / im.magfact;
145         for (int i = sgrid; i <= egrid; i++) {
146             int y = rrdGraph.mapper.ytr(gridstep * i);
147             if (y >= im.yorigin - im.ysize && y <= im.yorigin) {
148                 if (i % labfact == 0) {
149                     String graph_label;
150                     if (i == 0 || im.symbol == ' ') {
151                         if (scaledstep < 1) {
152                             if (i != 0 && gdef.altYGrid) {
153                                 graph_label = Util.sprintf(labfmt, scaledstep * i);
154                             }
155                             else {
156                                 graph_label = Util.sprintf("%4.1f", scaledstep * i);
157                             }
158                         }
159                         else {
160                             graph_label = Util.sprintf("%4.0f", scaledstep * i);
161                         }
162                     }
163                     else {
164                         if (scaledstep < 1) {
165                             graph_label = Util.sprintf("%4.1f %c", scaledstep * i, im.symbol);
166                         }
167                         else {
168                             graph_label = Util.sprintf("%4.0f %c", scaledstep * i, im.symbol);
169                         }
170                     }
171                     int length = (int) (worker.getStringWidth(graph_label, font));
172                     worker.drawString(graph_label, x0 - length - PADDING_VLABEL, y + labelOffset, font, fontColor);
173                     worker.drawLine(x0 - 2, y, x0 + 2, y, mGridColor, TICK_STROKE);
174                     worker.drawLine(x1 - 2, y, x1 + 2, y, mGridColor, TICK_STROKE);
175                     worker.drawLine(x0, y, x1, y, mGridColor, GRID_STROKE);
176                 }
177                 else if (!(gdef.noMinorGrid)) {
178                     worker.drawLine(x0 - 1, y, x0 + 1, y, gridColor, TICK_STROKE);
179                     worker.drawLine(x1 - 1, y, x1 + 1, y, gridColor, TICK_STROKE);
180                     worker.drawLine(x0, y, x1, y, gridColor, GRID_STROKE);
181                 }
182             }
183         }
184         return true;
185     }
186
187     static class YLab {
188         double grid;
189         int[] lfac;
190
191         YLab(double grid, int lfac1, int lfac2, int lfac3, int lfac4) {
192             this.grid = grid;
193             lfac = new int[] {lfac1, lfac2, lfac3, lfac4};
194         }
195     }
196 }
197