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 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 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 = true; 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; } if (true) continue; // draw bars. to do so, we make a histogram of visible items. t.histogram = new DoubleBag(); 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 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); } }