Wednesday, October 18, 2017

Simple countdown timer

Aloha,

When I was searching the web I stumbled upon a countdown timer that looks like this...



or this...





When I saw that I thought this should be easy to do with my TilesFX library...BUT I also saw that I did not have a Tile that simply shows a big character in the center.

So I've quickly created a CharacterTileSkin and added it to the library and now I'm able to create such a timer very easily by myself :)

First of all here is a screenshot of my version of the countdown timer...



As you can see this is really a very simple skin and it just took me a couple of minutes to create it. The code which is needed to create the timer looks like this...


public class Test extends Application {
    private static final int            SECONDS_PER_DAY    = 86_400;
    private static final int            SECONDS_PER_HOUR   = 3600;
    private static final int            SECONDS_PER_MINUTE = 60;
    private              Tile           days;
    private              Tile           hours;
    private              Tile           minutes;
    private              Tile           seconds;
    private              Duration       duration;
    private              long           lastTimerCall;
    private              AnimationTimer timer;


    @Override public void init() {
        days     = createTile("DAYS", "0");
        hours    = createTile("HOURS", "0");
        minutes  = createTile("MINUTES", "0");
        seconds  = createTile("SECONDS", "0");

        duration = Duration.hours(72);

        lastTimerCall = System.nanoTime();
        timer = new AnimationTimer() {
            @Override public void handle(final long now) {
                if (now > lastTimerCall + 1_000_000_000l) {
                    duration = duration.subtract(Duration.seconds(1));

                    int remainingSeconds = (int) duration.toSeconds();
                    int d = remainingSeconds / SECONDS_PER_DAY;
                    int h = (remainingSeconds % SECONDS_PER_DAY) / SECONDS_PER_HOUR;
                    int m = ((remainingSeconds % SECONDS_PER_DAY) % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE;
                    int s = (((remainingSeconds % SECONDS_PER_DAY) % SECONDS_PER_HOUR) % SECONDS_PER_MINUTE);

                    if (d == 0 && h == 0 && m == 0 && s == 0) { timer.stop(); }

                    days.setDescription(Integer.toString(d));
                    hours.setDescription(Integer.toString(h));
                    minutes.setDescription(String.format("%02d", m));
                    seconds.setDescription(String.format("%02d", s));

                    lastTimerCall = now;
                }
            }
        };
    }

    @Override public void start(Stage stage) {

        HBox pane = new HBox(20, days, hours, minutes, seconds);
        pane.setPadding(new Insets(10));
        pane.setBackground(new Background(new BackgroundFill(Color.web("#606060"), CornerRadii.EMPTY, Insets.EMPTY)));

        Scene scene = new Scene(pane);

        stage.setTitle("Countdown");
        stage.setScene(scene);
        stage.show();

        timer.start();
    }

    @Override public void stop() {
        System.exit(0);
    }

    public static void main(String[] args) {
        launch(args);
    }

    private Tile createTile(final String TITLE, final String TEXT) {
        return TileBuilder.create().skinType(SkinType.CHARACTER)
                          .prefSize(200, 200)
                          .title(TITLE)
                          .titleAlignment(TextAlignment.CENTER)
                          .description(TEXT)
                          .build();
    }
}

The CharacterTileSkin is part of the latest TilesFX release which is 1.4.7. and which can be found on github and bintray as always.

On the second example image above you see some kind of so called split flap like countdown timer and because I've created that control several times in different technologies I thought it might be a nice idea to have a tile that looks and works like a split flap element.

Well long story short, I've added a FlipTileSkin to TilesFX and here it is in action...



For those of you who would like to understand how such a SplitFlap element works you might want to check out wikipedia.

You can provide an array of strings which will be used for the set of characters the split flap element can display. To make it more convenient for you I've already added some useful sets of characters like

  • Numbers from 0 to 5 (Helper.TIME_0_TO_5) useful for clocks
  • Numbers from 5 to 0 (Helper.TIME_5_TO_0) useful for countdown timers
  • Numbers from 0 to 9 (Helper.TIME_0_TO_9) useful for clocks and other numbers
  • Numbers from 9 to 0 (Helper.TIME_9_TO_0) useful for countdown timers
  • Numbers from 0 to 12 (Helper.TIME_0_TO_12) useful for clocks
  • Numbers from 12 to 0 (Helper.TIME_12_TO_0) useful for countdown timers
  • Numbers from 1 to 23 (Helper.TIME_0_TO_24) useful for clocks
  • Numbers from 23 to 0 (Helper.TIME_24_TO_0) useful for countdown timers
  • Numbers from 0 to 9 and Space (Helper.NUMERIC)
  • Numbers from 0 to 9, Space and Characters from A-Z (Helper.ALPHANUMERIC)
  • Characters from A-Z and Space (Helper.ALPHA)
  • Characters from A-Z, Space and some special Characters (Helper.EXTENDED)
  • Characters from A-Z, Space, some special Characters and Umlauts (Helper.EXTENDED_UMLAUTE)
With this predefined set of characters you should be able to easily create a split flap panel.
In addition you can define the flipTime in milliseconds that will be used for each flip of the split flap element. To set the split flap element to a new character simply call the setFlipText method.

Attention:
Keep in mind that setting the text of the split flap element to a new character might lead to a lot of "flapping" before the element reaches the new character. Meaning to say do not call the setFlipText method before the split flap element has reached the new character, otherwise it will lead to bad visual effects.
So if you provide a characterList of 10 characters and set the flipTime to 1000ms in worst case setting the new character will take 10 seconds!

And this is the code you need to set the new skin...


Tile tile = TileBuilder.create()
                       .skinType(SkinType.FLIP)
                       .prefSize(200, 200)
                       .characters(Helper.ALPHANUMERIC)
                       .flipTimeInMS(500)
                       .flipText(" ")
                       .build();

Because I use a pseudo 3D animation here you might want to create a JavaFX camera and set it to the scene as follows...


PerspectiveCamera camera = new PerspectiveCamera();
camera.setFieldOfView(7);

Scene scene = new Scene(pane);
scene.setCamera(camera);

This camera will give you a better 3D effect during the flipping of the split flap element.

I've added the code for the countdown to the tilesfxdemo project which can also find on github.


Well that's it...a quick and simple way to create a JavaFX countdown timer with TilesFX...keep coding...

Friday, October 13, 2017

Friday Fun XLVII - Back to life...

Back to life...

after all that Serverside stuff in Singapore during the last months I'm finally back home and even more important back into JavaFX :)
So this week I have created a little JavaFX control which I saw on my iPhone and Mac. If you know iTunes you know that little progress/timer control which Apple uses to visualize the download of a song and also the playtime of that song.
It is not a really fancy control but maybe that is the reason why I like it, it is simple and does not need any explanation...very nice.
So here is a little screenshot of the control I'm talking about...




Yes it is very small so I did what I always do as a first step...I create a drawing which looks like follows...





So this control has more or less three states

  • STOPPED
  • WAITING
  • RUNNING
These states have different visualizations as you can see in the image above. 
The STOPPED state is visualized with a ring and a play icon which indicates to click it to start a process.
In the waiting state the color is different and the outer ring has a gap and is rotating. In addition the icon changed from a play icon to a stop icon which indicates that you can stop the waiting by pressing the control.
In the running state the color changed back to the original one and the progress is visualized by an additional progress bar.
In my implementation the control will fire events in different situations, so you will find a TimerEvent class which has a Type. The types are as follows...
  • STARTED       (fired when the timer was started)
  • STOPPED       (fired when the timer was stopped)
  • CONTINUED   (fired when the timer was stopped and not finished yet)
  • FINISHED       (fired when the timer finished)
  • RESET           (fired when the reset() method was called)
  • WAITING       (fired when the timer was set to waiting)
You can attach a TimerEventListener to the control and your program can react on the different events that the control will fire.
The control has the following properties which you can use...
  • backgroundColor
  • color
  • waitingColor
  • playButtonVisible
  • duration
Most of the properties are self explaining so I will only shortly explain the playButtonVisible property.
Because this control might also come in handy when visualizing a download etc. it is not always needed to show the play button but only the stop button when it is running. For this reason the play button can be switched off.
The duration defines the time the control will running until it is finished.

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


Attention: 
I have no really use case for this control and just created it because I like it and would like to see how much does it take to implement it in JavaFX

Well that's it for today, so as always you will find the code over at github...

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

Wednesday, June 14, 2017

TilesFX 1.4.4

Aloha,

Just on time before my next visit to Singapore I was able to release a new version of TilesFX. Last weekend I finally found some time to add some more features to TilesFX which I had on my list for some time.
First of all I've added a skin that simply shows a smoothed area chart called SmoothAreaChartTileSkin. As parameters you just have to add a list of ChartData objects.
The skin looks as follows...



This might sometime be useful for some dashboards if you would like to keep it simple :)

The next one that I've added is a RadarChartTileSkin which has two different Modes (Mode.POLYGON and Mode.SECTOR). Also the RadarChart takes a list of ChartData objects as parameter in Tile. The two different modes will look as follows...



As you can see both variants can be useful. In the example above I've used the RadarChart to visualize the temperature on every hour of the day which gives a nice temperature overview for measurements.
For the RadarChartTile I have implemented a limit of 128 ChartData elements which will be supported. The reason for this is that if you have more than 128 elements in a RadarChart you can't identify any value on the chart any more.

The third new skin I've added is a CountryTileSkin. In principle this tile simply shows the selected country as a SVGPath and a value with a unit.
This might come in handy if you would like to compare the data of a few countries on a dashboard with a little eye candy.
The CountryTileSkin looks like this...



Nothing really special but like I said...sometimes it could be handy :)
Because if I only show a single country I need SVG paths with a higher resolution which is the reason why I've added the hires.properties file that contains the SVG paths for nearly all countries that you can also find in Java Locale.
The problem with this high resolution SVG paths is that they are big...the properties file alone is 1.3 MB which is the reason why the library is now 1.3 MB big.
For the WorldTileSkin I've only used lo resolution SVG paths where the file is only 125kb big but they don't look nice when used as a single country.

Well that's it for today, as always you can find the source code and binaries here:

Source Code: github

Binaries      : bintray

If you would like to know how to use the different skins in TilesFX you might want to check out the code from github and take a look at the Demo.java Class that is part of the TilesFX library. If you run this Demo.java Class you will get this...



In this demo I make use of nearly all skins that are available in TilesFX at the moment.

If you have any idea for tiles you need for you dashboard, please let me know and don't forget...keep coding... ;)

Friday, June 9, 2017

Java Geek Bike Ride + BBQ

Aloha,

Over the years it became some kind of tradition that the Java User Group M√ľnster organizes a little community event...the Java BBQ at my place in the summer. But this year I thought we need to improve that a bit. Instead of only having the BBQ, I thought we first should do some exercise before we start the BBQ :)
And for that reason we will do a little Java Geek Bike ride this year followed by the traditional Java BBQ.
So here is my plan for our ride...it's around 25km which should be ok because we are not on a hurry..



Because we'll do the bike ride everyone who would like to attend should bring a bike :)
And no worries...it won't be a race but a relaxed ride with enough time to have some "Fahrbier" ;)
If you have no chance to bring a bike with you, I could offer one more bike, otherwise feel free to only join the BBQ part. I could also offer a place to sleep for at least 2 person so just let me know if you need a place to stay, otherwise there are some B&B close by which might work for you.
As always feel free to present things you would like to talk about, e.g. last year one of our attendees presented some interesting stuff which ended in a session at the JavaLand conference... :)

The date for the Java Geek Bike Ride + BBQ will be the 

Saturday the 29th of July

I would suggest that we will start not too late which means maybe around 12pm.
As always I will take care about the drinks and you only have to bring some stuff for the BBQ.
Everyone should bring the kind of meat/sausages etc. she/he would like to eat and it would be awesome if some of you might be able to also bring some salad and bread for the BBQ.

If you are interested but don't know if you are "allowed" to come...just ping me...everybody is welcome as always.

You can find the place here:



Looking forward to spend a great day with you guys...

Keep coding...

Thursday, June 8, 2017

Another new TilesFX skin...

Aloha,

Last time when I was sitting in Singapore skimming the web for some interesting stuff I've stumbled upon a dashboard where a gauge was in front of a line graph. Unfortunately I did not save the image but it was stuck in my head and I thought it might sometime be useful to see not only the current value but also a little history of formerly measured values.
Here is a little screenshot of what I came up with...


As you can see the control shows a bar graph gauge which visualizes the current value. In the center of this gauge you will find a line graph that shows the history of the measured values. In this case I've made use of the strokeWithGradient() feature in combination with gradientStops() to color the line graph.
The time in the lower right corner shows the time of the last update and the text in the lower center shows the time from the first measurement in the line graph to the last measurement.
I think I should also add min- and maxValue to the gauge to get a better idea about the possible range but that's not done yet.
I can imagine that this kind of visualization might be interesting for some use cases but to be honest I'm not sure :)

The new skin can be found in the latest release of TilesFX (1.4.3) which you can find here

Source: github

Binary: bintray

The name of the skin is: SkinType.GAUGE_SPARK_LINE

The screenshot above was create using the following TileBuilder code:

tile = TileBuilder.create().skinType(SkinType.GAUGE_SPARK_LINE)
                  .prefSize(400, 400)
                  .minValue(0)
                  .maxValue(100)
                  .title("Data")
                  .text("Test")
                  .textVisible(false)
                  .averagingPeriod(25)
                  .autoReferenceValue(true)
                  .tooltipText("")
                  .barColor(Tile.YELLOW_ORANGE)
                  .barBackgroundColor(Color.rgb(255, 255, 255, 0.1))
                  .sections(new Section(0, 33, Tile.LIGHT_GREEN),
                            new Section(33, 67, Tile.YELLOW),
                            new Section(67, 100, Tile.LIGHT_RED))
                  .sectionsVisible(true)
                  .highlightSections(true)
                  .animated(true)
                  .strokeWithGradient(true)
                  .gradientStops(new Stop(0.0, Tile.LIGHT_GREEN),
                                 new Stop(0.33, Tile.LIGHT_GREEN),
                                 new Stop(0.33,Tile.YELLOW),
                                 new Stop(0.67, Tile.YELLOW),
                                 new Stop(0.67, Tile.LIGHT_RED),
                                 new Stop(1.0, Tile.LIGHT_RED))
                  .build();

And that's it for today, short but hopefully useful :)

Keep coding...

Monday, May 1, 2017

Formatting numbers in Medusa

Aloha,

Because of the the current project in Singapore I do not have a lot of time to code JavaFX but I try make use of every minute I can find :)
Last week someone found an interesting bug in Medusa that I was not aware of because it never showed up in my tests.
The following screenshot of the bugreport directly shows the problem...


The gauges on the screenshot use the Medusa DashboardSkin and the interesting part is the visualization of the value text.
In Medusa I have a method to adjust the font size so that the given text will fit into a given width. Means if the width of the given text will exceed the given width the font size will be decreased as along as the text will fit in the given width.
This behaviour leads to the different font size used for e.g. -54.90 and 0.0 in the screenshot above.
Well if you just use one gauge or all gauges are always in the same range this is no problem but if you have multiple gauges with values in different ranges (which is often the case) it simply doesn't look good.
So I've started to fix this problem and figured out that it was not that easy as I first thought.

The solution to this problem (at least the one that I've found...there might be better ones) is as follows.
First I figure out the longest text for the value. Therefor I measure the length of the minValue and the maxValue text. When doing this I have to take the number of decimals into account that was set by the user. Doing this gives me the maximum number of characters that can appear in the value text incl. the minus for negative values.
With having this numbers I can make use of the String.format() method to make sure the text will be formatted the right way.
But before I can do that I also have to take into account that instead of rounding the values I would like to simply cut of the decimals after the given number of decimals.
Therefor I have to take into account to use Math.floor() for positive and Math.ceil() for negative values when using String.format().
You might think why not simply use NumberFormat in combination with DecimalFormat because with this you can use patterns like "000.00" and a RoundingMode to format numbers but here you will run into problems with negative numbers and their minus character.
Well like I mentioned my solution might not be the perfect one but it works for Medusa and because of the limited time I have it is good enough for me :)

Here is a method that will format a given value in the range of the given min- and maxValue, the given number of decimals and the given locale...

public static String formatNumber(final Locale LOCALE, final double MIN_VALUE, 
                                  final double MAX_VALUE, final int DECIMALS, 
                                  final double VALUE) {
    StringBuilder sb        = new StringBuilder("%.").append(DECIMALS).append("f");
    String        f         = sb.toString();
    int           minLength = String.format(Locale.US, f, MIN_VALUE).length();
    int           maxLength = String.format(Locale.US, f, MAX_VALUE).length();
    int           length    = Math.max(minLength, maxLength);

    StringBuilder formatStringBuilder = new StringBuilder("%").append(length).append(".").append(DECIMALS).append("f");
    String        formatString        = formatStringBuilder.toString();

    double value = VALUE;
    if (value > 0) {
        value = Math.floor(VALUE * Math.pow(10, DECIMALS)) / Math.pow(10, DECIMALS);
    } else if (value < 0) {
        value = Math.ceil(VALUE * Math.pow(10, DECIMALS)) / Math.pow(10, DECIMALS);
    }

    return String.format(LOCALE, formatString, value);
}

I don't know if this might be useful for someone else but even if not it fixed the bug in Medusa which is all I wanted :)

That's all for today, so...keep coding...


Friday, April 7, 2017

Friday Fun XLVI - Image Matrix

Aloha,

Last weekend when sitting in my hotel room in Singapore I had the idea to test the performance of my DotMatrix control again. So I thought what about pixelating an image and visualize it using the control.
Well to be honest it was just too easy to do...so here is the result...



On the left side you see the original picture and on the right side the related pixelated matrix image.
So I thought why not adding some text and figured out that when I draw the text on the DotMatrix control I usually set all "transparent" pixels to the dotOffColor which doesn't look good in this example.
Therefor I've added another method to the DotMatrix control which only draws the pixels in a character that are "on". The method is called

  • setCharAtWithBackground()

So with this it was easy to add some text on top of the pixelated image without destroying the existing background pixels.
Now that this was done I decided it might be nice to be able to simply shift the DotMatrix in each direction. Long story short I've implemented for additional methods which are

  • shiftLeft()
  • shiftRight()
  • shiftUp()
  • shiftDown()

When calling one of this methods the whole DotMatrix will be shifted by one dot in the choosen direction and redraws itself.
Now I could really test the capability of the DotMatrix by calling for example the shiftLeft method in an AnimationTimer with an update rate of 10ms. So the result was nice as you can see in the following video...



You could also combine the calls like first calling shiftLeft() and after that shiftUp(). It's not perfect because both times the drawMatrix() method will be called but even with this little drawback the DotMatrix is fast enough to create a smooth scrolling effect.

Please keep in mind that you should not go crazy with the no of dots in the DotMatrix control. You will definitely see a decrease in performance if you go to a high number of columns and rows. In the video I use 100x85 dots for the DotMatrix which I think is good enough to use it also for images.

So I don't have any use case for the DotMatrix control at the moment but maybe one of you has and therefor you can find the source code as always over at github.

You will also find 2 other demos in the source code (Main2 and Main3). In Main2 I show you how to create one DotMatrix out of two images and in Main3 I show you how to use two images and draw them alternating on the DotMatrix...so have fun playing around with it :)

Well that's it for today...like always I wish you a nice weekend and never forget...keep coding... ;)