Thứ Tư, 13 tháng 2, 2013

Styling JavaFX Pie Chart with CSS

JavaFX provides certain colors by default when rendering charts. There are situations, however, when one wants to customize these colors. In this blog post I look at changing the colors of a JavaFX pie chart using an example I intend to include in my presentation this afternoon at RMOUG Training Days 2013.

Some Java-based charting APIs provided Java methods to set colors. JavaFX, born in the days of HTML5 prevalence, instead uses Cascading Style Sheets (CSS) to allow developers to adjust colors, symbols, placement, alignment and other stylistic issues used in their charts. I demonstrate using CSS to change colors here.

In this post, I will look at two code samples demonstrating simple JavaFX applications that render pie charts based on data from Oracle's sample 'hr' schema. The first example does not specify colors and so uses JavaFX's default colors for pie slices and for the legend background. That example is shown next.

EmployeesPerDepartmentPieChart (Default JavaFX Styling)

package rmoug.td2013.dustin.examples;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

/**
* Simple JavaFX application that generates a JavaFX-based Pie Chart representing
* the number of employees per department.
*
* @author Dustin
*/
public class EmployeesPerDepartmentPieChart extends Application
{
final DbAccess databaseAccess = DbAccess.newInstance();

@Override
public void start(final Stage stage) throws Exception
{
final PieChart pieChart =
new PieChart(
ChartMaker.createPieChartDataForNumberEmployeesPerDepartment(
this.databaseAccess.getNumberOfEmployeesPerDepartmentName()));
pieChart.setTitle("Number of Employees per Department");
stage.setTitle("Employees Per Department");
final StackPane root = new StackPane();
root.getChildren().add(pieChart);
final Scene scene = new Scene(root, 800 ,500);
stage.setScene(scene);
stage.show();
}

public static void main(final String[] arguments)
{
launch(arguments);
}
}

When the above simple application is executed, the output shown in the next screen snapshot appears.

I am now going to adapt the above example to use a custom "theme" of blue-inspired pie slices with a brown background on the legend. Only one line is needed in the Java code to include the CSS file that has the stylistic specifics for the chart. In this case, I added several more lines to catch and print out any exception that might occur while trying to load the CSS file. With this approach, any problems loading the CSS file will lead simply to output to standard error stating the problem and the application will run with its normal default colors.

EmployeesPerDepartmentPieChartWithCssStyling (Customized CSS Styling)

package rmoug.td2013.dustin.examples;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

/**
* Simple JavaFX application that generates a JavaFX-based Pie Chart representing
* the number of employees per department and using style based on that provided
* in CSS stylesheet chart.css.
*
* @author Dustin
*/
public class EmployeesPerDepartmentPieChartWithCssStyling extends Application
{
final DbAccess databaseAccess = DbAccess.newInstance();

@Override
public void start(final Stage stage) throws Exception
{
final PieChart pieChart =
new PieChart(
ChartMaker.createPieChartDataForNumberEmployeesPerDepartment(
this.databaseAccess.getNumberOfEmployeesPerDepartmentName()));
pieChart.setTitle("Number of Employees per Department");
stage.setTitle("Employees Per Department");
final StackPane root = new StackPane();
root.getChildren().add(pieChart);
final Scene scene = new Scene(root, 800 ,500);
try
{
scene.getStylesheets().add("chart.css");
}
catch (Exception ex)
{
System.err.println("Cannot acquire stylesheet: " + ex.toString());
}
stage.setScene(scene);
stage.show();
}

public static void main(final String[] arguments)
{
launch(arguments);
}
}

The chart.css file is shown next:

chart.css

/*
Find more details on JavaFX supported named colors at
http://docs.oracle.com/javafx/2/api/javafx/scene/doc-files/cssref.html#typecolor
*/

/* Colors of JavaFX pie chart slices. */
.data0.chart-pie { -fx-pie-color: turquoise; }
.data1.chart-pie { -fx-pie-color: aquamarine; }
.data2.chart-pie { -fx-pie-color: cornflowerblue; }
.data3.chart-pie { -fx-pie-color: blue; }
.data4.chart-pie { -fx-pie-color: cadetblue; }
.data5.chart-pie { -fx-pie-color: navy; }
.data6.chart-pie { -fx-pie-color: deepskyblue; }
.data7.chart-pie { -fx-pie-color: cyan; }
.data8.chart-pie { -fx-pie-color: steelblue; }
.data9.chart-pie { -fx-pie-color: teal; }
.data10.chart-pie { -fx-pie-color: royalblue; }
.data11.chart-pie { -fx-pie-color: dodgerblue; }

/* Pie Chart legend background color and stroke. */
.chart-legend { -fx-background-color: sienna; }

Running this CSS-styled example leads to output as shown in the next screen snapshot. The slices are different shades of blue and the legend's background is "sienna." Note that while I used JavaFX "named colors," I could have also used "#0000ff" for blue, for example.

I did not show the code here for my convenience classes ChartMaker and DbAccess. The latter simply retrieves the data for the charts from the Oracle database schema via JDBC and the former converts that data into the Observable collections appropriate for the PieChart(ObservableList) constructor.

It is important to note here that, as Andres Almiray has pointed out, it is not normally appropriate to execute long-running processes from the main JavaFX UI thread (AKA JavaFX Application Thread) as I've done in this and other other blog post examples. I can get away with it in these posts because the examples are simple, the database retrieval is quick, and there is not much more to the chart rendering application than that rendering so it is difficult to observe any "hanging." In a future blog post, I intend to look at the better way of handling the database access (or any long-running action) using the JavaFX javafx.concurrent package (which is well already well described in Concurrency in JavaFX).

JavaFX allows developers to control much more than simply chart colors with CSS. Two very useful resources detailing what can be done to style JavaFX charts with CSS are the Using JavaFX Charts section Styling Charts with CSS and the JavaFX CSS Reference Guide. CSS is becoming increasingly popular as an approach to styling web and mobile applications. By supporting CSS styling in JavaFX, the same styles can easily be applied to JavaFX apps as the HTML-based applications they might coexist with.

Thứ Ba, 12 tháng 2, 2013

JavaFX Coming Soon to an Android or iOS Device Near You?

There has been big news recently in the world of JavaFX regarding many more components of JavaFX being open sourced as advertised at JavaOne 2012. In February Open Source Update, Richard Bair compiled a table of JavaFX projects that have been open sourced as of that post's writing (Monday, 11 February 2013). As exciting as all that open sourcing is, there was something even more exciting highlighted below the table: "We’re also going to open source our iOS and Android implementations over the next couple months."

Bair adds some timing and background information to this significant announcement:

The first bits and pieces for iOS should be out next week, with the rest of iOS and Android coming out at about the same time as the rest of prism (there is some timing dependency there). Both our ports are based on an as-yet unreleased version of JavaSE Embedded for iOS/Android.

After expressing the expected caveat "I’m not a lawyer", Bair also addresses licensing issues on iOS and points out that "both OpenJFX and OpenJDK are both licensed with the same GPLv2 with Classpath Extension." He further describes his understanding of the licensing situation: "this means that if you take OpenJFX + OpenJDK (minus any binary stubs released under a different license), then you can safely combine this with your application and release your application under your own license as a single application co-bundle." I am sure we'll hear more about the licensing details in the future as this develops.

Being able to develop Android and iOS applications with JavaFX will likely be a game-changer for JavaFX. I echo Bair's concluding sentence: "I am looking forward to seeing what you all will do with this contribution, and hope to be running many Java apps on my phone / iPad in the near future." I look forward to using (and maybe even writing) some JavaFX-based apps on my Droid! I am presenting on JavaFX at Rocky Mountain Oracle Users Group (RMOUG) Training Days 2013 tomorrow, so the timing of this announcement couldn't have been better.

Thứ Hai, 11 tháng 2, 2013

Hello GroovyFX

GroovyFX brings together two of my favorite things: Groovy and JavaFX. The main GroovyFX Project page describes GroovyFX as "[providing] a Groovy binding for JavaFX 2.0." GroovyFX is further described on that page:

GroovyFX is an API that makes working with JavaFX in Groovy much simpler and more natural. GroovyFX is focused on exploiting the power of the Groovy Builder pattern to make JavaFX development easier and more concise than what is possible in Java. GroovyFX also leverages Groovy's powerful DSL features and AST transformations to eliminate boilerplate, making GroovyFX code easier to write and, just as importantly, easier to read.

The just referenced main GroovyFX page includes a "Hello World" example. In this post, I look at an even simpler "Hello World" example using GroovyFX. After that, I look at a slightly more involved example of using GroovyFX to render a Pie Chart. Both of these are examples I intend to show at my RMOUG Training Days 2013 presentation ("Charting Oracle Database Data with JavaFX and Groovy") this coming week.

A bare-bones GroovyFX Hello World! example is shown in the next code listing.


import groovyx.javafx.GroovyFX
import groovyx.javafx.SceneGraphBuilder
import javafx.stage.StageStyle
import javafx.stage.Stage

GroovyFX.start
{
stage(title: 'RMOUG Training Days 2013',
width: 300, height: 100,
show: true)
{
scene
{
stackPane
{
text('Hello GroovyFX!', x: 50, y: 40)
}
}
}
}

Running the above script leads to the following output:

The code and screen snapshot show how the concise text of GroovyFX makes it easy in just a few lines of code to specify a fully functioning JavaFX graphical application.

The next code listing shows a slightly more involved examples that generates a JavaFX Pie Chart. The database access code is not shown here, but it is easily accomplished with JDBC or Groovy SQL.


import rmoug.td2013.dustin.examples.ChartMaker
import rmoug.td2013.dustin.examples.DbAccess
import groovyx.javafx.GroovyFX
import groovyx.javafx.SceneGraphBuilder
import javafx.stage.StageStyle
import javafx.stage.Stage

def databaseAccess = DbAccess.newInstance()

GroovyFX.start
{
stage(title: 'Employees Per Department',
width: 800, height: 500,
show: true)
{
scene
{
stackPane
{
pieChart(title: 'Number of Employees per Department',
data: ChartMaker.createPieChartDataForNumberEmployeesPerDepartment(
databaseAccess.getNumberOfEmployeesPerDepartmentName()))
}
}
}
}

The above GroovyFX code leads to the following screen snapshot.

The simple GroovyFX code shown above combines Groovy with JavaFX to render a pie chart representation of the number of employees per department in the Oracle 'hr' sample schema.

The next code sample indicates the roughly equivalent source code for a JavaFX application that does not use GroovyFX.


package rmoug.td2013.dustin.examples;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class EmployeesPerDepartmentPieChart extends Application
{
final DbAccess databaseAccess = DbAccess.newInstance();

@Override
public void start(final Stage stage) throws Exception
{
final PieChart pieChart =
new PieChart(
ChartMaker.createPieChartDataForNumberEmployeesPerDepartment(
this.databaseAccess.getNumberOfEmployeesPerDepartmentName()));
pieChart.setTitle("Number of Employees per Department");
stage.setTitle("Employees Per Department");
final StackPane root = new StackPane();
root.getChildren().add(pieChart);
stage.setScene(new Scene(root, 800 ,500));
stage.show();
}

public static void main(final String[] arguments)
{
launch(arguments);
}
}

The code for the direct JavaFX example can be compared to the GroovyFX example to see how the GroovyFX syntax is more concise (as is expected for something based on Groovy) and arguably more readable than the straight JavaFX code (though I maintain the JavaFX code is fairly readable in its own right). Comparing the two code samples also helps to see how GroovyFX uses property names well-known to users of the JavaFX API.

I am a fan of Groovy and of JavaFX and GroovyFX brings them together.