Now that Oracle has given us a Technical Preview of JDeveloper 11g which includes the Rich Components – that will also be made available as open source library through the Apache MyFaces project -, it is interesting to give it a spin and see what it can do for us.
I have created a very simple Web Application with Model and ViewController projects. The Model project contains an Application Module
– HrmModule – with a bunch of ViewObjects.
Since I have decided to create a Stacked BarChart that shows a bar per department and within that bar a section for every job, the height of the bar and the sections representing the sum of salaries, per job and for the entire department.
To present that data, I first need to get it and make it available through an ADF Data Control. I create a new ViewObject, SalPerJobPerDept. It is a read only query with a custom SQL statement, shown below.
I add the ViewObject to the Data Model of the Application Module:
Now it shows up in the Data Controls palette. I create a brand new JSF page, accepting all defaults. Next I drag and drop the SalPerJobPerDept Collection in the HrmModuleDataControl to my new page, dropping it as a Graph of type ADF Bar (Horizontal Stacked)
Now we have to configure the Graph Data Binding. This is where we tie the Data Control’s collection to the Bar Chart we are creating.
The Group Attributes in this case specify the stacks in the bars. Since we want stacks per Job, we select Job as the Group Attribute. The value to display for this Group is the value of the Job attribute itself.
We then specify the actual value to be represented in the graph: a typed attribute with Usage set to Numerical Value, Data Attribute set to SumSal as that is the attribute from the collection that we want to provide the value to be displayed in the chart and finally a label, set to Sum of Salaries. Next we can specify one or more categories, basically creating one or more bars. We want a bar per department, so we have to add a Typed Attribute with usage set to Data Category, Data Attribute set to Deptno and Label derived from Data Attribute. I do not know if we can assemble a Label using a combination of static text and dynamic data, such as: Department #{Deptno}. What we can do though is change the label for the Numeric Value to: Sum of Salaries for Department.
Note: for more details on binding graphs, see: http://www.oracle.com/technology/products/jdev/11/how-tos/graph/configuring_graph_types.html.
Press OK and the chart is presented in the WYSIWYG editor:
Let’s run the application, as the graph is now ready for the spotlight:
With a few additional configuration settings, we can quickly add Titles and a 3D effect:
Running the page gives this result:
Note that I am still within the first 10 minutes development time!
We can add listener to the graph that respond to click events. At this point I am trying to figure out how to get to the values of the Dimensions and Measure for clicked element. More on that later.
Let fiddle with some other config settings: style and imageFormat.
It turns out that imageFormats are not yet all available, or at least I get an error when I select SVG or Flash.
The Earth style gives me the following look and feel. Nice eh?
These charts are informative, appealing and pretty cool just the way they are. However, it gets even better: they are interactive! Clicking on the graph can trigger a response on several ways: drilling down, synchronizing a section on the screen based on the area selected, navigating somewhere, changing properties of the charts – anything you like.
The steps to listen to such click events and responding to them are amazingly straightforward.
Create a Managed Bean that will deal with the click events:
Create a method in the managed bean, for example called ClickListener, although more imaginative names may spring to mind.
Now set the ClickListener property for our Bar component, and have it refer to the method in the managed bean.
We now have to implement the ClickListener method. Go to the EmpSalBarListener class. The signature is simple: the method takes a ClickEvent input parameter and has a void return value.
And here I was stuck. I could not find a way to pry the values of the stack that was clicked on from the ClickEvent. I made some headway, but not enough. And just as I started feeling sorry for myself – trying this out yesterday afternoon at SFO airport just prior to catching my flight back home, I discover that Frank Nimphius blogged about this: http://www.orablogs.com/fnimphius/archives/001961.html – maybe triggered by my plea for help on the JDev 11g forum (http://forums.oracle.com/forums/thread.jspa?threadID=506982&tstart=0 ).
So now I can implement my ClickListener method as follows:
public void ClickListener(ClickEvent clickEvent) {
DataComponentHandle dch = (DataComponentHandle)clickEvent.getComponentHandle();
ComponentInfo ci = dch.getComponentInfo();
UIGraph graph = (UIGraph)clickEvent.getSource();
int iColNum = ((DataComponentHandle)dch).getColumn();
int iRowNum = ((DataComponentHandle)dch).getRow();
Object graphData = null;
try {
graphData =
graph.getGraphDataModel().getDataAccess().getValue(iRowNum,iColNum,DataMap.DATA_UNFORMATTED);
} catch (Exception e) {
// TODO
}
System.out.println("mouseClicked(): Data value clicked on: "+graphData.toString());
}
Now I know which value was selected. However, I do not yet know the dimension values (in this case the Deptno and Job value). I have asked Frank and he has promised to look into this. … Several days later: the thread on the OTN Discussion Forums has been updated by Katia Obradov who hands me the solution to how to get to the dimension values for the element clicked on in the graph. Using her valuable help, I can learn about the Job value like this:
String job = (String)graph.getGraphDataModel().getDataAccess().getMemberMetadata(DataDirector.ROW_EDGE,
0,/*layer*/
iRowNum,/*slice*/
MetadataMap.METADATA_LONGLABEL);
In a similar fashion, we can retrieve another Data Point:
String dataPoint = graph.getGraphDataModel().getDataAccess().getMemberMetadata(DataDirector.COLUMN_EDGE,
0,/*layer*/
iColNum,/*slice*/
MetadataMap.METADATA_LONGLABEL);
This fragment will always retrieve the value “Sum of Salariesâ€, the static value defined for the SumSal attribute’s Label.
Using the code shown above to get to the selected Job (the value for the Stack in the StackedBars), I can create a page where one component is updated when another is clicked upon. For example: whenever a stack (for a specific job) is clicked on, a table component lists all employees in that job. Ideally I would like to show all employees in that job in that department.
A somewhat more cryptic and complex piece of code can be used to find the Deprtament – the value of the Group Attribute:
String memberValue = graph.getGraphDataModel().getDataAccess().getMemberMetadata
( DataDirector.COLUMN_EDGE
, new int []{0,iGrpNum,0} // I do not know what the first and last element in the int array are doing
,2 // this parameter apparenty specifies which dimension’s value is returned:
// 0 is Data Point 0 (Sum of Sal), 1 is Job (Data Point 1) and 2 is Group (Deptno)
,0
, MetadataMap.METADATA_LONGLABEL
);
With this code at our disposal, we are ready to start tying together the graph with other data components in the page.
Note: the OTN Discussion thread http://forums.oracle.com/forums/thread.jspa?forumID=381&threadID=506982 has resulted in a simpler approrach to get at the value for the Group:
String group = m_graph.getGraphDataModel().getDataAccess().getSliceLabel
( DataDirector.COLUMN_EDGE
, iGrpNum
, MetadataMap.METADATA_LONGLABEL
);
This is of course much simpler! Without van JavaDoc available at this time for the Chart classes, it is sort of guessing and learning by trial and error.
Hello Lucas Jellema.
I am looking for a client side (javascript) equivalent of what you have made work getting value of bar chart on the server side. What I am trying to accomplish is to get the value of the bar chart on the client side (javascript), and invoke my custom javascript API passing the value of the selected bar chart. Have you came across with client side solution similar to what I am trying to do? Thank you.
Really it was so instructive thanks for all peaple who contribute