Friday, May 27, 2016

Java(FX) BBQ

Hello again...
Today I don't have any control for you but I would like to announce this years Java(FX) BBQ. It will happen as usual at my place and I will take care about the drinks, so the only thing you need to bring with you is the stuff that you would like to eat.
Well and it might be nice if one or the other could also bring some salad and/or sauce.

Here are the details for the BBQ:

Date      : Saturday, July 2nd
Time     : 3 pm
Location:



And it's not all about meat and beer but if you have something interesting to say/show you are welcome to do a short presentation about your topic.

So if you have the time and if you are in the area, feel free to join and have some fun but please let me know up front if you will join so that I now how many people will show up :)

Enjoy the upcoming weekend...and keep coding... :)

Friday, May 20, 2016

Friday Fun XXX

Aloha to another Friday... :)
Today I have a little component for you which is not really tricky to do but it was on my list for a very long time. So finally I've decided to create it and this time it is a segmented control.
You might have seen this control on various car-park routing systems. In Germany this kind of displays are very common and you will find it in many cities, here are a few examples...




In all of the examples you can see the yellow number display and that is exactly the control I'm talking about.

It looks like the control is build out of 15 elements where each element can have different states. One can see a fully filled element, rounded elements and elements that contains triangles.
So as always the first thing to do is creating a prototype in a vector drawing program and here is what it looks like. This prototype contains most of the needed elements.


I've created an extra control that contains one element and this element can have the following states:
  • EMPTY
  • SQUARE
  • ROUND_UPPER_LEFT
  • ROUND_UPPER_RIGHT
  • ROUND_LOWER_RIGHT
  • ROUND_LOWER_LEFT
  • TRIANGLE_TOP
  • TRIANGLE_UPPER_RIGHT
  • TRIANGLE_RIGHT
  • TRIANGLE_LOWER_RIGHT
  • TRIANGLE_BOTTOM
  • TRIANGLE_LOWER_LEFT
  • TRIANGLE_LEFT
  • TRIANGLE_UPPER_LEFT
  • NOT_TRIANGLE_TOP
  • NOT_TRIANGLE_RIGHT
  • NOT_TRIANGLE_BOTTOM
  • NOT_TRIANGLE_LEFT

The Element contains a StackPane and within this StackPane it holds a SVGPath node. Dependent on the State of the Element the context of this SVGPath node is set. Therefore I've created an enum that not only contains the name of the State but also the SVG path string for each state.
Then I've create the real Segment control that contains a GridPane (3x5) where each position in the grid holds one Element. Now I only needed to create the appropriate states for each Element and each Character. I just implemented the numbers 0-9 which seems to be ok for this kind of display. Well I could not withstand and also implemented the characters A-Z and a "-" which means you could now use 0-9 and A-Z in the Segment control :)

And this is how the control looks like...


As I said this is not a really fancy control but something that I now can take from my todo list :)

Here is also a little video of the control in action...


If you are interested in the code you can find it on github...as always :)

And that's it for today...so enjoy the upcoming weekend and keep coding...

Friday, May 13, 2016

Friday Fun XXIX

Finally Friday again...and with that comes another Friday Fun Component.
This time I stumbled upon a control that doesn't really look that fancy and to make it short here is a picture of what I am talking about...



This control is used over at orangetheory fitness where you do your workout in a group and the trainer can see the individual data on a monitor like on the image. As you can see the control itself is not really fancy but I liked the colors and it has again a little thing which was not that easy to implement.
I just had this image and I have no idea how the control works in reality so the first thing I did was creating a prototype in Adobe Fireworks which looks like follows...



As you can see I've modified the control a bit because I wanted to see the current zone in the lower right and put the BPM label instead of the other number (I have no idea what it means).
With this vector drawing in place it was easy to create the control in JavaFX but there was one little thing that I was missing. There are these little colored trapezoids on the lower left side of the control and if you take a look at the upper image you will see that in whatever zone I'm at the moment the little trapezoid with the same color as the current background is bigger than the others. And exactly this little feature was the main reason to build this control.
This little trapezoids have no special meaning but they give the control a special touch and so I started thinking about how could they work.
The first idea that came to my mind was they should be animated. Means as soon as the heart rate zone changes the trapezoid with the same color should increase it's size using an animation.
Nice idea but it comes with a problem...
Because the trapezoids are all the same just with different colors I thought it should be easy to just create a path for the small and for the big version and morph them when needed. Unfortunately JavaFX doesn't offer a morphing transition by default BUT Tom Schindl (create of E(fx)clipse and on twitter under @tomsontom) has created an excellent PathMorphTransition which takes a source and a target path and animates the points from the source path to the target path. (you can find the PathMorphAnimation class in the Eclipse source code and also in the sources of this friday fun component).
So I've put the 5 trapezoids in an HBox container and I was ready to go...well not really.
The first problem comes with resizing...because the Path is a Shape it has no setPrefSize() method. Well the workaround is to use setScaleX() and setScaleY() on the Path. But this comes with another problem...placement. The problem is that when you scale a node in JavaFX you have to take care about the placement in a different way to make sure that the scaled node stays at the correct position.
Well even this was not a big deal but there was another problem...
When morphing a trapezoid from the small to the big state the layout bounds of the trapezoid will change because we increase the width and height.
And because I've put the trapezoids in an HBox with a spacing of 0 it leads to the following effect...



When the gray trapezoid will be transformed the increase in width will lead to a bigger gap between the gray and the blue trapezoid...BAM
And because I can't adjust the spacing for each child of the HBox this approach did not work. :(
Well there are ways to realize this but that felt like a workaround which I did not like.
So I was looking for another approach and decided that the easiest way would be to create a separate control for the trapezoid that encapsulates the Path object in a Region.
To make this work you have to make sure that the Region always has the size of the big trapezoid. So I can put the Regions in a HBox and because the Region won't change it's layout bounds when the trapezoids morphs from one to the other state the distance between the trapezoids stays the same.
To make sure that the trapezoids are not too far away from each other I've use a negative spacing (keep in mind that when resizing the control you also have to resize the spacing of the HBox).
Long story short...here is the result of my JavaFX version...



To make the control work you have to initialize it with your age. I need that info to calculate the maximum heart rate for the control. The calculation of the maximum heart rate is based on the following equation which seems to be good enough...

    maxBpm = (207 - 0.7 * (age));

There are other equations but it seems this is more accurate (at least that's what I've found on the web).
If you initialize the control with an empty constructor it takes 30 as the default age.
Now you simply have to call the setBpm() method of the control to set the current heart rate and the control will react on it.
Because your heart can beat faster than the recommended max heart rate there is an indication that you are over 100% by blinking the text.
Means if your heart rate is higher than 100% it will still show 100% but the numbers will start to blink as long as your heart rate is higher than 100%.
Well maybe that was not a really fancy control but again it has a little feature that was interesting to implement.

Here is also a little video that shows the control in action...



If you are interested in the code you will find it as always on github.

That's it for today and even if I don't know if I will ever use this control I hope someone of you have learned something...enjoy the upcoming weekend...and keep coding... :)

Friday, April 29, 2016

Friday Fun XXVIII

And another friday which means time for some fun again...
It's interesting but again I've found a control that looks simple when you see it for the first time but at a second look you will figure out that it's not so easy to implement.
So here it is...



Apart from that the white bar seems to be misaligned in the picture above, the control has a neat effect. First of all the semitransparent white ring in the background makes it possible to put that control on whatever color and because it is translucent the background color will shine through like on the picture above.
In addition it comes with some 3D effect that is produced by the drop shadow of this ring.
Exactly this drop shadow is the thing that looks easy to do but it's not and the reason is the following.
If you create a ring (e.g. using a JavaFX Arc object) you can give it a strokeLineWidth and a Color. Adding a DropShadow is a no-brainer in JavaFX and in principle that's all you have to do. But because the Arc is translucent we will see the DropShadow shine through which will make the Arc appear darker which exactly is the problem.
To give you an idea what I'm talking about, here is a little screenshot of the effect...



As you can see we have a nice DropShadow on the Arc but we also see it shine through the ring which makes it appear dark. If you take a look on the picture above you will see that the ring appears bright and translucent plus the DropShadow...so how to achieve that???
Well the answer is trivial but the solution not... :)
First we need to draw an Arc with a DropShadow that will look as follows...



In the next step we have to create a mask that only contains the shadow without the ring, which we can do by creating two rings. Then we subtract the smaller ring from the bigger one like follows...



On the right side we now have our shape that we can use as a clipping mask which will only contain the DropShadow without the orange ring.
Now we can apply this clipping mask to the Arc that has the DropShadow and it will look similar to this (the white should be transparent)...



And in the last step we can draw the final Arc that will be filled with Color.rgb(255, 255, 255, 0.4) so that the background can shine through.
The code to realize this operation will look as follows...


Arc outerRing = new Arc(size * 0.5, size * 0.5,
                         size * 0.43125, size * 0.43125,
                         0, 360);
outerRing.setFill(null);
outerRing.setStroke(Color.WHITE);
outerRing.setStrokeLineCap(StrokeLineCap.BUTT);
outerRing.setStrokeWidth(size * 0.3);

Arc innerRing = new Arc(size * 0.5, size * 0.5,
                        size * 0.43125, size * 0.43125,
                        0, 360);
innerRing.setFill(null);
innerRing.setStroke(Color.WHITE);
innerRing.setStrokeLineCap(StrokeLineCap.BUTT);
innerRing.setStrokeWidth(size * 0.1375);

Shape shape = Shape.subtract(outerRing, innerRing);

backgroundRing.setCenterX(center);
backgroundRing.setCenterY(center);
backgroundRing.setRadiusX(size * 0.43125);
backgroundRing.setRadiusY(size * 0.43125);
backgroundRing.setStrokeWidth(size * 0.1375);
backgroundRing.setClip(shape);

barBackground.setCenterX(center);
barBackground.setCenterY(center);
barBackground.setRadiusX(size * 0.43125);
barBackground.setRadiusY(size * 0.43125);
barBackground.setStrokeWidth(size * 0.1375);


And we have to do this clipping everytime the size of the control changed. The final result of this operations will then look like follows...



And this is exactly how it should look like :)
For the implementation I make use of the Medusa gauge so there is a dependency on the Medusa project.

If you would like to see the code you will find it on github as always.

That's it for today, so I wish you all a nice weekend and...keep coding...

Friday, April 15, 2016

Friday Fun XXVII

And another friday and again time for some fun...
Well this time the control is small...very small and doesn't have any special features but I needed it and so I thought it might be a good idea to create it.
If you own an Android phone you might know the Material Design Circular Progress Indicator (indeterminate) which looks like this...



Like last weeks friday fun component the problem with this control is not obvious. In principle it's a simple arc where the arcs angle extend accelerates until it gets near to the arcs start, then it decelerates and the arc start angle accelerates. This happens in a combination with a rotation of the whole arc which gives us the nice effect.
I've tried different approaches before I came to the conclusion that an animated dashed arc might be the solution.
To be honest it was a lot of trial and error before I got the parameters right (at least good enough for this control).
After I've found a set of parameters that worked out I realized that the whole thing is dependend on the current size of the control. Means if you increase the size of the circle the dash array needs to be updated otherwise you will suddenly see more than one line moving around. Because it tooks some time to figure out the right parameters for one size I've decided to go with the easy approach...simply scaling the circle instead of really resizing it.
To make sure the circle always stays in the center of the pane I've exchanged the Pane (that I usually use) with a StackPane which does the centering for me. With this approach I'm able to create the circle and resize it properly. The progress indicator will switch to the indeterminate state if the progress is < 0. You can simply call .setProgress(ProgressIndicator.INDETERMINATE) to achieve that. If the progress is between 0 - 1 the circle will be replaced by an arc that shows the current progress. I did not add animation to the standard progress (0 - 1) which could be done by yourself if you like...simply animate the progress between 0 and 1 :)
So here is the result and because it doesn't make sense to show you a screen shot I've recorded a little video...




Another tiny blogpost finished...now enjoy your weekend and if you are interested in the code you can find it on github as always...

sources on github

Oh and don't forget...keep coding... :)

Friday, April 8, 2016

Friday Fun XXVI

And Friday again...finally :)
Today I have another little fun JavaFX component for you which took me some time to build. Those of you that own an Apple Watch (unfortunately I don't have one) might know this control already.
It is the Fitness Gauge that looks like this...



Well in principle this is an easy to do control...BUT...if you take close look the engineers/designers at Apple did again a fantastic job by creating this control. First of all it has a conical gradient on each arc (from a darker to a brighter color). Then it has this neat drop shadow at the end of the arc when it overlaps. 
This seems to be easy to implement but it's not...believe me :)
After some tweaking I got a solution that I'm quite happy with and this is what it looks like...



As you can see it's not really the same but it's not bad :)
You can set each bar individually, the max value for each bar and the color. The control is based on my Medusa library and uses three Medusa Gauges for the data model.

Here is also a little video that gives you an impression how it looks like in action...




So I think that's it for today...just a little fun...enjoy and btw if you need the code...here you go...

Github repository

Keep coding...

Thursday, March 10, 2016

Friday Fun XXV

And Friday again...means time for some fun... :)
This time I have two three (I've recently added a ColorRegulator) controls for you. When I was working on my mood light I stumbled upon some nice images on the web and one of those image was the following that I've found on Dribbble...


The temperature control on the right side of the image looked nice to me and I thought it might be worth creating a JavaFX control of it.
The control above only acts as some kind of slider which shows the target value but I thought by myself it would be nice it would also show the current value. Because then one can use it also as a display of the current temperature. So here is what I came up with...


As you can see it's really similar to the original image except some additional features...
  • Target value will be shown on top
  • Icon to visualize the property
  • An overlay on the color bar that shows the current value
The target value and the overlay will disappear as soon as the (int) current value == (in) target value.
When I've started this control I only thought about a temperature control but you can use it for whatever you like. Therefore I've added the possibility to set a custom color gradient for the bar and you could also define your own icon. 
The control will fire three different events
  • RegulatorEvent.TARGET_SET  fired when target value was set (Mouse released)
  • RegulatorEvent.ADJUSTING    in case the (int) current value != (int) target value
  • RegulatorEvent.ADJUSTED      in case the (int) current value == (int) target value
With this you could also use the control to define a point on the scale by using the rotation ring and as soon as the current value will reach the selected value it will fire an event on which you can react...you could think about a battery charger control that informs you if the battery is charged to 80%.
If we take the charger example let's have a look how to configure the control in this case...
FeedbackRegulator feedbackRegulator = 
    FeedbackRegulatorBuilder.create()
                            .prefSize(400, 400)
                            .minValue(0)
                            .maxValue(100)
                            .targetValue(80)
                            .currentValue(25)
                            .unit("%")
                            .gradientStops(new Stop(0.0, Color.RED),
                                     new Stop(0.5, Color.YELLOW),
                                     new Stop(0.75, Color.GREEN),
                                     new Stop(1.0, Color.LIME))
                            .symbolPath(1, 0.71428571, "M 11.7829 11.7647 L 9.3333 20 L 17.5 8.2353 L 12.7171 " +
                                                       "8.2353 L 15.1667 0 L 7 11.7647 L 11.7829 11.7647 ZM 1.1667 " +
                                                       "17.6471 L 8.8138 17.6471 L 9.5156 15.2941 L 2.3333 15.2941 " +
                                                       "L 2.3333 4.7059 L 10.4749 4.7059 L 12.1087 2.3529 L 1.1667 " +
                                                       "2.3529 C 0.5218 2.3529 0 2.8791 0 3.5294 L 0 16.4706 C 0 " +
                                                       "17.1209 0.5218 17.6471 1.1667 17.6471 ZM 26.8333 5.8824 L " +
                                                       "24.5 5.8824 L 24.5 3.5294 C 24.5 2.8791 23.9782 2.3529 23.3333" +
                                                       " 2.3529 L 15.6839 2.3529 L 14.9844 4.7059 L 22.1667 4.7059 " +
                                                       "L 22.1667 15.2941 L 14.0228 15.2941 L 12.3913 17.6471 " +
                                                       "L 23.3333 17.6471 C 23.9782 17.6471 24.5 17.1209 24.5 16.4706 " +
                                                       "L 24.5 14.1176 L 26.8333 14.1176 C 27.4782 14.1176 28 13.5915 " +
                                                       "28 12.9412 L 28 7.0588 C 28 6.4085 27.4782 5.8824 26.8333 5.8824 Z")
                            .build();

As you can see we can define the min- and maxValue of the control, the unit and the stops for the gradient bar. In addition we can define the symbolPath which is a SVG path and to get the scaling right we also have to define the scaleX and scaleY values for this path.
To get this path you usually use a vector drawing program like Inkscape, Adobe Illustrator etc. and export the vector drawing of the icon as SVG file. Usually you will find a <path> tag in the SVG file that should look similar to the above string. Simply copy that string that normally starts with a M for MoveTo and ends with a Z for ClosePath. To get the scaling right you simply have to calculate the scaling factor from the size of the image, e.g. the charging battery icon that I used here has the following size...

width : 28px
height: 20px

Divide the smaller value by the bigger value and set the bigger value to 1.0. This will give us the following values...

scaleY: 20 / 28 = 0.71428571
scaleX: 1.0

That's all you need to set your customized icon in the control and the result of the code above will look like this...


In this case we could also hook up an EventHandler to the FeedbackEvent.ADJUSTED EventType that will be fired as soon as the battery will be charged by 80%. To realize that you can simply add one line to the builder like follows...
.onAdjusted(e -> System.out.println("Battery charge is 80%"))
But you could also attach the handler later on in your code like follows
feedbackRegulator.addEventHandler(RegulatorEvent.ADJUSTED, event -> System.out.println("Battery charge is 80%"));
So far so good but now that I had a control with a ring to set values I thought it might also be useful to have a similar control that really only acts as some kind of a slider.
Long story short...here it is...


As you can see it's very similar to the other control except it can't visualize a current value but only the target value. So you can use it to control for example the brightness of a light etc.
In principle it comes with the same features as the FeedbackRegulator control except the gradient stops and the current value. But it has an additional property which is the barColor. So to create a control with the custom icon you can simply use the same approach as for the FeedbackRegulator. Here is a little example with a different bar color and a unit...
Regulator regulator = RegulatorBuilder.create()
                                      .prefSize(400, 400)
                                      .barColor(Color.rgb(255, 222, 102))
                                      .unit("%")
                                      .build();
And the result will look like this...


I did not implement properties for different colors of the ring, background etc. but if you are interested in changing it I (in the meantime I've added features to change the control color, text color and symbol color.)...fork it on github :)

Here is a screenshot of the currently available regulator controls...


As you can see on the right I've also added another color selector :)

That's it for today...so keep coding...