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


Thursday, June 11, 2020

TouchSlider control

Aloha,

Yesterday evening and this morning I've spent some time on creating a new control...a touch slider. To be honest I can't remember why I had the idea to create one but who cares...now it's ready :)
So here is a screenshot of it...


So it's not really fancy but it works and is customizable in many ways. So first of all one can set the orientation to either horizontal or vertical. 
You can set a name and you can also define if that name should be visible or not. In addition you can define if the current value should be visible or not.
The color of the bar background, the bar itself, the thumb, the value text, the name text and the zero indicator are also adjustable.
This control is based on the JavaFX Canvas node which means it does not use a lot of nodes. But even if it is based on the Canvas node it is still styleable by CSS. If you take a look at the Demo class in the github repo you will figure out that the black and blue sliders are styled using code but the red slider on the right side ist styled using CSS.
This works because JavaFX offers so called StyleableProperties which bridge the gap between code and CSS.
The plan is to use this slider in a specific Tile for TilesFX for control e.g. IoT projects.
Here is a little video of the slider in action...


In addition to the above mentioned features you can also define if the bar should start at the zero position, this might come in handy if you have to control values that go from a negative to a positive value.
In this control I've used a little bit different approach to set the min and max values. Here you can define the min value and the range. The value property of the slider will always be in the range from 0 - 1 but if you call the getSliderValue you will get the "real" value based on the min value and the range back.
The slider will fire TouchSliderEvents when you drag it so that you can attach an observer to it and react on the events.
Well that's in principle it and as always you can find the code at github...

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

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