I've been working with JGraph for a while and it appears there is a painting issue when you set label clipping to true:
The following boiled-down example shows the problem in a living application that you can mess with:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.view.mxGraph;
/** it's an app! */
public class GraphApp extends JFrame {
private mxGraph graph;
private mxGraphComponent graphComponent;
private boolean labelsClipped = false;
/** @return the splitpane */
public JSplitPane getSplitpane() {
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
graph = new mxGraph();
graph.getModel().beginUpdate();
graph.removeCells(graph.getChildCells(graph.getDefaultParent(), true, true));
for (int i = 0; i < 10; i++)
graph.insertVertex(null, null, "very_very_long_vertex_" + i, 10 * i, 10 * i, 100, 50);
graph.getModel().endUpdate();
graph.setLabelsClipped(labelsClipped);
graphComponent = new mxGraphComponent(graph);
JTextArea area = new JTextArea("There's overpaint below this text."); //$NON-NLS-1$
splitPane.add(graphComponent, JSplitPane.LEFT);
splitPane.add(area, JSplitPane.RIGHT);
splitPane.setDividerLocation(70);
return splitPane;
}
private JButton getButton() {
JButton button = new JButton(new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
labelsClipped = !labelsClipped;
graph.setLabelsClipped(labelsClipped);
GraphApp.this.repaint();
}
});
button.setText("Swap setLabelsClipped");
return button;
}
private JPanel getPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.add(getSplitpane(), BorderLayout.CENTER);
panel.add(getButton(), BorderLayout.SOUTH);
return panel;
}
public static void main(String[] args) {
GraphApp app = new GraphApp();
app.add(app.getPanel());
app.setPreferredSize(new Dimension(300, 100));
app.setVisible(true);
app.pack();
}
}
It's also interesting to note, that overpaint only happens within the confines of the vertex. Here are the names with clipping off:
And with clipping on:
I'm looking into the JGraphx source now to see where the problem lies. Has anyone worked around this before? Obviously setting graph.setLabelsClipped(false) works around it, but I'd rather not have my vertex labels spill out over the bounds of my vertices.
I found where the issue lies.
From com.mxgraph.view.mxGraph, if you add this little bit of painting code, you can see that the clip is incorrectly getting set to a rectangle that can be, as evidenced in my example, outside of the actual graph component.
If we paint the clipping area that the label is working with, we can see where the problem lies.
Realistically, we should only be painting the intersection of the original canvas, and the new clipping rectangle. This image shows what the clipping rectangle was before being trampled by the new one:
The fix for this is a simple one:
I'd be interested to hear if the original code did the clip setting as it did intentionally. I kind of doubt it.
My fix also defaults to their implementation in the case that someone does something wacky with their clip shapes, just as a sort of CYA. Probably not needed as clipping isn't guaranteed to work with anything other than rectangles:
http://docs.oracle.com/javase/1.4.2/docs/api/java/awt/Graphics.html#setClip(java.awt.Shape)
It appears that the code lives here on github, so hopefully I can get the fix pushed there:
https://github.com/jgraph/jgraphx