Showing posts with label control. Show all posts
Showing posts with label control. Show all posts

Thursday, December 23, 2021

DateRanger...

 Aloha,

Last week I needed some kind of a date picker which I can use to select ranges of dates. So I knew that I once created such a control when I was working for Canoo back in the days. But when I found it I saw that it was realized in JavaFX 2.0 that was based on JDK7 and made use of Skin and Behavior classes which changed in JDK8. 
Because I was not keen on rewriting that stuff I decided to simply create a new control...just for the fun of it :)
And because I used a lot of Canvas recently I made the decision to make use of CSS for this control and not use the Canvas node for it. Using CSS makes the whole thing more usable for standard applications because you can easily style the control to your needs where when using the Canvas node it needs more programming effort to get the same styleability.
So the first step was to figure out a control that I like to have some kind of template.
And I found this one...

It's not really fancy but I really like it's compact look which has all the info that I need. So I've created my version of it which looks as follows:


As you can see I more or less created a copy of the control. So the next step was to add the functionality to select a range of dates.
I've simply added a key listener and if you select a date by clicking somewhere with the mouse you can press the `SHIFT` key with the next click and it will create a range of dates for you.
The range then looks as follows:


Most of the nodes can be styled using CSS and you will find all the available styles in the `date-ranger.css` file.
The plain DateRanger comes without the month and year label and the buttons, so you can also use it for only showing the month. If you would like to use the version above, you can use the DateRangerControl which is also part of the code. This is in principle just a BorderPane that comes with the label and buttons on the top.

It's nothing really fancy but maybe it will be useful for one or the other.
The code is available on github and also on maven central.

Well I guess that's it for 2021...I wish all of you a merry christmas and a happy new year...oh and keep coding... :)

Sunday, December 12, 2021

A versus B

 Aloha,

last week I was searching the web for some comparison between an older iMac and an older Macbook Pro. And when I was skimming the web for such comparison pages I saw those comparison charts on some of the pages I've found.

Well I just checked "comparison chart" on Google and took a look at the images and found something like this:


And you will find a lot of similar charts on the web. This could be a really useful chart for some use cases and the best of all...it's really easy to implement :)

Long story short...here is my version of a ComparisonBarChart...


Just up front...the header with the "Product A" label and the "A" in the circle is NOT part of the chart. Because you not always need this labels I've decided to not add them to the chart itself but leave it to the user to add such things manually. So the chart only contains the bars and the categories.

More or less all of the chart is configurable, so here are just a few points that can be adjusted

- The colors of the background, the bars, the bar background, the text etc.

- The number format incl. no of decimals, percentage, shortened etc.


There are some things you have to keep in mind to make the chart and the comparison work. Because you can only compare options that are available on both things you try to compare, the charts takes 2 ChartItemSeries with identical number of items. Each item needs to have the category property set to a category. You need to use the same categories (at least they should have the same name) for both series and their items.

To create the sample above I first have created a list of categories. Then I've created 2 maps with the categories as key and the chart items as value. This can be done in one loop like this:

for (int i = 0 ; i < 5 ; i++) {
Category category = new Category("Option " + i);
categories.add(category);
optionsProductA.put(category, ChartItemBuilder.create().name("Product A (Option " + i + ")").category(category).value(0).build());
optionsProductB.put(category, ChartItemBuilder.create().name("Product B (Option " + i + ")").category(category).value(0).build());
}

Now you can create the ChartItemSeries by using it's builder and set the items to the e.g. new ArrayList<>(optionsProductA.values()).

To set the bar color for each series you can set the fill for the series for example to a LinearGradient or to a plain color.

Now you can create the ComparisonBarChart using it's builder as follows

chart = ComparisonBarChartBuilder.create(series1, series2)
.prefSize(600, 300)
.backgroundFill(Color.rgb(244, 250, 255))
.categoryBackgroundFill(new LinearGradient(0, 0, 0, 1, true, CycleMethod.NO_CYCLE,
new Stop(0.0, Color.rgb(244, 250, 255)),
new Stop(0.05, Color.WHITE),
new Stop(0.95, Color.WHITE),
new Stop(1.0, Color.rgb(244, 250, 255))))
.barBackgroundFill(Color.rgb(232, 240, 252))
.barBackgroundVisible(true)
.shadowsVisible(true)
.textFill(Color.WHITE)
.categoryTextFill(Color.rgb(64, 66, 100))
.shortenNumbers(false)
.sorted(false)
.order(Order.DESCENDING)
.numberFormat(NumberFormat.PERCENTAGE)
.doCompare(false)
.categorySumVisible(false)
.betterColor(Color.BLUE)
.poorerColor(Color.RED)
.build();

To create the chart above you don't need to set all the options that you see in the code above. I've simply added it to show that they are available. For example .doCompare(false), .sorted(false), .categorySumVisible(false), .order(Order.DESCENDING) etc. are all not needed in this case.

If you only would like to compare two feature sets than this is all you need but if you would like to do more...well you can :)

You can for example sort the bars either ascending or descending by the sum of each category items. Meaning to say order it by the sum of the left and the right bar value of each category. This sum can also be shown by setting categorySumVisible to true.

If you set doCompare to true the color of the bars will change so that the one with the higher value (which is always be the "better" value in this chart) get's a different color than the bar with the smaller value (which always is the "poorer" value in this chart). There are some default colors like green for better and orange for poorer but these colors can also be set.

In addition you can also switch some visual effects on by setting shadowsVisible = true. This will add a shadow to each bar and also to the category area (the rectangle in the center of the chart).

If you don't really want to set all colors manually you will find 2 convenience methods for setting the bar colors which are setBetterColor() and setPoorerColor().

When calling these methods the poorerDarkerColor, poorerBrighterColor, betterDarkerColor and betterBrighterColor will automatically be set.

If you don't want to see a gradient for the bar fill you simply have to set the brighter and darker colors to the same values.

The easiest way to figure out how it works is to take a look at the ComparisonBarChartTest class.

This class contains the code for the screenshot above and should be starting point for your own version of the chart.

You will find this new ComparisonBarChart in the jdk17 branch of my JavaFX charts libray on github.

And of course it is also available on Maven Central...but keep in mind...you need to use JDK17 to run it...

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


Friday, December 3, 2021

All things countries...

Aloha,

As some of you might know I've created a JavaFX world map component a while back which I also integrated in my TilesFX and charts library.

Well the component itself works so far but it was always only a world map. I mean it is possible to strip out single countries and draw them but then you have the problem that this country map won't come with the same features as the world map.

So in principle I was always looking for something similar to Googles GeoChart. Well...long story short...I've created something similar :)

And I simply named it countries...because it is all about countries. It is another JavaFX library and it comes with 3 JavaFX controls:

- CountryPane

- RegionPane

- WorldPane

Each of those panes has more or less the same functionality. They show at least 1 country (CountryPane), a set of countries (RegionPane) or the whole world (WorldPane).

The WorldPane and the RegionPane in addition have the ability to select countries by clicking on them.

All 3 panes can overlay a heatmap and also so called connections (e.g. flight connections between airports).

In addition to the countries with their shapes the library also contains around 41000 cities with information about their population (if available), location, country and if it is a capital (if available). In addition I've also added around 8500 airports that you can use.

Countries can have value objects (metadata if you like) and can also have simple values, you can color them as you like. I hope I have build in enough capabilities to use for data visualization (if you miss something...just let me know).

Yep this is great...but it comes with lots of data...so the library is 13 MB in size!!!

But to be honest I don't care, it is just handy if you can directly make use of this data without loading other external data. Of course you can use your own data if you like, as long as you have latitude/longitude information it will work.

The library is build on JDK17, meaning to say if you would like to use it...move your stuff to JDK17 ;)

To give you an idea how it could be used, here are some screenshots...

This is the CountryPane showing Germany with some cities (population > 300000). To make it easier I simply added the same cities as heatmapSpots. In addition you see a connection between the FMO airport and the MUC airport.


Here you see the RegionPane showing the European Union. In this map I show the available capitals (cyan dots) and used cities with a population > 200000 for the heatmap. In addition I here show 3 connections between some airports (LIS -> ARN, MAD -> ARN, FMO -> ARN). I already added some predefined country regions in the BusinessRegion class. There you will find regions like DACH, EMEA, APAC, AMERICAS, CENTRAL_ASIA, NORTHERN_AMERICA etc. You can define your own regions by using the CountryRegion class.



And finally the WorldPane which again shows the available capitals (cyan spots), cities with a population > 1000000 for the heatmap and again some connections between international airports.

Not sure if this might be interesting for you but I needed it :)

As always the source is available over at github where you can also find the latest release. And of course it is also availble on maven central.

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


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 :)


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

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

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

Tuesday, June 2, 2020

Touch me...

Aloha,

Last weekend I've spend a lot of time in front of the TV to follow the flight of SpaceX Crew Dragon to the International Space Station.
It's great to see that finally a commercial company is able to send people to the lower orbit and to the ISS.
When I saw the touch user interface of the Crew Dragon I've got the idea to create a little touch joystick control in JavaFX.
I've did not spend a lot of time to think through the functionality so there is as always room for improvement :)
So I took my standard approach, first draw the control in a vector program which looked like this:


As you can see it's not a hyper fancy control but it should be useful first :)
The idea was to have a touch point that can be dragged around. A little ring outside that indicates that you touched the control (because your finger might block your view on the touch point itself).
8 buttons around the control that can be used to make small adjustments with given directions.
I've also added an indicator made out of chevron shapes. The more you drag the point to one direction the longer the bar of chevrons will get. First I thought to let it go from the center of the control to the touch point but if you use your finger to drag the point, your hand might block your view and so I've decided to put the chevron bar on the opposite side of the touch point to make it as visible as possible.
I've created a little video that shows how the control works...


As always you can find the code over at github...

If you would like to start the demo you just have to make sure you are on Java 11 and then you can execute gradle Demo on the console.

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

Friday, May 29, 2020

TilesFX 11.37

Aloha,

Time for some new stuff...
Last weekend I've stumbled upon some dashboards that had some interesting visualizations. The first one was a visualization of sales cycle steps that looked as follows:


The interesting part here for me is the chart where each bar starts where the last bar ended. I took a look at TilesFX but did not found something that made stuff like this possible in an easy way. So I decided to add a new skin that I called CycleStepTileskin (I know I'm not good in naming things). Here is how it looks like:


To be honest I'm not sure if this is useful but you never know right :)

The other tile I've found was nothing really special but I realized it has something that I missed in TilesFX...flags. This is what I'm talking about...


Not everyone needs flags but sometimes they come in really handy and so I was looking for flag images that I could use. Lucky me I've found free flags over at flaticon and added them to TilesFX. I've added them as enum and control.
So if you need an icon image you can now simply do something like follows:

ImageView flagImage = new ImageView(Flag.GERMANY.getImage(48));

The Flag enum has two methods to get an image, the standard getImage() method always returns a flag image with the size of 30x30 px. If you need a different size you can simply call the getImage(SIZE) method to get the flag in the size you want it.
The flag images are always square!
The other class I've added is called FlagIcon which is more or less a wrapper around an ImageView of the given image. Meaning to say it behaves like a control, so it will be resized automatically BUT it will resize the image based on the given flagSize. So if you have a flag of size 48 px and you increase the size of the FlagIcon it will get pixelated.
So if you would like to avoid pixelation you need to set the FlagSize to a bigger value but that will also increase memory consumption...so it's up to you.
In the end the FlagIcon is just a convenience class that comes in handy if you simply need a flag somewhere. You can use it as follows:

FlagIcon flagIcon = new FlagIcon(Flag.SINGAPORE, 24);

This will give you a control that shows a flag that is based on an image with 24px.

As an example of what you can do with that I've simply added a tile that shows the Covid-19 cases of some countries based on data from Mai 26th 2020. For this tile I simply used the custom tile skin and added a VBox with some HBoxes. If you are interested in how I did that, please take a look at the Demo class in the TilesFX project.



Here is a little bigger screenshot of it...


That's it for today so as always you can find the code over at github and the binary either at bintray or at maven central.

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