1   
28  package demo.view.anim;
29  
30  import demo.view.DemoDefaults;
31  import y.anim.AnimationFactory;
32  import y.anim.AnimationObject;
33  import y.anim.AnimationPlayer;
34  import y.anim.CompositeAnimationObject;
35  import y.base.EdgeCursor;
36  import y.base.Node;
37  import y.base.NodeCursor;
38  import y.geom.Geom;
39  import y.util.DefaultMutableValue2D;
40  import y.util.MutableValue2D;
41  import y.util.Value2DSettable;
42  import y.view.Arrow;
43  import y.view.BezierEdgeRealizer;
44  import y.view.Drawable;
45  import y.view.EdgeLabel;
46  import y.view.EdgeRealizer;
47  import y.view.Graph2D;
48  import y.view.Graph2DView;
49  import y.view.SmartEdgeLabelModel;
50  import y.view.ViewAnimationFactory;
51  
52  import javax.swing.JFrame;
53  import javax.swing.JPanel;
54  import javax.swing.JRootPane;
55  import javax.swing.Timer;
56  import java.awt.BorderLayout;
57  import java.awt.Color;
58  import java.awt.Graphics2D;
59  import java.awt.Rectangle;
60  import java.awt.EventQueue;
61  import java.awt.event.ActionEvent;
62  import java.awt.event.ActionListener;
63  import java.awt.geom.AffineTransform;
64  import java.awt.geom.GeneralPath;
65  
66  
67  
70  public class LabelAnimationDemo {
71    private static final int PREFERRED_DURATION = 10000;
72  
73    private final Graph2DView view;
74    private EdgeLabel[] labels;
75    private Timer timer;
76  
77    
81    public LabelAnimationDemo() {
82      this.view = new Graph2DView();
83      this.view.setFitContentOnResize(true);
84      init();
85    }
86  
87    
92    private void init() {
93      final Graph2D graph = view.getGraph2D();
94  
95          Node node;
97      node = graph.createNode(225, 125);
98      graph.getRealizer(node).setSize(0, 0);
99  
100     EdgeRealizer er;
101     er = graph.getRealizer(graph.createEdge(node, node));
102     er.setLineColor(Color.LIGHT_GRAY);
103     er.clearBends();
104     er.appendBend(225, 25);
105 
106 
107     final BezierEdgeRealizer ber = new BezierEdgeRealizer();
108     ber.appendBend(100, 0);
109     ber.appendBend(200, 400);
110     ber.appendBend(300, 100);
111     ber.setTargetArrow(Arrow.DELTA);
112     ber.setLineColor(Color.LIGHT_GRAY);
113     graph.createEdge(graph.createNode(50, 200), graph.createNode(400, 200),
114         ber.createCopy());
115 
116     ber.clearBends();
117     ber.appendBend(300, 250);
118     ber.appendBend(200, 550);
119     ber.appendBend(100, 250);
120     graph.createEdge(graph.createNode(400, 350), graph.createNode(50, 350),
121         ber.createCopy());
122 
123 
124     for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
125       graph.getRealizer(nc.node()).setVisible(false);
126     }
127 
128     final String[] labelTexts = {
129         "Selfloop",
130         "A Label",
131         "Another Label"
132     };
133 
134     labels = new EdgeLabel[labelTexts.length];
135 
136     final EdgeCursor ec = graph.edges();
137     for (int i = 0, n = labelTexts.length; i < n; ++i, ec.next()) {
138       labels[i] = new EdgeLabel(labelTexts[i]);
139       final SmartEdgeLabelModel model = new SmartEdgeLabelModel();
140       labels[i].setLabelModel(model, model.getDefaultParameter());
141       labels[i].bindRealizer(graph.getRealizer(ec.edge()));
142     }
143 
144     node = graph.createNode(10, 10);
145     graph.getRealizer(node).setSize(0, 0);
146 
147     er = graph.getRealizer(graph.createEdge(node, node));
148     er.setLineColor(Color.LIGHT_GRAY);
149     er.clearBends();
150     er.appendBend(470, 10);
151     er.appendBend(470, 470);
152     er.appendBend(10, 470);
153 
154 
155     timer = new Timer(PREFERRED_DURATION + 500,
156         new ActionListener() {
157           private boolean invert;
158 
159           public void actionPerformed(final ActionEvent e) {
160             play(invert);
161             invert = !invert;
162           }
163         });
164     timer.setInitialDelay(1000);
165     timer.start();
166   }
167 
168   
174   private void play(final boolean invert) {
175     final Graph2D graph = view.getGraph2D();
176     EdgeRealizer er;
177 
178     final EdgeCursor ec = graph.edges();
179     int i = 0;
180 
181     final ViewAnimationFactory factory = new ViewAnimationFactory(view);
182 
183             
187         er = graph.getRealizer(ec.edge());
189     ec.next();
190 
191         final Drawable selfloopLabel = ViewAnimationFactory.createDrawable(labels[i++]);
193 
194             final AnimationObject selfloopAnimation =
197         factory.traversePath(er.getPath(), false, selfloopLabel, true, false, PREFERRED_DURATION);
198 
199         er = graph.getRealizer(ec.edge());
201     ec.next();
202 
203         final Drawable standardLabel = ViewAnimationFactory.createDrawable(labels[i++]);
205 
206             final AnimationObject standardAnimation =
209         factory.traversePath(er.getPath(), invert, standardLabel, true, true, PREFERRED_DURATION);
210 
211                             
219         er = graph.getRealizer(ec.edge());
221     ec.next();
222     final GeneralPath path = er.getPath();
223 
224         final AnimationDrawable offsetLabel = new AnimationDrawable(ViewAnimationFactory.createDrawable(labels[i]));
226 
227             final AnimationObject offsetAnimation = new AnimationObject() {
230       private final AnimationObject delegate =
231           factory.traversePath(path, invert,
232               offsetLabel.getPositionMutable(),
233               offsetLabel.getDirectionMutable(),
234               PREFERRED_DURATION);
235       
236       private final Value2DSettable internalOffset =
237           offsetLabel.getOffsetMutable();
238 
239       public void initAnimation() {
240         graph.addDrawable(offsetLabel);
241         delegate.initAnimation();
242       }
243 
244       public void calcFrame(final double time) {
245                         internalOffset.setX(invert ? time : 1.0 - time);
248         delegate.calcFrame(time);
249       }
250 
251       public void disposeAnimation() {
252         delegate.disposeAnimation();
253         graph.removeDrawable(offsetLabel);
254       }
255 
256       public long preferredDuration() {
257         return delegate.preferredDuration();
258       }
259     };
260 
261 
262     er = graph.getRealizer(ec.edge());
263     final GeneralPath border = er.getPath();
264 
265     final CompositeAnimationObject arrows = AnimationFactory.createConcurrency();
266 
267     final AnimationObject NO_TIME = AnimationFactory.createPause(0);
268     final long pause = PREFERRED_DURATION / 19;
269     final long rest = PREFERRED_DURATION % 19;
270     final long duration = pause * 10 + rest;
271     for (int j = 0; j < 10; ++j) {
272       final Drawable arrowDrawable = new Drawable() {
273         private final Arrow arrow = Arrow.STANDARD;
274 
275         public void paint(final Graphics2D gfx) {
276           final Color oldColor = gfx.getColor();
277           gfx.setColor(Color.GRAY);
278           arrow.paint(gfx, 0, 0, 1, 0);
279           gfx.setColor(oldColor);
280         }
281 
282         public Rectangle getBounds() {
283           return arrow.getShape().getBounds();
284         }
285       };
286 
287       final CompositeAnimationObject sequence = AnimationFactory.createLazySequence();
288       sequence.addAnimation(AnimationFactory.createPause(j * pause));
289       sequence.addAnimation(
290           factory.traversePath(border, false, arrowDrawable, true, false,
291               duration));
292       sequence.addAnimation(NO_TIME);
293       arrows.addAnimation(sequence);
294     }
295 
296     final CompositeAnimationObject concurrency = AnimationFactory.createConcurrency();
297     concurrency.addAnimation(selfloopAnimation);
298     concurrency.addAnimation(standardAnimation);
299     concurrency.addAnimation(offsetAnimation);
300     concurrency.addAnimation(arrows);
301 
302     final AnimationPlayer player = factory.createConfiguredPlayer();
303     player.animate(concurrency);
304   }
305 
306   
311   private void start(final String title) {
312     final JFrame frame = new JFrame(title);
313 
314     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
315     addContentTo(frame.getRootPane());
316     frame.pack();
317     frame.setLocationRelativeTo(null);
318     frame.setVisible(true);
319   }
320 
321   public final void addContentTo(final JRootPane rootPane) {
322     final JPanel contentPane = new JPanel(new BorderLayout());
323     contentPane.add(view, BorderLayout.CENTER);
324 
325     rootPane.setContentPane(contentPane);
326   }
327 
328   public void dispose() {
329     if (timer != null) {
330       if (timer.isRunning()) {
331         timer.stop();
332       }
333       timer = null;
334     }
335   }
336 
337   public static void main(String[] args) {
338     EventQueue.invokeLater(new Runnable() {
339       public void run() {
340         DemoDefaults.initLnF();
341         (new LabelAnimationDemo()).start("Label Animations");
342       }
343     });
344   }
345 
346 
347   
351   private static final class AnimationDrawable implements Drawable {
352     private final Drawable wrappee;
353     private final Rectangle bounds;
354 
355     
356     private MutableValue2D position;
357 
358     
363     private MutableValue2D offset;
364 
365     
366     private MutableValue2D direction;
367 
368     AnimationDrawable(final Drawable wrappee) {
369       this.wrappee = wrappee;
370       final Rectangle wrappeeBounds = wrappee.getBounds();
371       this.position = DefaultMutableValue2D.create(wrappeeBounds.getCenterX(),
372           wrappeeBounds.getCenterY());
373       this.offset = DefaultMutableValue2D.create(0, 1);
374       this.direction = DefaultMutableValue2D.create();
375       this.bounds = new Rectangle(wrappeeBounds);
376     }
377 
378     public Rectangle getBounds() {
379       final Rectangle wrappeeBounds = wrappee.getBounds();
380       final double w = Math.ceil(wrappeeBounds.getWidth());
381       final double h = Math.ceil(wrappeeBounds.getHeight());
382 
383       final double x = position.getX();
384       final double y = position.getY();
385 
386             final AffineTransform transform = new AffineTransform();
388       transform.translate(x, y);
389       transform.rotate(radians());
390       transform.translate(-x, -y);
391 
392       Geom.calcTransformedBounds(x - w * offset.getX(),
393           y - h * offset.getY(),
394           w, h, transform, bounds);
395       return bounds;
396     }
397 
398     public void paint(final Graphics2D gfx) {
399       final AffineTransform oldAt = gfx.getTransform();
400       final Rectangle wrappeeBounds = wrappee.getBounds();
401             gfx.translate(position.getX(), position.getY());
403       gfx.rotate(radians());
404                         gfx.translate(-wrappeeBounds.x, -wrappeeBounds.y);
408                         gfx.translate(-wrappeeBounds.getWidth() * offset.getX(), -wrappeeBounds.getHeight() * offset.getY());
412       wrappee.paint(gfx);
413       gfx.setTransform(oldAt);
414     }
415 
416     Value2DSettable getPositionMutable() {
417       return position;
418     }
419 
420     Value2DSettable getDirectionMutable() {
421       return direction;
422     }
423 
424     Value2DSettable getOffsetMutable() {
425       return offset;
426     }
427 
428     private static final double PI_HALF = Math.PI * 0.5;
429 
430     private double radians() {
431       double radians = Math.atan2(direction.getY(), direction.getX());
432       if (radians < -PI_HALF) {
433         radians += Math.PI;
434       } else if (radians > PI_HALF) {
435         radians -= Math.PI;
436       }
437       return radians;
438     }
439   }
440 }
441