Friday, June 5, 2020

And another one...TilesFX 11.38

Aloha,

Here we go again...the last couple of evenings/nights I've spend creating new skins for TilesFX and because in the meantime I have 4 new skins it's time for another release of TilesFX :)

So let's take a look at the new skins that I have added.

ColorTileSkin
This skin always visualizes the current value in percentage and the background color will change according to the value.
The different colors that will be used are predefined by using sections.
The default sections that will be used if nothing else is defined are:
new Section(0.00, 0.25, ColorSkin.GREEN),
new Section(0.25, 0.50, ColorSkin.YELLOW),
new Section(0.50, 0.75, ColorSkin.ORANGE),
new Section(0.75, 1.00, ColorSkin.RED)
With this sections in place the color will for example be orange if the value is between 50% and 75% of the range that is defined by minValue and maxValue of the tile.
Of course you can override the sections with your own sections but keep in mind that the values of the sections should be in the range of 0.0 to 1.0 as shown in the example above.
That's fine but sometimes you would prefer having more finegrained colors for the values. One solution would be to define lot's of sections but you could also make use of the gradientStops feature in TilesFX.
For this you simply define the color stops you would like to use for the interpolation as follows in the TileBuilder:

tile1 = TileBuilder.create().skinType(SkinType.COLOR)
.prefSize(WIDTH, HEIGHT)
.title("Color (Sections)")
.description("CPU temp")
.text("Text")
.unit("\u0025C")
.animated(true)
.build();

tile2 = TileBuilder.create().skinType(SkinType.COLOR)
.prefSize(WIDTH, HEIGHT)
.title("Color (Gradient)")
.description("CPU temp")
.text("Text")
.unit("\u0025C")
.animated(true)
.gradientStops(new Stop(0.0, Medium.GREEN),
new Stop(0.2, Medium.GREEN_YELLOW),
new Stop(0.4, Medium.YELLOW_ORANGE),
new Stop(0.6, Medium.ORANGE),
new Stop(0.8, Medium.ORANGE_RED),
new Stop(1.0, Medium.RED))
.fillWithGradient(true)
.build();
In principle it would also have been enough to define the 0.0, 0.5 and 1.0 values with for example green, yellow and red to get a similar result.
Long story short, here is a little video of the result where the section approach is on the left side and the gradient approach on the right side:



TurnoverTileSkin
The next new skin that I have added is the TurnoverTileSkin. This skin can be used to show an image with a value and a text and visualize a ranking and a special effect if the given threshold was reached.
The effect I'm talking about is the RotationEffect that I also have added to the library. To make use of the ranking you have to use the Rank class to define the ranks you need.
As an example let's define the ranks, first, second and third as follows:
Rank first  = new Rank(Ranking.FIRST, Color.GOLD);
Rank second = new Rank(Ranking.SECOND, Color.SILVER);
Rank third = new Rank(Ranking.THIRD, Color.web("#cd7f32"));
So each rank has a ranking (the Ranking enum goes from first to tenth) and with a color.
In the following little video I created 5 tiles for some persons and put them in an HBox container. As you will see in the video the ranking changes and will be visualized when the values change. 
In addition you will see the rotation effect kick in as soon as one of the person value reaches the threshold of 500. So here is the video to give you an idea...


Here is some code that gives you an idea how I handle the ranking in the video above.
private Tile createPersonTile(final String title, final String name, final Image image) {
return TileBuilder.create()
.skinType(SkinType.TURNOVER)
.prefSize(300, 300)
.title(title)
.unit("$")
.image(image)
.text(name)
.maxValue(2000)
.threshold(500) // Will trigger the rotationEffect when reached
.animated(true)
.build();
}

private void checkHighscores(final List<Tile> persons) {
List<Tile> sorted = persons.stream()
.sorted(Comparator.comparingDouble(Tile::getValue).reversed())
.collect(Collectors.toList());
sorted.get(0).setRank(first);
sorted.get(0).setValueColor(first.getColor());
sorted.get(0).setUnitColor(first.getColor());

sorted.get(1).setRank(second);
sorted.get(1).setValueColor(second.getColor());
sorted.get(1).setUnitColor(second.getColor());

sorted.get(2).setRank(third);
sorted.get(2).setValueColor(third.getColor());
sorted.get(2).setUnitColor(third.getColor());

for (int i = 3 ; i < sorted.size() ; i++) {
sorted.get(i).setRank(Rank.DEFAULT);
sorted.get(i).setValueColor(Tile.FOREGROUND);
sorted.get(i).setUnitColor(Tile.FOREGROUND);
}
}
The createPersonTile method is used to create the tile for each person and the checkHighscores method is always called after the values have been set.

FluidTileSkin
The next new skin that was added is the FluidTileSkin. This skin shows the current value and visualizes it by filling the background of the tile with a fluid like effect.
The code that is used in the following video looks as follows:

tile = TileBuilder.create().skinType(SkinType.FLUID)
.prefSize(WIDTH, HEIGHT)
.title("Fluid")
.text("Waterlevel")
.unit("\u0025")
.decimals(0)
.barColor(Tile.BLUE) // defines the fluid color
.animated(true)
.build();

If you would like to see a more colorful fluid you can make use of sections or the gradientStops like shown above in the ColorTileSkin example.
Here is how it looks like in action...



FireSmokeTileSkin
The last skin I have added is the FireSmokeTileSkin. Well this is another fun skin to visualize the point where the value exceeds the defined threshold.
As you might guess by the name the preferred usage for this skin might be visualizing a temperature value. 
The code used for the next video looks as follows...
tile = TileBuilder.create().skinType(SkinType.FLUID)
.prefSize(WIDTH, HEIGHT)
.title("Fire Smoke")
.text("CPU temp")
.unit("\u00b0C")
.threshold(70) // triggers the fire and smoke effect
.decimals(0)
.animated(true)
.build();
The best way to describe this skin is to see it in action...so here you go...


As you can see the fire and smoke starts when the value exceeds the threshold of 70 and stops when the value falls back below 70.

Well that was a lot of new stuff and as always you can find the latest version of TilesFX at




That's it for today...so keep coding and stay healthy...

2 comments:

  1. Good afternoon Gerrit,
    Your fantastic work caught my eye when looking for gauges to use in a monitoring system I am creating for my boat. I have several esp32 modules MQTT'ing to a rasp pi running node-red. I find the basic node-red dashboard gauges to be visually unimpressive so went looking for better solutions.

    I am a novice so learning as I go by reading, trying and reading some more. In hunting for beter gauges I stumbled upon your steelseries and was able to implemented a couple before realizing they were from 2011 and that you had further (greatly!) expanded and modernized to your most recent medusa and tilesFX libraries. I read your entire blog from steelseries forward! It is so interesting and applicable to what I am trying to create.

    That brings me to today where I have downloaded medusa from Github into my IntelliJ environment (which I am just beginning to learn as well). This is probably where I am going wrong as I don't know the in's and out's of gradle and intellij just yet - I right clicked on DemoLauncher and select "Run" and was expecting to see a window open with all the gauges but that did not happen. IntelliJ shows that it is being complied. There is one red text exception output during the build "> Task :DemoLauncher.main() Exception in Application start method".

    Any guidance you can provide to get me over this problem or send a link that shows how to execute medusa demo would be greatly appreciated.

    All the best and I am trying to "Keep coding..."!,
    Tim Connolly
    St Petersburg, FL

    ReplyDelete
  2. Hi! Can you help my. I use TileFX for my desktop app, It is really cool lib, but I need input element, like tuning knob and text field in led style. Can you help me?

    ReplyDelete