Sunday, September 15, 2019

Custom skins for TilesFX

Aloha,

Today I will tell you something about customs skins for TilesFX. This year at CodeOne in San Francisco the Oracle team created a really nice Raspberry Pi SuperComputer. And for this Pi cluster the guys from Gluon created a dashboard that monitors the cpu and memory usage and also the temperature of each Pi.
Lucky me they decided to go with TilesFX to create the dashboard but they had the problem that there was no skin that was good enough to visualize the CPU and memory usage in one Tile.
So they asked me if I could help them out with a skin and so I've created the CpuMemTileSkin which looks as follows:



If you would like to make use of the skin feel free to take the code from this gist.

To use the skin you first need to set it up as follows:

Random         rnd      = new Random();
ChartData      cpuItem  = new ChartData("CPU", Bright.RED);
ChartData      memItem  = new ChartData("MEM", Bright.BLUE);
GradientLookup gradient = new GradientLookup(Arrays.asList(
    new Stop(0.0, Bright.GREEN),
    new Stop(0.4, Bright.YELLOW),
    new Stop(0.8, Bright.RED)));


Tile cpuMemTile = TileBuilder.create()
                             .skinType(SkinType.CUSTOM)
                             .prefSize(200, 200)
                             .unit("\u0025")
                             .title("Node XY")
                             .chartData(memItem, cpuItem)
                             .build();
cpuMemTile.setSkin(new CpuMemTileSkin(cpuMemTile);

// Creating random values for cpu and mem
double cpu = rnd.nextDouble() * 100.0;
double mem = rnd.nextDouble() * 100.0;

// Set the cpu color related to it's value and set the value
cpuItem.setFillColor(gradient.getColorAt(cpu / 100));
cpuItem.setValue(cpu);

// Set the mem color related to it's value and set the value
memItem.setFillColor(gradient.getColorAt(mem / 100));
memItem.setValue(mem);


So you set up two ChartData objects, one for cpu and one for mem and add them to the tiles chartData property in the TileBuilder.
Then you create a GradientLookup to change the color of each bar dependent on the current value (from green over yellow to red).
When this is done you can set the color and value of each bar by changing the value of the ChartData objects and that's all you need to do to make use of the custom TilesFX skin.

I hope this will help one or the other of you and if you have created a nice TilesFX skin please let me know...I'm always keen on seeing new stuff... :)

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

Monday, September 9, 2019

A new skin for TilesFX

Aloha,

Finally found some time to add some more features to TilesFX. This time I've added a new skin to visualize timeline data. Because our son has diabetes I would like to monitor his blood glucose values more closely using my TilesFX based dashboard at home.
So I figured out that there was no really useful skin available for TilesFX that I can use. But now there is...the TimelineTileSkin.
Here is a little screenshot of the new skin:


In principle the skin looks very similar to the SparklineTileSkin but here I simply can use time based to data. There is a ChartData class in TilesFX that has a timestamp property and so instead of using the value property of the Tile class one now simply add ChartData to the Tile.
To be able to visualize time based data I've added properties for a time period and for a max time period.
On the screenshot above the timePeriod is 3 hours which means the width of the tile represents 3 hours counting from now to 3 hours back in time. Every chartData object that you add which has a timestamp that is within the last 3 hours will be drawn. The tile will keep a max no of data defined by the maxTimePeriod property. Data that is older than 3 hours will move out of the graph on the left side and new data will be added on the right side. It is also possible to define a resolution in TimeUnits.
So if you would like to visualize the last 3 hours with a resolution of minutes you can define it by setting the timePeriodResolution with TimeUnit.MINUTES.
The smallest possible resolution is seconds, even if you set it to milliseconds or smaller it will be set back to seconds.
It is possible to use seconds, minutes, days and months. 
In addition to this I've also added a lowerThreshold with a lowerThresholdColor. The threshold and the lowerThreshold will be visualized with a dashed line that will be stroked with their given colors.
One could also define Sections with colors (the two red and one green areas on the screenshot above).
On the left side of the graph you see the minimum and maximum measured value (taken from the visible values!) In this case the highest measured value within the last 3 hours has been 349.
Like with the other charts one can define a number of stops that will be used to stroke the line when strokeWithGradient == true. Otherwise it will use the barColor to stroke the line. If you enable smoothing the line between the points will be smoothed, otherwise it will simply connect the data points.
On the right side of the chart you see the minimum and maximum value of the chart (0 and 350).
The small percentage values on the left side will show how many data points that are within the timePeriod are in each section. In the screenshot above this would mean for example that 18% of all visible data points are in the green section.

I've created the TimelineTimeSkin because I have a need for it to visualize the blood glucose values of our son, meaning to say it might not fit for your needs. So please let me know if you find some bugs or if you need something else and maybe I can help you with that.

The new skin is part of the latest version 11.6 which can be found here:


I hope this additional skin might help one or the other, so that's it for today...keep coding...

Friday, July 12, 2019

Some fun again...

Aloha everyone,

I think I'm too busy these days...just saw that my last post was from March...ZOMG
So last week I was in Basel at the Karakun office and met with my old friend Andres Almiray (which always is a pleasure) and we talked about some JavaFX and SVG stuff. After he left the office I was thinking about how to visualize multi-color SVG paths in JavaFX and started to create my own SvgNode.
But first why do I not use the already SVGNode in JavaFX to solve that problem? Well the SVGNode is nice but comes with the drawback that it only supports one single path with it's fill and stroke and that's it.
This works for almost all things I need but sometimes you simply need to support more than one path with separate fill and stroke for each path.
Here is a little example SVG that I've found on the web (over at flaticon.com) which shows the problem...

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 513 513" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
    <path d="M235.135,235.135C159.925,310.345 135.231,275.075 26.004,422.225C17.921,433.114 20.496,448.544 31.694,456.194L33.637,457.521C38,460.501 43.224,461.88 48.503,461.642C58.83,461.176 80.859,464.825 116.106,492.951C167.374,533.862 226.035,500.058 252.374,473.719C281.232,450.167 320.774,395.21 285.236,340.081C273.056,321.188 266.597,306.174 263.368,294.601C258.079,275.643 275.644,258.078 294.602,263.367C306.175,266.596 321.188,273.055 340.082,285.235C395.21,320.773 450.168,281.233 473.72,252.373C500.06,226.033 533.863,167.373 492.952,116.105C464.826,80.858 461.176,58.829 461.643,48.502C461.881,43.223 460.503,37.999 457.522,33.636L456.195,31.693C448.545,20.495 433.115,17.921 422.226,26.003C275.075,135.231 310.344,159.925 235.135,235.135Z" style="fill:rgb(253,111,113);fill-rule:nonzero;"/>
    <path d="M85.968,403.053C106.035,377.514 146.121,331.223 206.362,303.757C214.498,300.047 224.098,301.902 230.29,308.353C252.48,331.471 295.699,389.535 234.658,451.558C177.284,509.854 117.679,460.332 87.834,431.163C80.132,423.636 79.314,411.522 85.968,403.053Z" style="fill:rgb(133,231,255);fill-rule:nonzero;"/>
    <path d="M109.686,409.31C101.985,401.784 101.167,389.668 107.82,381.2C113.481,373.995 120.737,365.137 129.588,355.518C110.289,373.237 95.743,390.609 85.966,403.054C79.313,411.521 80.131,423.637 87.832,431.164C117.677,460.334 177.283,509.855 234.656,451.559C238.431,447.724 241.803,443.904 244.81,440.106C191.186,481.359 137.507,436.5 109.686,409.31Z" style="fill:rgb(87,208,230);fill-rule:nonzero;"/>
    <path d="M61.163,438.023C64.067,435.193 62.465,430.262 58.452,429.679L45.283,427.766C43.689,427.534 42.312,426.534 41.599,425.09L35.71,413.157C33.915,409.52 28.729,409.52 26.935,413.157L21.046,425.09C20.333,426.534 18.956,427.535 17.362,427.766L4.193,429.679C0.18,430.262 -1.421,435.194 1.482,438.023L11.01,447.311C12.164,448.435 12.689,450.054 12.417,451.641L10.169,464.757C9.484,468.754 13.679,471.801 17.268,469.914L29.046,463.722C30.471,462.973 32.174,462.973 33.599,463.722L45.377,469.914C48.966,471.801 53.161,468.753 52.476,464.757L50.227,451.642C49.955,450.055 50.48,448.436 51.634,447.312L61.163,438.023Z" style="fill:rgb(250,220,96);fill-rule:nonzero;"/>
    <path d="M403.053,85.968C377.514,106.035 331.223,146.121 303.757,206.362C300.047,214.498 301.902,224.098 308.353,230.29C331.471,252.48 389.535,295.699 451.558,234.658C509.854,177.284 460.332,117.679 431.163,87.834C423.636,80.132 411.52,79.315 403.053,85.968Z" style="fill:rgb(133,231,255);fill-rule:nonzero;"/>
    <path d="M330.206,208.437C323.755,202.245 321.902,192.645 325.61,184.509C339.693,153.62 358.724,128.045 377.37,107.736C352.891,130.259 323.473,163.116 303.756,206.362C300.046,214.498 301.9,224.098 308.352,230.29C331.47,252.48 389.534,295.699 451.556,234.658C455.511,230.765 458.954,226.863 461.957,222.959C404.341,268.579 351.895,229.255 330.206,208.437Z" style="fill:rgb(87,208,230);fill-rule:nonzero;"/>
    <path d="M463.722,33.601C462.972,32.175 462.972,30.473 463.722,29.048L469.914,17.27C471.8,13.681 468.753,9.486 464.757,10.171L451.642,12.421C450.055,12.693 448.436,12.167 447.311,11.014L438.023,1.485C435.192,-1.419 430.262,0.184 429.677,4.196L427.763,17.365C427.531,18.959 426.531,20.336 425.087,21.049L413.154,26.939C409.517,28.734 409.517,33.918 413.154,35.713L425.087,41.603C426.531,42.316 427.532,43.693 427.763,45.287L429.677,58.456C430.26,62.469 435.192,64.072 438.023,61.167L447.311,51.638C448.435,50.485 450.054,49.959 451.642,50.231L464.757,52.481C468.753,53.166 471.801,48.971 469.914,45.382L463.722,33.601Z" style="fill:rgb(250,220,96);fill-rule:nonzero;"/>

</svg>

If you open that file in a browser or graphics program you will see something like this...



As you can see this SVG contains multiple paths with different colors and it would simply be great to be able to visualize this in JavaFX.

So my SvgNode can handle multiple SvgPath objects which can be created using the SvgPathBuilder as follows:


SvgPath svgPath = SvgPathBuilder.create()
                                .path("M0,0L100,0L100,100,L0,100,L0,0Z")
                                .fill(Color.web("#85E7FF"))
                                .stroke(Color.TRANSPARENT)
                                .strokeWidth(0)
                                .lineCap(StrokeLineCap.ROUND)
                                .lineJoin(StrokeLineJoin.BEVEL)
                                .effect(new DropShadow())
                                .build();

Then you can create a SvgNode as follows:


SvgNode svgNode = new SvgNode(svgPath);
svgNode.setPrefSize(100, 100);

The initial size of the SvgNode should be the original size of your SVG file to get the best results. 
The SvgNode will parse the given path string and will draw the path on a JavaFX canvas node. This works great even with multiple paths but comes with one problem...scaling.
If you scale the SvgNode control it will scale the embedded Canvas node which can lead to blurred shapes if your original size was small and you size the control to a large size.
So for the best result you should create the SVG in the size you later on need the SVG in your application.
To come back to the example in the beginning...here is the representation of the sunglasses using my JavaFX SvgNode...


Not too bad for a quick hack... :)

As always you can find the source code over at github

I hope this will help one or the other...enjoy the upcoming weekend and keep coding...

Friday, March 1, 2019

TilesFX 11.1

Aloha,

Finally I've found some time to port TilesFX to Java 11. There are no new features yet but only the ability to use TilesFX with JDK11 and above.

Binaries for the different platforms can be found here:

JDK 8
Version 1.6.5 bintray 

Version 1.6.5 maven central.


JDK 11
Version 11.1 bintray

Version 11.1 maven central.

And that's it already, so keep coding...

Thursday, February 28, 2019

New charts...

Aloha,

Last year I superivsed two students from the FHNW in Switzerland at a work which was about creating two charts for my JavaFX charts library.
Unfortunately I simply was too busy to add them to the library but yesterday I finally found the time to do so.
So now you will find two new charts in the charts library which are a Pareto chart and a Force Directed Chart.
But first I have to say a big thank you to the two guys who did most of the work to make this charts happen, it is

Michael Läuchli and Stefan Mettler

They did a fantastic job in implementing these two charts and I'm more than happy to have the charts in my library.

The Pareto chart looks as follows:


The demo to test that chart can be found in the test package so feel free to play around with it.

The Force Directed Graph is more or less a copy of the d3 version of that chart and looks as follows:


You can load in different data and visualize it either using the mouse to organize the chart or use physics to let the chart organize itself.

The charts library can be found as always on github...

So have fun playing around with charts and keep coding...


Wednesday, February 6, 2019

Style it baby...

Aloha,

The people that know me know that I first was not a big fan of CSS in JavaFX and a year after that I was THE big fan of CSS but another year later I switched back to code only. There are several reasons for that but mainly it was about the performance of the CSS implementation and about missing features in CSS that made me mix up code and CSS which I did not like.
So I switched to code only in my Medusa and TilesFX library where I also use JavaFX Canvas which content is not styleable by CSS in the way the other nodes are.
Well don't get me wrong, I'm not completely against CSS in JavaFX, esp. for application level stuff it is great and fast enough. But when it comes to controls I do not really like it.
I knew that someday someone will ask me how to style a Medusa gauge or a TilesFX tile and here we go...

So if you really need to style a Medusa gauge by using CSS here is an example on how to do it.
In principle you need to create a new skin that makes use of CSS, in this example let's create a styleable version of the new PlainAmpSkin. It is simply a copy of the existing skin class where I removed the code that directly sets the colors and gradients and added some style classes.
The idea is to extend the Gauge class and in this new class add some styleable properties for the things that cannot be styled directly (e.g. the tickmarks and ticklabels because they are drawn in a Canvas node).
The styleable properties will be triggered by loading a css stylesheet that contains the defined style classes. So we simply add listeners to the styleable properties and trigger the appropriate properties in the Gauge class with the values from the styleable properties.
I hope you understand what I'm talking about :)
So the example is as follows:

1. We create a StyleableGauge class that has a styleable property named styleableTickmarkColor as follows:

public class StyleableGauge extends Gauge {

    private static final StyleablePropertyFactory<StyleableGauge> FACTORY = 
        new StyleablePropertyFactory<>(Control.getClassCssMetaData());
    
    private static final CssMetaData<StyleableGauge, Color> TICKMARK_COLOR = 
        FACTORY.createColorCssMetaData("-tickmark-color", 
        g -> g.styleableTickmarkColor, Color.rgb(220, 220, 220), false);
    
    private final StyleableProperty<Color> styleableTickmarkColor;


    
    public StyleableGauge() {
        this(SkinType.GAUGE);
    }
    public StyleableGauge(@NamedArg("SKIN_TYPE") final SkinType SKIN_TYPE) {
        super(SKIN_TYPE);
        styleableTickmarkColor = 
            new SimpleStyleableObjectProperty<>(TICKMARK_COLOR, 
                                                this, 
                                                "tickmark-color");
    }


    public Color getStyleableTickmarkColor() { 
        return styleableTickmarkColor.getValue(); 
    }
    public void setStyleableTickmarkColor(final Color COLOR) { 
        styleableTickmarkColor.setValue(COLOR); 
    }
    public ObjectProperty<Color> styleableTickmarkColorProperty() { 
        return (ObjectProperty<Color>) styleableTickmarkColor; 
    }


    @Override public String getUserAgentStylesheet() {
        return StyleableGauge.class.getResource("custom-plain-amp.css").toExternalForm();
    }

    public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
        return FACTORY.getCssMetaData(); }
    @Override public List<CssMetaData<? extends Styleable, ?>> getControlCssMetaData() { 
        return FACTORY.getCssMetaData(); 
    }
}



2. We create a css file named "custom-plain-amp.css" that looks as follows:

.gauge {
    BRIGHT_COLOR   : rgb(220, 220, 220);

    -tickmark-color: BRIGHT_COLOR;
}

3. Now we need to create our custom skin named "CustomPlainAmpSkin".
In this skin we make use of the css style classes. Because the skin file simply is too long to show it here.
The complete example can be found in the medusademo project on github.

With this you can style even canvas node content indirectly by triggering "standard" properties in the control by making use of "styleable" properties. 
I would not recommend to use this approach as the standard approach but it is good enough to make use of CSS even if the controls do not support CSS styling directly.

I hope that was more or less clear for you to understand...otherwise just let me know :)

Oh and do not forget to keep coding... ;)

Friday, February 1, 2019

Friday Fun LXI Part 2

Aloha,
Found some additional time today to close some bugs in my Medusa JavaFX library and in addition I've quickly created another skin called PlainAmpSkin.
There was the request for the ability to switch off the black part of the AmpSkin and just show the scale to save place.
Instead of adding another property to the Gauge class I've simply created another skin based on the AmpSkin but without the black frame.
Here are images of both skins to give you a better understanding of what I'm talking about...



Both controls have the same size but it is obvious that the lower control makes better use of the available space.
So I hope this new skin will fit the needs of the people that requested the feature.
This additional skin and some bugfixes can be found in the latest Medusa release which is now 8.2.

As always you can find the 

source at github

binary at bintray

and on maven central.

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

Friday Fun LXI

Aloha,

In the current project I needed a matrix like data structure that is observable and because I was not aware of one (even I'm pretty sure that there is something out there) I created my own observable matrix.
This little class is more or less a wrapper around an 2-dimensional array of objects which offers some convenient methods to add columns and rows.
Meaning to say it can hold for example a matrix of your own custom objects and it will fire different kind of events in case you added/removed/changed an item in the matrix. There are also events if columns/rows have been added or removed from the matrix.
If you remove a column item by item until all items of that column are gone the matrix will fire an event as soon as the column only contains null objects.
Because this is only a data structure and nothing fancy, I do not have any nice and shiny images to show this time.
The source code is available on github as always and you will find a little demo class in the source that demonstrates the functionality.

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

Friday, November 30, 2018

Friday Fun LX

Aloha,

Last monday I was up early and created a little control that I would do (again) for a long time. It is some kind of a rolling counter...well an odometer.
The whole thing was based on the JavaFX Canvas node which is great on desktop but not so good for JPro applications. 
So I thought about having a control like a single digit spinning wheel based on an ImageView. To be able to create such a control you need to create an image stripe that contains all the values you would like to "spin through".
This image has to be created every time you resize the control so you have to be aware of that. I've started with a numbering control that counts from 0-9 which means it contains at least 10 images. So far this is no problem but when I've started into an alphabetical control that counts from A-Z I had to handle at least 26 images plus an empty one if you would like to visualize a space character.
Meaning to say you should be careful when creating a lot of this alphabetical controls in a row because you will have to handle a lot of more or less big images (dependent on the size of the controls).
But long story short...here is a screenshot of the controls I'm talking about...



On top you see the Odometer control which is a simple counter that just counts up values. One can define the background and foreground colors for the digits and for the decimals independently. In addition one can define the number of digits you would like to see and the number of decimals.
On the lower image you see some combinations of the Spinner control, the upper part shows 7 alphabetical spinners in an HBox where the lower part shows the numerical spinners in HBoxes.

The Spinner control is available as ImageSpinner and CanvasSpinner with the exact same functionality just one is based on the ImageView and the other on the Canvas.

To give you an idea what it looks like I've recorded a little screen video of the controls in action...



As always you can find the source code over at github
I will also show this control next week at JavaFX days conference in Zurich.

That's it for today...so keep coding and hopefully see you next week in Zurich... :)

Sunday, November 25, 2018

TilesFX 1.6.5

Aloha,

I finally found some time to prepare another release of TilesFX. This release mainly contains fixes of different issues and one new skin.
First of all I would like to say thank's to the external pull requests that fixed two issues, it's always good to see people take over and fix things.
The skin I've mentioned is nothing that could not have done before with a custom tile skin but I saw some dashboard like apps that simply showed pictures of people on kind of tiles. Here is a little example of what I am talking about...


An so I thought this might be some nice add on to the library and was easy to do...so here you go...


Nothing really fancy but there might be some use cases for this kind of skin.
The skin takes the given image and a so called ImageMask which can be either

  • NONE
  • ROUND
  • RECTANGULAR

And this is how these ImageMasks look like...


That's all for the latest TilesFX release, I have ideas for more stuff to come but simply do not have the time at the moment...so please be patient... :)

***********************
Java 11
Another thing is porting the library to Java 11, I've started with a port to Java 11 but due to a lack of time was not able to finish this yet.
My plan was to create a new project for the Java 11 version which will be TilesFX11.

If one of you is interested and has the time he can start porting the library to Java 11.
It will be highly appreciated, so if you are interested, just ping me and we will figure out a way to work together.
***********************

The latest source code and binaries can be find at the following sites as always...

Source:    github

Binary:    bintray

Maven:    maven central


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

Wednesday, November 7, 2018

AnglePicker

Aloha,

Well it was just a question of time before I started to create a control for picking an angle as you might have guessed from my last post.
And here it is...a simple angle picker control:







You can simply rotate the knob to adjust the angle and if you double click on the control you can also enter the value directly into the text field.

The control has an angle property that contains the current angle that was set.

I needed this control for my gradient picker and thought you might want to use it too for whatever project you have :)

Watch this little video to see how it works...



So as always the source code can be found over at github

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

Wednesday, October 31, 2018

Another LinearGradient...

Aloha,

I was playing around with a JavaFX application for a customer and missed a functionality from the JavaFX LinearGradient. So you can define a linear gradient by defining a start and end point and fill it either proportional or not.
Well this works most of the time but if you have to create the linear gradient from code it sometimes could be useful if you simply could define an angle and a list of stops to define the gradient. So here is a little drawing that explains it a bit better:



In principle I would just need to extend the existing LinearGradient but unfortunately this is not possible :(
So I have to create a new class, in this case I named it LinearGradientD and this simply wraps a LinearGradient and takes an angle and a list of Stops as parameters.
So the main thing you have to do is to turn the angle in xy coordinates for the gradient and the code is really simple, so here it is:


private void init(final double angle, final List<Stop> stops) {
    this.angle = angle % 360;

    double angleRad = Math.toRadians(angle);
    double x        = Math.cos(angleRad);
    double y        = Math.sin(-angleRad);

    double x1 = x > 0 ? 0 : Math.abs(x);
    double y1 = y > 0 ? 0 : Math.abs(y);
    double x2 = x > 0 ? Math.abs(x) : 0;
    double y2 = y > 0 ? Math.abs(y) : 0;

    gradient = new LinearGradient(x1, y1, x2, y2, true, CycleMethod.NO_CYCLE, stops);
}

As you can see we simply calculate the xy values from the angle using some trigonometry and set the resulting xy coordinates in the wrapped LinearGradient object.
One advantage of using the angle to describe the gradient is that you can now also easily rotate the gradient as you can see in the following video:



Well I guess that's already it for today, nothing special but I thought it might be worth blogging about it.
Of course the code is available on github, so feel free to use it for whatever you need it.

So...keep coding... :)

Tuesday, October 23, 2018

Color Chooser

Aloha from San Francisco,

The last weeks I was really busy working on a customer project in JavaFX. At the moment I can't really show something but I needed an additional control which I now will open source. It is a color chooser as you can also find in some vector drawing programs.
Here is a screenshot of that control to give you an idea...


So as you can see this control is made to select a fill and a stroke which could than be applied to a shape or whatever you like.
You can switch between different color modes e.g. RGB, RGB Hex and HSL which will directly affect the three sliders. 
When choosing HSL the sliders will be used for Hue, Saturation and Luminance. I might also add HSB support but at the moment it only supports the three modes mentioned above.
You could either use the sliders or type in the values in the textfields behind the sliders. Or if you like you could also type in the color in the text field below the sliders.
In addition you can also select a color by clicking in the multi-gradient field.
For each selected color you can define the opacity by either using the opacity slider or select a predefined opacity from the drop down box besides the opacity slider.
You can define a color for the fill and one for the stroke depending on what you have selected on the top left.
The selection color (red in the screenshot) can also be defined.
Like mentioned I needed that control for a current customer project and so created it the way I need it. Meaning to say it might not directly work for you but as always you can find the code over at github, so feel free to fork it :)

Source at github

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

Sunday, August 26, 2018

Medusa Morphing Clock

Aloha,

During my vacation in Greece I've saw a nice video on youtube about a DIY morphing led matrix clock. There is a nice instruction on how to build this clock over here.
If you just would like to see what it looked like, here is a little video from that clock...


When I saw the animation of the 7-Segment elements I had the idea to add this as a clock skin to my Medusa library.
Yesterday I've added a skin that shows the same behaviour so that one can now use it within Medusa.

Here is a little video of how it looks:



I did not add the colons because in my version one can define a color for the hour, minute and second digits and I had no property for the colon color. So I simply did not at them :)

Here is a little code snippet that shows how to use the new skin:

Clock clock = ClockBuilder.create()
                          .skinType(ClockSkinType.MORPHING)
                          .locale(Locale.GERMAN)
                          .hourColor(Color.web("#0288FF"))
                          .minuteColor(Color.web("#0288FF"))
                          .secondColor(Color.web("#0288FF"))
                          .time(ZonedDateTime.of(2018, 8, 26, 6, 58, 0, 0, ZoneId.systemDefault()))
                          .running(true)

                          .build();

As you can see it is used in the same way as the other skins in Medusa. It will switch to am/pm mode if you set the local to Locale.US, otherwise it will use 24h format.

The skin will be part of the next Medusa release but is already in the source code.
As always the stuff can be found here:

Source at github

Binary at bintray

Enjoy your weekend and...keep coding... 

Sunday, July 22, 2018

Rolling Gradient

Aloha,

Last week I've stumbled upon an old blogpost from 2011 where I implemented an animated progressbar in Java Swing. At that time I was fascinated by the animated progressbar in OS X.
And when I saw the animated gradient I thought by myself why not do that in JavaFX???
In Swing we have immediate mode rendering which makes these kind of animated gradients easy because you do the whole rendering on your own. In JavaFX where we have retained mode rendering (so the rendering is managed by JavaFX) you have to find a way to update the gradient fill for a node for each animation step.
My approach is as follows, the RollingGradient uses an AnimationTimer to calculate the gradient and on each modification it fires an UpdateEvent which can be used to fill a shape with the gradient. The gradient is part of the event.
If you simply would like to fill a JavaFX shape you can also set the shape in the RollingGradient and it will be filled from there.

So you could either use the event as follows:

Rectangle       rectangle = new Rectangle(200, 20);
RollingGradient gradient  = RollingGradientBuilder.create()
                                                  .firstColor(Color.rgb(250, 0, 0))
                                                  .secondColor(Color.rgb(180, 0, 0))
                                                  .smoothGradient(true)
                                                  .direction(Direction.LEFT)
                                                  .interval(Speed.NORMAL.getInterval())
                                                  .period(5)
                                                  .onUpdateEvent(e -> rectangle.setFill(e.getGradient()))
                                                  .start()
                                                  .build();

Or you can set the shape in the RollingGradient and let it do the fill as follows:


Rectangle       rectangle = new Rectangle(200, 20);
RollingGradient gradient  = RollingGradientBuilder.create()
                                                  .firstColor(Color.rgb(250, 0, 0))
                                                  .secondColor(Color.rgb(180, 0, 0))
                                                  .smoothGradient(true)
                                                  .direction(Direction.LEFT)
                                                  .interval(Speed.NORMAL.getInterval())
                                                  .shape(rect)
                                                  .period(5)
                                                  .start()
                                                  .build();

Both approaches will lead to the following output:


As you can see from the code there are some properties you can use to modify the gradient:

  • firstColor (set first color of gradient)
  • endColor (set second color of gradient)
  • smoothGradient
  • direction (rolling to left or right)
  • interval (defines the time in nanoseconds for the animation speed)
  • shape (a given shape that will be filled with the gradient)
  • period (defines the width for one color change)
  • start (when called will start the rolling gradient)

In the next example I've changed some parameters to give you an idea of what you can do:


Rectangle       rectangle = new Rectangle(200, 20);
RollingGradient gradient  = RollingGradientBuilder.create()
                                                  .firstColor(Color.rgb(88, 154, 227))
                                                  .secondColor(Color.rgb(50, 130, 222))
                                                  .smoothGradient(false)
                                                  .direction(Direction.RIGHT)
                                                  .interval(Speed.FAST.getInterval())
                                                  .shape(rect)
                                                  .period(15)
                                                  .start()
                                                  .build();

With this settings the gradient will look like follows:


And because images are boring I've recorded a short video for you that shows the rolling gradient in action...



Well that's it for today and as always you can find the source code on github.

So keep coding...

Tuesday, July 17, 2018

Anchor Selector control

Aloha,

Another control that I saw in Adobe Fireworks and other drawing programs is a control that is used to select an anchor. One can use it to select the origin or to define the position in a layout etc.
Here is a little screenshot of the control in Adobe Fireworks:


The original control is not very big which explains the blurry screenshot, so here is my version of that control implemented in JavaFX:


It's not very fancy that's for sure but sometimes you might need exactly such a control and then you know where to find it :)

The method getSelectedAnchor() will return a Pos object that you can use for whatever you need it.

Here is also a little video that shows the control in action...




In principle that's it and as always you can find the source code at github.

Keep coding...

Saturday, July 14, 2018

GradientPicker reloaded...

Aloha,

Because I worked a lot with Adobe Fireworks over the last 10 years I was using it's gradient tool very often. It is a handy tool to create color gradients where you can simply add new gradient stops and set the color and opacity for each stop either with a slider or by typing in the value.
This is how the Adobe Fireworks gradient tool looks like:



The functionality of the upper handles is to adjust the opacity of the selected stop where the lower handle is to set the color of the stop.
In 2013 I've already created a gradient picker in JavaFX but it was not a separate control but more part of a screen color picker.
So far so good but I always wanted to redo the gradient picker I've created at that time.
Well...after some night hacks I finally finished that gradient picker and so you can now also use it if you like. Here is what the current result looks like:



In principle it has the same functionality as the gradient tool in Adobe Fireworks. I've created a little video that demonstrates it's functionality:



And that's it for today, as always you can find the source code at github.

I hope this control will be useful for one or the other of you and don't forget...keep coding...

Friday, July 6, 2018

Tiles 1.6.4

Aloha,

During the last days and nights I've found some time to add some stuff to TilesFX.
First of all I've modified the calculation of the color gradient that is used in the SparkLineTileSkin and GaugeSparkLineTileSkin.
Because the spark lines only show the line between the low and high value that was measured in the given range it might happen that the color gradient has to be adjusted to the visible range of values.
This now works as expected (at least expected by me).

The code to define the following tile is:

Tile tile = TileBuilder.create()
                       .skinType(SkinType.SPARK_LINE)
                       .prefSize(400, 400)
                       .title("CO2")
                       .unit("ppm")
                       .minValue(400)
                       .maxValue(60000)
                       .decimals(0)
                       .tickLabelDecimals(0)
                       .time(ZonedDateTime.now(ZoneId.of("Europe/Berlin")))
                       .gradientStops(new Stop(0, Color.web("#1CAF4D")),
                                      new Stop(0.0075, Color.web("#1CAF4D")),
                                      new Stop(0.00751, Color.web("#91CA40")),
                                      new Stop(0.01166, Color.web("#91CA40")),
                                      new Stop(0.01167, Color.web("#F8C610")),
                                      new Stop(0.01666, Color.web("#F8C610")),
                                      new Stop(0.01667, Color.web("#F29222")),
                                      new Stop(0.025, Color.web("#F29222")),
                                      new Stop(0.02501, Color.web("#EC1D24")),
                                      new Stop(1.0, Color.web("#EC1D24")))
                       .strokeWithGradient(true)
                       .averagingPeriod(96)
                       .smoothing(true)

                       .build();

And the result when using TilesFX < 1.6.4 looks as follows:


As you can see the gradient used to color the spark line was just a linear gradient from the color calculated for the low value (here 400) to the high value (here 1036). There are no other colors in between even if the gradient stops in the builder contain more stops.
When using the same tile in TilesFX >= 1.6.4 the result will look as follows:


Based on the gradient stops defined in the builder we now see all levels for the different zones we defined.
Meaning to say the color gradient used to stroke the spark line will now always dynamically calculated dependent on the low and high value.
In addition I've added a  new skin named BarGaugeTileSkin which is another gauge visualization that you often can find in dashboards. It looks as follows...



As you can see it shows the current value, a bar with the min and max value and a threshold indicator with a text.
The color of the bar can be customized by

  • bar color property
  • sections
  • gradient stops

So if you would just simply change the color of the bar you just set the bar color by calling

setBarColor(YOUR COLOR) or .barColor(YOUR COLOR) in the TileBuilder.

If you would like to set the bar color dependent on sections (e.g. color the bar red if the value is higher than 80) you might want to define sections and enable them as follows:

Tile tile = TileBuilder.create()
                       .skinType(SkinType.BAR_GAUGE)
                       .prefSize(200, 200)
                       .minValue(0)
                       .maxValue(100)
                       .sectionsVisible(true)
                       .sections(new Section(80, 100, Color.RED))
                       .build();

And if you would like to set the bar color along a defined color gradient you have to define the gradient stops and enable them as follows:

Tile tile = TileBuilder.create()
                       .skinType(SkinType.BAR_GAUGE)
                       .prefSize(200, 200)
                       .minValue(0)
                       .maxValue(100)
                       .strokeWithGradient(true)
                       .gradientStops(new Stop(0.0, Bright.BLUE),
                                      new Stop(0.5, Bright.GREEN),
                                      new Stop(1.0, Bright.RED))
                       .build();

In principle that's all I did but I thought it was worth a new release, so as always please find the latest version here:

Source: github

Binary: bintray

Maven Central

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