package prefuse.demos;
import java.awt.Cursor;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.util.Iterator;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import prefuse.Constants;
import prefuse.Display;
import prefuse.Visualization;
import prefuse.action.ActionList;
import prefuse.action.RepaintAction;
import prefuse.action.assignment.ColorAction;
import prefuse.action.assignment.SizeAction;
import prefuse.action.layout.RandomLayout;
import prefuse.action.layout.graph.ForceDirectedLayout;
import prefuse.activity.Activity;
import prefuse.activity.ActivityAdapter;
import prefuse.activity.ActivityListener;
import prefuse.controls.ControlAdapter;
import prefuse.data.Schema;
import prefuse.data.Table;
import prefuse.data.io.DelimitedTextTableReader;
import prefuse.data.tuple.TupleSet;
import prefuse.render.DefaultRendererFactory;
import prefuse.render.LabelRenderer;
import prefuse.util.ColorLib;
import prefuse.util.PrefuseLib;
import prefuse.util.force.DragForce;
import prefuse.util.force.ForceItem;
import prefuse.util.force.ForceSimulator;
import prefuse.util.force.NBodyForce;
import prefuse.util.force.SpringForce;
import prefuse.util.ui.BrowserLauncher;
import prefuse.visual.VisualItem;
import prefuse.visual.sort.ItemSorter;
/**
* @author <a href="http://jheer.org">jeffrey heer</a>
*/
public class DataMountain extends Display {
public DataMountain(Table t) {
super(new Visualization());
m_vis.addTable("data", t);
LabelRenderer nodeRenderer = new LabelRenderer(null, "image");
nodeRenderer.setTextField(null);
nodeRenderer.setVerticalAlignment(Constants.BOTTOM);
nodeRenderer.setHorizontalPadding(0);
nodeRenderer.setVerticalPadding(0);
nodeRenderer.setMaxImageDimensions(100,100);
m_vis.setRendererFactory(new DefaultRendererFactory(nodeRenderer));
ActionList init = new ActionList();
init.add(new RandomLayout());
init.add(new DataMountainSizeAction());
m_vis.putAction("init", init);
ActionList update = new ActionList();
update.add(new DataMountainSizeAction());
update.add(new ColorAction("data", VisualItem.STROKECOLOR) {
public int getColor(VisualItem item) {
return ColorLib.rgb((item.isHover() ? 255 : 0), 0, 0);
}
});
update.add(new RepaintAction());
m_vis.putAction("update", update);
// we run this to make sure the forces are stabilized
ActionList preforce = new ActionList(1000);
preforce.add(new DataMountainForceLayout(true));
m_vis.putAction("preforce", preforce);
// this will cause docs to move out of the way when dragging
final ForceDirectedLayout fl = new DataMountainForceLayout(false);
ActivityListener fReset = new ActivityAdapter() {
public void activityCancelled(Activity a) {
fl.reset();
}
};
ActionList forces = new ActionList(Activity.INFINITY);
forces.add(fl);
forces.add(update);
forces.addActivityListener(fReset);
m_vis.putAction("forces", forces);
setSize(640,450);
setDamageRedraw(false); // disable due to Java2D image clipping errors
setBorder(BorderFactory.createEmptyBorder(30,20,5,20));
setItemSorter(new DataMountainSorter());
addControlListener(new DataMountainControl());
// pre-load images, otherwise they will be loaded asynchronously
nodeRenderer.getImageFactory().preloadImages(m_vis.items(),"image");
// initialize and present the interface
m_vis.run("init");
m_vis.runAfter("preforce", "update");
m_vis.run("preforce");
}
// ------------------------------------------------------------------------
public static void main(String[] args) {
JFrame frame = new JFrame("p r e f u s e | d a t a m o u n t a i n");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(demo());
frame.pack();
frame.setVisible(true);
}
public static JComponent demo() {
String datafile = "/amazon.txt";
Table data = null;
try {
data = (new DelimitedTextTableReader()).readTable(datafile);
data.addColumn("image","CONCAT('/images/',id,'.01.MZZZZZZZ.jpg')");
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
return new DataMountain(data);
}
// ------------------------------------------------------------------------
public static class DataMountainSorter extends ItemSorter {
public int score(VisualItem item) {
return (int)(10000*item.getY());
}
} // end of inner class DataMountainComparator
public class DataMountainSizeAction extends SizeAction {
public double getSize(VisualItem item) {
double y = item.getEndY();
return 0.2 + y/1400;
}
} // end of inner class DataMountainSizeAction
private static final String ANCHORITEM = "_anchorItem";
private static final Schema ANCHORITEM_SCHEMA = new Schema();
static {
ANCHORITEM_SCHEMA.addColumn(ANCHORITEM, ForceItem.class);
}
public class DataMountainForceLayout extends ForceDirectedLayout {
public DataMountainForceLayout(boolean enforceBounds) {
super("data",enforceBounds,false);
ForceSimulator fsim = new ForceSimulator();
fsim.addForce(new NBodyForce(-0.4f, 25f, NBodyForce.DEFAULT_THETA));
fsim.addForce(new SpringForce(1e-5f,0f));
fsim.addForce(new DragForce());
setForceSimulator(fsim);
m_nodeGroup = "data";
m_edgeGroup = null;
}
protected float getMassValue(VisualItem n) {
return n.isHover() ? 5f : 1f;
}
public void reset() {
Iterator iter = m_vis.visibleItems(m_nodeGroup);
while ( iter.hasNext() ) {
VisualItem item = (VisualItem)iter.next();
ForceItem aitem = (ForceItem)item.get(ANCHORITEM);
if ( aitem != null ) {
aitem.location[0] = (float)item.getEndX();
aitem.location[1] = (float)item.getEndY();
}
}
super.reset();
}
protected void initSimulator(ForceSimulator fsim) {
// make sure we have force items to work with
TupleSet t = (TupleSet)m_vis.getGroup(m_group);
t.addColumns(ANCHORITEM_SCHEMA);
t.addColumns(FORCEITEM_SCHEMA);
Iterator iter = m_vis.visibleItems(m_nodeGroup);
while ( iter.hasNext() ) {
VisualItem item = (VisualItem)iter.next();
// get force item
ForceItem fitem = (ForceItem)item.get(FORCEITEM);
if ( fitem == null ) {
fitem = new ForceItem();
item.set(FORCEITEM, fitem);
}
fitem.location[0] = (float)item.getEndX();
fitem.location[1] = (float)item.getEndY();
fitem.mass = getMassValue(item);
// get spring anchor
ForceItem aitem = (ForceItem)item.get(ANCHORITEM);
if ( aitem == null ) {
aitem = new ForceItem();
item.set(ANCHORITEM, aitem);
aitem.location[0] = fitem.location[0];
aitem.location[1] = fitem.location[1];
}
fsim.addItem(fitem);
fsim.addSpring(fitem, aitem, 0);
}
}
} // end of inner class DataMountainForceLayout
public class DataMountainControl extends ControlAdapter {
public static final String URL = "http://www.amazon.com/exec/obidos/tg/detail/-/";
private VisualItem activeItem;
private Point2D down = new Point2D.Double();
private Point2D tmp = new Point2D.Double();
private boolean wasFixed, dragged;
private boolean repaint = false;
public void itemEntered(VisualItem item, MouseEvent e) {
Display d = (Display)e.getSource();
d.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
d.setToolTipText(item.getString("id"));
activeItem = item;
wasFixed = item.isFixed();
}
public void itemExited(VisualItem item, MouseEvent e) {
if ( activeItem == item ) {
activeItem = null;
item.setFixed(wasFixed);
}
Display d = (Display)e.getSource();
d.setToolTipText(null);
d.setCursor(Cursor.getDefaultCursor());
}
public void itemPressed(VisualItem item, MouseEvent e) {
if (!SwingUtilities.isLeftMouseButton(e)) return;
// set the focus to the current node
Visualization vis = item.getVisualization();
vis.getFocusGroup(Visualization.FOCUS_ITEMS).setTuple(item);
item.setFixed(true);
dragged = false;
Display d = (Display)e.getComponent();
down = d.getAbsoluteCoordinate(e.getPoint(), down);
vis.run("forces");
}
public void itemReleased(VisualItem item, MouseEvent e) {
if (!SwingUtilities.isLeftMouseButton(e)) return;
if ( dragged ) {
activeItem = null;
item.setFixed(wasFixed);
dragged = false;
}
// clear the focus
Visualization vis = item.getVisualization();
vis.getFocusGroup(Visualization.FOCUS_ITEMS).clear();
vis.cancel("forces");
}
public void itemClicked(VisualItem item, MouseEvent e) {
if (!SwingUtilities.isLeftMouseButton(e)) return;
if ( e.getClickCount() == 2 ) {
String id = item.getString("id");
BrowserLauncher.showDocument(URL+id);
}
}
public void itemDragged(VisualItem item, MouseEvent e) {
if (!SwingUtilities.isLeftMouseButton(e)) return;
dragged = true;
Display d = (Display)e.getComponent();
tmp = d.getAbsoluteCoordinate(e.getPoint(), tmp);
double dx = tmp.getX()-down.getX();
double dy = tmp.getY()-down.getY();
PrefuseLib.setX(item, null, item.getX()+dx);
PrefuseLib.setY(item, null, item.getY()+dy);
down.setLocation(tmp);
if ( repaint )
item.getVisualization().repaint();
}
} // end of inner class DataMountainControl
} // end of class DataMountain