1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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
42
43
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
59
60
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
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
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
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 }