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  // RibbonCanvas.java
20  // Since: Jul 13, 2009
21  //
22  // $URL$ 
23  // $Author$
24  //--------------------------------------
25  package org.utgenome.gwt.utgb.client.canvas;
26  
27  import java.util.ArrayList;
28  import java.util.List;
29  import java.util.TreeSet;
30  
31  import org.utgenome.gwt.utgb.client.track.TrackWindow;
32  
33  import com.google.gwt.core.client.GWT;
34  import com.google.gwt.dom.client.ImageElement;
35  import com.google.gwt.user.client.ui.Composite;
36  import com.google.gwt.widgetideas.graphics.client.Color;
37  import com.google.gwt.widgetideas.graphics.client.GWTCanvas;
38  import com.google.gwt.widgetideas.graphics.client.ImageLoader;
39  
40  /**
41   * Ribbon coordinate ruler
42   * 
43   * @author leo
44   * 
45   */
46  public class RibbonRuler extends Composite {
47  	private TrackWindow window;
48  
49  	private GWTCanvas canvas = new GWTCanvas();
50  
51  	private TreeSet<RibbonCrease> ribbonPoint = new TreeSet<RibbonCrease>();
52  
53  	private enum RibbonType {
54  		GAP, FOLD, NORMAL
55  	}
56  
57  	/**
58  	 * folding/gap point on a ribbon
59  	 * 
60  	 * @author leo
61  	 * 
62  	 */
63  	private static class RibbonCrease implements Comparable<RibbonCrease> {
64  		public final int pos;
65  		public final int len;
66  
67  		private final RibbonType type;
68  		private boolean isOpen = true;
69  
70  		public RibbonCrease(RibbonType type, int pos, int len) {
71  			this.type = type;
72  			this.pos = pos;
73  			this.len = len;
74  		}
75  
76  		public boolean contains(long indexOnGenome) {
77  			return (pos <= indexOnGenome && indexOnGenome <= (pos + len));
78  		}
79  
80  		public long getEnd() {
81  			switch (type) {
82  			case GAP:
83  				return pos;
84  			case FOLD:
85  			case NORMAL:
86  			default:
87  				return pos + len - 1;
88  			}
89  
90  		}
91  
92  		public int compareTo(RibbonCrease o) {
93  			return (this.pos - o.pos);
94  		}
95  	}
96  
97  	private static class RibbonBlock {
98  		public final long startOnGenome;
99  		public final int size;
100 		public final RibbonType type;
101 
102 		public RibbonBlock(RibbonType type, long start, int size) {
103 			this.startOnGenome = start;
104 			this.size = size;
105 			this.type = type;
106 		}
107 
108 		public long getEnd() {
109 			switch (type) {
110 			case GAP:
111 				return startOnGenome;
112 			case FOLD:
113 			case NORMAL:
114 			default:
115 				return startOnGenome + size - 1;
116 			}
117 
118 		}
119 
120 	}
121 
122 	private ImageElement fontPanel = null;
123 
124 	public RibbonRuler() {
125 		initWidget(canvas);
126 
127 	}
128 
129 	private final int RIBBON_HEIGHT = 17;
130 
131 	void drawFold(int x, int baseLength) {
132 
133 	}
134 
135 	void drawGap(int x, int baseLength) {
136 
137 	}
138 
139 	void redraw() {
140 		canvas.clear();
141 		canvas.setCoordSize(window.getPixelWidth(), RIBBON_HEIGHT);
142 		canvas.setPixelSize(window.getPixelWidth(), RIBBON_HEIGHT);
143 
144 		long genomeCursor = window.getStartOnGenome();
145 		List<RibbonBlock> ribbonBlocks = new ArrayList<RibbonBlock>();
146 		// build logical ribbon blocks 
147 		for (RibbonCrease rp : ribbonPoint) {
148 			if (rp.getEnd() < genomeCursor)
149 				continue;
150 
151 			if (genomeCursor < rp.pos)
152 				ribbonBlocks.add(new RibbonBlock(RibbonType.NORMAL, rp.pos, (int) (rp.pos - genomeCursor)));
153 
154 			if (rp.isOpen)
155 				ribbonBlocks.add(new RibbonBlock(rp.type, rp.pos, rp.len));
156 			else
157 				ribbonBlocks.add(new RibbonBlock(rp.type, rp.pos, 0));
158 
159 			genomeCursor = rp.getEnd() + 1;
160 		}
161 
162 		if (genomeCursor < window.getEndOnGenome())
163 			ribbonBlocks.add(new RibbonBlock(RibbonType.NORMAL, genomeCursor, (int) (window.getEndOnGenome() - genomeCursor)));
164 
165 		double pixelWidthPerBase = window.getPixelLengthPerBase();
166 		int numBase = 0;
167 		genomeCursor = window.getStartOnGenome();
168 
169 		// draw ribbon
170 		for (RibbonBlock rb : ribbonBlocks) {
171 			boolean drawLeftSide = true;
172 			long left = rb.startOnGenome;
173 			if (rb.startOnGenome < genomeCursor && genomeCursor < rb.getEnd()) {
174 				drawLeftSide = false;
175 				left = genomeCursor;
176 			}
177 
178 			float x1 = (float) (numBase * pixelWidthPerBase) + 0.5f;
179 			float x2 = (float) ((numBase + rb.size) * pixelWidthPerBase) - 0.5f;
180 
181 			switch (rb.type) {
182 			case FOLD:
183 
184 				break;
185 			case GAP:
186 				break;
187 			case NORMAL:
188 				canvas.setFillStyle(new Color("#FFEEEE"));
189 				canvas.setGlobalAlpha(0.7f);
190 				canvas.fillRect(x1, 0, x2 - x1, RIBBON_HEIGHT);
191 				break;
192 			}
193 			numBase += rb.size;
194 			genomeCursor = rb.getEnd();
195 		}
196 
197 		// draw tick
198 		if (fontPanel == null) {
199 			ImageLoader.loadImages(new String[] { GWT.getModuleBaseURL() + "utgb-core/FontPanel?fontsize=9.5&color=0x663333" }, new ImageLoader.CallBack() {
200 				public void onImagesLoaded(ImageElement[] imageElements) {
201 					fontPanel = imageElements[0];
202 					drawTick();
203 				}
204 			});
205 		}
206 		else
207 			drawTick();
208 
209 	}
210 
211 	void drawTick() {
212 		int displayedGenomeWidth = (window.getEndOnGenome() - window.getStartOnGenome());
213 		if (displayedGenomeWidth < 0)
214 			displayedGenomeWidth = -displayedGenomeWidth;
215 
216 		if (displayedGenomeWidth > 300)
217 			return;
218 
219 		int fontWidth = 7;
220 		int fontHeight = 13;
221 		canvas.setLineWidth(0.5f);
222 		canvas.setGlobalAlpha(1f);
223 		canvas.setStrokeStyle(new Color("#EEDDDD"));
224 		for (int s = (window.getStartOnGenome() / 10) * 10; s < window.getEndOnGenome(); s += 10L) {
225 
226 			if (s <= 0)
227 				s = 1;
228 
229 			float x = window.convertToPixelX(s);
230 
231 			canvas.beginPath();
232 			canvas.moveTo(x + 0.5f, 0);
233 			canvas.lineTo(x + 0.5f, RIBBON_HEIGHT);
234 			canvas.stroke();
235 
236 			String tick = Long.toString(s);
237 			for (int i = 0; i < tick.length(); ++i) {
238 				char c = tick.charAt(i);
239 				canvas.drawImage(fontPanel, (c) * fontWidth, 0, fontWidth, fontHeight, (int) x + i * fontWidth + 3, 2, fontWidth, fontHeight);
240 			}
241 
242 		}
243 	}
244 
245 	public void setWindow(TrackWindow w) {
246 		this.window = new TrackWindow(w.getPixelWidth() - 100, w.getStartOnGenome(), w.getEndOnGenome());
247 
248 		redraw();
249 	}
250 
251 	public void setGap(int indexOnGenome, int gapLength) {
252 		ribbonPoint.add(new RibbonCrease(RibbonType.GAP, indexOnGenome, gapLength));
253 	}
254 
255 	public void setFold(int indexOnGenome, int foldLength) {
256 		ribbonPoint.add(new RibbonCrease(RibbonType.FOLD, indexOnGenome, foldLength));
257 	}
258 
259 }