1 package jalview.renderer.seqfeatures;
3 import jalview.datamodel.SequenceFeature;
4 import jalview.datamodel.SequenceI;
6 import java.awt.AlphaComposite;
8 import java.awt.FontMetrics;
9 import java.awt.Graphics;
10 import java.awt.Graphics2D;
11 import java.awt.image.BufferedImage;
13 public class FeatureRenderer extends
14 jalview.viewmodel.seqfeatures.FeatureRendererModel
21 boolean offscreenRender = false;
45 protected SequenceI lastSeq;
51 int av_charHeight, av_charWidth;
53 boolean av_validCharWidth, av_isShowSeqFeatureHeight;
55 protected void updateAvConfig()
57 av_charHeight = av.getCharHeight();
58 av_charWidth = av.getCharWidth();
59 av_validCharWidth = av.isValidCharWidth();
60 av_isShowSeqFeatureHeight = av.isShowSequenceFeaturesHeight();
63 void renderFeature(Graphics g, SequenceI seq, int fstart, int fend,
64 Color featureColour, int start, int end, int y1)
67 if (((fstart <= end) && (fend >= start)))
70 { // fix for if the feature we have starts before the sequence start,
71 fstart = start; // but the feature end is still valid!!
78 int pady = (y1 + av_charHeight) - av_charHeight / 5;
79 for (i = fstart; i <= fend; i++)
83 if (jalview.util.Comparison.isGap(s))
88 g.setColor(featureColour);
90 g.fillRect((i - start) * av_charWidth, y1, av_charWidth,
93 if (offscreenRender || !av_validCharWidth)
98 g.setColor(Color.white);
99 charOffset = (av_charWidth - fm.charWidth(s)) / 2;
100 g.drawString(String.valueOf(s), charOffset
101 + (av_charWidth * (i - start)), pady);
107 void renderScoreFeature(Graphics g, SequenceI seq, int fstart, int fend,
108 Color featureColour, int start, int end, int y1, byte[] bs)
111 if (((fstart <= end) && (fend >= start)))
114 { // fix for if the feature we have starts before the sequence start,
115 fstart = start; // but the feature end is still valid!!
122 int pady = (y1 + av_charHeight) - av_charHeight / 5;
123 int ystrt = 0, yend = av_charHeight;
126 // signed - zero is always middle of residue line.
129 yend = av_charHeight * (128 - bs[1]) / 512;
130 ystrt = av_charHeight - yend / 2;
134 ystrt = av_charHeight / 2;
135 yend = av_charHeight * (bs[1] - 128) / 512;
140 yend = av_charHeight * bs[1] / 255;
141 ystrt = av_charHeight - yend;
144 for (i = fstart; i <= fend; i++)
146 s = seq.getCharAt(i);
148 if (jalview.util.Comparison.isGap(s))
153 g.setColor(featureColour);
154 int x = (i - start) * av_charWidth;
155 g.drawRect(x, y1, av_charWidth, av_charHeight);
156 g.fillRect(x, y1 + ystrt, av_charWidth, yend);
158 if (offscreenRender || !av_validCharWidth)
163 g.setColor(Color.black);
164 charOffset = (av_charWidth - fm.charWidth(s)) / 2;
165 g.drawString(String.valueOf(s), charOffset
166 + (av_charWidth * (i - start)), pady);
172 BufferedImage offscreenImage;
174 public Color findFeatureColour(Color initialCol, SequenceI seq, int res)
176 return new Color(findFeatureColour(initialCol.getRGB(), seq, res));
180 * This is used by the Molecule Viewer and Overview to get the accurate
181 * colourof the rendered sequence
183 public synchronized int findFeatureColour(int initialCol, final SequenceI seq,
186 if (!av.isShowSequenceFeatures())
191 final SequenceI aseq = (seq.getDatasetSequence() != null) ? seq
192 .getDatasetSequence() : seq;
196 sequenceFeatures = aseq.getSequenceFeatures();
197 if (sequenceFeatures != null)
199 sfSize = sequenceFeatures.length;
204 if (sequenceFeatures != aseq.getSequenceFeatures())
206 sequenceFeatures = aseq.getSequenceFeatures();
207 if (sequenceFeatures != null)
209 sfSize = sequenceFeatures.length;
214 if (sequenceFeatures == null || sfSize == 0)
219 if (jalview.util.Comparison.isGap(lastSeq.getCharAt(column)))
221 return Color.white.getRGB();
224 // Only bother making an offscreen image if transparency is applied
225 if (transparency != 1.0f && offscreenImage == null)
227 offscreenImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
230 currentColour = null;
231 // TODO: non-threadsafe - each rendering thread needs its own instance of
232 // the feature renderer - or this should be synchronized.
233 offscreenRender = true;
235 if (offscreenImage != null)
237 offscreenImage.setRGB(0, 0, initialCol);
238 drawSequence(offscreenImage.getGraphics(), lastSeq, column, column, 0);
240 return offscreenImage.getRGB(0, 0);
244 drawSequence(null, lastSeq, lastSeq.findPosition(column), -1, -1);
246 if (currentColour == null)
252 return ((Integer) currentColour).intValue();
258 private volatile SequenceFeature[] sequenceFeatures;
268 public synchronized void drawSequence(Graphics g, final SequenceI seq,
269 int start, int end, int y1)
271 final SequenceI aseq = (seq.getDatasetSequence() != null) ? seq
272 .getDatasetSequence() : seq;
273 if (aseq.getSequenceFeatures() == null
274 || aseq.getSequenceFeatures().length == 0)
281 fm = g.getFontMetrics();
286 if (lastSeq == null || seq != lastSeq
287 || aseq.getSequenceFeatures() != sequenceFeatures)
290 sequenceFeatures = aseq.getSequenceFeatures();
293 if (transparency != 1 && g != null)
295 Graphics2D g2 = (Graphics2D) g;
296 g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
300 if (!offscreenRender)
302 spos = lastSeq.findPosition(start);
303 epos = lastSeq.findPosition(end);
306 sfSize = sequenceFeatures.length;
308 for (int renderIndex = 0; renderIndex < renderOrder.length; renderIndex++)
310 type = renderOrder[renderIndex];
312 if (type == null || !showFeatureOfType(type))
317 // loop through all features in sequence to find
318 // current feature to render
319 for (sfindex = 0; sfindex < sfSize; sfindex++)
321 if (!sequenceFeatures[sfindex].type.equals(type))
326 if (featureGroups != null
327 && sequenceFeatures[sfindex].featureGroup != null
328 && sequenceFeatures[sfindex].featureGroup.length() != 0
330 .containsKey(sequenceFeatures[sfindex].featureGroup)
332 .get(sequenceFeatures[sfindex].featureGroup)
339 && (sequenceFeatures[sfindex].getBegin() > epos || sequenceFeatures[sfindex]
345 if (offscreenRender && offscreenImage == null)
347 if (sequenceFeatures[sfindex].begin <= start
348 && sequenceFeatures[sfindex].end >= start)
350 // this is passed out to the overview and other sequence renderers
351 // (e.g. molecule viewer) to get displayed colour for rendered
353 currentColour = new Integer(
354 getColour(sequenceFeatures[sfindex]).getRGB());
355 // used to be retreived from av.featuresDisplayed
356 // currentColour = av.featuresDisplayed
357 // .get(sequenceFeatures[sfindex].type);
361 else if (sequenceFeatures[sfindex].type.equals("disulfide bond"))
364 renderFeature(g, seq,
365 seq.findIndex(sequenceFeatures[sfindex].begin) - 1,
366 seq.findIndex(sequenceFeatures[sfindex].begin) - 1,
367 getColour(sequenceFeatures[sfindex])
368 // new Color(((Integer) av.featuresDisplayed
369 // .get(sequenceFeatures[sfindex].type)).intValue())
371 renderFeature(g, seq,
372 seq.findIndex(sequenceFeatures[sfindex].end) - 1,
373 seq.findIndex(sequenceFeatures[sfindex].end) - 1,
374 getColour(sequenceFeatures[sfindex])
375 // new Color(((Integer) av.featuresDisplayed
376 // .get(sequenceFeatures[sfindex].type)).intValue())
380 else if (showFeature(sequenceFeatures[sfindex]))
382 if (av_isShowSeqFeatureHeight
383 && sequenceFeatures[sfindex].score != Float.NaN)
385 renderScoreFeature(g, seq,
386 seq.findIndex(sequenceFeatures[sfindex].begin) - 1,
387 seq.findIndex(sequenceFeatures[sfindex].end) - 1,
388 getColour(sequenceFeatures[sfindex]), start, end, y1,
389 normaliseScore(sequenceFeatures[sfindex]));
393 renderFeature(g, seq,
394 seq.findIndex(sequenceFeatures[sfindex].begin) - 1,
395 seq.findIndex(sequenceFeatures[sfindex].end) - 1,
396 getColour(sequenceFeatures[sfindex]), start, end, y1);
404 if (transparency != 1.0f && g != null && transparencyAvailable)
406 Graphics2D g2 = (Graphics2D) g;
407 g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
412 boolean transparencyAvailable = true;
414 protected void setTransparencyAvailable(boolean isTransparencyAvailable)
416 transparencyAvailable = isTransparencyAvailable;
420 public boolean isTransparencyAvailable()
422 return transparencyAvailable;
426 * Called when alignment in associated view has new/modified features to
427 * discover and display.
430 public void featuresAdded()