package org.seqcode.viz.metaprofile.swing; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.event.ActionEvent; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Writer; import javax.imageio.ImageIO; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.JFileChooser; import javax.swing.JPanel; import org.apache.batik.dom.GenericDOMImplementation; import org.apache.batik.svggen.SVGGraphics2D; import org.seqcode.viz.metaprofile.BinningParameters; import org.seqcode.viz.metaprofile.Profile; import org.seqcode.viz.metaprofile.ProfilePaintable; import org.seqcode.viz.paintable.PaintableChangedEvent; import org.seqcode.viz.paintable.PaintableChangedListener; import org.seqcode.viz.paintable.PaintableScale; import org.w3c.dom.DOMImplementation; import org.w3c.dom.Document; public class ProfilePanel extends JPanel implements PaintableChangedListener { private Profile profile; private ProfilePaintable profilePainter; private PaintableScale scale; private int fontSize=12; private int border=20; private int lineHeight=20, lineWidth=4; private Color fontColor=Color.black; private Color peakColor=Color.blue; private String style = "line"; private boolean transparent = false; public ProfilePanel(Profile p, PaintableScale sc) { profile = p; scale = sc; profilePainter = new ProfilePaintable(scale, profile); profilePainter.addPaintableChangedListener(this); setPreferredSize(new Dimension(500, 300)); } public void updateFontSize(int size) { fontSize = size; repaint(); } public void updateColor(Color c) { peakColor=c; repaint(); } public void setStyle(String s) { style = s; repaint(); } public void setTransparent(boolean c){ transparent = c; } public Action createSaveImageAction() { return new AbstractAction("Save Meta-Point Image...") { /** * Comment for <code>serialVersionUID</code> */ private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { String pwdName = System.getProperty("user.dir"); JFileChooser chooser; if(pwdName != null) { chooser = new JFileChooser(new File(pwdName)); } else { chooser = new JFileChooser(); } int v = chooser.showSaveDialog(null); if(v == JFileChooser.APPROVE_OPTION) { File f = chooser.getSelectedFile(); try { saveImage(f, getWidth(), getHeight(), true); //System.out.println("Saved Image [" + sImageWidth + " by " + sImageHeight + "]"); } catch(IOException ie) { ie.printStackTrace(System.err); } } } }; } public void saveImage(File f, int w, int h, boolean raster) throws IOException { if(raster){ if(transparent) this.setOpaque(false); this.setSize(new Dimension(w, h)); repaint(); BufferedImage im = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); Graphics2D graphics = im.createGraphics(); graphics.setRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)); this.print(graphics); graphics.dispose(); ImageIO.write(im, "png", f); }else{ DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation(); // Create an instance of org.w3c.dom.Document Document document = domImpl.createDocument(null, "svg", null); // Create an instance of the SVG Generator SVGGraphics2D svgGenerator = new SVGGraphics2D(document); svgGenerator.setSVGCanvasSize(new Dimension(w,h)); // Ask the test to render into the SVG Graphics2D implementation if(!transparent){ svgGenerator.setColor(Color.white); svgGenerator.fillRect(0,0,w,h); } this.paintComponent(svgGenerator); // Finally, stream out SVG to the standard output using UTF-8 // character to byte encoding boolean useCSS = true; // we want to use CSS style attribute FileOutputStream outStream = new FileOutputStream(f); Writer out = new OutputStreamWriter(outStream, "UTF-8"); svgGenerator.stream(out, useCSS); outStream.flush(); outStream.close(); } } public Color getPeakColor(){return peakColor;} protected void paintComponent(Graphics g) { int w = getWidth(), h = getHeight(); super.paintComponent(g); Graphics2D g2 = (Graphics2D)g; if(!transparent){ g2.setColor(Color.white); g2.fillRect(0, 0, w, h); } profilePainter.setColor(peakColor); profilePainter.setStyle(style); profilePainter.paintItem(g, border, 0, w, h-border); int binPix = w / (profile.length()+1); //Paint labels & Y-axis stuff FontMetrics metrics; g2.setFont(new Font("Arial", Font.PLAIN, fontSize)); metrics = g2.getFontMetrics(); g2.setColor(Color.black); if(profile.max()<10 && profile.max()>1) g2.drawString(String.format("%.2f", scale.getMax()), border/2, fontSize); else if(profile.max()>=1 || profile.max()==0) g2.drawString(String.format("%.0f", scale.getMax()), border/2, fontSize); else g2.drawString(String.format("%.2e", scale.getMax()), border/2, fontSize); if(profile.min()==0 || profile.min()<=-1) g2.drawString(String.format("%.0f", scale.getMin()), border/2, h-border-1); else g2.drawString(String.format("%.2e", scale.getMin()), border/2, h-border-1); String counter=String.format("%d datapoints", profile.getNumProfiles()); g2.drawString(counter, w-border-metrics.stringWidth(counter), fontSize); //X-axis int xaxispos=h-border; if(profile.min()<0){ double frac =scale.getMax()/(scale.getMax()-scale.getMin()); xaxispos = (int)((double)((h-border-1))*frac); g2.drawString("0", border/2, xaxispos); } g2.setColor(Color.DARK_GRAY); g2.drawLine(border, h-border, (binPix*profile.length())+border, h-border); BinningParameters bps = profile.getBinningParameters(); String minVal = String.format("%d", -1*(bps.getWindowSize()/2)); String maxVal = String.format("%d", (bps.getWindowSize()/2)); g2.drawString(maxVal, border+(binPix*profile.length())-metrics.stringWidth(maxVal), h); g2.drawString(minVal, border, h); //Title //Draw marker line g2.setColor(Color.black); if(profile.isStranded()){ g2.setStroke(new BasicStroke((float)lineWidth)); int [] a=new int [7]; int [] b=new int [7]; arrangeArrow(a, b, lineHeight, border+(binPix*(profile.length()/2)), border+(binPix*(profile.length()/2))+150, h-border); g2.drawPolyline(a, b, 7); }else{ g2.fillRect(border+(binPix*(profile.length()/2))-lineWidth/2, h-lineHeight-(border/2), lineWidth, lineHeight); } } public void paintableChanged(PaintableChangedEvent pce) { repaint(); } private void arrangeArrow(int[] a, int[] b, int height, int gx1, int gx2, int my) { double arrowHt =0.1 *height; double arrowWd = 2; int a1, a2, a3; int startX = gx1; a1 = startX; a2 = (int) Math.round(startX + (arrowWd * 6)); a3 = (int) Math.round(startX + (arrowWd * 10)); a[0] = a1; a[1] = a1; a[2] = a2; a[3] = a2; a[4] = a3; a[5] = a2; a[6] = a2; int b1 = (int) Math.round(my); int b2 = (int) Math.round(my - (arrowHt * 13)); int b3 = (int) Math.round(my - (arrowHt * 10)); int b4 = (int) Math.round(my - (arrowHt * 16)); b[0] = b1; b[1] = b2; b[2] = b2; b[3] = b3; b[4] = b2; b[5] = b4; b[6] = b2; } }