【问题标题】:How to programatically pan a VisualizationViewer with Jung (the java library)?如何使用 Jung(Java 库)以编程方式平移 VisualizationViewer?
【发布时间】:2011-08-10 08:27:21
【问题描述】:

经过大量调查,我无法找到以下问题的方便答案:如何使用 Jung 以编程方式平移 VisualizationViewer?

我有一个带有图形顶点列表的 GUI,我希望双击列表中的一项(即节点描述)对单击的节点执行 VisualizationViewer 的“居中操作”。 如何编码这样的行为?看起来很简单,但我没有找到方便的答案。

如果有人可以帮忙,谢谢!

詹姆斯

【问题讨论】:

    标签: java graph visualization jung


    【解决方案1】:

    我试图弄清楚如何以给定顶点为中心并遇到了这个问题,但不幸的是它并不是特别有用,我花了相当多的时间来弄清楚如何去做。因此,在这里分享我的经验,以防对其他人有所帮助。

    我正在编写的应用程序有一个 VisualizationViewer,它加载在 GraphZoomScrollPane 中。我有一个已添加到 VisualizationViewer 的 GraphMouseListener,它允许用户在滚动窗格的可视区域中右键单击一个顶点,并在弹出菜单中选择以该顶点为中心。

    该线程上投票最多的答案引用了来自 LAYOUT 层的 MutableTransformer 的用法,它使用该转换器的 translate 方法来执行居中操作。不幸的是,如果您使用缩放/滚动,那么您并不真正知道布局层相对于视图层的大小和位置,而无需进行大量额外的数学运算。

    使用缩放/滚动窗格时,我建议在窗格表示的图形可视区域中找到顶点的位置,然后调整视图窗格的位置。

    这是我编写的代码的 sn-p:

    void center(MouseEvent me, GraphZoomScrollPane gzsp) {
      VisualizationViewer<V,E> vv = 
        (VisualizationViewer<V,E>)me.getSource();
      MutableTransformer viewTransformer = 
        vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.VIEW);
      double scaleFromViewTransformer = viewTransformer.getScale();
      Dimension paneSize = gzsp.getSize();
      Point2D positionOfVertexInPane = me.getPoint();
      double[] centerOfPane = new double[] {
        paneSize.getWidth()/2d, 
        paneSize.getHeight()/2d
      };
      double[] amountToMovePane = new double[] {
        (centerOfPane[0]-positionOfVertexInPane.getX())/scaleFromViewTransformer,
        (centerOfPane[1]-positionOfVertexInPane.getY())/scaleFromViewTransformer
      };
      viewTransformer.translate(amountToMovePane[0], amountToMovePane[1]);
    }
    

    【讨论】:

      【解决方案2】:

      AnimatedPickingGraphMousePlugin中已经实现了节点中心功能

      http://sourceforge.net/p/jung/discussion/252062/thread/18b4b941

      在拾取模式下 ctrl+单击一个顶点使其居中。

      @SuppressWarnings("unchecked")
      public void mouseReleased(MouseEvent e) {
          if (e.getModifiers() == modifiers) {
              final VisualizationViewer<V,E> vv = (VisualizationViewer<V,E>) e.getSource();
              if (vertex != null) {
                  Layout<V,E> layout = vv.getGraphLayout();
                  Point2D q = layout.transform(vertex);
                  Point2D lvc = vv.getRenderContext().getMultiLayerTransformer().inverseTransform(vv.getCenter());
                  final double dx = (lvc.getX() - q.getX()) / 10;
                  final double dy = (lvc.getY() - q.getY()) / 10;
      
                  Runnable animator = new Runnable() {
      
                      public void run() {
                          for (int i = 0; i < 10; i++) {
                              vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.LAYOUT).translate(dx, dy);
                              try {
                                  Thread.sleep(100);
                              } catch (InterruptedException ex) {
                              }
                          }
                      }
                  };
                  Thread thread = new Thread(animator);
                  thread.start();
              }
          }
      }
      

      【讨论】:

        【解决方案3】:

        因为我只是在寻找这个问题的答案,而上面的工作非常糟糕;这是我在 AnimatedPickingGraphMousePlugin 中找到的代码 sn-p,它将重新定位:

        Layout<V,E> layout = vv.getGraphLayout();
        Point2D q = layout.transform(vertex);
        Point2D lvc = 
            vv.getRenderContext().getMultiLayerTransformer().inverseTransform(vv.getCenter());
        final double dx = (lvc.getX() - q.getX());
        final double dy = (lvc.getY() - q.getY());
        vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.LAYOUT).translate(dx, dy);
        

        【讨论】:

          【解决方案4】:
          public void centerViewsOnVertex(SynsetVertex v) {
            //the following location have sense in the space of the layout
            Point2D v_location = layout.transform(v);
            Point2D vv1_center_location = vv1.getRenderContext()
                          .getMultiLayerTransformer()
                          .inverseTransform(Layer.LAYOUT, vv1.getCenter());
          
            double scale = vv1.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.VIEW).getScale();
          
            vv1.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.LAYOUT).translate(
                                  -(v_location.getX() - vv1_center_location.getX()) * 1
                                          / scale,
                                  -(v_location.getY() - vv1_center_location.getY()) * 1
                                          / scale);
          
            refreshViews();
          }
          

          【讨论】:

          • 你能解释一下你在 LAYOUT 层而不是 VIEW 层上选择了 inverseTransform 吗?
          【解决方案5】:

          其实我已经通过下一个解决方案找到了:

          //the following location have sense in the space of the layout
              Point2D v_location = layout.transform(v);
              Point2D vv1_center_location = vv1.getRenderContext()
                      .getMultiLayerTransformer()
                      .inverseTransform(Layer.LAYOUT, vv1.getCenter());
          
              vv1.getRenderContext()
                      .getMultiLayerTransformer()
                      .getTransformer(Layer.LAYOUT)
                      .translate(-(v_location.getX() - vv1_center_location.getX()),
                              -(v_location.getY() - vv1_center_location.getY()));
          

          【讨论】:

          • 类似,但由于缩放而忽略了比例因子。你仍然可以改进它
          【解决方案6】:

          这里是如何在JUNG2中右键单击一个节点后弹出一个菜单,然后选择居中到这个节点:

          graphMouse.add(new MyPopupGraphMousePlugin());
          
          /**
           * a GraphMousePlugin that offers popup
           * menu support
           */
          protected class MyPopupGraphMousePlugin extends AbstractPopupGraphMousePlugin
          implements MouseListener {
          
              public MyPopupGraphMousePlugin() {
                  this(MouseEvent.BUTTON3_MASK);
              }
              public MyPopupGraphMousePlugin(int modifiers) {
                  super(modifiers);
              }
          
              /**
               * If this event is over a node, pop up a menu to
               * allow the user to center view to the node
               *
               * @param e
               */
              protected void handlePopup(MouseEvent e) {
                  final VisualizationViewer<Node,Link> vv =
                      (VisualizationViewer<Node,Link>)e.getSource();
                  final Point2D p = e.getPoint(); 
          
                  GraphElementAccessor<Node,Link> pickSupport = vv.getPickSupport();
                  if(pickSupport != null) {
                      final Node station = pickSupport.getVertex(vv.getGraphLayout(), p.getX(), p.getY());
                      if(station != null) {
                          JPopupMenu popup = new JPopupMenu();
          
                          String center = "Center to Node";
          
                          popup.add(new AbstractAction("<html><center>" + center) {
                              public void actionPerformed(ActionEvent e) {
          
                                  MutableTransformer view = vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.VIEW);
                                  MutableTransformer layout = vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.LAYOUT);
          
                                  Point2D ctr = vv.getCenter(); 
                                  Point2D pnt = view.inverseTransform(ctr);
          
                                  double scale = vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.VIEW).getScale();
          
                                  double deltaX = (ctr.getX() - p.getX())*1/scale;
                                  double deltaY = (ctr.getY() - p.getY())*1/scale;
                                  Point2D delta = new Point2D.Double(deltaX, deltaY);
          
                                  layout.translate(deltaX, deltaY);
                              }
                          });
          
                          popup.show(vv, e.getX(), e.getY());
                      } else {
          
                      }
                  }
              }
          }
          

          已编辑:终于!具有比例因子计算的正确节点到中心视图...

          【讨论】:

          • 其实这段代码也有问题。仅管理比例是不够的,在去缩放时,布局空间中视图中心的计算不正确...仍然缺少真正的解决方案...
          • 澄清:当使用鼠标滚轮和 GraphZoomPane 进行缩放和缩小时,视图存在隐式转换,我认为问题出在此处。
          • 当我提供此解决方案时,我在 JUNG2 WorldMapGraphDemo.class 示例中使用的 StaticLayout 上对其进行了测试。使用这种布局验证目标位置真的很容易。复查查看位置,可以参考stackoverflow.com/questions/5663897/…
          猜你喜欢
          • 1970-01-01
          • 2017-04-04
          • 2023-03-03
          • 1970-01-01
          • 2022-06-11
          • 1970-01-01
          • 2022-01-20
          • 2019-08-25
          • 1970-01-01
          相关资源
          最近更新 更多