An Enhanced Gauge control using HorizontalBar

I thought this one was worth writing up because it highlights a couple of really nice features within the ADF DVT charts -  Reference Objects and Alerts. The scenario was based on a problem where there was a requirement for a conventional horizontal gauge control, showing the normal thresholds for the control - shown in this image here as the red, yellow and green zones:

Basic Gauge

The twist in this case was that we required an extra reference marker on the data bar that indicated the "optimal" value within a particular threshold. So in the image above imagine that within the green zone, 150 was the optimal value and we need to somehow indicate that.

Simply using the gauge it is possible to do this using an extra threshold value at the required value, or rather two extra threshold definitions, we have to terminate the threshold that currently starts at 90 at 150 (the reference value we want to mark), then a short threshold from 150-151 just to provide the reference marker we need, then an extra green threshold from 152 to 200 to complete the green bar.  You end up with this:

Gauge with reference line

So that works pretty well - but it's a limitation of the use of thresholds that all you can achieve is a block of colour or line behind the indicator bar, plus the fact that I've used an extra level of the thresholdset here means it's not very dynamic (although of course it could be if you want to start writing code). Think about if we wanted to overlay several different dynamic markers such as min/max levels reached in the last 24 hours. That would be do-able but it is getting messy. 

Another approach to take is to use the bar chart (horizontal in this case) to simulate the gauge. We don't have the dvt:threshold /dvt:thresholdSet  in the case of charts but we do have the equivalent with dvt:referenceObject. Reference objects allow you to place a filled area or line in front or behind the data series so we can emulate the same look that we had with the gauge:

Gauge using horizontal bar chart

As you can see it looks pretty similar, although there are some slight differences:

  1. Unlike the gauge, which displays value labels at the threshold boundaries, the axis on the chart has a regular labelling at fixed intervals based on the y1Axis setting.
  2. We're missing the tick marks between the Y axis and the labels - well in fact that's a slight bug, they are there, but the size in proportional to the height of the chart (46px in this case). In 11.1.2 and above you should see them correctly.
  3. The proportions of the series bar / chart area are  slightly different to the gauge. But that's only noticeable if you are mixing and matching.

 Let's break down how to create some of the features here:

Overall Size

The height / width of the cart had to be controlled somewhat to bring it down to gauge dimensions.  This is acheived using inlineStyle on the horizontalBarGraph tag:

<dvt:horizontalBarGraph id="gaugeClone"

We also need to ensure that the y axis is fixed. By default it will be scaled based on the max value of the data which we don't want. To do this we define the min/max values on the nested y1Axis tag and set the axisMaxAutoScaled attribute to false. We also define the tickmark label interval to 30 here.

<dvt:y1Axis axisMinValue="0"

Bar Styling

By default the gauge has that grey-ish colour  whereas the deafult colour for the first series in a bar chart will be a blue (which is nice, but for the sake of consistency I wanted to change). The colours / shapes used for bars, lines and markers in charts are all controlled by dvt:series tags. So here I've set up the values for series 0 which defines the bar data and set both the fill and the border to emulate the look of the gauge. Note that the series tag needs to be wrapped in a seriesSet.

  <dvt:series index="0" 

Threshold banding

Next we want to add the banding to emulate the gauge thresholds. To do this we use the referenceObject tag with the RO_AREA type set to make it fill the defined area rather than draw a line. Again the referenceObject tags need to be enclosed in a parent, referenceObjectSet:

   <dvt:referenceObject index="1" type="RO_AREA"
                        association="SERIES" location="RO_BACK"
                        lowValue="0" highValue="30"/>
   <dvt:referenceObject index="2" type="RO_AREA"
                        association="SERIES" location="RO_BACK"
                        lowValue="30" highValue="90"/>
   <dvt:referenceObject index="3" type="RO_AREA"
                        association="SERIES" location="RO_BACK"
                        lowValue="90" highValue="200"/>
   <dvt:referenceObject index="4" type="RO_AREA"
                        association="SERIES" location="RO_BACK"
                        lowValue="200" highValue="230"/>
   <dvt:referenceObject index="5" type="RO_AREA"
                        association="SERIES" location="RO_BACK"
                        lowValue="230" highValue="280"/>

The Reference Line 

Just like with the gauge we manipulate the reference object set to add the reference line at 150. However, reference object actually has a line subtype so we can simply use that rather than having to use an area with width of 1. We add the following into the referenceObjectSet:

<dvt:referenceObject index="6" type="RO_LINE" lineValue="150.0"
                     association="SERIES" location="RO_BACK"
                     color="#000000" /> 

The nice thing here is that we can flip this line so it overlays the series. This is not something we can do with Gauge:

<dvt:referenceObject index="6" type="RO_LINE" lineValue="150.0"
                     association="SERIES" location="RO_FRONT"
                     color="#000000" /> 

Which gives us this:

Bar based gauge with overlay reference

The lineValue attribute can, of course, be an EL expression rather than a hard-coded value so you can make the reference point dynamic.

Using Alerts to Add Markers

The final twist is to move away from these plain lines that we've been using as marker values so far and just retain the referenceObjectSet for the threshold banding.  Graph supplies a second "set" of things - the alertSet, which will allow us to overlay gif and png images over the series. Using that we can overlay multiple markers that look a little more attractive - like this:

Bar based gauge with overlay marker icons

You could imagine this being used to reflect min / max values or that kind of thing, it's a really neat capability. To do this all we need to do is add a simple alertSet (note that all of the hardcoded values here could be replaced by Expression Language for a dynamic gauge).

   <dvt:alert xValue="Power Consumption"
              yValue="150" yValueAssignment="Y1AXIS"
   <dvt:alert xValue="Power Consumption"
              yValue="220" yValueAssignment="Y1AXIS"

The xValue attribute maps the alert marker onto the required series bar.

Finally, just for fun, see if you can work out how to do this one:

The puzzle

Answers in a comment please...

Final Thoughts

So should you use this technique rather than the out of the box gauge control? Well only of you really need to.  Gauge is simple and lightweight and if all you need is a simple reference line, thresholds do the trick quite well. However, this technique does go to show that if  you think out of the box a little you can do a lot with the DVT tools at your disposal. If nothing else you now know about referenceObjects and alerts!


This is a really great technique... thanks!

Posted by Steve Stein on January 09, 2012 at 08:48 AM GMT #

Nice explanation. Thanks Duncan, that is going to be useful.


Posted by Lucas on January 10, 2012 at 12:14 AM GMT #

A Nice article Duncan,
I believe the solution to your quiz is creating an extra y2axis like so

<dvt:y2Axis axisMinValue="0" axisMaxValue="280" majorIncrement="30" axisMaxAutoScaled="false"/>

and then creating two other alerts with the other images point to the y2axis like so

<dvt:alert yValue="150"
xValue="Power Consumption" imageSource="/images/slidery.png"
<dvt:alert yValue="220"
xValue="Power Consumption" imageSource="/images/slidery.png"

and ofcourse increate the height in inlinestyle to showall the results...

that's an assumption btw, as I didn't try it out yet

Posted by Amr Gawish on January 12, 2012 at 05:06 PM GMT #

Sounds like it might work, although it's not the technique I used as I didn't use the Y2 axis - give it a go though and let us know.

Posted by Duncan on January 13, 2012 at 02:21 AM GMT #

Post a Comment:
Comments are closed for this entry.

Hawaii, Yes! Duncan has been around Oracle technology way too long but occasionally has interesting things to say. He works in the Development Tools Division at Oracle, but you guessed that right? In his spare time he contributes to the Hudson CI Server Project at Eclipse
Follow DuncanMills on Twitter

Note that comments on this blog are moderated so (1) There may be a delay before it gets published (2) I reserve the right to ignore silly questions and comment spam is not tolerated - it gets deleted so don't even bother, we all have better things to do with our lives.
However, don't be put off, I want to hear what you have to say!


« January 2017