/*
* (C) Copyright IBM Corp. 2009
*
* LICENSE: Eclipse Public License v1.0
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.ibm.gaiandb.draw;
import java.awt.BasicStroke;
import java.awt.Insets;
import java.awt.Shape;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import javax.swing.BorderFactory;
import prefuse.Constants;
import prefuse.action.ActionList;
import prefuse.action.RepaintAction;
import prefuse.action.assignment.ColorAction;
import prefuse.action.assignment.StrokeAction;
import prefuse.action.layout.AxisLabelLayout;
import prefuse.action.layout.AxisLayout;
import prefuse.data.expression.parser.ExpressionParser;
import prefuse.data.query.RangeQueryBinding;
import prefuse.render.AbstractShapeRenderer;
import prefuse.render.AxisRenderer;
import prefuse.render.Renderer;
import prefuse.render.RendererFactory;
import prefuse.util.ColorLib;
import prefuse.visual.VisualItem;
import prefuse.visual.expression.VisiblePredicate;
public class ConnectedSeriesChart extends Chart {
// Use PROPRIETARY notice if class contains a main() method, otherwise use COPYRIGHT notice.
public static final String COPYRIGHT_NOTICE = "(c) Copyright IBM Corp. 2009";
private static final long serialVersionUID = 3256785306768329206L;
private static final int accelerometerRange = 50;
protected int maxDuration = 10;
private static final String xAxisName = "X";
private static final String yAxisName = "Y";
private static final String zAxisName = "NODE";
private static final String wAxisName = "RECEIVED";
private static final int axisWidth = 20;
private static final int axisHeight = 10;
private static final int lineWidth = 5;
private Rectangle2D barChartBounds = new Rectangle2D.Double();
private Rectangle2D xAxisBounds = new Rectangle2D.Double();
private Rectangle2D yAxisBounds = new Rectangle2D.Double();
private HashMap<String, HashSet<VisualItem>> graphPoints =
new HashMap<String, HashSet<VisualItem>>();
public ConnectedSeriesChart(PreparedStatement statement, Object... params)
throws SQLException {
super(statement, params);
keys.add(wAxisName);
keys.add(zAxisName);
setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
}
protected void prepareVis() {
vt = m_vis.addTable(GROUP, data);
m_vis.setRendererFactory(new RendererFactory() {
private int counter;
private Renderer yAxisRenderer = new AxisRenderer(
Constants.LEFT, Constants.CENTER);
private Renderer xAxisRenderer = new AxisRenderer(
Constants.CENTER, Constants.FAR_BOTTOM);
private Renderer seriesRenderer = new AbstractShapeRenderer() {
protected Shape getRawShape(VisualItem item) {
// Get the list of points on the same node.
String node = item.getString(zAxisName);
HashSet<VisualItem> nodeItems;
synchronized (graphPoints) {
nodeItems = graphPoints.get(node);
if (null == nodeItems) {
nodeItems = new HashSet<VisualItem>();
graphPoints.put(node, nodeItems);
}
}
// Find the latest point prior to this one.
VisualItem lastItem = null;
for (VisualItem currentItem : nodeItems) {
if ((null == lastItem ||
lastItem.getLong(wAxisName) < currentItem.getLong(wAxisName)) &&
currentItem.getLong(wAxisName) < item.getLong(wAxisName)) {
lastItem = currentItem;
}
}
nodeItems.add(item);
Line2D line;
if (null != lastItem) {
line = new Line2D.Double(
lastItem.getX(), lastItem.getY(),
item.getX(), item.getY()
);
}
else {
line = new Line2D.Double(
item.getX(), item.getY(),
item.getX(), item.getY()
);
counter = vt.getRowCount();
}
item.setStrokeColor(ColorLib.setAlpha(
item.getStrokeColor(),
255 * counter-- / vt.getRowCount()));
return line;
}
};
public Renderer getRenderer(VisualItem item) {
return item.isInGroup(yAxisName) ? yAxisRenderer :
item.isInGroup(xAxisName) ? xAxisRenderer :
seriesRenderer;
}
});
AxisLayout xAxis = new AxisLayout(
GROUP, xAxisName, Constants.X_AXIS, VisiblePredicate.TRUE);
AxisLayout yAxis = new AxisLayout(
GROUP, yAxisName, Constants.Y_AXIS, VisiblePredicate.TRUE);
RangeQueryBinding xAxisRange = new RangeQueryBinding(data, xAxisName);
xAxis.setRangeModel(xAxisRange.getModel());
xAxisRange.getNumberModel().setValueRange
(-accelerometerRange, accelerometerRange,
-accelerometerRange, accelerometerRange);
RangeQueryBinding yAxisRange = new RangeQueryBinding(data, yAxisName);
yAxis.setRangeModel(yAxisRange.getModel());
yAxisRange.getNumberModel().setValueRange
(-accelerometerRange, accelerometerRange,
-accelerometerRange, accelerometerRange);
xAxis.setLayoutBounds(barChartBounds);
yAxis.setLayoutBounds(barChartBounds);
AxisLabelLayout xAxisLabel = new AxisLabelLayout(
xAxisName, xAxis, xAxisBounds, 40);
AxisLabelLayout yAxisLabel = new AxisLabelLayout(
yAxisName, yAxis, yAxisBounds);
if (null == colorAction) {
colorAction = new ColorAction(GROUP, VisualItem.STROKECOLOR);
}
ActionList axes = new ActionList();
axes.add(xAxis);
axes.add(yAxis);
axes.add(xAxisLabel);
axes.add(yAxisLabel);
m_vis.putAction("axes", axes);
ActionList draw = new ActionList();
draw.add(new StrokeAction(GROUP, new BasicStroke(
lineWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL)));
draw.add(colorAction);
draw.add(new RepaintAction());
m_vis.putAction("draw", draw);
// Reset the object boundaries whenever the window is resized.
addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
updateVisualization();
}
});
updateVis();
}
// Sets the boundaries of the objects (chart and axes)
// relative to the current window.
protected void updateVis() {
// Remove old data from the table.
long latestTime = System.currentTimeMillis() / 1000;
String expression = latestTime + " - [" + wAxisName + "] > " + maxDuration;
data.remove(ExpressionParser.predicate(expression));
// Remove old data from the list of nodes.
synchronized (graphPoints) {
for (String node : graphPoints.keySet()) {
HashSet<VisualItem> nodeItems = graphPoints.get(node);
Iterator<VisualItem> i = nodeItems.iterator();
while (i.hasNext()) {
VisualItem item = i.next();
try {
item.getInt(xAxisName);
}
catch (IllegalStateException e) {
i.remove();
}
}
}
}
// Update the axis and chart boundaries.
Insets insets = getInsets();
int width = getWidth();
int height = getHeight();
int insetsWidth = insets.left + insets.right;
int insetsHeight = insets.top + insets.bottom;
barChartBounds.setRect(
insets.left + axisWidth,
insets.top,
width - insetsWidth - axisWidth,
height - insetsHeight - axisHeight);
xAxisBounds.setRect(
insets.left + axisWidth,
height - insets.bottom - axisHeight,
width - insetsWidth - axisWidth,
axisHeight);
yAxisBounds.setRect(
insets.left,
insets.top,
width - insetsWidth,
height - insetsHeight - axisHeight);
m_vis.run("axes");
m_vis.run("draw");
}
};