Как анимировать края чертежа с помощью JUNG

Я новичок в JUNG. У меня есть FRLayout, который представляет топологию сети с ключевыми узлами или вершинами красного цвета, а остальные вершины синими. Ребра от начального узла до конечного узла окрашены в синий цвет. пути к конечному узлу. Как можно анимировать рисование ребер от start_node до end_node с заданным интервалом времени? Можете ли вы предоставить или сослаться на пример?


person user1772523    schedule 15.11.2012    source источник


Ответы (1)


Вы можете прикрепить ключевой кадр к своим данным Edge. Затем каждый раз, когда вы рисуете (с помощью преобразователя), вы можете использовать ключевой кадр для настройки градиента края:

RenderContext<V, E> context = vv.getRenderContext();
context.setEdgeDrawPaintTransformer(new KeyframeGradientTransformer());

public class KeyframeGradientTransformer() implements Transformer<E, Paint> {
        @Override
        public Paint transform(Edge edge) {
            // TODO: Here you would determine the gradient information
            // based on the edge.getKeyframe().
            Paint gradient = new GradientPaint(...);
            return gradient;
        }
}

РЕДАКТИРОВАТЬ:

Я написал быстрый пример:

введите здесь описание изображения

Это анимирует от одной вершины к другой (вдоль одного края). Если вы хотите анимировать прохождение через несколько вершин, потребуется больше логики. Тем не менее, это выглядит довольно круто и должно дать вам начало. Если вам (или кому-то еще) нужны дополнительные комментарии, просто дайте мне знать, и я постараюсь сделать это более понятным.

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.LinearGradientPaint;
import java.awt.Paint;
import java.awt.Stroke;
import java.awt.geom.Point2D;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import org.apache.commons.collections15.Factory;
import org.apache.commons.collections15.Transformer;

import edu.uci.ics.jung.algorithms.generators.random.EppsteinPowerLawGenerator;
import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.algorithms.layout.SpringLayout;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.SparseMultigraph;
import edu.uci.ics.jung.graph.util.Pair;
import edu.uci.ics.jung.visualization.VisualizationViewer;

public class Test {

    public static void main(String[] args) {

        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.setPreferredSize(new Dimension(1024, 768));
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                JPanel content = new JPanel();

                // Set up the graph and the display.
                int numV = 70;
                int numE = 50;
                EppsteinPowerLawGenerator<String, String> gen = new EppsteinPowerLawGenerator<String, String>(
                        new GraphFactory(), new CountFactory(),
                        new CountFactory(), numV, numE, 10);
                Graph<String, String> graph = gen.create();
                Layout<String, String> layout = new SpringLayout<String, String>(
                        graph);
                VisualizationViewer<String, String> vv = new VisualizationViewer<String, String>(
                        layout);
                vv.getRenderContext().setEdgeStrokeTransformer(
                        new Transformer<String, Stroke>() {

                            @Override
                            public Stroke transform(String edge) {
                                return new BasicStroke(1.5f);
                            }
                        });

                content.add(vv);

                frame.setContentPane(content);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                // Animate the edges!
                AnimationTimerTask at = new AnimationTimerTask(vv);
                Timer timer = new Timer();
                timer.scheduleAtFixedRate(at, 10, 30);
            }

        });
    }

    static class AnimationTimerTask extends TimerTask {

        private final double width = 0.1; // Size of the colored line.
        private final double stepsize = 0.01;
        private double keyframe = 0 + width; // Between 0.0 and 1.0
        private VisualizationViewer<String, String> vv = null;

        public AnimationTimerTask(VisualizationViewer<String, String> vv) {
            this.vv = vv;
        }

        @Override
        public void run() {
            vv.getRenderContext().setEdgeDrawPaintTransformer(
                    new Transformer<String, Paint>() {

                        @Override
                        public Paint transform(String edge) {
                            // Find both points of the edge.
                            Pair<String> vs = vv.getGraphLayout().getGraph()
                                    .getEndpoints(edge);
                            Point2D p1 = vv.getGraphLayout().transform(
                                    vs.getFirst());
                            Point2D p2 = vv.getGraphLayout().transform(
                                    vs.getSecond());

                            // This code won't handle self-edges.
                            if (p1.equals(p2)) {
                                return Color.red;
                            }

                            Color[] colors = { Color.gray, Color.red,
                                    Color.gray };
                            float start = (float) Math.max(0.0, keyframe
                                    - width);
                            float end = (float) Math.min(1.0, keyframe + width);
                            float[] fractions = { start, (float) keyframe, end };
                            return new LinearGradientPaint(p1, p2, fractions,
                                    colors);
                        }

                    });
            vv.repaint();
            keyframe += stepsize;
            keyframe %= 1.0;
        }
    }

    static class GraphFactory implements Factory<Graph<String, String>> {

        @Override
        public Graph<String, String> create() {
            return new SparseMultigraph<String, String>();
        }
    }

    static class CountFactory implements Factory<String> {

        private int count = 0;

        @Override
        public String create() {
            return String.valueOf(count++);
        }
    }
}

Кроме того, я немного потрудился над этим раньше, поэтому: для этого требуется библиотека JUNG. Если у вас его нет, вы не сможете запустить SSCCEE.

person sdasdadas    schedule 27.11.2012
comment
Не могли бы вы подробнее рассказать о ключевом кадре - person Nabegh; 04.06.2013
comment
@Nabegh Взгляните на редактирование - надеюсь, оно имеет смысл. (Я не уверен, насколько это эффективно, но кажется, что это работает для ‹ 500 вершин и ребер.) - person sdasdadas; 05.06.2013
comment
это очень полезно. Спасибо. Я полагаю, что для изменения обводки края мне нужно будет реализовать setEdgeStrokeTransformer, используя ту же логику? - person Nabegh; 06.06.2013
comment
@Nabegh Да, я действительно меняю обводку края и в этом примере, но только потому, что это было трудно увидеть с оригинальными тонкими линиями. Вы можете видеть, где я добавляю преобразователь сразу после создания VisualizationViewer. - person sdasdadas; 06.06.2013