View Javadoc

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 java.awt.*;
28  import java.text.SimpleDateFormat;
29  import java.util.Calendar;
30  import java.util.Date;
31  import java.util.Locale;
32  
33  class TimeAxis implements RrdGraphConstants {
34  	private static final TimeAxisSetting[] tickSettings = {
35  			new TimeAxisSetting(0, SECOND, 30, MINUTE, 5, MINUTE, 5, 0, "HH:mm"),
36  			new TimeAxisSetting(2, MINUTE, 1, MINUTE, 5, MINUTE, 5, 0, "HH:mm"),
37  			new TimeAxisSetting(5, MINUTE, 2, MINUTE, 10, MINUTE, 10, 0, "HH:mm"),
38  			new TimeAxisSetting(10, MINUTE, 5, MINUTE, 20, MINUTE, 20, 0, "HH:mm"),
39  			new TimeAxisSetting(30, MINUTE, 10, HOUR, 1, HOUR, 1, 0, "HH:mm"),
40  			new TimeAxisSetting(60, MINUTE, 30, HOUR, 2, HOUR, 2, 0, "HH:mm"),
41  			new TimeAxisSetting(180, HOUR, 1, HOUR, 6, HOUR, 6, 0, "HH:mm"),
42  			new TimeAxisSetting(600, HOUR, 6, DAY, 1, DAY, 1, 24 * 3600, "EEE"),
43  			new TimeAxisSetting(1800, HOUR, 12, DAY, 1, DAY, 2, 24 * 3600, "EEE"),
44  			new TimeAxisSetting(3600, DAY, 1, WEEK, 1, WEEK, 1, 7 * 24 * 3600, "'Week 'w"),
45  			new TimeAxisSetting(3 * 3600, WEEK, 1, MONTH, 1, WEEK, 2, 7 * 24 * 3600, "'Week 'w"),
46  			new TimeAxisSetting(6 * 3600, MONTH, 1, MONTH, 1, MONTH, 1, 30 * 24 * 3600, "MMM"),
47  			new TimeAxisSetting(48 * 3600, MONTH, 1, MONTH, 3, MONTH, 3, 30 * 24 * 3600, "MMM"),
48  			new TimeAxisSetting(10 * 24 * 3600, YEAR, 1, YEAR, 1, YEAR, 1, 365 * 24 * 3600, "yy"),
49  			new TimeAxisSetting(-1, MONTH, 0, MONTH, 0, MONTH, 0, 0, "")
50  	};
51  
52  	private TimeAxisSetting tickSetting;
53  	private RrdGraph rrdGraph;
54  	private double secPerPix;
55  	private Calendar calendar;
56  
57  	TimeAxis(RrdGraph rrdGraph) {
58  		this.rrdGraph = rrdGraph;
59  		if (rrdGraph.im.xsize > 0) {
60  			this.secPerPix = (rrdGraph.im.end - rrdGraph.im.start) / rrdGraph.im.xsize;
61  		}
62  		this.calendar = Calendar.getInstance(Locale.getDefault());
63  		this.calendar.setFirstDayOfWeek(rrdGraph.gdef.firstDayOfWeek);
64  	}
65  
66  	void draw() {
67  		chooseTickSettings();
68  		if (tickSetting == null) {
69  			return;
70  		}
71  		drawMinor();
72  		drawMajor();
73  		drawLabels();
74  	}
75  
76  	private void drawMinor() {
77  		if (!rrdGraph.gdef.noMinorGrid) {
78  			adjustStartingTime(tickSetting.minorUnit, tickSetting.minorUnitCount);
79  			Paint color = rrdGraph.gdef.colors[COLOR_GRID];
80  			int y0 = rrdGraph.im.yorigin, y1 = y0 - rrdGraph.im.ysize;
81  			for (int status = getTimeShift(); status <= 0; status = getTimeShift()) {
82  				if (status == 0) {
83  					long time = calendar.getTime().getTime() / 1000L;
84  					int x = rrdGraph.mapper.xtr(time);
85  					rrdGraph.worker.drawLine(x, y0 - 1, x, y0 + 1, color, TICK_STROKE);
86  					rrdGraph.worker.drawLine(x, y0, x, y1, color, GRID_STROKE);
87  				}
88  				findNextTime(tickSetting.minorUnit, tickSetting.minorUnitCount);
89  			}
90  		}
91  	}
92  
93  	private void drawMajor() {
94  		adjustStartingTime(tickSetting.majorUnit, tickSetting.majorUnitCount);
95  		Paint color = rrdGraph.gdef.colors[COLOR_MGRID];
96  		int y0 = rrdGraph.im.yorigin, y1 = y0 - rrdGraph.im.ysize;
97  		for (int status = getTimeShift(); status <= 0; status = getTimeShift()) {
98  			if (status == 0) {
99  				long time = calendar.getTime().getTime() / 1000L;
100 				int x = rrdGraph.mapper.xtr(time);
101 				rrdGraph.worker.drawLine(x, y0 - 2, x, y0 + 2, color, TICK_STROKE);
102 				rrdGraph.worker.drawLine(x, y0, x, y1, color, GRID_STROKE);
103 			}
104 			findNextTime(tickSetting.majorUnit, tickSetting.majorUnitCount);
105 		}
106 	}
107 
108 	private void drawLabels() {
109 		// escape strftime like format string
110 		String labelFormat = tickSetting.format.replaceAll("([^%]|^)%([^%t])", "$1%t$2");
111 		Font font = rrdGraph.gdef.smallFont;
112 		Paint color = rrdGraph.gdef.colors[COLOR_FONT];
113 		adjustStartingTime(tickSetting.labelUnit, tickSetting.labelUnitCount);
114 		int y = rrdGraph.im.yorigin + (int) rrdGraph.worker.getFontHeight(font) + 2;
115 		for (int status = getTimeShift(); status <= 0; status = getTimeShift()) {
116 			String label = formatLabel(labelFormat, calendar.getTime());
117 			long time = calendar.getTime().getTime() / 1000L;
118 			int x1 = rrdGraph.mapper.xtr(time);
119 			int x2 = rrdGraph.mapper.xtr(time + tickSetting.labelSpan);
120 			int labelWidth = (int) rrdGraph.worker.getStringWidth(label, font);
121 			int x = x1 + (x2 - x1 - labelWidth) / 2;
122 			if (x >= rrdGraph.im.xorigin && x + labelWidth <= rrdGraph.im.xorigin + rrdGraph.im.xsize) {
123 				rrdGraph.worker.drawString(label, x, y, font, color);
124 			}
125 			findNextTime(tickSetting.labelUnit, tickSetting.labelUnitCount);
126 		}
127 	}
128 
129 	private static String formatLabel(String format, Date date) {
130 		if (format.contains("%")) {
131 			// strftime like format string
132 			return String.format(format, date);
133 		}
134 		else {
135 			// simple date format
136 			return new SimpleDateFormat(format).format(date);
137 		}
138 	}
139 
140 	private void findNextTime(int timeUnit, int timeUnitCount) {
141 		switch (timeUnit) {
142 			case SECOND:
143 				calendar.add(Calendar.SECOND, timeUnitCount);
144 				break;
145 			case MINUTE:
146 				calendar.add(Calendar.MINUTE, timeUnitCount);
147 				break;
148 			case HOUR:
149 				calendar.add(Calendar.HOUR_OF_DAY, timeUnitCount);
150 				break;
151 			case DAY:
152 				calendar.add(Calendar.DAY_OF_MONTH, timeUnitCount);
153 				break;
154 			case WEEK:
155 				calendar.add(Calendar.DAY_OF_MONTH, 7 * timeUnitCount);
156 				break;
157 			case MONTH:
158 				calendar.add(Calendar.MONTH, timeUnitCount);
159 				break;
160 			case YEAR:
161 				calendar.add(Calendar.YEAR, timeUnitCount);
162 				break;
163 		}
164 	}
165 
166 	private int getTimeShift() {
167 		long time = calendar.getTime().getTime() / 1000L;
168 		return (time < rrdGraph.im.start) ? -1 : (time > rrdGraph.im.end) ? +1 : 0;
169 	}
170 
171 	private void adjustStartingTime(int timeUnit, int timeUnitCount) {
172 		calendar.setTime(new Date(rrdGraph.im.start * 1000L));
173 		switch (timeUnit) {
174 			case SECOND:
175 				calendar.add(Calendar.SECOND, -(calendar.get(Calendar.SECOND) % timeUnitCount));
176 				break;
177 			case MINUTE:
178 				calendar.set(Calendar.SECOND, 0);
179 				calendar.add(Calendar.MINUTE, -(calendar.get(Calendar.MINUTE) % timeUnitCount));
180 				break;
181 			case HOUR:
182 				calendar.set(Calendar.SECOND, 0);
183 				calendar.set(Calendar.MINUTE, 0);
184 				calendar.add(Calendar.HOUR_OF_DAY, -(calendar.get(Calendar.HOUR_OF_DAY) % timeUnitCount));
185 				break;
186 			case DAY:
187 				calendar.set(Calendar.SECOND, 0);
188 				calendar.set(Calendar.MINUTE, 0);
189 				calendar.set(Calendar.HOUR_OF_DAY, 0);
190 				break;
191 			case WEEK:
192 				calendar.set(Calendar.SECOND, 0);
193 				calendar.set(Calendar.MINUTE, 0);
194 				calendar.set(Calendar.HOUR_OF_DAY, 0);
195 				int diffDays = calendar.get(Calendar.DAY_OF_WEEK) - calendar.getFirstDayOfWeek();
196 				if (diffDays < 0) {
197 					diffDays += 7;
198 				}
199 				calendar.add(Calendar.DAY_OF_MONTH, -diffDays);
200 				break;
201 			case MONTH:
202 				calendar.set(Calendar.SECOND, 0);
203 				calendar.set(Calendar.MINUTE, 0);
204 				calendar.set(Calendar.HOUR_OF_DAY, 0);
205 				calendar.set(Calendar.DAY_OF_MONTH, 1);
206 				calendar.add(Calendar.MONTH, -(calendar.get(Calendar.MONTH) % timeUnitCount));
207 				break;
208 			case YEAR:
209 				calendar.set(Calendar.SECOND, 0);
210 				calendar.set(Calendar.MINUTE, 0);
211 				calendar.set(Calendar.HOUR_OF_DAY, 0);
212 				calendar.set(Calendar.DAY_OF_MONTH, 1);
213 				calendar.set(Calendar.MONTH, 0);
214 				calendar.add(Calendar.YEAR, -(calendar.get(Calendar.YEAR) % timeUnitCount));
215 				break;
216 		}
217 	}
218 
219 
220 	private void chooseTickSettings() {
221 		if (rrdGraph.gdef.timeAxisSetting != null) {
222 			tickSetting = new TimeAxisSetting(rrdGraph.gdef.timeAxisSetting);
223 		}
224 		else {
225 			for (int i = 0; tickSettings[i].secPerPix >= 0 && secPerPix > tickSettings[i].secPerPix; i++) {
226 				tickSetting = tickSettings[i];
227 			}
228 		}
229 	}
230 
231 }