/* * The MIT License (MIT) * * Copyright (c) 2007-2015 Broad Institute * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.broad.igv.maf; import org.broad.igv.renderer.GraphicUtils; import org.broad.igv.renderer.SequenceRenderer; import org.broad.igv.track.RenderContext; import org.broad.igv.track.Track; import org.broad.igv.ui.FontManager; import java.awt.*; import java.util.List; import java.util.Map; /** * @author jrobinso */ public class MAFRenderer { // static Map<Character, Color> nucleotideColors = new HashMap(); // // // static { // // nucleotideColors.put('A', Color.GREEN); // nucleotideColors.put('a', Color.GREEN); // nucleotideColors.put('C', Color.BLUE); // nucleotideColors.put('c', Color.BLUE); // nucleotideColors.put('T', Color.RED); // nucleotideColors.put('t', Color.RED); // nucleotideColors.put('G', new Color(242, 182, 65)); // nucleotideColors.put('g', new Color(242, 182, 65)); // nucleotideColors.put('N', Color.gray); // nucleotideColors.put('n', Color.gray); // } /** * Constructs ... */ public MAFRenderer() { } public void renderGaps(List<MultipleAlignmentBlock.Gap> gaps, RenderContext context, Rectangle rect) { double origin = context.getOrigin(); double locScale = context.getScale(); if (locScale > 1) { return; } for (MultipleAlignmentBlock.Gap gap : gaps) { int pixelPosition = (int) ((gap.position - origin) / locScale); Graphics2D g = context.getGraphic2DForColor(Color.BLACK); g.drawLine(pixelPosition, rect.y + rect.height - 5, pixelPosition, rect.y + rect.height); Rectangle textRect = new Rectangle(rect); textRect.x = pixelPosition - 6; textRect.width = 12; textRect.height = rect.height - 7; GraphicUtils.drawCenteredText(String.valueOf(gap.size), textRect, g); } } /** * Method description * * @param context * @param trackRectangle * @param track */ public void renderSequence( MultipleAlignmentBlock multipleAlignment, MultipleAlignmentBlock.Sequence alignedSequence, MultipleAlignmentBlock.Sequence reference, List<MultipleAlignmentBlock.Gap> gaps, RenderContext context, Rectangle trackRectangle, Track track) { Map<Character, Color> nucleotideColors = SequenceRenderer.getNucleotideColors(); double origin = context.getOrigin(); double locScale = context.getScale(); if (locScale > 1) { return; } double pixelStart = ((multipleAlignment.getStart() - origin) / locScale); int w = Math.max(1, (int) (trackRectangle.width)); int h = (int) Math.max(1, trackRectangle.getHeight() - 2); int y = (int) (trackRectangle.getY() + (trackRectangle.getHeight() - h) / 2); Rectangle rect = new Rectangle((int) pixelStart, y, w, h); if (locScale < 1) { int pY = (int) rect.getY(); int dY = (int) rect.getHeight(); int dX = (int) (1.0 / locScale); // Get a graphics to use Graphics2D g = context.getGraphics2D("SEQUENCE"); if (dX >= 8) { Font f = FontManager.getFont(Font.BOLD, Math.min(dX, 12)); g.setFont(f); } // Loop through base pair coordinates int windowStart = (int) origin - 1; int windowEnd = (int) context.getEndLocation() + 1; int start = Math.max(windowStart, multipleAlignment.getStart()); int end = Math.min(windowEnd, multipleAlignment.getEnd()); byte[] alignmentBytes = alignedSequence.getText().getBytes(); byte[] refBytes = reference.getText().getBytes(); for (int loc = start; loc < end; loc++) { int pX0 = (int) ((loc - origin) / locScale); int idx = multipleAlignment.getGapAdjustedIndex(loc); char c = (char) alignmentBytes[idx]; char refBase = (char) refBytes[idx]; boolean misMatch = Character.toUpperCase(c) != Character.toUpperCase(refBase); char charToDraw = misMatch || reference == alignedSequence ? c : '.'; Color color = nucleotideColors.get(charToDraw); if ((dX >= 8) && (dY >= 12) || charToDraw == '.') { // Graphics2D gBackground = context.getGraphic2DForColor(background); // gBackground.fillRect(pX0, pY, dX, dY); if (charToDraw == '.') { color = Color.LIGHT_GRAY; } else if (color == null) { color = Color.black; } g.setColor(color); drawCenteredText(g, new char[]{charToDraw}, pX0, pY + 2, dX, dY - 2); } else { if (color != null) { g.setColor(color); g.fillRect(pX0, pY, dX - 1, dY); } } } // Check for insertion if (gaps != null) { Graphics2D gapG = context.getGraphic2DForColor(Color.black); for (MultipleAlignmentBlock.Gap gap : gaps) { for (int idx = gap.startIdx; idx < gap.startIdx + gap.size; idx++) { if (alignmentBytes[idx] != '-') { int pX0 = (int) ((gap.position - origin) / locScale); gapG.drawLine(pX0, pY, pX0, pY + dY); break; } } } } } } private void drawCenteredText(Graphics2D g, char[] chars, int x, int y, int w, int h) { // Get measures needed to center the message FontMetrics fm = g.getFontMetrics(); // How many pixels wide is the string int msg_width = fm.charsWidth(chars, 0, 1); // How far above the baseline can the font go? int ascent = fm.getMaxAscent(); // How far below the baseline? int descent = fm.getMaxDescent(); // Use the string width to find the starting point int msgX = x + w / 2 - msg_width / 2; // Use the vertical height of this font to find // the vertical starting coordinate int msgY = y + h / 2 - descent / 2 + ascent / 2; g.drawChars(chars, 0, 1, msgX, msgY); } }