1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package org.utgenome.gwt.utgb.client.track.lib;
24
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.Comparator;
28 import java.util.List;
29
30 import org.utgenome.gwt.utgb.client.bio.ChrLoc;
31 import org.utgenome.gwt.utgb.client.bio.CompactWIGData;
32 import org.utgenome.gwt.utgb.client.canvas.BarGraphCanvas;
33 import org.utgenome.gwt.utgb.client.canvas.GWTGraphCanvas.GraphStyle;
34 import org.utgenome.gwt.utgb.client.canvas.GraphScale;
35 import org.utgenome.gwt.utgb.client.canvas.TrackWindowChain;
36 import org.utgenome.gwt.utgb.client.canvas.TrackWindowChain.WindowUpdateInfo;
37 import org.utgenome.gwt.utgb.client.track.Track;
38 import org.utgenome.gwt.utgb.client.track.TrackBase;
39 import org.utgenome.gwt.utgb.client.track.TrackConfig;
40 import org.utgenome.gwt.utgb.client.track.TrackConfigChange;
41 import org.utgenome.gwt.utgb.client.track.TrackFrame;
42 import org.utgenome.gwt.utgb.client.track.TrackGroup;
43 import org.utgenome.gwt.utgb.client.track.TrackGroupPropertyChange;
44 import org.utgenome.gwt.utgb.client.track.TrackWindow;
45 import org.utgenome.gwt.utgb.client.track.UTGBProperty;
46 import org.utgenome.gwt.widget.client.Style;
47
48 import com.google.gwt.core.client.GWT;
49 import com.google.gwt.user.client.rpc.AsyncCallback;
50 import com.google.gwt.user.client.ui.AbsolutePanel;
51 import com.google.gwt.user.client.ui.FlexTable;
52 import com.google.gwt.user.client.ui.Widget;
53
54
55
56
57
58
59
60 public class WIGTrack extends TrackBase {
61
62 public static TrackFactory factory() {
63 return new TrackFactory() {
64 @Override
65 public Track newInstance() {
66 return new WIGTrack();
67 }
68 };
69 }
70
71 private final AbsolutePanel panel = new AbsolutePanel();
72 private final FlexTable layoutTable = new FlexTable();
73 private final GraphScale scale = new GraphScale();
74
75 private TrackWindowChain chain = new TrackWindowChain();
76 private final List<List<BarGraphCanvas>> buffer = new ArrayList<List<BarGraphCanvas>>(2);
77 private int frontBufferID = 0;
78
79 private final GraphStyle style = new GraphStyle();
80
81 {
82 buffer.add(new ArrayList<BarGraphCanvas>());
83 buffer.add(new ArrayList<BarGraphCanvas>());
84 }
85
86 public WIGTrack() {
87 super("WIG Track");
88 layoutTable.setBorderWidth(0);
89 layoutTable.setCellPadding(0);
90 layoutTable.setCellSpacing(0);
91 Style.margin(layoutTable, 0);
92 Style.padding(layoutTable, 0);
93 Style.fullSize(layoutTable);
94
95 panel.add(scale, 0, 0);
96 layoutTable.setWidget(0, 0, panel);
97 }
98
99 public Widget getWidget() {
100 return layoutTable;
101 }
102
103
104
105
106 private final static String CONFIG_PATH = "path";
107
108 @Override
109 public void setUp(TrackFrame trackFrame, TrackGroup group) {
110 TrackConfig config = getConfig();
111 config.addConfigString("Path", CONFIG_PATH, "");
112 style.setup(config);
113 }
114
115 @Override
116 public void onChangeTrackHeight(int newHeight) {
117 style.windowHeight = newHeight;
118 needToUpdateStyle = true;
119 refresh();
120 }
121
122 private boolean needToUpdateStyle = true;
123
124 private void updateStyle() {
125
126 style.load(getConfig());
127
128 needToUpdateStyle = false;
129 }
130
131 private List<BarGraphCanvas> getFrontBuffer() {
132 return buffer.get(frontBufferID);
133 }
134
135 private List<BarGraphCanvas> getBackgroundBuffer() {
136 return buffer.get((frontBufferID + 1) % 2);
137 }
138
139 private void clearBuffer() {
140 for (List<BarGraphCanvas> each : buffer) {
141 clearBuffer(each);
142 }
143 }
144
145 private void clearBuffer(List<BarGraphCanvas> buffer) {
146 for (Widget each : buffer) {
147 each.removeFromParent();
148 }
149 buffer.clear();
150 }
151
152 @Override
153 public void draw() {
154
155 boolean needRedrawing = false;
156
157 if (needToUpdateStyle) {
158 updateStyle();
159 needRedrawing = true;
160 }
161
162 final TrackWindow newWindow = getTrackWindow();
163 panel.setPixelSize(newWindow.getPixelWidth(), style.windowHeight);
164
165
166 if (chain.getViewWindow() != null && !chain.getViewWindow().hasSameScaleWith(newWindow)) {
167
168 frontBufferID = (frontBufferID + 1) % 2;
169 clearBuffer(getFrontBuffer());
170 }
171
172
173 WindowUpdateInfo updateInfo = chain.setViewWindow(newWindow);
174 GWT.log(chain.getTrackWindowList().toString());
175
176
177 for (TrackWindow toDiscard : updateInfo.windowToDiscard) {
178 for (BarGraphCanvas each : getBackgroundBuffer()) {
179 TrackWindow old = each.getTrackWindow();
180 if (old.equals(toDiscard)) {
181 each.setTrackWindow(old.newPixelWidthWindow(newWindow.convertToPixelLength(old.getSequenceLength())),
182 newWindow.convertToPixelX(old.getStartOnGenome()));
183 }
184 }
185 }
186
187
188 Collections.sort(updateInfo.windowToCreate, new Comparator<TrackWindow>() {
189 public int compare(TrackWindow o1, TrackWindow o2) {
190 int d1 = Math.abs(o1.center() - newWindow.center());
191 int d2 = Math.abs(o2.center() - newWindow.center());
192 return d1 - d2;
193 }
194 });
195
196
197 for (BarGraphCanvas each : getFrontBuffer()) {
198 int x = newWindow.convertToPixelX(each.getTrackWindow().getStartOnGenome());
199 Style.scrollX(each, x, 0.5);
200 }
201
202
203 String filePath = resolvePropertyValues(getConfig().getString(CONFIG_PATH, ""));
204 List<BarGraphCanvas> front = getFrontBuffer();
205 for (final TrackWindow queryWindow : updateInfo.windowToCreate) {
206 final BarGraphCanvas graph = new BarGraphCanvas(queryWindow, style.windowHeight);
207 int x = newWindow.convertToPixelX(queryWindow.getStartOnGenome());
208 panel.add(graph, x, 0);
209 front.add(graph);
210
211 int s = queryWindow.getStartOnGenome();
212 int e = queryWindow.getEndOnGenome();
213 ChrLoc l = new ChrLoc(getTrackGroupProperty(UTGBProperty.TARGET), s, e);
214 getBrowserService().getCompactWigDataList(filePath, queryWindow.getPixelWidth(), l, new AsyncCallback<List<CompactWIGData>>() {
215 public void onFailure(Throwable e) {
216 error("failed to retrieve wig data: " + e.getMessage());
217 clearBackgroundGraph(queryWindow);
218 }
219
220 public void onSuccess(List<CompactWIGData> graphData) {
221 graph.setGraphData(graphData);
222 if (style.autoScale)
223 calculateScale();
224
225
226 scale.draw(style, newWindow);
227
228
229 graph.draw(graphData, style);
230 clearBackgroundGraph(queryWindow);
231 }
232 });
233
234 }
235
236
237 boolean scaleHasChanged = style.autoScale && calculateScale();
238 if (needRedrawing || scaleHasChanged) {
239
240 if (updateInfo.windowToCreate.isEmpty())
241 scale.draw(style, newWindow);
242
243
244 for (BarGraphCanvas each : getFrontBuffer()) {
245 each.redraw(style);
246 }
247 }
248
249 }
250
251 void clearBackgroundGraph(TrackWindow window) {
252 for (BarGraphCanvas each : getBackgroundBuffer()) {
253 if (each.getTrackWindow().overlapWith(window)) {
254 each.removeFromParent();
255 each.clear();
256 }
257 }
258
259 }
260
261
262
263
264
265 boolean calculateScale() {
266
267 if (!style.autoScale)
268 return false;
269
270 float autoScaledMinValue = 0.0f;
271 float autoScaledMaxValue = 0.0f;
272
273 final TrackWindow view = getTrackWindow();
274 for (BarGraphCanvas each : getFrontBuffer()) {
275 List<CompactWIGData> graphData = each.getGraphData();
276 if (graphData == null)
277 continue;
278
279 TrackWindow graphWindow = each.getTrackWindow();
280
281 int start = graphWindow.getStartOnGenome();
282 int s = view.convertToPixelX(start);
283
284 int pw = view.getPixelWidth();
285 int pw_e = graphWindow.getPixelWidth();
286
287 for (CompactWIGData wigData : graphData) {
288
289 int loopStart, loopEnd;
290 if (!view.isReverseStrand()) {
291 loopStart = Math.max(-s, 0);
292 loopEnd = Math.min(pw - s, pw_e);
293 }
294 else {
295 loopStart = Math.max(s - pw, 0);
296 loopEnd = Math.min(s, pw_e);
297 }
298
299 float data[] = wigData.getData();
300 for (int pos = loopStart; pos < loopEnd; pos++) {
301 autoScaledMinValue = Math.min(autoScaledMinValue, data[pos]);
302 autoScaledMaxValue = Math.max(autoScaledMaxValue, data[pos]);
303 }
304 }
305
306 }
307 GWT.log("scale: " + autoScaledMinValue + " - " + autoScaledMaxValue);
308
309
310 if (autoScaledMinValue == autoScaledMaxValue) {
311 autoScaledMinValue = style.minValue;
312 autoScaledMaxValue = style.maxValue;
313 }
314
315
316 boolean hasChanged = (autoScaledMinValue != style.autoScaledMin || autoScaledMaxValue != style.autoScaledMax);
317 style.autoScaledMin = autoScaledMinValue;
318 style.autoScaledMax = autoScaledMaxValue;
319
320 return hasChanged;
321 }
322
323 @Override
324 public void onChangeTrackConfig(TrackConfigChange change) {
325
326 if (change.contains(CONFIG_PATH)) {
327 needToUpdateStyle = true;
328 refresh();
329 }
330 else {
331 needToUpdateStyle = true;
332 refresh();
333 }
334 }
335
336 @Override
337 public void onChangeTrackWindow(TrackWindow newWindow) {
338 refresh();
339 }
340
341 @Override
342 public void onChangeTrackGroupProperty(TrackGroupPropertyChange change) {
343
344 if (change.containsOneOf(new String[] { UTGBProperty.TARGET, UTGBProperty.REVISION, UTGBProperty.SPECIES })) {
345
346 chain.clear();
347 clearBuffer();
348 refresh();
349 }
350 }
351
352 }