Tuesday, November 23, 2021

TilesFX 17.0.11

Aloha,

when working with dashboard using my TilesFX library I came across some missing things...first of all I needed a Tile that simply has a text in the center of it. Well nothing easier than that...I simply added a CenterTextTileSkin class that offers exactly this functionality. Here is a little screenshot that shows it in action...


As you can see I needed it to visualize the state of a server. If the server goes down the text will change from "ONLINE" to "OFFLINE" and the background color of the tile will change from green to red...very simple but very effective :)

To change the text you have to set the description of the tile.

Here is the code to create the tile above:

Tile serverTile = TileBuilder.create()
.skinType(SkinType.CENTER_TEXT)
.title("Server")
.text("Last check")
.backgroundColor(Dark.GREEN)
.description("ONLINE")
.build();

The other thing I stumbled upon was the fact that handling big numbers in a dashboard can really suck. When you have a dashboard with lots of tiles, there is sometimes simply not enough space to show those big numbers.

So the idea again is simple...just shorten the big numbers to a more readable format. For example 2350 can become 2.3k and 1230401 can become 1.2M. With this you can also show big numbers in a small tile.

The feature to use here is the property shortenNumbers in Tile. I've added it for some tiles where I thought it might come in handy but there might still be places where it is missing...so if you find a place where it could make sense, please file an issue over at github

You could also use the method Helper.shortenNumber(final long value) to shorten the numbers on your own before you set it somewhere. The method will return the formatted number as a String.

The result of using the shortenNumber property in Tile can be seen in the left Tile on image above.

Those new features can be found in the latest version of TilesFX which is 17.0.11 and which is available on github and also on Maven central.

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


Tuesday, November 16, 2021

Panel Barchart

 Aloha,

I'm currently working on a dashboard where I needed a way to visualize data in a specific way. Let's say we would like to compare the load of 3 servers for each day of a week. And in addition we would like to be able to compare the current week with the last week.

There are probably different ways how you can visualize this and I decided to go with a so called Panel Barchart.

Here is an example of such a chart:


In principle this is some kind of a rotated stacked bar chart where the segments are separated from each other. So my version looks a bit different but you will see it's similar, here you go:


So in the upper chart you see the server load of our 3 servers for this week (of course the numbers don't make sense and are random but you get the idea).

You need to define categories (here it's the days of the week). Now you need to add a series of chart items for each category and each server.

In upper chart eh bars are colored by the categories (workdays = gray, weekend = red). This colors can be defined in the categories. 

If you switch this feature off (colorByCategory = false [default]) it will use the colors of the items in each series.

The chart will show the name of the series on the far left column and the sum of each series on the far right column.

On top of each category column it will show the sum per category (in this case per day). On the upper right corner it will show the overall sum of all values.

Well that's good but sometimes you would like to compare the current values with values from another point in time e.g. last week or last year.

To make this possible you can switch enableComparison to true and as you might already thought you need to define the data of the things you would like to compare.

To be able to compare data you need the exact same number of series in the listOfSeries and the comparisonListOfSeries. In addition the items in the each lisOfSeries need to use the same categories that you use in the comparisonListOfSeries.

When you fullfill these requirements the chart will now show name and the comparisonName in the upper left corner (yes you can set the colors for both of them separately). Now you will also see the items for both series of data and if you like you can also define the colors for the series sums and the category sums separately.

The chart is interactive in the way that you can click on each item and a little popup will show you some text and the value of the item. The text that will be shown in the popup could either be the name of the item or the description of the item. If you set both (name and description) it will take the description.

You can find the code for the example above in the PanelBarChartTest class in the test package of the current jdk17 branch of my charts library.

The latest release is available on github (at the moment it is 17.0.11) and also on maven central.

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


Monday, September 20, 2021

Mission Timer X

Aloha,

Last week I've watched the live stream of SpaceX Mission "Inspiration4". When following the countdown on the screen I saw a nice control on the bottom of the screen...a mission timer. Well my very first Swing control I've created was the mission timer of the Apollo missions. As you can see I always was fascinated by those things... :)

So here is the screenshot I took:


The thing I really liked is the idea of having a circle where the upcoming events moving around. Very nice design. Of course there are details like colors, dots within the event circles etc. So I just had this screenshot and tried to re-create this control in JavaFX.

First thing to do (as always)...create a good vector drawing of the control.

So here you go:


My version also supports days which is the reason why I have the format in the way you see it on the image above. Another thing which I might improve is the changing colors of the items. In my version the color depends on the angle of the item on the circle but I think fading the item color might be better...we will see, maybe I will add this later on.

Also the font is not really the same as the one used by SpaceX. I've tried to find an appropriate one and decided to use the one in the image above.

The intersting thing about this control is that the width of the control is the only thing I used to do all the calculations. This was needed to make sure the aspect ratio of the control is always the same.

The MissionTimerX control also fires events of the type MissionTimerXEvent.PROCESSED. These events will be fired once an item reaches the center of the control which means it happens :)

Here is a little gif that shows the control in action...


And as always the code is available over at github.

Well...that's it...so keep coding...


Wednesday, July 7, 2021

SpinnerTileSkin

 Aloha,

I finally found some time to continue working on TilesFX. There was an issue in the TilesFX repo over at github that I would like to do for a long time but never really found the time.

So I now added a new skin called SpinnerTileSkin which is based on this issue/request. It does not look exactly like the requested one but I think it's close enough.

In principle the skin shows a numerical value that when changed will spin through the numbers from 0-9 as if they where on a wheel.

Because a screenshot won't really show the effect, here is a little video:


As you can see it is nothing really special but sometimes it might be exactly what you need.

To set it up you simple need the following code:

Tile tile = TileBuilder.create()
.skinType(SkinType.SPINNER)
.prefSize(300, 300)
.title("SpinnerTile")
.minValue(-50)
.maxValue(50)
.value(0)
.decimals(2)
.text("Animated number spinner")
.animated(false)
.build();
tile.currentValueProperty().addListener((o, ov, nv) -> {
if (nv.doubleValue() < 0) {
tile.setValueColor(Tile.RED);
} else {
tile.setValueColor(Tile.FOREGROUND);
}
});


Switching the color from white to red in case the number is negative is done by the listener attached to the currentValueProperty of the tile and is not the standard behavior.

Because I'm preparing my libraries for the upcoming JDK17 LTS release, this skin can only be found in the JDK16 branch of TilesFX. Not sure if I will backport it to the JDK11 master branch.

At the moment the JDK16 branch is not available on Maven Central but I will probably create a release in the coming days...so stay tuned...and keep coding :)


Friday, July 2, 2021

BubbleGridChart

 Aloha,

Last week I was playing around with some data and could not find the right chart to visualize it.

To give you an idea about the data, let's take the harvest of some fruits as an example. You will have ripe and unripe fruits, fruits that have been eaten by birds or caterpillars. Some of them might have been damaged by hail or did not get enough water, others might be rotten or mouldy. For each fruit you have those different numbers and you have the sum of each fruit and the sum of all fruits.

The best way to compare all those numbers would be a matrix style chart. So I've stumbled upon the so called Bubble Grid Chart. So here is an example that I've found on the web:

As you can see it shows the fruit data that I described above.

The value of each crosspoint e.g. 90 Apples that are ripe will be visualized by the size of the bubble. Sizing the bubbles is a bit tricky because you would like to avoid having a few big bubbles and a lot of tiny bubbles. So you need to make sure that the size of the bubbles has no linear relationship to it's value.

In addition the max size of a bubble is given by either the height of the y-category items or the width of the x-category items, depends on which is smaller.

I also would like to have a grid in the background to make it easier to find specific coordinates. So, long story short, here is my version of the BubbleGridChart:


As you can see I've decided to put the x-category items on the bottom and also added the ability to show not only the values on the bubbles but also on the rows and columns of the chart. I really was impressed on how much information you can get out of one chart. At a glance you can see that the number of all ripe fruits is 215 which is 43% of all fruits. Because in this example the number of each fruit was always 100 you cannot really compare by the x-category but this could be different.

You can see that 90 Apples have been ripe which is 18% of all fruits. This information will be shown in a little info that will popup when you click on the bubble. In addition I've added the ability to sort the chart in x- and y-direction by either their indices or their values.

To be able to sort the items by their index you have to define it upfront.

Let me show you how to set up the x- and y-category items for the chart above.

Y-Category Items:

ChartItem ripe = ChartItemBuilder.create().name("Ripe").index(0).fill(Color.BLUE).build();

ChartItem unripe = ChartItemBuilder.create().name("Unripe").index(0).fill(Color.RED).build();

X-Category Items:

ChartItem peaches = ChartItemBuilder.create().name("Peaches").index(0).fill(Color.ORANGERED).build();

ChartItem apples = ChartItemBuilder.create().name("Apples").index(1).fill(Color.LIMEGREEN).build();

BubbleChart Items:

BubbleGridChartItem peaches1 = BubbleGridChartBuilder.create().categoryXItem(peaches).categoryYItem(ripe).value(60).fill(Color.ORANGERED).build();

BubbleGridChartItem peaches2 = BubbleGridChartBuilder.create().categoryXItem(peaches).categoryYItem(unripe).value(5).fill(Color.ORANGERED).build();

BubbleGridChartItem apples1 = BubbleGridChartBuilder.create().categoryXItem(apples).categoryYItem(ripe).value(90).fill(Color.LIMEGREEN).build();

BubbleGridChartItem apples2 = BubbleGridChartBuilder.create().categoryXItem(apples).categoryYItem(ripe).value(0).fill(Color.LIMEGREEN).build();

The index that you define will later be used to sort the items, just make sure you don't have duplicate indices because I do not check that at the moment (I just needed something that works quickly). So you first create the x- and y-category items and from those you create the actual BubbleGridChart items that will be used to visualize the chart.

The BubbleGridChart itself can be create as follows:

BubbleGridChart bubbleGridChart = 
    BubbleGridChartBuidler.create()
                          .chartBackground(Color.web("#0e0e0e"))
                          .textColor(Color.WHITE)
                          .gridColor(Color.rgb(255, 255, 255, 0.1))
                          .showGrid(true)
                          .showValues(true)
                          .showPercentage(true)
                          .items(bubbleGridChartItems)
                          .sortXCategoryItemsByIndexAscending()
                          .sortYCategoryItemsByIndexDescending()
                          .useXCategoryFill()
                          .useGradientFill(false)
                          .gradient(new LinearGradient(0, 0, 1, 0, true
                                    CycleMethod.NO_CYCLE
                                    new Stop(0, Color.BLUE), 
                                    new Stop(1, Color.RED))
                          .build();

Sorting the categories via the build only works if you also provide the items, otherwise you have to call the sorting methods like sortXCategoryItemsByIndexAscending() after you have added the bubbleGridChartItems. For me the charts now works fine but you might have other requirements, so please do not hesitate to file issues/request over at github.

The BubbleGridChart can be find in the current jdk16 branch which is also available on maven central. The jdk16 branch is more a temporary branch that I use to test stuff before JDK17 will come out in September. Because this will be the next long term stable version I will create a jdk17 branch in the future which will become the new main branch then.

That's it for today, so enjoy the upcoming weekend and...keep coding... :)

Wednesday, June 16, 2021

Fun Selector

 Aloha,

Time flies, it's already mid of June so it's time for another little blogpost about a fun control I've created last week.

It's a selector between two states and the fun is the animation when switching between the two states.

Here is a little demonstration of the control...


So the light green ball defines the selected state. It's not really something special but I like the idea of using animations in a fun way. Always keep in mind that such effects are nice in tools that you use once or twice but you don't want to use these things in a business app every day :)

As always the code is available over at github.

And that's it for today...so keep coding...

Friday, April 9, 2021

Friday Fun LXIII - JDKMon

 Aloha,

I've took some days off this week and continued working on a little tool I wrote, JDKMon. Because I have a couple of JDK's on my machine and I usually don't use tools like sdkman or other installers but instead install the JDK's by hand I always wanted to have a tool that keeps track on the latest available versions and inform me about updates.

Well because I've created the Disco API for foojay I'm now able to use this api to create this tool. In principle the tool will try to find all JDK's installed in a folder (that you can define) and checks the Disco API for updates for each of the JDK's found. If an update was found it will tell you the latest available version for the distribution and give you the ability to download the different available versions.

Just to be clear, the tool won't scan your whole harddrive for installed JDK's but only the given folder with all it's subfolders. For me that works fine because I have all JDK's installed in the same folder. 

On MacOS this folder usually can be found at /Library/Java/JavaVirtualMachines where on Windows it can be C:\Program Files\Java and on Linux it might be /usr/lib/jvm. But like mentioned you can choose the folder JDKMon should look for JDK's.

JDKMon will scan for new updates every 3 hours and will show you a notification if there are updates available. The app makes use of FXTrayIcon which makes it possible to have the app running in the SystemTray (if available). On MacOS and Windows that works fine. On Linux it won't work so in this case it is simply an app that comes with a menu.

After the app started it will scan for JDK's and will then show a window with all JDK's found. On MacOS that window will like look like follows:


On the screenshot above you see the alphabetical list of JDK's found in the folder that is shown on top. The distributions where the tool found updates will have additional info like the arrow followed by the latest available version and some colored buttons. The buttons on the right will show the available archive types for each distribution. Once you click on one button it will ask you for a folder to download the package to and after you have selected one it will download the selected package to that folder.

So the tool won't install automatically the downloaded JDK...this is up to you. The tool will also adopt to the selected screen mode (dark/bright) on MacOS and Windows. I've also tried to make the main window and notifications look like the native windows. Here is a screenshot of the Windows version on a bright themed Windows 10 installation:


The supported distributions at the moment are:

- Adoptium (but there are no packages yet)

- AdoptOpenJDK HotSpot

- AdoptOpenJDK OpenJ9

- Corretto

- Dragonwell

- GraalVM CE

- Liberica

- Liberica Native

- Mandrel

- Microsoft Build of OpenJDK*

- OJDK Build

- Oracle JDK (no direct download)

- Oracle OpenJDK

- RedHat (no direct download)

- SAP Machine

- Trava

- Zulu

* The Microsoft Build of OpenJDK is currently not available on the public Disco API but only on my own server which is the reason why you can see it on the Windows screenshot. But it will come with the next deployment.


Like already mentioned this is just a tool that I needed for my own machine and I also used it to test the detection of dark/light mode etc.

Because the Disco API still is under development it might come to situation where you don't find the latest available JDK of a distribution directly but I'm working on that so that it will hopefully be up to date most of the times.

As always the source code is available over at github where you can also find the installers/jars in the releases section.

I'm using github actions to build and upload the artifacts with each build so that you can also find the latest available artifacts for MacOS and Windows in the actions section.

The tool is not finished yet because it needs a bit more love for Linux which will be the next task to do. At least it should look not like a MacOS app on Linux forever. So I will try to adjust it to maybe the Ubuntu UI.

That's it for today, so enjoy the upcoming weekend and...keep coding...