View Javadoc

1   /*--------------------------------------------------------------------------
2    *  Copyright 2009 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  // SAMCanvas.java
20  // Since: Mar. 15, 2010
21  //
22  // $URL$ 
23  // $Author$
24  //--------------------------------------
25  package org.utgenome.gwt.utgb.client.canvas;
26  
27  import java.util.List;
28  
29  import org.utgenome.gwt.utgb.client.bio.SAMRead;
30  import org.utgenome.gwt.utgb.client.track.TrackWindow;
31  import org.utgenome.gwt.utgb.client.ui.FormLabel;
32  
33  import com.google.gwt.core.client.GWT;
34  import com.google.gwt.dom.client.ImageElement;
35  import com.google.gwt.user.client.Event;
36  import com.google.gwt.user.client.ui.AbsolutePanel;
37  import com.google.gwt.user.client.ui.Composite;
38  import com.google.gwt.user.client.ui.FlexTable;
39  import com.google.gwt.widgetideas.graphics.client.Color;
40  import com.google.gwt.widgetideas.graphics.client.GWTCanvas;
41  import com.google.gwt.widgetideas.graphics.client.ImageLoader;
42  
43  /**
44   * Text Alignment Viewer using SAM format data
45   * 
46   * @author yoshimura
47   * 
48   */
49  public class SAMCanvas extends Composite {
50  	private static final boolean isDebug = true;
51  	private TrackWindow window;
52  	private int windowWidth = 800;
53  	private int windowHeight = 200;
54  	private int labelWidth = 100;
55  
56  	private boolean isC2T = false;
57  
58  	public boolean isC2T() {
59  		return isC2T;
60  	}
61  
62  	public void setC2T(boolean isC2T) {
63  		this.isC2T = isC2T;
64  	}
65  
66  	private String colorMode = null;
67  
68  	public String getColorMode() {
69  		return colorMode;
70  	}
71  
72  	public void setColorMode(String colorMode) {
73  		this.colorMode = colorMode;
74  	}
75  
76  	// widget
77  	private FlexTable layoutTable = new FlexTable();
78  	private GWTCanvas canvas = new GWTCanvas();
79  	private AbsolutePanel panel = new AbsolutePanel();
80  
81  	//	private HashMap<String, ImageElement> fontPanel = new HashMap<String, ImageElement>();
82  	private ImageElement[] fontPanel = null;
83  
84  	//	private ImageElement fontPanel = null;
85  
86  	private void initWidget() {
87  		layoutTable.setBorderWidth(0);
88  		layoutTable.setCellPadding(0);
89  		layoutTable.setCellSpacing(0);
90  
91  		panel.add(canvas, 0, 0);
92  		layoutTable.setWidget(0, 1, panel);
93  		initWidget(layoutTable);
94  
95  		sinkEvents(Event.ONMOUSEMOVE | Event.ONMOUSEOVER | Event.ONMOUSEDOWN);
96  	}
97  
98  	public SAMCanvas() {
99  		initWidget();
100 
101 	}
102 
103 	private final int _OFFSET = 6;
104 	private final int _HEIGHT = 17;
105 	private int fontWidth = 7;
106 	private int fontHeight = 13;
107 
108 	public void clear() {
109 		canvas.clear();
110 	}
111 
112 	void redraw() {
113 		canvas.clear();
114 		canvas.setCoordSize(window.getPixelWidth(), windowHeight);
115 		canvas.setPixelSize(window.getPixelWidth(), windowHeight);
116 		panel.setPixelSize(window.getPixelWidth(), windowHeight);
117 	}
118 
119 	public void setWindow(TrackWindow w, int leftMargin) {
120 		this.window = new TrackWindow(w.getPixelWidth(), w.getStartOnGenome(), w.getEndOnGenome());
121 
122 		redraw();
123 	}
124 
125 	public void setPixelHeight(int height) {
126 		canvas.setCoordHeight(height);
127 		canvas.setPixelHeight(height);
128 		panel.setHeight(height + "px");
129 	}
130 
131 	public void setPixelWidth(int width) {
132 		canvas.setCoordWidth(width);
133 		canvas.setPixelWidth(width);
134 		//		panel.setWidth(width + "px");
135 		panel.setPixelSize(width, windowHeight);
136 	}
137 
138 	public void drawSAMRead(final int count, final SAMRead read) {
139 		windowHeight = (count + 1) * (_HEIGHT * _OFFSET);
140 		setPixelHeight(windowHeight);
141 
142 		if (isDebug) {
143 			GWT.log("draw read : " + read.qname, null);
144 			GWT.log("read  : " + read.seq, null);
145 			GWT.log("ref   : " + read.refSeq, null);
146 			GWT.log("CIGAR : " + read.cigar, null);
147 		}
148 
149 		if (fontPanel == null) {
150 			// get charactor images
151 			if (isDebug)
152 				GWT.log("get images:" + count, null);
153 
154 			ImageLoader.loadImages(new String[] { GWT.getModuleBaseURL() + "utgb-core/FontPanel?fontsize=9.5&color=0x000000", // black
155 					GWT.getModuleBaseURL() + "utgb-core/FontPanel?fontsize=9.5&color=0xe0a000", // yellow
156 					GWT.getModuleBaseURL() + "utgb-core/FontPanel?fontsize=9.5&color=0x0000ff", // blue
157 					GWT.getModuleBaseURL() + "utgb-core/FontPanel?fontsize=9.5&color=0x00a000", // green
158 					GWT.getModuleBaseURL() + "utgb-core/FontPanel?fontsize=9.5&color=0xff0000" }, // red
159 					new ImageLoader.CallBack() {
160 						public void onImagesLoaded(ImageElement[] imageElements) {
161 							fontPanel = imageElements;
162 							if (isDebug)
163 								GWT.log("draw images:" + count, null);
164 
165 							drawSAMCanvas(count, read);
166 						}
167 					});
168 		}
169 		else {
170 			drawSAMCanvas(count, read);
171 		}
172 	}
173 
174 	public void drawSAMRead(final List<SAMRead> readList) {
175 		windowHeight = readList.size() * (_HEIGHT * _OFFSET);
176 		setPixelHeight(windowHeight);
177 
178 		if (fontPanel == null) {
179 			// get charactor images
180 			if (isDebug)
181 				GWT.log("get images", null);
182 
183 			ImageLoader.loadImages(new String[] { GWT.getModuleBaseURL() + "utgb-core/FontPanel?fontsize=9.5&color=0x000000", // black
184 					GWT.getModuleBaseURL() + "utgb-core/FontPanel?fontsize=9.5&color=0xe0a000", // yellow
185 					GWT.getModuleBaseURL() + "utgb-core/FontPanel?fontsize=9.5&color=0x0000ff", // blue
186 					GWT.getModuleBaseURL() + "utgb-core/FontPanel?fontsize=9.5&color=0x00a000", // green
187 					GWT.getModuleBaseURL() + "utgb-core/FontPanel?fontsize=9.5&color=0xff0000" }, // red
188 					new ImageLoader.CallBack() {
189 						public void onImagesLoaded(ImageElement[] imageElements) {
190 							fontPanel = imageElements;
191 							draw(readList);
192 						}
193 					});
194 		}
195 		else {
196 			draw(readList);
197 		}
198 	}
199 
200 	private void draw(List<SAMRead> readList) {
201 		int count = 0;
202 
203 		for (SAMRead read : readList) {
204 			if (isDebug) {
205 				GWT.log("draw read : " + read.qname, null);
206 				GWT.log("read  : " + read.seq, null);
207 				GWT.log("ref   : " + read.refSeq, null);
208 				GWT.log("CIGAR : " + read.cigar, null);
209 			}
210 
211 			drawSAMCanvas(count, read);
212 			count++;
213 		}
214 	}
215 
216 	public void drawSAMCanvas(int count, SAMRead read) {
217 		StringBuilder num = new StringBuilder();
218 		char readc, refc, diffc;
219 		int readi = 0, refi = 0, position = 0;
220 
221 		for (int cursor = 0; cursor < read.cigar.length(); cursor++) {
222 			char temp = read.cigar.charAt(cursor);
223 			if ('0' <= temp && temp <= '9') {
224 				num.append(temp);
225 			}
226 			else {
227 				for (int i = 0; i < Integer.valueOf(num.toString()); i++, position++) {
228 
229 					if (temp == 'I') {
230 						readc = read.seq.charAt(readi++);
231 						refc = '*';
232 					}
233 					else if (temp == 'S') {
234 						refc = ' ';
235 						readc = read.seq.toLowerCase().charAt(readi++);
236 					}
237 					else if (temp == 'D') {
238 						refc = read.refSeq.charAt(refi++);
239 						readc = '*';
240 					}
241 					else if (temp == 'P') {
242 						refc = '*';
243 						readc = '*';
244 					}
245 					else if (temp == 'H') {
246 						position--;
247 						continue;
248 					}
249 					else {
250 						refc = read.refSeq.charAt(refi++);
251 						readc = read.seq.charAt(readi++);
252 					}
253 
254 					if (temp == 'P' || temp == 'S')
255 						diffc = ' ';
256 					else if (refc != readc)
257 						if (isC2T && readc == 'T' && refc == 'C')
258 							diffc = 'T';
259 						else
260 							diffc = 'X';
261 					else
262 						diffc = '|';
263 
264 					// draw indent line
265 					canvas.setFillStyle(Color.BLACK);
266 					if (refc != ' ' && refc != '*') {
267 						canvas.fillRect(position * fontWidth + 3, _HEIGHT * (count * _OFFSET + 1), fontWidth, 1);
268 						String indent = String.valueOf(read.getStart() + refi - 1);
269 						if ((read.getStart() + refi - 1) % (int) (Math.ceil(indent.length() / 5.0) * 5) == 0) {
270 							canvas.fillRect((position + 0.5) * fontWidth + 2, _HEIGHT * (count * _OFFSET + 1) - 3, 1, 5);
271 							for (int j = 0; j < indent.length(); j++)
272 								canvas.drawImage(fontPanel[0], (indent.charAt(j)) * fontWidth, 0, fontWidth, fontHeight, (position + j) * fontWidth + 2,
273 										_HEIGHT * (count * _OFFSET), fontWidth, fontHeight);
274 						}
275 					}
276 
277 					// draw reference sequence
278 					canvas.drawImage(fontPanel[getColorInt(refc)], (refc) * fontWidth, 0, fontWidth, fontHeight, position * fontWidth + 3, _HEIGHT
279 							* (count * _OFFSET + 1) + 3, fontWidth, fontHeight);
280 					// draw reference sequence
281 					canvas.drawImage(fontPanel[0], (diffc) * fontWidth, 0, fontWidth, fontHeight, position * fontWidth + 3, _HEIGHT * (count * _OFFSET + 2),
282 							fontWidth, fontHeight);
283 					// draw read sequence
284 					canvas.drawImage(fontPanel[getColorInt(readc)], (readc) * fontWidth, 0, fontWidth, fontHeight, position * fontWidth + 3, _HEIGHT
285 							* (count * _OFFSET + 3) - 3, fontWidth, fontHeight);
286 				}
287 
288 				num = new StringBuilder();
289 			}
290 		}
291 
292 		// draw tag
293 		for (int cursor = 0; cursor < read.toString().length(); cursor++) {
294 			canvas.drawImage(fontPanel[0], (read.toString().charAt(cursor)) * fontWidth, 0, fontWidth, fontHeight, cursor * fontWidth + 3, _HEIGHT
295 					* (count * _OFFSET + 4) - 6, fontWidth, fontHeight);
296 		}
297 	}
298 
299 	public void drawLabelPanel(int count, SAMRead read, AbsolutePanel panel, int leftMargin) {
300 		panel.setHeight(windowHeight + "px");
301 
302 		// draw reference label
303 		//		FixedWidthLabel refSeqLabel = new FixedWidthLabel(read.rname, leftMargin);
304 		FormLabel refSeqLabel = new FormLabel(read.rname);
305 		refSeqLabel.setStyleName("search-label");
306 		// draw read label
307 		//		FixedWidthLabel readLabel = new FixedWidthLabel(read.qname, leftMargin);
308 		FormLabel readLabel = new FormLabel(read.qname);
309 		readLabel.setStyleName("search-label");
310 
311 		panel.add(refSeqLabel);
312 		panel.setWidgetPosition(refSeqLabel, 0, _HEIGHT * (count * _OFFSET + 1) + 5);
313 		panel.add(readLabel);
314 		panel.setWidgetPosition(readLabel, 0, _HEIGHT * (count * _OFFSET + 3) - 1);
315 	}
316 
317 	public void drawLabelPanel(List<SAMRead> readList, AbsolutePanel panel, int leftMargin) {
318 		panel.setHeight(windowHeight + "px");
319 
320 		//		FixedWidthLabel[] refSeqLabel = new FixedWidthLabel[readList.size()];
321 		//		FixedWidthLabel[] readLabel = new FixedWidthLabel[readList.size()];
322 
323 		FormLabel[] refSeqLabel = new FormLabel[readList.size()];
324 		FormLabel[] readLabel = new FormLabel[readList.size()];
325 
326 		int count = 0;
327 		for (SAMRead read : readList) {
328 			// draw reference label
329 			refSeqLabel[count] = new FormLabel(read.rname);
330 			refSeqLabel[count].setStyleName("search-label");
331 			// draw read label
332 			readLabel[count] = new FormLabel(read.qname);
333 			readLabel[count].setStyleName("search-label");
334 
335 			panel.add(refSeqLabel[count]);
336 			panel.setWidgetPosition(refSeqLabel[count], 0, _HEIGHT * (count * _OFFSET + 1) + 5);
337 			panel.add(readLabel[count]);
338 			panel.setWidgetPosition(readLabel[count], 0, _HEIGHT * (count * _OFFSET + 3) - 1);
339 
340 			count++;
341 		}
342 	}
343 
344 	private int getColorInt(char nucleotide) {
345 		int color = 0; // black
346 		if (colorMode.equals("nucleotide")) {
347 			if (nucleotide == 'G' || nucleotide == 'g')
348 				color = 1; // yellow
349 			else if (nucleotide == 'C' || nucleotide == 'c')
350 				color = 2; // blue
351 			else if (nucleotide == 'A' || nucleotide == 'a')
352 				color = 3; // green
353 			else if (nucleotide == 'T' || nucleotide == 't')
354 				color = 4; // red
355 		}
356 		return color;
357 	}
358 
359 	public int countNucleotides(String cigar) {
360 		int count = 0;
361 		StringBuilder num = new StringBuilder();
362 		for (int cursor = 0; cursor < cigar.length(); cursor++) {
363 			char temp = cigar.charAt(cursor);
364 			if ('0' <= temp && temp <= '9') {
365 				num.append(temp);
366 			}
367 			else if (temp != 'H') {
368 				count += Integer.valueOf(num.toString()).intValue();
369 				num = new StringBuilder();
370 			}
371 		}
372 		return count;
373 	}
374 
375 	public int getReadWidth(String cigar) {
376 		return (countNucleotides(cigar) + 1) * fontWidth + 3;
377 	}
378 }