View Javadoc

1   /*--------------------------------------------------------------------------
2    *  Copyright 2010 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  // CanvasChain.java
20  // Since: Jun 4, 2010
21  //
22  //--------------------------------------
23  package org.utgenome.gwt.utgb.client.canvas;
24  
25  import java.util.ArrayList;
26  import java.util.Collections;
27  import java.util.List;
28  
29  import org.utgenome.gwt.utgb.client.track.TrackWindow;
30  
31  /**
32   * A chain of {@link TrackWindow}s for supporting GoogleMap-style graphic drawing.
33   * 
34   * <pre>
35   *              (V: view window) 
36   *               |----------|
37   * |--------||--------||--------||--------|
38   *    (w1)      (w2)      (w3)     (w4:prefetch)
39   *     |--------------------------------|
40   *         (G: global view, 3V size) 
41   *                                
42   *                                
43   * After scrolling to right:                               
44   * 
45   *                       (V: view window) 
46   *                         |-----------|
47   * |--------||--------||--------||--------||--------|
48   *  (w1:discard) (w2)     (w3)      (w4)       (w5:prefetch) 
49   *             |----------------------------------|
50   *                  (G: global view, 3V size)
51   * </pre>
52   * 
53   * @author leo
54   * 
55   */
56  public class TrackWindowChain {
57  
58  	private ArrayList<TrackWindow> windowList = new ArrayList<TrackWindow>();
59  
60  	public TrackWindowChain() {
61  
62  	}
63  
64  	private TrackWindow viewWindow;
65  	private TrackWindow globalWindow;
66  
67  	private int PREFETCH_FACTOR = 1; // (left) f*V + (current) V + (right) f*V = 3V (when f=1)
68  
69  	public static class WindowUpdateInfo {
70  		public final List<TrackWindow> windowToCreate;
71  		public final List<TrackWindow> windowToDiscard;
72  
73  		private WindowUpdateInfo(List<TrackWindow> windowToCreate, List<TrackWindow> windowToDiscard) {
74  			this.windowToCreate = windowToCreate;
75  			this.windowToDiscard = windowToDiscard;
76  		}
77  	}
78  
79  	public void clear() {
80  		windowList.clear();
81  	}
82  
83  	public void setPrefetchFactor(int factor) {
84  		this.PREFETCH_FACTOR = factor;
85  	}
86  
87  	public List<TrackWindow> getTrackWindowList() {
88  		return windowList;
89  	}
90  
91  	public TrackWindow getGlobalWindow() {
92  		return globalWindow;
93  	}
94  
95  	public TrackWindow getViewWindow() {
96  		return viewWindow;
97  	}
98  
99  	public WindowUpdateInfo setViewWindow(TrackWindow view) {
100 
101 		final int factor = PREFETCH_FACTOR * 2 + 1;
102 		final int viewSize = view.getSequenceLength();
103 		final int viewExtensionDirection = view.isReverseStrand() ? -1 : 1;
104 		int gvStart = view.getStartOnGenome() - viewSize * PREFETCH_FACTOR * viewExtensionDirection;
105 		int gvEnd = view.getEndOnGenome() + viewSize * PREFETCH_FACTOR * viewExtensionDirection;
106 		this.globalWindow = new TrackWindow(view.getPixelWidth() * factor, gvStart, gvEnd);
107 
108 		ArrayList<TrackWindow> windowToPreserve = new ArrayList<TrackWindow>();
109 		ArrayList<TrackWindow> windowToDiscard = new ArrayList<TrackWindow>();
110 
111 		if (viewWindow != null && viewWindow.hasSameScaleWith(view)) {
112 			// scroll
113 			// update the window list
114 			for (TrackWindow each : windowList) {
115 				// discard the windows that do not overlap with the global window 
116 				if (each.overlapWith(globalWindow)) {
117 					windowToPreserve.add(each);
118 				}
119 				else {
120 					windowToDiscard.add(each);
121 				}
122 			}
123 		}
124 		else {
125 			windowToDiscard.addAll(windowList);
126 		}
127 		this.viewWindow = view;
128 
129 		// compute the missing window list
130 		ArrayList<TrackWindow> newWindowList = new ArrayList<TrackWindow>();
131 
132 		// sort the windows by the view start order
133 		Collections.sort(windowToPreserve);
134 		int gridStartOnGenome = windowToPreserve.isEmpty() ? view.getViewStartOnGenome() : windowToPreserve.get(0).getViewStartOnGenome();
135 		while (gridStartOnGenome > globalWindow.getViewStartOnGenome()) {
136 			gridStartOnGenome -= viewSize;
137 		}
138 		while (gridStartOnGenome < globalWindow.getViewEndOnGenome()) {
139 			TrackWindow grid;
140 			if (view.isPositiveStrand()) {
141 				grid = view.newWindow(gridStartOnGenome, gridStartOnGenome + viewSize);
142 			}
143 			else {
144 				grid = view.newWindow(gridStartOnGenome + viewSize, gridStartOnGenome);
145 			}
146 
147 			if (!windowToPreserve.contains(grid)) {
148 				newWindowList.add(grid);
149 			}
150 
151 			gridStartOnGenome += viewSize;
152 		}
153 
154 		windowList.clear();
155 		windowList.addAll(windowToPreserve);
156 		windowList.addAll(newWindowList);
157 
158 		return new WindowUpdateInfo(newWindowList, windowToDiscard);
159 	}
160 
161 }