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...

1 comment: