Thursday, November 29, 2012

Shapes Shapes Shapes...

Hi there,
Today I have just something small for you that might be handy in some situations. In JavaFX you could use SVG paths in CSS files to style e.g. a Region. One use case for this could be the arrow in combo box control etc.
My problem was that I needed to convert a JavaFX Path object into a SVG path and so I wrote a little method that did the trick.
Well after I wrote this method I thought it might become handy to have a tool that could convert all available JavaFX Shapes into SVG paths. The available Shapes at the moment are

  • Arc
  • Circle
  • CubicCurve
  • Ellipse
  • Line
  • Path
  • Polygon
  • Polyline
  • QuadCurve
  • Rectangle
  • SVGPath
  • Text
To convert SVGPath into a SVG path doesn't make sense and converting Text into a SVG path is not possible at the moment because there is no way to get the Path from a Shape (which I would love to see in a future version). Means there is no support for SVGPath and Text but for all the other Shapes I created a class named ShapeConverter that contains the following public static methods...
  • shapeToSvgString(Shape param)
  • shapeToSvgPath(Shape param)
  • convertArc(Arc param)
  • convertCircle(Circle param)
  • convertCubicCurve(CubicCurve param)
  • convertEllipse(Ellipse param)
  • convertLine(Line param)
  • convertPath(Path param)
  • convertPolygon(Polygon param)
  • convertPolyline(Polyline param)
  • convertQuadCurve(QuadCurve param)
  • convertRectangle(Rectangle param)

So you could either convert a Shape object to a String like this...


Line line = new Line(10, 10, 50, 50);
String svgString = ShapeConverter.shapeToSvgString(line);
System.out.println(svgString);
M 10 10 L 50 50


    or convert a Shape object to a SVGPath object like this...


    Line line = new Line(10, 10, 50, 50);
    
    SVGPath svgPath = ShapeConverter.shapeToSvgPath(line);
    System.out.println(svgPath.getContent());
    M 10 10 L 50 50


    or you could directly use the specific method if you know what kind of Shape you would like to convert to a String.

    I commited the ShapeConverter class to the JFXtras project so if you are interested in the code, please take a look here.

    If you just would like to see the code...no problem...

    I'm not sure if this might be useful for someone but I needed it and thought it might be worth sharing it with you...


    UPDATE:
    It is now possible to convert also Text into SVG paths. I used a little trick to do this. Because Text is a special form of a Shape it's possible to do something like 

    Shape.subtract(new Text("Han Solo"), new Rectangle(0, 0)) 

    This will return a Shape which is a Path and contains the path of the text. And a Path could be converted into a SVG path :)
    That means you could use it to create SVG symbols from characters which might be useful when using a Symbol font.

    so have fun and keep coding...

    5 comments:

    1. Hi.

      Great ! Inkscape does allow to transform objets to path in order to manipulate the edges. Usefull if we want to disrupt a shape starting from a known one.
      Just a simple though, may you us isAssignableFrom() instance of Class equality in order to handle inheritage ?

      Thanks

      MrLoNee

      ReplyDelete
    2. Is there any way available to use directly SVG file as JavaFX node?

      ReplyDelete
      Replies
      1. Hi Frank,
        Not directly but you can use SVGPath in Code or -fx-path in CSS for svg paths.
        Cheers,
        Gerrit

        Delete
      2. Hi Gerrit,

        I've came across your blog and I'm currently using your ShapeConverter class to translate Javafx nodes to SVG. My goal is to produce a PDF which keep everything in vectors; I'm using Apache FOP to do the conversion.

        My current issue is migrating the clip on a node. The equivalent in SVG is ClipPath but the including shapes are not using the layout properties (stroke-width). I've tried to use the static methods union/intersect/subtract on the Shape class but these don't use the layout properties. Is there a way of producing a new Shape which includes the stroke width already in the shape definition?

        Cheers,
        Ced.

        Delete
      3. Hi Cedric,

        Did I get it correct, if you clip a shape with another shape, the resulting shape should get the same stroke as the original shape? It should be no problem applying the style vrom the original shape to the new shape...but maybe I got it wrong. It might be easier to understand by using a real code example.

        Cheers,

        Gerrit

        Delete