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.track.lib;
26
27 import java.util.List;
28
29 import org.utgenome.gwt.utgb.client.UTGBEntryPointBase;
30 import org.utgenome.gwt.utgb.client.bio.ChrLoc;
31 import org.utgenome.gwt.utgb.client.bio.GenomeDB;
32 import org.utgenome.gwt.utgb.client.bio.GenomeDB.DBType;
33 import org.utgenome.gwt.utgb.client.bio.GraphWindow;
34 import org.utgenome.gwt.utgb.client.bio.OnGenome;
35 import org.utgenome.gwt.utgb.client.bio.OnGenomeDataVisitorBase;
36 import org.utgenome.gwt.utgb.client.bio.ReadCoverage;
37 import org.utgenome.gwt.utgb.client.bio.ReadQueryConfig;
38 import org.utgenome.gwt.utgb.client.bio.ReadQueryConfig.Layout;
39 import org.utgenome.gwt.utgb.client.canvas.GWTGenomeCanvas;
40 import org.utgenome.gwt.utgb.client.canvas.LocusClickHandler;
41 import org.utgenome.gwt.utgb.client.canvas.ReadDisplayStyle;
42 import org.utgenome.gwt.utgb.client.db.ValueDomain;
43 import org.utgenome.gwt.utgb.client.db.datatype.StringType;
44 import org.utgenome.gwt.utgb.client.track.Track;
45 import org.utgenome.gwt.utgb.client.track.TrackBase;
46 import org.utgenome.gwt.utgb.client.track.TrackConfig;
47 import org.utgenome.gwt.utgb.client.track.TrackConfigChange;
48 import org.utgenome.gwt.utgb.client.track.TrackFrame;
49 import org.utgenome.gwt.utgb.client.track.TrackGroup;
50 import org.utgenome.gwt.utgb.client.track.TrackGroupPropertyChange;
51 import org.utgenome.gwt.utgb.client.track.TrackWindow;
52 import org.utgenome.gwt.utgb.client.track.UTGBProperty;
53 import org.utgenome.gwt.utgb.client.util.BrowserInfo;
54 import org.utgenome.gwt.utgb.client.util.CanonicalProperties;
55 import org.utgenome.gwt.utgb.client.util.Properties;
56
57 import com.google.gwt.core.client.GWT;
58 import com.google.gwt.user.client.Window;
59 import com.google.gwt.user.client.rpc.AsyncCallback;
60 import com.google.gwt.user.client.ui.FlexTable;
61 import com.google.gwt.user.client.ui.Widget;
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170 public class ReadTrack extends TrackBase {
171
172
173 private final String CONFIG_DB_TYPE = "dbType";
174 private final String CONFIG_PATH = "path";
175 private final String CONFIG_WIG_PATH = "wig path";
176 private final String CONFIG_GRAPH_WINDOW = "window function";
177 private final String CONFIG_LAYOUT = "layout";
178 private final String CONFIG_ONCLICK_ACTION = "onclick.action";
179 private final String CONFIG_ONCLICK_URL = "onclick.url";
180 private final String CONFIG_ONCLICK_P_KEY = "onclick.set";
181
182 private ReadDisplayStyle style = new ReadDisplayStyle();
183
184
185 private FlexTable layoutTable = new FlexTable();
186 private GWTGenomeCanvas geneCanvas = new GWTGenomeCanvas();
187
188 public static TrackFactory factory() {
189 return new TrackFactory() {
190 @Override
191 public Track newInstance() {
192 return new ReadTrack();
193 }
194 };
195 }
196
197 public ReadTrack() {
198 this("Read Track", "AUTO");
199
200 }
201
202 public ReadTrack(String trackName, String dbType) {
203 super("Read Track");
204
205 getConfig().setParameter(CONFIG_DB_TYPE, dbType);
206
207 layoutTable.setBorderWidth(0);
208 layoutTable.setCellPadding(0);
209 layoutTable.setCellSpacing(0);
210 layoutTable.setWidget(0, 1, geneCanvas);
211
212 updateClickAction();
213 }
214
215 public String resolveURL(String urlTemplate, OnGenome locus) {
216 String url = urlTemplate;
217 if (url == null)
218 return url;
219
220 if (locus != null) {
221 if (locus.getName() != null) {
222 if (url.contains("%q"))
223 url = url.replaceAll("%q", locus.getName());
224 if (url.contains("%qname"))
225 url = url.replaceAll("%qname", locus.getName());
226 }
227
228 if (url.contains("%qstart"))
229 url = url.replaceAll("%qstart", Integer.toString(locus.getStart()));
230 if (url.contains("%qend"))
231 url = url.replaceAll("%qend", Integer.toString(locus.getEnd()));
232 if (url.contains("%qlen"))
233 url = url.replaceAll("%qlen", Integer.toString(locus.length()));
234
235 }
236
237
238 return resolvePropertyValues(url);
239 }
240
241 private void updateClickAction() {
242
243 String clickAction = getConfig().getParameter(CONFIG_ONCLICK_ACTION);
244 if (clickAction == null)
245 return;
246 if ("none".equals(clickAction)) {
247 geneCanvas.setLocusClickHandler(null);
248 }
249 else if ("link".equals(clickAction)) {
250 geneCanvas.setLocusClickHandler(new LocusClickHandler() {
251 public void onClick(int x, int y, OnGenome locus) {
252 String url = getConfig().getParameter(CONFIG_ONCLICK_URL);
253 url = resolveURL(url, locus);
254 Window.open(url, "locus", "");
255 }
256 });
257 }
258 else if ("info".equals(clickAction)) {
259 geneCanvas.setLocusClickHandler(new LocusClickHandler() {
260 public void onClick(int x, int y, OnGenome locus) {
261 geneCanvas.displayInfo(x, y, locus);
262 }
263 });
264 }
265 else if ("set".equals(clickAction)) {
266 geneCanvas.setLocusClickHandler(new LocusClickHandler() {
267 public void onClick(int clientX, int clientY, OnGenome locus) {
268 String key = getConfig().getParameter(CONFIG_ONCLICK_P_KEY);
269 if (key == null)
270 return;
271
272
273 String[] actions = key.split(",");
274 if (actions == null)
275 return;
276
277 Properties prop = new Properties();
278 for (String each : actions) {
279 String[] keyAndValue = each.split(":");
280 if (keyAndValue == null || keyAndValue.length != 2)
281 continue;
282
283 String value = resolveURL(keyAndValue[1].trim(), locus);
284 if (value == null)
285 return;
286 prop.put(keyAndValue[0].trim(), value);
287 }
288
289 getTrackGroup().getPropertyWriter().setProperty(prop);
290 }
291 });
292 }
293
294 }
295
296 public Widget getWidget() {
297 return layoutTable;
298 }
299
300 @Override
301 public void setUp(TrackFrame trackFrame, TrackGroup group) {
302
303 geneCanvas.setTrackGroup(group);
304
305 update(group.getTrackWindow(), true);
306 TrackConfig config = getConfig();
307 config.addConfig("DB Path", new StringType(CONFIG_PATH), "");
308 config.addConfig("WIG DB Path", new StringType(CONFIG_WIG_PATH), "");
309 ValueDomain windowFuncitionTypes = ValueDomain.createNewValueDomain(new String[] { "MAX", "MIN", "MEDIAN", "AVG" });
310 config.addConfig("Window Function", new StringType(CONFIG_GRAPH_WINDOW, windowFuncitionTypes), "MEDIAN");
311 config.addHiddenConfig(CONFIG_DB_TYPE, "AUTO");
312
313 style.setup(config);
314
315 ValueDomain actionTypes = ValueDomain.createNewValueDomain(new String[] { "none", "link", "info", "set" });
316 config.addConfig("On Click Action", new StringType(CONFIG_ONCLICK_ACTION, actionTypes), "none");
317 config.addConfig("On Click URL", new StringType(CONFIG_ONCLICK_URL), "http://www.google.com/search?q=%q");
318 config.addConfig("On Click Set (key:value, ...)", new StringType(CONFIG_ONCLICK_P_KEY), "read:%q");
319
320 updateClickAction();
321 }
322
323 private boolean needUpdateForGraphicRefinement = false;
324
325 @Override
326 public void beforeChangeTrackWindow(TrackWindow newWindow) {
327
328 if ("coverage".equals(style.layout) && current != null && !current.hasSameScaleWith(newWindow)) {
329 needUpdateForGraphicRefinement = true;
330 }
331
332 }
333
334 @Override
335 public void draw() {
336
337
338
339 geneCanvas.setReadStyle(style);
340
341 geneCanvas.draw();
342 getFrame().loadingDone();
343
344 }
345
346 public static int calcXPositionOnWindow(long indexOnGenome, long startIndexOnGenome, long endIndexOnGenome, int windowWidth) {
347 double v = (indexOnGenome - startIndexOnGenome) * (double) windowWidth;
348 double v2 = v / (endIndexOnGenome - startIndexOnGenome);
349 return (int) v2;
350 }
351
352 @Override
353 public void onChangeTrackWindow(TrackWindow newWindow) {
354
355 update(newWindow, false);
356 }
357
358 @Override
359 public void onChangeTrackGroupProperty(TrackGroupPropertyChange change) {
360
361 if (change.containsOneOf(new String[] { UTGBProperty.SPECIES, UTGBProperty.REVISION, UTGBProperty.TARGET })) {
362 geneCanvas.clear();
363 update(change.getTrackWindow(), false);
364 }
365 }
366
367 private TrackWindow current;
368
369 protected void update(TrackWindow newWindow, boolean forceReload) {
370
371 current = newWindow;
372
373 if (!forceReload && geneCanvas.hasCacheCovering(newWindow)) {
374 if (!needUpdateForGraphicRefinement) {
375 geneCanvas.setTrackWindow(newWindow, false);
376 refresh();
377 return;
378 }
379 }
380
381 geneCanvas.setTrackWindow(newWindow, true);
382
383
384 TrackWindow prefetchWindow = geneCanvas.getPrefetchWindow();
385 String chr = getTrackGroupProperty(UTGBProperty.TARGET);
386
387 ReadQueryConfig queryConfig = new ReadQueryConfig(prefetchWindow.getPixelWidth(), BrowserInfo.isCanvasSupported(), Layout.valueOf(Layout.class,
388 style.layout.toUpperCase()), style.numReadsMax, getWIGPath());
389 queryConfig.window = GraphWindow.valueOf(GraphWindow.class, getConfig().getString(CONFIG_GRAPH_WINDOW, "MEDIAN"));
390
391 getFrame().setNowLoading();
392 getBrowserService().getOnGenomeData(getGenomeDB(), new ChrLoc(chr, prefetchWindow.getStartOnGenome(), prefetchWindow.getEndOnGenome()), queryConfig,
393 new AsyncCallback<List<OnGenome>>() {
394
395 public void onFailure(Throwable e) {
396 GWT.log("failed to retrieve gene data", e);
397 UTGBEntryPointBase.showErrorMessage("read data retrieval failed: " + e.getMessage());
398 needUpdateForGraphicRefinement = true;
399 getFrame().loadingDone();
400 }
401
402 public void onSuccess(List<OnGenome> dataSet) {
403
404 if ("pileup".equals(style.layout) && dataSet.size() > 0 && DataChecker.isReadCoverage(dataSet.get(0))) {
405 needUpdateForGraphicRefinement = true;
406
407 float prefetchFactor = geneCanvas.getPrefetchFactor();
408 prefetchFactor /= 2.0;
409 geneCanvas.setPrefetchFactor(prefetchFactor);
410 }
411 else {
412 float newPrefetchFactor = geneCanvas.getPrefetchFactor() * 2.0f;
413 if (newPrefetchFactor > 1.0f)
414 newPrefetchFactor = 1.0f;
415
416
417 geneCanvas.setPrefetchFactor(newPrefetchFactor);
418 needUpdateForGraphicRefinement = false;
419 }
420 geneCanvas.resetData(dataSet);
421 refresh();
422 }
423
424 });
425
426 }
427
428 private static class DataChecker extends OnGenomeDataVisitorBase {
429 public boolean flag = false;
430
431 public static boolean isReadCoverage(OnGenome data) {
432 DataChecker dataChecker = new DataChecker();
433 data.accept(dataChecker);
434 return dataChecker.flag;
435 }
436
437 @Override
438 public void visitReadCoverage(ReadCoverage readCoverage) {
439 flag = true;
440 }
441 }
442
443 protected String getPath() {
444 String path = getConfig().getParameter(CONFIG_PATH);
445 return resolvePropertyValues(path);
446 }
447
448 protected String getWIGPath() {
449 String path = getConfig().getParameter(CONFIG_WIG_PATH);
450 return resolvePropertyValues(path);
451 }
452
453
454
455
456
457
458 public GenomeDB getGenomeDB() {
459 String ref = getTrackGroupProperty(UTGBProperty.REVISION);
460 String dbType = getConfig().getString("dbType", "AUTO");
461 return new GenomeDB(DBType.valueOf(DBType.class, dbType), getPath(), ref);
462 }
463
464 @Override
465 public void onChangeTrackConfig(TrackConfigChange change) {
466
467 style.loadConfig(getConfig());
468
469 if (change.containsOneOf(new String[] { CONFIG_ONCLICK_ACTION, CONFIG_ONCLICK_URL })) {
470 updateClickAction();
471 }
472
473 if (change.containsOneOf(new String[] { CONFIG_PATH, CONFIG_WIG_PATH, CONFIG_DB_TYPE })) {
474 refresh();
475 }
476
477 if (change.containsOneOf(new String[] { ReadDisplayStyle.CONFIG_SHOW_LABELS, ReadDisplayStyle.CONFIG_PE_OVERLAP,
478 ReadDisplayStyle.CONFIG_SHOW_BASE_QUALITY, ReadDisplayStyle.CONFIG_READ_HEIGHT, ReadDisplayStyle.CONFIG_MIN_READ_HEIGHT,
479 ReadDisplayStyle.CONFIG_COVERAGE_STYLE, ReadDisplayStyle.CONFIG_DRAW_SHADOW, ReadDisplayStyle.CONFIG_SHOW_STRAND })) {
480 refresh();
481 }
482
483 if (change.containsOneOf(new String[] { CONFIG_LAYOUT, CONFIG_GRAPH_WINDOW, ReadDisplayStyle.CONFIG_NUM_READ_MAX })) {
484 update(getTrackWindow(), true);
485 }
486 }
487
488 @Override
489 public void restoreProperties(CanonicalProperties properties) {
490 super.restoreProperties(properties);
491 updateClickAction();
492 style.loadConfig(getConfig());
493 }
494
495 }