## Hand drawing effect with JavaFX

Some days ago Thierry Wasylczenko blogged about 12 of his favorite JS libs. On of the libs is js-sequence-diagrams that I did know. By using the library you can draw sequence diagrams in a browser. I really like the hand drawn theme of the tool that draw all the diagrams like they are sketched with a pen. Here is an example of the theme:

After having a look at the source code of js-sequence-diagrams I found the methods that render all the hand drawn lines. Cubic curves are used here and the control points of the curves are calculated by using random values. These two control points define the bend of the curve as you can see in the following picture:

Once I’ve seen this I wanted to try if I can do the same with JavaFX 🙂

Thankfully JavaFX contains support for cubic curves. The Path shape can contain curves that can be defined by the CubicCurveTo class. By using this class you can create lines and shapes that look like hand drawn onces by using the same algorithm as in js-sequence-diagrams. I created a simple test class that draws some arrows, lines and rectangles by using this algorithm. Here are some results:

As you can see in the picture the shapes look different in each of them. This is caused by the random values that are part of the algorithm. If you want to try this here is my one class gist that contains all the code:

Thanks, I’ll definitely use that 🙂 I’m curious though. Is there a reason why you didn’t use the inbuilt functions and instead used the core math (sqrt, cos, sin, etc)? Because e. g. instead of

`double wobble = Math.sqrt((endPoint.getX() - startPoint.getX()) * (endPoint.getX() - startPoint.getX()) + (endPoint.getY() - startPoint.getY()) * (endPoint.getY() - startPoint.getY())) / 25;`

you could as well have used

`double wobble = startPoint.distance(endPoint) / 25;`

I tried with less math 😀

public Shape createHandDrawnArrow(double x1, double y1, double x2, double y2, double strokeWidth, Color color) {

Point2D startPoint = new Point2D(x1, y1);

Point2D endPoint = new Point2D(x2, y2);

double arrowLength = strokeWidth * 5;

// create curve

CubicCurve line = createHandDrawnLine( startPoint, endPoint, strokeWidth, color);

// create arrow

CubicCurve arrowLeft = createHandDrawnLine( new Point2D( 0,0), new Point2D(5, arrowLength), strokeWidth, color);

CubicCurve arrowRight = createHandDrawnLine(new Point2D( 0,0), new Point2D(-5, arrowLength), strokeWidth, color);

Shape arrow = Shape.union(arrowLeft, arrowRight);

// get angle at end point

Point2D tan = new Point2D( line.getEndX() - line.getControlX2(), line.getEndY()-line.getControlY2());

double angle = Math.atan2( tan.getY(), tan.getX());

// set rotation for arrow

Rotate rz = new Rotate();

rz.setAxis(Rotate.Z_AXIS); // pivot point

rz.setAngle(Math.toDegrees(angle) + 90); // rotate works in deg instead of rad; arrow origin is top => apply additional offset of 90 deg

// move arrow from 0/0 to end point

arrow.setTranslateX(endPoint.getX());

arrow.setTranslateY(endPoint.getY());

arrow.getTransforms().add(rz);

return Shape.union(line, arrow);

}

public CubicCurve createHandDrawnLine(Point2D startPoint, Point2D endPoint, double strokeWidth, Color color) {

double wobble = startPoint.distance(endPoint) / 25;

double r1 = Math.random();

double r2 = Math.random();

double xfactor = Math.random() > 0.5 ? wobble : -wobble;

double yfactor = Math.random() > 0.5 ? wobble : -wobble;

Point2D control1 = new Point2D((endPoint.getX() - startPoint.getX()) * r1 + startPoint.getX() + xfactor, (endPoint.getY() - startPoint.getY()) * r1 + startPoint.getY() + yfactor);

Point2D control2 = new Point2D((endPoint.getX() - startPoint.getX()) * r2 + startPoint.getX() - xfactor, (endPoint.getY() - startPoint.getY()) * r2 + startPoint.getY() - yfactor);

`CubicCurve curve = new CubicCurve( startPoint.getX(), startPoint.getY(), control1.getX(), control1.getY(), control2.getX(), control2.getY(), endPoint.getX(), endPoint.getY());`

curve.setStrokeLineCap(StrokeLineCap.ROUND);

curve.setStroke(color);

curve.setStrokeWidth(strokeWidth + (strokeWidth * (Math.random() - 0.5) / 8.0));

curve.setStrokeType(StrokeType.CENTERED);

curve.setFill(null);

return curve;

}

Oh, cool 🙂 I don’t saw this method

Pingback:JavaFX links of the week, November 17 // JavaFX News, Demos and Insight // FX Experience

thanks, been looking for this sketch-effect since last year! Eureka!