How to automatically adjust node bounds to the node's label
Applies to: yFiles 2.5, yFiles 2.4 print article email article

Type: Questions & Answers

This article explains how to adjust a node's width and height according to the node's label, and contains a working demo example.

The easiest way to adjust a node's size according to its label is to get noticed whenever the label is being changed. Afterwards one can manually set the node size so that the label will fit.

A NodeLabel can be edited by using Graph2DView.openLabelEditor(y.view.YLabel, double, double) or Graph2DView.openLabelEditor(y.view.YLabel, double, double, java.beans.PropertyChangeListener).
Calling one of these methods will show a TextField where the label can be edited with the difference, that when we use the latter method, we can hand over our own PropertyChangeListener and can adjust the node size whenever the property changed event is fired.

So we can register the following Action to whatever we use to trigger our "edit label" action (PopupMenu, Button, Key Binding).
/**
   * Action that opens a text editor for the label of a node
   */
  class EditNodeLabel extends AbstractAction {
    private NodeLabel label;

    EditNodeLabel(NodeLabel label) {
      super( "Edit Label" );
      this.label = label;
    }

    public void actionPerformed( ActionEvent e ) {
      view.openLabelEditor( label,
          label.getLocation().getX(),
          label.getLocation().getY(),
          getLabelChangeListener()
      );
    }
  }
The set LabelChangeListener will then be informed when the label editing ends and can adjust the node size as follows:
class LabelChangeListener implements PropertyChangeListener{
    private static final int INDENTATION = 5;

    public void propertyChange(PropertyChangeEvent evt) {
      NodeLabel label = (NodeLabel) evt.getSource();
      adjustNodeSize(label.getRealizer());
    }

    void adjustNodeSize(NodeRealizer realizer) {
      NodeLabel label = realizer.getLabel();
      FontMetrics fm = view.getGraphics().getFontMetrics(label.getFont());
      String labelText = label.getText();

      //find max needed width
      Pattern pat = Pattern.compile("(.*)", Pattern.MULTILINE);
      Matcher matcher = pat.matcher(labelText);
      int maxWidth = 0;
      while (matcher.find()) {
        String currentLine = matcher.group();
        int currentWidth = fm.stringWidth(currentLine);
        if (currentWidth > maxWidth) {
          maxWidth = currentWidth;
        }
      }
      if (maxWidth > 0) {
        realizer.setWidth(maxWidth + 2 * INDENTATION);
      } else {//fallback width if no label is set
        realizer.setWidth(view.getGraph2D().getDefaultNodeRealizer().getWidth());
      }

      //find max needed height
      int lineCount = 1;
      for (Matcher m = Pattern.compile("\n").matcher(labelText); m.find();) {
        lineCount++;
      }
      int lineHeight = fm.getHeight();
      if (labelText.length() > 0) {
        realizer.setHeight(lineHeight * lineCount + 2 * INDENTATION);
      } else {//fallback height if no label is set
        realizer.setHeight(view.getGraph2D().getDefaultNodeRealizer().getHeight());
      }
    }
  }
Another possibility would be to register a Graph2DListener on the Graph2D using Graph2D.addGraph2DListener(y.view.Graph2DListener). A Graph2DListener will get Graph2DEvents and can handle them accordingly. To react on node label changes the listener will look as follows:
class LabelChangedListener implements Graph2DListener{
    private static final int INDENTATION = 5;

    public void onGraph2DEvent(Graph2DEvent e) {
      Node v = null;
      String p = e.getPropertyName();
      if(e.getSubject() instanceof NodeLabel && "text".equals(p)){
        v = ((NodeLabel)e.getSubject()).getNode();
      } else if(e.getSubject() instanceof Node &&  "realizer".equals(p)){
        v = (Node)e.getSubject();
      }

      if(v != null){
        adjustNodeSize(view.getGraph2D().getRealizer(v));
      }
    }

    private void adjustNodeSize(NodeRealizer realizer) {
      /** 
       do adjustment here
       */
    }
  }
Warning
When registering a Graph2DListener to the graph, the node size changes will happen everytime the label text is set or the NodeRealizer changes. This does for example also happen when loading the graph and will result in other node sizes than the loaded file really had.
Thus it is recommended to use the first solution for adjusting node labels after they have been edited.
Note
You can download and execute the attached demos. Please save them to <yfilesDir>/src/demo/view/layout/labeling

Keywords: Node - NodeLabel - size - label - node size - width - height - NodeRealizer - realizer - openLabelEditor - PropertyChangeListener - listener

Provide feedback:
How useful was this article?    less 1 2 3 4 5 more
Email address (optional):
COPYRIGHT © 2008 yWorks · ALL RIGHTS RESERVED imprint | top | home