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