View Javadoc

1   /*--------------------------------------------------------------------------
2    *  Copyright 2008 utgenome.org
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   *--------------------------------------------------------------------------*/
16  //--------------------------------------
17  // utgb-core Project
18  //
19  // GeneCanvas.java
20  // Since: Jan 17, 2008
21  //
22  // $URL$ 
23  // $Author$
24  //--------------------------------------
25  package org.utgenome.graphics;
26  
27  import java.awt.Color;
28  import java.awt.Font;
29  import java.awt.FontMetrics;
30  import java.awt.Graphics2D;
31  import java.awt.RenderingHints;
32  import java.awt.geom.Rectangle2D;
33  import java.awt.image.BufferedImage;
34  import java.io.IOException;
35  import java.util.ArrayList;
36  
37  import javax.imageio.ImageIO;
38  import javax.servlet.http.HttpServletResponse;
39  
40  import org.xerial.util.log.Logger;
41  
42  /**
43   * A canvas class for drawing genes. Modify this implementation so that it can handle Ribbon coordinate
44   * 
45   * @author leo
46   * 
47   */
48  public class GenomeCanvas {
49  
50  	private static Logger _logger = Logger.getLogger(GenomeCanvas.class);
51  
52  	private final GenomeWindow window;
53  	private BufferedImage image;
54  	private Graphics2D g;
55  	private int canvasWidth;
56  	private int canvasHeight;
57  
58  	private int yOffset = 0;
59  
60  	private boolean isReverse = false;
61  
62  	private ArrayList<Integer> lastGeneEnds = new ArrayList<Integer>();
63  
64  	private int geneHeight = 5;
65  
66  	public void setGeneHeight(int height) {
67  		this.geneHeight = height;
68  	}
69  
70  	public Graphics2D getGraphics() {
71  		return g;
72  	}
73  
74  	public GenomeWindow getGenomeWindow() {
75  		return window;
76  	}
77  
78  	public GenomeCanvas(int width, int height, GenomeWindow window) {
79  		this.window = window;
80  		setPixelSize(width, height);
81  
82  		isReverse = window.getReverse();
83  		if (!isReverse)
84  			this.lastGeneEnds.add(Integer.MIN_VALUE);
85  		else
86  			this.lastGeneEnds.add(Integer.MAX_VALUE);
87  	}
88  
89  	public int getWidth() {
90  		return canvasWidth;
91  	}
92  
93  	public BufferedImage getBufferedImage() {
94  		return image;
95  	}
96  
97  	public void drawTag(long startIndexOnGenome, long endIndexOnGenome) {
98  		drawTag(startIndexOnGenome, endIndexOnGenome, Color.GRAY);
99  	}
100 
101 	public void drawTag(long startIndexOnGenome, long endIndexOnGenome, Color color) {
102 		int start = window.getXPosOnWindow(startIndexOnGenome, canvasWidth);
103 		int end = window.getXPosOnWindow(endIndexOnGenome, canvasWidth);
104 
105 		if (start > end) {
106 			int temp = start;
107 			start = end;
108 			end = temp;
109 		}
110 
111 		int width = end - start;
112 		if (width <= 0)
113 			width = 1;
114 
115 		drawRect(start, yOffset, width, geneHeight - 1, color);
116 		yOffset += geneHeight;
117 		if (yOffset > canvasHeight)
118 			yOffset = 0;
119 	}
120 
121 	public void drawGeneRect(long startIndexOnGenome, long endIndexOnGenome, int yOffset, int height, Color color) {
122 		int start = window.getXPosOnWindow(startIndexOnGenome, canvasWidth);
123 		int end = window.getXPosOnWindow(endIndexOnGenome, canvasWidth);
124 
125 		if (start > end) {
126 			int temp = start;
127 			start = end;
128 			end = temp;
129 		}
130 
131 		int width = end - start;
132 		if (width <= 0)
133 			width = 1;
134 
135 		if (start <= canvasWidth && end >= 0)
136 			drawRect(start, yOffset, width, height, color);
137 	}
138 
139 	public void drawRect(int x, int y, int width, int height, Color color) {
140 		Rectangle2D rect = new Rectangle2D.Double(x, y, width, height);
141 		g.setColor(color);
142 		g.fill(rect);
143 	}
144 
145 	public void drawBase(String text, long startIndexOnGenome, long endIndexOnGenome, int yOffset, float fontSize, Color color) {
146 		int start = window.getXPosOnWindow(startIndexOnGenome, canvasWidth);
147 		int end = window.getXPosOnWindow(endIndexOnGenome, canvasWidth);
148 		int drawStart;
149 
150 		Font f = new Font("SansSerif", Font.PLAIN, 1);
151 		f = f.deriveFont(fontSize);
152 		g.setFont(f);
153 
154 		FontMetrics fontMetrics = g.getFontMetrics();
155 		int fontWidth = fontMetrics.stringWidth(text);
156 
157 		g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
158 		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
159 		g.setColor(color);
160 
161 		if (isReverse) {
162 			int temp = start;
163 			start = end;
164 			end = temp;
165 		}
166 
167 		drawStart = (int) (start + (end - start) / 2.0f - fontWidth / 2.0f);
168 		if (drawStart < 0)
169 			drawStart = end;
170 
171 		g.drawString(text, drawStart, yOffset);
172 
173 	}
174 
175 	/**
176 	 * @param text
177 	 * @param startIndexOnGenome
178 	 *            font range start
179 	 * @param endIndexOnGenome
180 	 *            font range end
181 	 * @param yOffset
182 	 *            offset value of Y-axis
183 	 * @param fontSize
184 	 * @param color
185 	 * @throws IOException
186 	 */
187 	public void drawText(String text, long startIndexOnGenome, long endIndexOnGenome, int yOffset, float fontSize, Color color) {
188 		int start = window.getXPosOnWindow(startIndexOnGenome, canvasWidth);
189 		int end = window.getXPosOnWindow(endIndexOnGenome, canvasWidth);
190 		int drawStart;
191 
192 		Font f = new Font("Arial", Font.PLAIN, 1);
193 		f = f.deriveFont(fontSize);
194 		g.setFont(f);
195 
196 		FontMetrics fontMetrics = g.getFontMetrics();
197 		int fontWidth = fontMetrics.stringWidth(text);
198 		//		g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
199 		//g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
200 
201 		g.setColor(color);
202 
203 		if (isReverse) {
204 			int temp = start;
205 			start = end;
206 			end = temp;
207 		}
208 
209 		drawStart = (int) (start + (end - start) / 2.0f - fontWidth / 2.0f);
210 		if (drawStart < 0)
211 			drawStart = end;
212 
213 		g.drawString(text, drawStart, yOffset);
214 	}
215 
216 	public void drawText(String text, long startIndexOnGenome, long endIndexOnGenome, int yOffset, int fontSize, Color color) {
217 		int start = window.getXPosOnWindow(startIndexOnGenome, canvasWidth);
218 		int end = window.getXPosOnWindow(endIndexOnGenome, canvasWidth);
219 		int drawStart;
220 
221 		g.setFont(new Font("Arial", Font.PLAIN, fontSize));
222 		FontMetrics fontMetrics = g.getFontMetrics();
223 		int fontWidth = fontMetrics.stringWidth(text) + 2;
224 		g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
225 		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
226 
227 		g.setColor(color);
228 
229 		if (isReverse) {
230 			int temp = start;
231 			start = end;
232 			end = temp;
233 		}
234 		drawStart = start - fontWidth;
235 		if (drawStart < 0)
236 			drawStart = end + 2;
237 
238 		g.drawString(text, drawStart, yOffset + (int) (fontSize * 0.85));
239 	}
240 
241 	public void drawLocusLabel(String text, long startIndexOnGenome, long endIndexOnGenome, int yOffset, float fontSize, Color color) {
242 		int start = window.getXPosOnWindow(startIndexOnGenome, canvasWidth);
243 		int end = window.getXPosOnWindow(endIndexOnGenome, canvasWidth);
244 
245 		int drawStart;
246 
247 		Font f = new Font("Arial", Font.PLAIN, 1);
248 		f = f.deriveFont(fontSize);
249 		g.setFont(f);
250 
251 		FontMetrics fontMetrics = g.getFontMetrics();
252 		int fontWidth = fontMetrics.stringWidth(text);
253 		//	g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
254 		//		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
255 
256 		g.setColor(color);
257 
258 		if (isReverse) {
259 			int temp = start;
260 			start = end;
261 			end = temp;
262 		}
263 
264 		drawStart = (start - fontWidth) - 1;
265 
266 		g.drawString(text, drawStart, yOffset);
267 	}
268 
269 	public void outputImage(HttpServletResponse response, final String imageType) throws IOException {
270 		response.setContentType("image/" + imageType);
271 		ImageIO.write(image, imageType, response.getOutputStream());
272 	}
273 
274 	public void setPixelSize(int width, int height) {
275 		canvasWidth = width;
276 		canvasHeight = height;
277 
278 		image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
279 		g = image.createGraphics();
280 
281 	}
282 
283 	public void drawLine(long x1, long y1, long x2, long y2, Color lineColor) {
284 		g.setColor(lineColor);
285 		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
286 		g.drawLine((int) (window.getXPosOnWindow(x1, canvasWidth) + 0.5f), (int) y1, (int) (window.getXPosOnWindow(x2, canvasWidth) - 0.5f), (int) y2);
287 	}
288 
289 	public void setPixelHeight(int height) {
290 
291 		canvasHeight = height;
292 
293 		image = new BufferedImage(canvasWidth, height, BufferedImage.TYPE_INT_ARGB);
294 		g = image.createGraphics();
295 
296 	}
297 
298 	public int getFontWidth(String text) {
299 		FontMetrics metrics = g.getFontMetrics(g.getFont());
300 		return metrics.stringWidth(text);
301 	}
302 
303 	public int getXPosOnWindow(long indexOnGenome) {
304 		return window.getXPosOnWindow(indexOnGenome, canvasWidth);
305 	}
306 
307 	public int getOffset(String text, int fontSize, long startIndexOnGenome, long endIndexOnGenome, int gapWidth) {
308 		int offset = 0;
309 		boolean isSpace = false;
310 
311 		int start = window.getXPosOnWindow(startIndexOnGenome, canvasWidth);
312 		int end = window.getXPosOnWindow(endIndexOnGenome, canvasWidth);
313 		if (isReverse) {
314 			int temp = start;
315 			start = end;
316 			end = temp;
317 		}
318 
319 		g.setFont(new Font("SansSerif", Font.PLAIN, fontSize));
320 		FontMetrics fontMetrics = g.getFontMetrics();
321 		int textWidth = fontMetrics.stringWidth(text);
322 
323 		// calculate offset
324 		if (!isReverse) {
325 			for (int i = 0; i < lastGeneEnds.size(); i++) {
326 				if (start - textWidth <= lastGeneEnds.get(i).intValue()) {
327 					offset++;
328 				}
329 				else {
330 					lastGeneEnds.set(i, Integer.valueOf(getEndIndex(text, fontSize, start, end, gapWidth)));
331 					isSpace = true;
332 					break;
333 				}
334 			}
335 			if (!isSpace) {
336 				lastGeneEnds.add(getEndIndex(text, fontSize, start, end, gapWidth));
337 			}
338 		}
339 		else {
340 			for (int i = 0; i < lastGeneEnds.size(); i++) {
341 				if (getEndIndex(text, fontSize, start, end, gapWidth) >= lastGeneEnds.get(i).intValue()) {
342 					offset++;
343 				}
344 				else {
345 					lastGeneEnds.set(i, Integer.valueOf(start - textWidth));
346 					isSpace = true;
347 					break;
348 				}
349 			}
350 			if (!isSpace) {
351 				lastGeneEnds.add(start - textWidth);
352 			}
353 		}
354 
355 		return offset;
356 	}
357 
358 	public int getEndIndex(String text, int fontSize, int start, int end, int gapWidth) {
359 		String tempText = "a";
360 
361 		g.setFont(new Font("SansSerif", Font.PLAIN, fontSize));
362 		FontMetrics fontMetrics = g.getFontMetrics();
363 
364 		int fontWidth = fontMetrics.stringWidth(text);
365 		int tempWidth = fontMetrics.stringWidth(tempText);
366 
367 		if (start - fontWidth < 0) {
368 			fontWidth += tempWidth * gapWidth;
369 		}
370 		else {
371 			fontWidth = tempWidth * gapWidth;
372 		}
373 		return end + fontWidth;
374 	}
375 }