Wednesday, November 30, 2016

Medusa KPI Skins

At the current project I'm working on a JavaFX dashboard using gauges...which is awesome :)
And so I was looking for interesting designs that might be useful for a dashboard visualizing KPI's (Key Performance Indicators). So I stumbled upon two interesting designs that might be a good fit for a grid or tile based dashboard layout.
So here they are...



The TileTextKpiSkin on the left side shows the current value by the text, a bar, the maximum value it could reach (here 100) and the value in percentage.
The TileKpiSkin on the right side shows the current value by it's number, a defined threshold (75) and a needle that shows where the current value is in the given range.
Both tiles also show a title on the upper left corner.
Well...it's nothing special but didn't take long to implement it so why not :)

Both skins are part of the latest Medusa version (6.3) which you can find here


*** UPDATE ***
After playing around with the new skins I came to the conclusion that it would also make sense to have the ability to visualize sections. So I've added them to both skins and they will be available with the next version (6.4) of Medusa.
Here is a little screenshot of how they will look like...


So as soon as you have sections enabled the threshold won't be shown on the left skin (TileKpiSkin) but only the active section.
On the right right skin (TileTextKpiSkin) the bar and the percentage text will either be colored with the default value (barColor) or with the color of the active section. I've also added the unit text for the right skin.

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

Saturday, November 19, 2016

WorldMap Cosmetics

Aloha again,

Remember the the world map control that I've created during JavaOne? Because it is based on high resolution SVG data the map is big (from a memory point of view). Sometimes you need high res but sometimes you don't...long story short...I've created also a low resolution version of the map.

Here is a little screenshot that shows both maps (the upper one is the low-res version and the lower one the high-res version)...



At the moment both maps are in the same repo which you can find on github

Oh and before I forget to mention it, there is now also support for CSS styling available.

That's it for a Saturday morning...now I need more coffee ;) 

*** UPDATE ***
More fun on a Sunday morning... :)

I've added the possibility to visualize locations by their latitude and longitude. With this you could mark locations like airports, cities etc. At the moment the indicator is just a simple circle but I might change this in the near future. It would be cool if one could also use icons like fontawesome etc. to visualize the location (maybe I'll be able to implement this next week).
Here is a screenshot that shows some major airports on the world map...




Oh and be warned that there will be modifications coming soon...just need more time :)

*** UPDATE 2 ***
Like mentioned there have been more modifications but now I guess the world map component is ready to go. At least I have no further ideas anymore at the moment.
Here is a list of changes that I did...

  • got rid of the scalable content pane
  • moved the SVG paths to property files
  • added support for Ikonli icons
  • added mouse wheel zooming at mouseposition
  • added selectable countries
  • added zoom to country method
  • mouse handler support for locations
  • clean ups

Here is another screenshot...




*** UPDATE 3 ***

The more I play around with it the more ideas are coming... :)
While I was skimming the web for some new ideas I saw some worldmaps in business dashboards where they use it to visualize regions like APAC, EMEA etc.
So I thought it might be useful to support those business regions and add some convenience methods to handle them.



On the map above you see the European Union (in it's current state) colored and centered. To get this view you simply have to call two methods now...


BusinessRegion.EU.setColor(Color.rgb(124, 208, 255));
world.zoomToRegion(BusinessRegion.EU);

I thought this might be useful for dashboard kind of things so you will now find a new enum called Business Region which contains the following regions

  • AMERICAS
  • APAC
  • APJC
  • ANZ
  • BENELUX
  • BRICS
  • DACH
  • EMEA
  • EU
  • NORAM

Because I do not know which other business regions could be useful I've also added the possibility to add your own region by using the new CountryRegion class. So if you would like to create a region with the countries Belgium, Netherlands and Luxemburg (which are the Benelux) you can do this with the following line of code...

CountryRegion myRegion = new CountryRegion("BENELUX", BE, NL, LU);

There is one little problem at the moment when zooming to the region APAC. Because  APAC contains countries on the very right and left of the map (this is related to the used Mercator projection) which makes zooming in not really useful.

If you have other needs or ideas on how to improve the world map control, please let me know :)

So feel free to use it for what ever you need it...

And don't forget...keep coding...

Friday, November 18, 2016

Medusa Industrial Clock Skin

And another one...
Yesterday I was in Stuttgart and on my way back one of my train connections was canceled. This gave me another hour of coding in the Starbucks at the Cologne train station. I mean coffee and code...what could be more productive ;)
So I was searching the picture app on my mac and stumbled upon a clock that I would like to implement for a long time, to be honest it have been two clocks but take a look yourself, here they are...



As you can see it is the same watch face just in two different colors. This clock looks similar to one of the Apple Watch watch faces and so I decided to create a new clock skin for Medusa.
Here is my implementation in Medusa...



The only thing that's missing is the glossy overlay but that can be added later by yourself. The new skin is named IndustrialClockSkin and will be available in the upcoming release 6.3 of Medusa.

To create the dark version of the clock you need to create it like follows...

clock = ClockBuilder.create()
                    .skinType(ClockSkinType.INDUSTRIAL)
                    .prefSize(400, 400)
                    .locale(Locale.GERMANY)
                    .shadowsEnabled(true)                    
                    .running(true)
                    .backgroundPaint(Color.web("#1f1e23"))
                    .hourColor(Color.web("#dad9db"))
                    .minuteColor(Color.web("#dad9db"))
                    .secondColor(Color.web("#d1222b"))
                    .hourTickMarkColor(Color.web("#9f9fa1"))
                    .minuteTickMarkColor(Color.web("#9f9fa1"))
                    .build();

For those of you that would like to use before...just grab the code from github...

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

Wednesday, November 9, 2016

Medusa DesignClock Skin

Aloha,

Last weekend I was looking for some inspiration for new UI controls and stumbled upon a really interesting watch design. The moment I saw it I knew I need to create a JavaFX control of it.
Well lucky me with Medusa in place I only had to create the clock skin which was an easy task (after I wrapped my brain around the transformation and clipping stuff).
So here is the original version that I've found on the web...



And here is a little video of my Medusa version...



I think my version is close enough to the original one and because it's now part of Medusa you can enjoy it too :)

It will be part of the next Medusa release which will be 6.2 but if you can't wait feel free to check out the latest version of Medusa at github.

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

Tuesday, November 1, 2016

Medusa update...

Aloha,

Last weekend I've found some time to give some love the Medusa project again. Besides some minor cosmetics I've decided to add a moving average feature to the Gauge class.
Usually I would say that such a feature should not be part of a control but in this case I've decided to add it anyway. It's just nice if a Gauge or LCD display could display a moving average of the measured values. And for this reason I've added all the needed properties to the Gauge class.
These properties are

  • averagingEnabled (switch averaging in general on/off)
  • averagingPeriod (defines the number of values to average over from 1-1000)
  • averageVisible (defines the visibility of an average indicator)
  • averageColor (defines the color for an average indicator)

In addition you will now find new methods in the Gauge class to get the average. These methods are

  • getAveragingWindow() (returns the list of Data objects used for the average)
  • getAverage() (returns the moving average over the given averagePeriod)
  • getTimeBasedAverageOf(Duration) (returns the moving average over a given duration)

The default value for the moving average period is 10 which means if averaging is enabled the getAverage() method will always return the average over last 10 measured values.
Because sometimes you are more interested in the average over the last 10 minutes or 60 seconds, I've decided to add a method that will calculate the average for a given duration.
Means if you call the getTimeBasedAverageOf(Duration.ofMinutes(10)) method it will calculate the average from the values that have been measured within the last 10 minutes. Please keep in mind that you have to know how often you measure/display data using the gauge to get proper results.
So it doesn't make sense to calculate the time based average of the last 10 seconds if the value was not changed within the last 10 seconds.
As a start I've implemented the new feature in the Gauge.skin and Lcd.skin class. In the Gauge.skin there is a new indicator which looks like the threshold indicator but with a different color (Magenta as default) and in the Lcd.skin it will show the average value instead of the lastMeasured value in the lower center text (if averageVisible == true).
Keep in mind that you have to enable averaging otherwise the value won't change.

On the following screenshot of the Lcd.skin you can see how it looks like:


This feature will be part of the next Medusa release which will be 6.1 so stay tuned.

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

Friday, October 14, 2016

Friday Fun XLI

Aloha,

Today I'm a bit late but it's still Friday and so I have some control for you again...
The first time I saw such a control was after I've updated my iPhone to iOS 10. In that release Apple added a sleep timer to the Clock app and this sleep timer looks like follows...



I can't really tell you why but somehow this control looks nice. In this case the use case is very specific but I thought such a control could be fun to use as a time selector. So my idea was to create a control that makes it possible to define a start- and an end-time where the possible range should be within 24 hours.
And this is the biggest difference between Apple's and my control, mine has double as many hours to select.
Well, long story short, here is a litte screenshot of the control...



Because I don't use it as a sleep timer I modified the start and stop icon to a simple triangle for start and a rectangle for stop. This icons are defined in the css file where everything else is done in code.
And to give you an idea how it looks in action here is a little screen video of it...



And as always if you are interested in the code, feel free to fork it at github...

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

Friday, October 7, 2016

Friday Fun XL

And here we go again...
Today I have another component for you which is a bit more than a simple component. For JavaOne I've created a Weather widget which I used for Anton Epple's and mine "Hack your brush" session and I thought some of you might be interested in the code for that widget.

ATTENTION:
To get the weather widget running you will need an API key for Dark Sky and for MapQuest. Both vendors offer a free plan with limited no of requests per day.
Here are the links to get your API key:



The Dark Sky key is needed to get the weather information for a given location (defined by latitude and longitude) and the MapQuest key is needed to geo code and reverse geo code addresses and locations (in case you don't know the latitude and longitude of your location). If you know the latitude and longitude of your location you won't need the MapQuest key. In this case you can create a Location object as follows:


Location home = new Location(LATITUDE, LONGITUDE, "Home");

If you don't add the the name string for your location the app will try to lookup the name of the city by using the mapquest reverse geocoding feature.
In the current version you need to set bot API keys as environment variables on your system in order to get WeatherFX running. You could also replace the code in the ApiKeys class with the following snippet to get it running:

Current version:
public class ApiKeys {
    public static final Optional<String> DARK_SKY_API_KEY = Optional.ofNullable(System.getenv("DARK_SKY_API_KEY"));
    public static final Optional<String> MAPQUEST_API_KEY = Optional.ofNullable(System.getenv("MAPQUEST_API_KEY"));
}

Modified version:
public class ApiKeys {
    public static final String DARK_SKY_API_KEY = YOUR_DARK_SKY_KEY;
    public static final String MAPQUEST_API_KEY = YOUR_MAP_QUEST_KEY;
}

If you change the code in the ApiKeys class you also have to replace all calls in DarkSky.java and GeoCode.java from 


DARK_SKY_API_KEY.get() and MAPQUEST_API_KEY.get()

to


DARK_SKY_API_KEY and MAPQUEST_API_KEY

So I've stripped the WeatherFX stuff out of the demo and now I'm able to give it to you. Here is what it looks like...



The following data will be shown:

  • City name (either set manual or reverse geocoded)
  • Date and current time
  • Current weather condition
  • Current temperature
  • Current pressure
  • Current humidity
  • Current windspeed
  • Weather forecast for the next 5 days incl. Weather condition, min- and max-temperature
But there is much more information in the response, I only show a little part of it to avoid overloading the UI. The information that is available can be found at 


The weather will automatically be updated every 15 minutes from the Location class and the free developer API key from Dark Sky allows you to request the weather information 1000x each day which should be more than enough.
The background of the panel can be styled by adjusting the -fx-background-color setting in the .weather-panel selector in the weatherfx.css file.
The WeatherPanel is the main widget that you can use your JavaFX application. Instead of using existing icons like the WeatherIcons from Ikonli I've decided to create my own icons. This icons are Regions that will be styled using CSS.
I see this widget as a little demo that shows how to create a weather widget but because I just created it for a demo there is a lot of room for improvements :)

Feel free to fork the code as always on github.

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