package timeflow.vis.timeline; import timeflow.data.db.*; import timeflow.data.time.*; import timeflow.model.*; import timeflow.vis.Mouseover; import timeflow.vis.MouseoverLabel; import timeflow.vis.VisualAct; import timeflow.util.*; import java.awt.*; import java.awt.geom.AffineTransform; import java.util.*; import java.util.List; public class TimelineRenderer { private TimelineVisuals visuals; private int dy; public TimelineRenderer(TimelineVisuals visuals) { this.visuals=visuals; } public void setDY(int dy) { this.dy=dy; } public void render(Graphics2D g, Collection<Mouseover> objectLocations) { AffineTransform old=g.getTransform(); g.setTransform(AffineTransform.getTranslateInstance(0, -dy)); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); TFModel model=visuals.getModel(); Display display=model.getDisplay(); ActDB db=model.getDB(); if (display.emptyMessage(g, model)) return; // need to check this, because resize events don't (and shouldn't) register with central TFModel. visuals.layoutIfChanged(); java.util.List<VisualAct> visualActs=visuals.getVisualActs(); if (visualActs==null || visualActs.size()==0) { g.drawString("No data",10,30); return; } Rectangle bounds=visuals.getBounds(); boolean colorTrackLabels=db.getField(VirtualField.COLOR)==null || db.getField(VirtualField.COLOR).equals(db.getField(VirtualField.TRACK)); // draw tracks, if more than 1. if (visuals.trackList.size()>1) { boolean zebra=false; for (TimelineTrack t: visuals.trackList) { if (zebra) { g.setColor(display.getColor("timeline.zebra")); g.fillRect(bounds.x,t.y0,bounds.width,t.y1-t.y0); } zebra=!zebra; g.setColor(display.getColor("timeline.grid")); g.drawLine(bounds.x,t.y0,bounds.x+bounds.width,t.y0); } } Interval screenInterval=visuals.getViewInterval().subinterval(-.5,1.5); AxisTicMarks tics=AxisTicMarks.histoTics(screenInterval.start, screenInterval.end); for (TimelineTrack t: visuals.trackList) { // now... if not in graph mode, just draw items if (visuals.getLayoutStyle()!=TimelineVisuals.Layout.GRAPH)//max<(t.y1-t.y0)/20) { for (VisualAct v: t.visualActs) { Mouseover o=v.draw(g, null, bounds, display, true, true); if (o!=null) { o.y-=dy; objectLocations.add(o); } } continue; } // draw bars. to do so, we make a histogram of visible items. t.histogram=new DoubleBag<Long>(); for (VisualAct v: t.visualActs) { long time=v.getStart().getTime(); if (screenInterval.contains(time)) { t.histogram.add(tics.unit.roundDown(v.getStart().getTime()).getTime(), 1);//v.getSize()); } } // get max of items. double max=t.histogram.getMax(); // now draw bars on screen. Color fg=colorTrackLabels ? model.getDisplay().makeColor(t.label) : Color.gray; if (visuals.trackList.size()<2) fg=Color.gray; List<Long> keys=t.histogram.unordered(); Collections.sort(keys); for (Long r: keys) { double num=t.histogram.num(r); int x1=visuals.getTimeScale().toInt(r); int x2=visuals.getTimeScale().toInt(tics.unit.roundUp(r+1).getTime()); int barY=t.y1-(int)(.9*((t.y1-t.y0)*num)/max); g.setColor(new Color(230,230,230)); int m=12; g.fillRoundRect(x1+3,barY+3,x2-x1-1,t.y1-barY, m, m); g.setColor(fg); g.fillRoundRect(x1,barY,x2-x1-1,t.y1-barY, m, m); MouseoverLabel mouse=new MouseoverLabel(""+Math.round(num), "items",x1,barY,x2-x1-1,t.y1-barY); objectLocations.add(mouse); } } // finally label the tracks. we do this last so that the labels go on top of the data. if (visuals.trackList.size()>1) { boolean zebra=false; FontMetrics hugeFm=display.hugeFontMetrics(); for (TimelineTrack t: visuals.trackList) { // now label the track. if (t.y1-t.y0>23) { Color fg=colorTrackLabels ? model.getDisplay().makeColor(t.label) : Color.darkGray; Color bg=zebra ? display.getColor("timeline.zebra") : Color.white; String label=t.label; if (label.equals(Display.MISC_CODE)) { label=display.getMiscLabel(); } else if (label.length()==0) { label=display.getNullLabel(); } else label=display.format(label, 20, false); // draw background. g.setColor(bg); int sw=hugeFm.stringWidth(label); g.fillRect(0,t.y1-20,sw+8,19); // draw foreground (actual label) g.setFont(display.huge()); g.setColor(fg); g.drawString(label, 2, t.y1-5); } zebra=!zebra; } } g.setTransform(old); } }