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


Saturday, February 6, 2021

"Poor man's" dark mode detection

 Aloha,

I recently read a lot about how to detect the dark mode on MacOS or Windows from Java which is really interesting when you develop desktop applications in Java (yes they still exists).

And there are different ways in figuring this out, one of them is to use jSystemThemeDetector which not only detects the theme but also gives you the ability to listen to changes of the theme. This little library makes use of different other libraries like OSHI, JFA, Jetbrains Annotations and JNA. 

Because I also wrote a little tool that helps me to figure out the system color theme I thought I might share this with you.

So my approach is a bit different in the way that I simply make use of the already existing operating systems tools to get the information I need. If you don't need to listen to theme switches (which is usually the case because users do not change their theme all the time) but only need to know if the operating system is currently using the dark theme or the light theme then you might want to use my approach.

I simply call operating system routines on the command line using Java's Runtime.getRuntime().exec() method and parse the result.

Because I'm on MacOS I've also added the ability to get the current accent color that is used in MacOS which is useful if your application should be as close to the native MacOS apps as possible.

Because the JavaFX stage does not recognize the current MacOS theme means you have to draw the window frame on your own dependent on the current theme but that's fine. I might add another blogpost about the native looking MacOS windows frame I've created.

The thing that I like most about my little tool is that it is only one class that offers some utility methods and everything is plain Java without any dependencies. 

It works on MacOS and Windows 10 and for those of you that are interested in that tool, I've created a little gist.

At the moment this utility class is made for JavaFX but it should be easy to change the Color definitions from JavaFX to Java Swing if you need them :)

That's it for today, enjoy your weekend and keep coding... :)

Wednesday, January 6, 2021

Neumorphism...just for the fun of it...

 Aloha,

First of all happy new year to all of you. I took this week off which gave me some time to play around with new stuff and as you can already guess it's about neumorphism.

Well you might ask yourself what the heck is neumorphism and how is it related to ui stuff. If you remember the early days of the the iPhone, there was a ui style that was called skeumorphism which means the ui design looked really realistic. Sometimes a bit too realistic but to be honest I'm still a fan of skeumorphism, especially if you take a look at older people that are not that used to modern technology. They really have a hard time to understand all the new technology. But if you show them a ui that looks like things they know from the real world, they recognize them and know how to use them.

At some point the whole skeumorphism was a bit too much and Apple decided to radically change the complete ui design to the so called flat ui. And to be honest the first version was simply terrible. Even for experienced users the ui was not self explaining any more but you have to learn that colored text might be a button but doesn't have to be. I really like the clean style of a flat ui but it comes with a drawback when you look at the usability. The self explanation of a ui simply got lost. 

Over the years Apple learned that the pure flat ui was a bit too flat and decided to make the whole thing a bit more usable again which leads us to the current ui design (which still is hard to learn for unexperienced people).

At some point neumorphism became a thing which is a bit like a mixture from skeumorphism and flat ui design. So there is no real definition of skeumorphism and for that reason you will find ui's that look not all the same as in the flat ui era but have different looks (which is good).

If you are interested in some examples you might want to take a look at dribbble.

Neumorphism makes use of shadows to define ui component borders which gives a button in principle two states an embossed or rised and a sunken state. In combination with rounded corners the whole ui becomes a more soft touch which can work for specific apps.

The problem with neumorphism is that it does not work with all color combinations. This is because of the shadows it uses, they won't work on white or black backgrounds. On some colors the shadows work great on others not so neumorphism is not the general solution for ui design but just another ui design style that can be useful and refreshing for some applications.

So I've spend every day around 1.5 hours in the early morning to play around with JavaFX and neumorphism to get figure out how to make it work. I would love to use css for this because in principle this would mean you could simply load another css file and you are done...BUT...unfortunately in the JavaFX css you cannot chain effects as you can do in code.

Meaning to say in JavaFX code you can chain effects like a DropShadow that can have an input of another DropShadow. With this you can simply create an effect of a sunken button etc.

But this is not possible in JavaFX css where you can only have one effect on one node which is not enough :(

So for that reason I've decided to create my own controls (at least a few to play around with). And again I used the JavaFX Canvas node for that. I found myself more and more using the Canvas node for all kinds of things simply because it saves nodes on the scene graph, it's fast and if you need it you can simply port it to HTML.

And this is what I came up with...


I've created a Button, ToggleButton, TextField, RadioButton, CheckBox, ChoiceBox, Switch and a Container.

Just keep in mind that these controls are not meant to be used in production because they miss some features but they might work for some demos (at least I will use them for demos) :)

The Container component which you can see in the lower row of components can be used to give other controls the ability to make use of the shadow effects. If you would like to use a circular Medusa gauge in a neumorphic ui you could add it to a circular Container.

To see how it can be used you might want to take a look at the Demo class.

The code is as always available over at github.

So that's it for today and don't forget...keep coding...

Sunday, December 27, 2020

JavaFX monitor component

 Aloha,

There was always something I would like to do but never found the time to do it...a control that looks more or less like a heart rate monitor. Well it's not really about monitoring the heart rate but I like the heart rate signal, so it's more about the older tube based oscilloscopes. And the thing that makes me want to create such a control is the fade out of the beam when it moves across the screen. In the tube based devices this was coming from a metallized layer that was applied to the front of the glass tube. When electrons hit this layer, it absorbed a part of the kinetic energy of the electron and released it in the form of light (so called fluorescence). The layer on the glass is metallized so that the electric charge of the electrons can flow off.

Now when the electron beam was moving across the screen the electrons left behind a fluorescent line which formed the signal. Ok so that is the thing that I would like to create...not an oscilloscope but this fading effect when visualizing a signal.

So what we need is a line that fades out over time...sounds easy (and in the end the solution is easy) but getting the right idea on how to implement it took me some walks with the dog :)

The first idea is you simple draw a line and apply a horizontal linear gradient to the stroke that fades out to transparency. As long as the signal has a predominantly horizontal orientation this works really fine. But as soon as the signal also has significant vertical values we will run into a problem. Let me try to visualize this in a little graphic:


On the picture above you see two signals that have the same horizontal width but a different signal length. On top I've added two rectangles that shows the horizontal linear gradient that is used to fade out the signal. The effect of fading out should be related to the length of the line and not to the width of the signal. 

To achieve this behavior I need to fade out the signal along the line and not only in horizontal direction. So the fade out should follow the line. My idea was to use a queue with a fixed size, when filled up to the given size it should remove the head element when a new element was added to the end. With such a queue in place I could simply draw a line between each element of the queue and fade out these line segments when I'm iterating over them during the drawing process.

I simply created a FixedSizeQueue that is based on an ArrayBlockingQueue and added the "auto-remove" functionality in the add() method. So the queue looks like this:

public class FixedSizeQueue<E> extends ArrayBlockingQueue<E> {
private int size;

public FixedSizeQueue(final int size) {
super(size);
this.size = size;
}

@Override public boolean add(final E element) {
if (super.size() == this.size) { this.remove(); }
return super.add(element);
}

public E getElementAt(final int index) {
if (index < 0 || index > size() - 1) { throw new IllegalArgumentException("Index out of bounds."); }
return (E) toArray()[index];
}
}

With this queue in place I can now use it as some kind of a signal buffer. I was playing around with different factors to fade out the signal but ended up with a simply linear approach. So I calculate the opacity factor by simply dividing 1/noOfElements. And when iterating through the points in the queue I just multiply the current index with the opacity factor as you can see in the code snippet below:

final Point[] points = queue.toArray(new Point[0]);
double opacityFactor = 1.0 / points.length;
for (int i = 0; i < length - 1; i += 1) {
if (points[i].x < points[i + 1].x) {
lineCtx.setStroke(Color.color(red, green, blue, i * opacityFactor));
lineCtx.strokeLine(points[i].x, points[i].y, points[i + 1].x, points[i + 1].y);
}
}

You could because I draw the lines from left to right the opacity of the elements will in this case fade in the line segments by increasing their opacity from 0 - 1.

So the result looks good enough to me:


But this is only the effect of fading out a line along it's elements...what about the rest of the control?

For the monitor control I use three Canvas nodes and an ImageView that are placed inside a Region. So the whole control uses 5 nodes on the scene graph. 

It's good practice to think about which elements in your control needs to be drawn and when. This is sometimes a bit boring because with the given compute power of today's machines you won't really see a big difference between the optimized drawing and the let's call it brute force drawing. Optimized drawing only draws the elements that are needed where brute force drawing simply draws everything everytime. A good way of testing your controls is to run it on an older Raspberry Pi. This device is fast for it's size but slow compared to your desktop computer and on such a Raspberry Pi you will directly get a visual feedback on how efficient your code is. On an older Pi everything counts...means if you only draw the stuff that is important you will really see the effect on the Pi.

So as I mentioned I use three Canvas nodes

  • background (rect filled with background color and raster with text)
  • line (the line segments)
  • dot (the leading dot with the glow effect)
You might argue I should draw the dot in the same Canvas as the line but this only works for the mode where I fade out the signal line. The monitor control also has another mode where it always leaves the signal on the screen and only removes the part in front of the current position. This mode is common in todays heart rate monitors as you know it from the local hospital. For this mode I don't want to clear the background of the line Canvas on each draw and so I need to draw the dot on a separate Canvas.

Because I separated the background with the raster from the foreground with the line and the dot I only need to draw it when either a parameter has changed (e.g. the background color etc.) or when the control was resized. This is what I mean with optimized drawing, I could also draw the background all the time and put it in the same Canvas as the line but this is just not efficient.

In addition to the Canvas nodes I also use an ImageView to overlay the whole control with what I call a crystal overlay. The main idea is to make the whole UI look more realistic. The main thing here is noise...adding noise to a surface makes it look more natural because in the real world nearly no surface is perfect. For example if you take a look at a liquid crystal display (lcd), you will see some kind of structure on the background. This structure I try to imitate with a an image that contains semi-transparent noise. If you simply put such an image on top of your control it will look more realistic.

Here is an example screenshot of the monitor control with both variants:


As you can see the upper image has the crystal overlay effect switched off where the lower image has it switched on. In the monitor control you can decide if you would like to use it or not.

So in principle we simply stack all the different layers over each other and so get the final result.

I have also added some themes that contain common used color combinations for oscilloscopes but you can of course also set all the different colors separately.

There is a Demo class in the code that gives you the ability to play around with the parameters and if you would like to see it in action here is a little video:

As always the code/binary is available in the following places:

github

bintray

maven central

I guess that's it for today...so keep coding...

Friday, December 4, 2020

Worldmap connections...

Aloha,

Everytime I'm sitting on an airplane I'm taking out the magazine where it shows the flight connections of the airline on a worldmap. Somehow I really like that kind of visualization.

For those that don't know what I'm talking about, it's something like this:


When I've created the last update of my charts library I stumbled upon my worldmap and thought by myself...why not creating such a visualization by using the worldmap I already have.

You can choose this kind of visualization for different kind of data, e.g. simple connections, weighted connections to visualize a flow, incoming/outgoing connections and more.

Long story short...I've added the ability to cover some use cases I came up with. The first one is just a visualization of simple connections without showing any direction.



This really only shows the connections between points on the map. Nice but what if we would like to use colors and also show the direction? No problem, in this case it could look as follows...

Not bad but what if we would like to indicate the points with the highest volume of outgoing connections? No problem, here you go...


Hmm...so far so good but what if we would like to visualize a data flow from one point to another? Therefor the connection itself need to have a value which defines the thickness of the connection. Well...here it is...

Ok that's nice...so what about gradients...would it not be nice to have the connections change their color on their way from their startpoint to their endpoint? Yes it would be...so...


Allright...with this I covered all things I've implemented so far and as always I have no idea if someone has a use for that because I simply created it for the fun of it.

But if you can use it and you need more features...just let me know and I will try to make it happen.

If you are interested in how the above charts have been done you can find the code for it in the WorldmapConnectionsTest.java file in the test package.

In principle you can add MapPoint objects with a name, a color and latitude/longitude coordinates to show the points. The connections are of type MapConnection which takes 2 MapPoints, a value, a color or gradient and a tooltip text.

Attention: The connections are not clickable yet...so there is no tooltip and no user interaction implemented right now but it might follow.

The code can be found over at github at: https://github.com/HanSolo/charts

You will find the changes in the dev branch.

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


Saturday, November 21, 2020

Arc charts...

Aloha,

I really need to post more often, it's already November...

When I was looking for some interesting charts that I might add to my JavaFX charts library I stumbled upon an arc diagram. It's a chart that is very specific and cannot be used to visualize all kinds of data but it's great to visualize interactions or flows between items. More info about this diagram can be found at wikipedia.

As always this chart was just created for the fun of it and not because I really need it, so I always try to make it as useful as possible but I don't know the special needs in the industry. So whenever you find something that can improve the handling of these charts, please let me know and I will try to make it better.

The hardest part is always to find some data to play with and this time I've found an interesting dataset about the interactions between the characters in the movie Star Wars Episode I.

So I gave it a try and here are some results by using my new arcchart:





As you can see there are different options one can enable/disable in this chart.

Each connection between two items can have a value which can be used to weight the connection (wider strokes mean bigger values => stronger connection). One could also weight the dots of each item by the sum of their connection values. If you click on an item it will highlight all it's connections.

In the last image you see that you can also make use of the full circle for connections. In this case you read the chart clockwise, meaning to say outgoing connections to the right will be in the upper part and outgoing connections to the left will be in the lower part.

The items are sorted by the sum of their connection values from left to right. As you can see in the image above, Anakin has the most interactions in Episode I, followed by Jar Jar and Qui Gon.

The most interesting part is that creating the whole new chart took not longer than 3-4h last night which again shows how productive you can be by using JavaFX...love it :)

In addition one could also create a cluster to group items. For this I've simply created another chart without any meaning just to show the clustering. So in this case the clusters are europe and asia. The items in each cluster are sorted by the sum of their connection values from left to right.


If you have clustered items all connections from the cluster will get the color of the cluster. A cluster will be created as follows:

Cluster europe = new Cluster("Europe", Color.BLUE, germany, france, italy, spain);

Where germany, france, italy and spain are PlotItems that can be created as follows:

PlotItem germany = new PlotItem("GERMANY", 1_250_000, Color.RED);

The connections between the items can be created as follows:

germany.addToOutgoing(india, 150_000);

If you would like to highlight a specific connection you can get it as follows:

arcChart.getConnection(germany, india).setFill(Color.GREEN);

Oh and the new ArcChart is part of the last release of my charts library which you can find at:

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