javajgraphx

Rotate an edge label in JgraphX


I have an edge which is vertical and I want to rotate the edge-label accordingly.

For example replace the "helloworld.java" drawing part with:

try
{
    Object v1 = graph.insertVertex(parent, "1", "TopLeft",
        20, 20, 80, 80);
    Object v3 = graph.insertVertex(parent, "2", "BottomLeft",
        20, 240, 80, 80);
    Object e1 = graph.insertEdge(parent, null, "edgelabel", 
        v1, v3, "dashed=true;endArrow=none;rotation=0");
}

Setting rotation=90 rotates the edge but not the label. I found mxCurveLabelShape, but I do not understand how to use it. I tried somewhat, but the edge-mxCell does not contain a mxCurve. I tried:

 List<mxPoint> pl = ((mxCell)e1).getGeometry().getPoints();
 mxCellState ecs1 = new mxCellState(graph.getView(),e1,null);
 mxCurveLabelShape cls = new mxCurveLabelShape(ecs1,(mxCurve)pl);

which obviously cannot work since the edge mxCell also does not contain non-empty mxPoints. Could I use the locations where the edge connects to its ends? Is there a way to address only the label and use rotation for that?

Any ideas?


Solution

  • OK, I have figured it out, it's not pretty and it does not (yet) work for orthogonal edges, i.e., edges that consist of horizontal and vertical segments.

    The way I can make it work is by overwriting one and introducing one function for mxGraphComponent. Namely, the drawLabel function now checks whether the label comes from an edge and if so it selects a different createTemporaryGraphics function. In the latter the box of the edge as well as the label is known and the rotation is computed given the edge-box. There is a boolean passed along (quadrant) which tells if the edge is between NorthEast and SouthWest of the rectangle (quadrant = true), or between NorthWest and SouthEast (quadrant = false). This is currently not optimal in the sense of location (i.e., vertical labels might end on top of the edge). But I leave the tweaking for whoever wants to use this ;)

    Here we go: (place this wherever you initiate the graphComponent)

    mxGraphComponent graphComponent = new mxGraphComponent(graph){
    public mxInteractiveCanvas createCanvas()
        {
            return new mxInteractiveCanvas(){
                @Override
                public Object drawLabel(String text, mxCellState state, boolean html)
                {
                    Map<String, Object> style = state.getStyle();
                    mxIShape shapeL = getShape(style);
                    mxITextShape shape = getTextShape(style, html);
                    if (g != null && shape != null && drawLabels && text != null
                            && text.length() > 0)
                    {
                        // Creates a temporary graphics instance for drawing this shape
                        float opacity = mxUtils.getFloat(style,
                                mxConstants.STYLE_TEXT_OPACITY, 100);
                        Graphics2D previousGraphics = g;
                        if(((mxCell) state.getCell()).isVertex()){
                            g = createTemporaryGraphics(style, opacity, null);                                  
                        }else{
                            //quadrant will be true if the edge is NE or SW
                            Object target = ((mxCell) state.getCell()).getTarget();
                            Object source = ((mxCell) state.getCell()).getSource();
                            boolean quadrant = false;
                            if(((mxCell)target).getGeometry().getCenterX()<((mxCell)source).getGeometry().getCenterX()){
                                if(((mxCell)target).getGeometry().getCenterY()>((mxCell)source).getGeometry().getCenterY()){
                                    quadrant =  true;
                                }
                            }
                            if(((mxCell)target).getGeometry().getCenterX()>((mxCell)source).getGeometry().getCenterX()){
                                if(((mxCell)target).getGeometry().getCenterY()<((mxCell)source).getGeometry().getCenterY()){
                                    quadrant =  true;
                                }
                            }
                            g = createTemporaryGraphics(style, opacity, state, state.getLabelBounds(),quadrant);
                        }
    
                        // Draws the label background and border
                        Color bg = mxUtils.getColor(style,
                                mxConstants.STYLE_LABEL_BACKGROUNDCOLOR);
                        Color border = mxUtils.getColor(style,
                                mxConstants.STYLE_LABEL_BORDERCOLOR);
                        paintRectangle(state.getLabelBounds().getRectangle(), bg, border);
    
                        // Paints the label and restores the graphics object
                        shape.paintShape(this, text, state, style);
                        g.dispose();
                        g = previousGraphics;
                    }
    
                    return shape;
                }
                public Graphics2D createTemporaryGraphics(Map<String, Object> style,
                        float opacity, mxRectangle bounds, mxRectangle labelbounds, boolean quad)
                {
                    Graphics2D temporaryGraphics = (Graphics2D) g.create();
    
                    // Applies the default translate
                    temporaryGraphics.translate(translate.x, translate.y);
    
                    // setup the rotation for the label
                    double angle = java.lang.Math.atan(bounds.getHeight()/bounds.getWidth());
                    double rotation = Math.toDegrees(angle);
                    if(quad){
                        rotation = - rotation;
                    }
                    //get the translation needed
                    double diff = labelbounds.getHeight()*(1-Math.cos(angle));
                    double plusy = diff * Math.sin(angle);
                    double plusx = diff * Math.cos(angle);
                    // Applies the rotation and translation on the graphics object
                    if (bounds != null)
                    {
                        if (rotation != 0)
                        {
                            temporaryGraphics.rotate(Math.toRadians(rotation),
                                    labelbounds.getCenterX(), labelbounds.getCenterY());
                            temporaryGraphics.translate(
                                    - plusx, plusy);
                        }
                    }
    
                    // Applies the opacity to the graphics object
                    if (opacity != 100)
                    {
                        temporaryGraphics.setComposite(AlphaComposite.getInstance(
                                AlphaComposite.SRC_OVER, opacity / 100));
                    }
    
                    return temporaryGraphics;
                }
            };
        }
    
    };