001: package prefuse.demos;
002:
003: import java.awt.Cursor;
004: import java.awt.event.MouseEvent;
005: import java.awt.geom.Point2D;
006: import java.util.Iterator;
007:
008: import javax.swing.BorderFactory;
009: import javax.swing.JComponent;
010: import javax.swing.JFrame;
011: import javax.swing.SwingUtilities;
012:
013: import prefuse.Constants;
014: import prefuse.Display;
015: import prefuse.Visualization;
016: import prefuse.action.ActionList;
017: import prefuse.action.RepaintAction;
018: import prefuse.action.assignment.ColorAction;
019: import prefuse.action.assignment.SizeAction;
020: import prefuse.action.layout.RandomLayout;
021: import prefuse.action.layout.graph.ForceDirectedLayout;
022: import prefuse.activity.Activity;
023: import prefuse.activity.ActivityAdapter;
024: import prefuse.activity.ActivityListener;
025: import prefuse.controls.ControlAdapter;
026: import prefuse.data.Schema;
027: import prefuse.data.Table;
028: import prefuse.data.io.DelimitedTextTableReader;
029: import prefuse.data.tuple.TupleSet;
030: import prefuse.render.DefaultRendererFactory;
031: import prefuse.render.LabelRenderer;
032: import prefuse.util.ColorLib;
033: import prefuse.util.PrefuseLib;
034: import prefuse.util.force.DragForce;
035: import prefuse.util.force.ForceItem;
036: import prefuse.util.force.ForceSimulator;
037: import prefuse.util.force.NBodyForce;
038: import prefuse.util.force.SpringForce;
039: import prefuse.util.ui.BrowserLauncher;
040: import prefuse.visual.VisualItem;
041: import prefuse.visual.sort.ItemSorter;
042:
043: /**
044: * @author <a href="http://jheer.org">jeffrey heer</a>
045: */
046: public class DataMountain extends Display {
047:
048: public DataMountain(Table t) {
049: super (new Visualization());
050: m_vis.addTable("data", t);
051:
052: LabelRenderer nodeRenderer = new LabelRenderer(null, "image");
053: nodeRenderer.setTextField(null);
054: nodeRenderer.setVerticalAlignment(Constants.BOTTOM);
055: nodeRenderer.setHorizontalPadding(0);
056: nodeRenderer.setVerticalPadding(0);
057: nodeRenderer.setMaxImageDimensions(100, 100);
058:
059: m_vis.setRendererFactory(new DefaultRendererFactory(
060: nodeRenderer));
061:
062: ActionList init = new ActionList();
063: init.add(new RandomLayout());
064: init.add(new DataMountainSizeAction());
065: m_vis.putAction("init", init);
066:
067: ActionList update = new ActionList();
068: update.add(new DataMountainSizeAction());
069: update.add(new ColorAction("data", VisualItem.STROKECOLOR) {
070: public int getColor(VisualItem item) {
071: return ColorLib.rgb((item.isHover() ? 255 : 0), 0, 0);
072: }
073: });
074: update.add(new RepaintAction());
075: m_vis.putAction("update", update);
076:
077: // we run this to make sure the forces are stabilized
078: ActionList preforce = new ActionList(1000);
079: preforce.add(new DataMountainForceLayout(true));
080: m_vis.putAction("preforce", preforce);
081:
082: // this will cause docs to move out of the way when dragging
083: final ForceDirectedLayout fl = new DataMountainForceLayout(
084: false);
085: ActivityListener fReset = new ActivityAdapter() {
086: public void activityCancelled(Activity a) {
087: fl.reset();
088: }
089: };
090: ActionList forces = new ActionList(Activity.INFINITY);
091: forces.add(fl);
092: forces.add(update);
093: forces.addActivityListener(fReset);
094: m_vis.putAction("forces", forces);
095:
096: setSize(640, 450);
097: setDamageRedraw(false); // disable due to Java2D image clipping errors
098: setBorder(BorderFactory.createEmptyBorder(30, 20, 5, 20));
099: setItemSorter(new DataMountainSorter());
100: addControlListener(new DataMountainControl());
101:
102: // pre-load images, otherwise they will be loaded asynchronously
103: nodeRenderer.getImageFactory().preloadImages(m_vis.items(),
104: "image");
105:
106: // initialize and present the interface
107: m_vis.run("init");
108: m_vis.runAfter("preforce", "update");
109: m_vis.run("preforce");
110: }
111:
112: // ------------------------------------------------------------------------
113:
114: public static void main(String[] args) {
115: JFrame frame = new JFrame(
116: "p r e f u s e | d a t a m o u n t a i n");
117: frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
118: frame.getContentPane().add(demo());
119: frame.pack();
120: frame.setVisible(true);
121: }
122:
123: public static JComponent demo() {
124: String datafile = "/amazon.txt";
125: Table data = null;
126: try {
127: data = (new DelimitedTextTableReader()).readTable(datafile);
128: data.addColumn("image",
129: "CONCAT('/images/',id,'.01.MZZZZZZZ.jpg')");
130: } catch (Exception e) {
131: e.printStackTrace();
132: System.exit(1);
133: }
134: return new DataMountain(data);
135: }
136:
137: // ------------------------------------------------------------------------
138:
139: public static class DataMountainSorter extends ItemSorter {
140: public int score(VisualItem item) {
141: return (int) (10000 * item.getY());
142: }
143: } // end of inner class DataMountainComparator
144:
145: public class DataMountainSizeAction extends SizeAction {
146: public double getSize(VisualItem item) {
147: double y = item.getEndY();
148: return 0.2 + y / 1400;
149: }
150: } // end of inner class DataMountainSizeAction
151:
152: private static final String ANCHORITEM = "_anchorItem";
153: private static final Schema ANCHORITEM_SCHEMA = new Schema();
154: static {
155: ANCHORITEM_SCHEMA.addColumn(ANCHORITEM, ForceItem.class);
156: }
157:
158: public class DataMountainForceLayout extends ForceDirectedLayout {
159:
160: public DataMountainForceLayout(boolean enforceBounds) {
161: super ("data", enforceBounds, false);
162:
163: ForceSimulator fsim = new ForceSimulator();
164: fsim.addForce(new NBodyForce(-0.4f, 25f,
165: NBodyForce.DEFAULT_THETA));
166: fsim.addForce(new SpringForce(1e-5f, 0f));
167: fsim.addForce(new DragForce());
168: setForceSimulator(fsim);
169:
170: m_nodeGroup = "data";
171: m_edgeGroup = null;
172: }
173:
174: protected float getMassValue(VisualItem n) {
175: return n.isHover() ? 5f : 1f;
176: }
177:
178: public void reset() {
179: Iterator iter = m_vis.visibleItems(m_nodeGroup);
180: while (iter.hasNext()) {
181: VisualItem item = (VisualItem) iter.next();
182: ForceItem aitem = (ForceItem) item.get(ANCHORITEM);
183: if (aitem != null) {
184: aitem.location[0] = (float) item.getEndX();
185: aitem.location[1] = (float) item.getEndY();
186: }
187: }
188: super .reset();
189: }
190:
191: protected void initSimulator(ForceSimulator fsim) {
192: // make sure we have force items to work with
193: TupleSet t = (TupleSet) m_vis.getGroup(m_group);
194: t.addColumns(ANCHORITEM_SCHEMA);
195: t.addColumns(FORCEITEM_SCHEMA);
196:
197: Iterator iter = m_vis.visibleItems(m_nodeGroup);
198: while (iter.hasNext()) {
199: VisualItem item = (VisualItem) iter.next();
200: // get force item
201: ForceItem fitem = (ForceItem) item.get(FORCEITEM);
202: if (fitem == null) {
203: fitem = new ForceItem();
204: item.set(FORCEITEM, fitem);
205: }
206: fitem.location[0] = (float) item.getEndX();
207: fitem.location[1] = (float) item.getEndY();
208: fitem.mass = getMassValue(item);
209:
210: // get spring anchor
211: ForceItem aitem = (ForceItem) item.get(ANCHORITEM);
212: if (aitem == null) {
213: aitem = new ForceItem();
214: item.set(ANCHORITEM, aitem);
215: aitem.location[0] = fitem.location[0];
216: aitem.location[1] = fitem.location[1];
217: }
218:
219: fsim.addItem(fitem);
220: fsim.addSpring(fitem, aitem, 0);
221: }
222: }
223: } // end of inner class DataMountainForceLayout
224:
225: public class DataMountainControl extends ControlAdapter {
226: public static final String URL = "http://www.amazon.com/exec/obidos/tg/detail/-/";
227: private VisualItem activeItem;
228: private Point2D down = new Point2D.Double();
229: private Point2D tmp = new Point2D.Double();
230: private boolean wasFixed, dragged;
231: private boolean repaint = false;
232:
233: public void itemEntered(VisualItem item, MouseEvent e) {
234: Display d = (Display) e.getSource();
235: d.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
236: d.setToolTipText(item.getString("id"));
237: activeItem = item;
238: wasFixed = item.isFixed();
239: }
240:
241: public void itemExited(VisualItem item, MouseEvent e) {
242: if (activeItem == item) {
243: activeItem = null;
244: item.setFixed(wasFixed);
245: }
246: Display d = (Display) e.getSource();
247: d.setToolTipText(null);
248: d.setCursor(Cursor.getDefaultCursor());
249: }
250:
251: public void itemPressed(VisualItem item, MouseEvent e) {
252: if (!SwingUtilities.isLeftMouseButton(e))
253: return;
254:
255: // set the focus to the current node
256: Visualization vis = item.getVisualization();
257: vis.getFocusGroup(Visualization.FOCUS_ITEMS).setTuple(item);
258:
259: item.setFixed(true);
260: dragged = false;
261: Display d = (Display) e.getComponent();
262: down = d.getAbsoluteCoordinate(e.getPoint(), down);
263:
264: vis.run("forces");
265: }
266:
267: public void itemReleased(VisualItem item, MouseEvent e) {
268: if (!SwingUtilities.isLeftMouseButton(e))
269: return;
270: if (dragged) {
271: activeItem = null;
272: item.setFixed(wasFixed);
273: dragged = false;
274: }
275: // clear the focus
276: Visualization vis = item.getVisualization();
277: vis.getFocusGroup(Visualization.FOCUS_ITEMS).clear();
278:
279: vis.cancel("forces");
280: }
281:
282: public void itemClicked(VisualItem item, MouseEvent e) {
283: if (!SwingUtilities.isLeftMouseButton(e))
284: return;
285: if (e.getClickCount() == 2) {
286: String id = item.getString("id");
287: BrowserLauncher.showDocument(URL + id);
288: }
289: }
290:
291: public void itemDragged(VisualItem item, MouseEvent e) {
292: if (!SwingUtilities.isLeftMouseButton(e))
293: return;
294: dragged = true;
295: Display d = (Display) e.getComponent();
296: tmp = d.getAbsoluteCoordinate(e.getPoint(), tmp);
297: double dx = tmp.getX() - down.getX();
298: double dy = tmp.getY() - down.getY();
299:
300: PrefuseLib.setX(item, null, item.getX() + dx);
301: PrefuseLib.setY(item, null, item.getY() + dy);
302: down.setLocation(tmp);
303: if (repaint)
304: item.getVisualization().repaint();
305: }
306: } // end of inner class DataMountainControl
307:
308: } // end of class DataMountain
|