Chapter 2. Oracle APEX 4.0 Charts Inside Out

by Dimitri Gielis

This chapter will cover the charting possibilities in Oracle Application Express 4.0 and explain in great detail how APEX charts work behind the scenes.

In my experience, a lot of people who have been developing in APEX for years don't use charts that much or haven't really invested time in reviewing all the different options APEX provides. That is why, although this is an expert book, we will start this chapter by explaining what APEX charts are, how they work, and what types of charts you can create with the built-in functionality of APEX. In the second half of the chapter we will go up a level and discuss how to produce more advanced charts.

The release of APEX 4.0 brought a lot of changes compared to APEX 3.x, including a complete new charting engine and a lot more functionalities which are now provided declaratively.

By understanding the different components of a chart and how APEX handles them, you'll be able to visually display your data in almost any way you like. From combined charts to charts with thresholds, to dashboards, this chapter will explain it all step by step. We'll also make charts more interactive and combine them with other elements on the page; for example, when you change your chart, a report on the same page changes automatically based on your change in the chart, and the other way around.

Finally, we will look both at the future of charts in APEX and how you can already benefit from the latest and greatest in the charting world.

APEX 4.0 includes two different kinds of charts: HTML charts and Flash charts. HTML charts are very limited and we'll only cover them briefly. Most of this chapter focuses on Flash charts. Flash charts consist of different types of charts, but you can categorize them into three big groups: Charts, Gantts, and Maps. This chapter will discuss charts in great detail and will combine them with other components such as reports later on. Gantts and Maps are not covered, but the way they work is very similar to charts; the techniques to debug them and see what is happening behind the scenes is exactly the same as with the Flash charts described in this chapter.

Warning

The information in this chapter is based on Oracle APEX 4.0.2.00.07. Previous or future versions might behave slightly differently, especially the bugs mentioned in this chapter. The initial release of APEX 4.0 contained other bugs which were fixed in the latest patch set. As you read this chapter, you might find that the issues mentioned here have already been solved in the version of APEX you are running.

HTML Charts

HTML Charts are useful when you don't have much bandwidth, you only need a very basic chart, or the device that runs the chart isn't capable of rendering Flash content. Having said that, the HTML charts that come with APEX are so minimal that they are hardly ever used; nevertheless, we'll cover them briefly so you understand the concepts when you need them, as they are very different from Flash charts.

Using the HTML Charts Wizard

To add an HTML chart to your page, run the Create Region wizard and select Chart – HTML Chart. Follow the rest of the wizard. There's actually only one important screen in that wizard which defines the entire chart: the Source screen (see Figure 2-1). There you enter the query to retrieve the data for the chart to use, and you define how you want the chart to look. That HTML charts are very limited is demonstrated by the number of chart types you can use. You can only select whether the chart will show horizontal or vertical bars. Also, there are only three possible scales for the charts: 200, 400, and 600.

HTML Chart Source

Figure 2-1. HTML Chart Source

The query is always in the same format:

select link, label, value
from table

The link column stands for the URL you can navigate to when you click the label, the label is the text that goes with the bar, the value is the numeric column that defines the bar size, and the table is the table or view you want to query from.

The Result

We created two HTML charts on top of the DEMO_PRODUCTS table. The result looks like Figure 2-2. On the left is a vertical HTML chart with all available attributes selected, and on the right is a horizontal HTML chart with minimal attributes selected.

HTML chart result

Figure 2-2. HTML chart result

Debugging and Performance

Running a page with HTML charts is very fast and there is almost no overhead generating the chart. The time that is necessary to render the page is completely linked to the query. Looking at the debug output in Figure 2-3, you can see that timing is negligible.

Debug output of a page with two HTML charts as in Figure 2-2

Figure 2-3. Debug output of a page with two HTML charts as in Figure 2-2

Behind the Scenes

The reason HTML charts render so quickly becomes clear when you look behind the scenes. As the name states, HTML charts render straight HTML. Basically, a table gets rendered with a couple of columns (<td> tags).

Inside these <td> tags there is a one-by-one pixel image rendered, with a specific height and width, calculated by APEX based on the results of the query, so the image looks bigger.

You can see a part of the HTML code for the first chart:

<table class="standardLook">
<tbody>
  <tr><td align="center" colspan="10"></td></tr>
  <tr>
    <td valign="bottom">
      <img src="/i/blue.gif" alt="Business Shirt - 50" width="40" height="67" style=
Behind the Scenes
"border-left:1px #ffffff solid; border-top:1px #ffffff solid; border-right:1px #000000
Behind the Scenes
solid; border-bottom:1px #000000 solid;"> </td> <td valign="bottom"> <img src="/i/green.gif" alt="Trousers - 80" width="40" height="107" style=
Behind the Scenes
"border-left:1px #ffffff solid; border-top:1px #ffffff solid; border-right:1px #000000
Behind the Scenes
solid; border-bottom:1px #000000 solid;"> </td>

Inline HTML Charts in Report

The technique that was used to generate the bar, using a 1×1 pixel image (the color varies depending on which image is used) with a custom width and height and a style attached to it, might be useful in other parts of your Oracle APEX project—for example, if you want to have an inline chart in your report to represent a percentage or if you want to show how much has already been consumed of a total.

In APEX itself you find this method used in a couple of other places as well, for example, in Administration

Inline HTML Charts in Report
Graph inline in Application Changes by Day report

Figure 2-4. Graph inline in Application Changes by Day report

The method APEX uses in the HTML chart could be even a bit more performant if it always used the same image instead of using a different image by color. The image would need to be a transparent 1×1 pixel image that has a style attached to it to give it the color you selected. Obviously we are talking about very small gains, but the browser would have to do only one request for the one transparent image, whereas now it has to do multiple requests depending on the number of different colors you have.

One of the attributes of the chart is the color; if you go with just one color instead of "random colors", the performance would be the same as with the transparent image.

In the Monitor Activity section where APEX uses this technique in the reports, APEX uses a transparent 1-pixel image, which is more performant.

If you want to verify yourself how many requests the browser is doing for your page, you can easily do that with Firebug, which is a plug-in of Firefox.

In Figure 2-5 you find the Firebug output of the chart with the random colors for the bar. In Figure 2-6 it is the same chart but with only one color. If you compare the time it takes, the number of requests it handles, and the amount of data it transfers to render the chart, you can see the difference.

HTML chart with random colors

Figure 2-5. HTML chart with random colors

HTML chart with one color

Figure 2-6. HTML chart with one color

If you are creating HTML charts yourself and are really concerned about performance, you could even opt to only work with <div> tags instead of images. That would mean the browser doesn't have to do any request for the image. You would have two <div> tags on top of each other but with a different style (background-color and width).

Flash Charts

Normally when you want to do serious charting in APEX, you use Flash charts. Compared to HTML charts, Flash charts offer so much more — more chart types, more animations, more ways to adapt the look and feel, and so on. The Flash charting capabilities in Oracle APEX 4.0 got completely revised from APEX 3.x and now offer many more options declaratively (through the wizard). As with any other component in APEX, you create charts with the wizard. A chart is built as a region in APEX, so you either need to use the Create Application, Create Page, or Create Region wizard.

Background

Flash charts were introduced with the release of APEX 3.0 in 2007. Next to HTML and SVG charts you could now create Flash-based charts. The Oracle APEX development team also made it clear that Flash-based charts would become the preferred charting engine and SVG wouldn't be developed further. The APEX development team didn't build the Flash charts from scratch, and instead opted for a third-party solution. Oracle made an agreement with AnyChart (www.anychart.com) to license their Flash charts. What Oracle still needed to do was to create native Oracle APEX wizards to include these charts easily in an APEX project.

I believe Oracle made a great decision here in not trying to build a Flash chart engine themselves because charting is a whole area in itself and evolves very quickly. There are many charting engines around, but going with AnyChart was definitely not a bad choice, as they are committed to evolving their product along with the rest of the charting world.

That AnyChart wouldn't stand still proved to be true over time. In Oracle APEX 3.0, version 3.3 of the AnyChart product was included, but a year later AnyChart 4 was already out, and soon after that, version 5. With the patch releases of APEX 3.x, Oracle included newer versions of AnyChart, but it was only in the Interactive Reports that AnyChart 4 and later AnyChart 5 were used.

With the release of APEX 4.0, AnyChart 5 is now completely supported in the wizards. In fact, all new charts you create will automatically use the AnyChart 5 engine. As Oracle wants APEX to be compatible with older versions and needs to support existing applications using Flash charts, AnyChart 3.3 is also included in APEX 4.0. So if you run your APEX 3.x application in APEX 4.0, it will still show AnyChart 3.3 charts. Please note that the version of AnyChart 5 is a special version compiled for Oracle and doesn't include all available chart types that AnyChart 5 supports.

Over time, AnyChart has developed other charting components. Next to the AnyChart charting solution, they now also have AnyGantt, AnyMap, and AnyStock. In APEX 4.0, Oracle decided to also license AnyGantt Gantt charts and AnyMap Interactive maps. The Oracle APEX development team built wizards around these engines so you can create Gantt and map types declaratively too.

Creating a Flash Chart

Let's say you have a blank page in an APEX application and you want to add a chart to it. From APEX 4 onwards, I recommend you use the Tree view instead of the Component view for your page. The Tree view allows you to access the different components (and make changes) a lot more quickly. That is why all screenshots and the actions I'll describe will be based on using the Tree view.

To add your first chart, right click Regions in the Tree view of the page and select Create in the menu to add a new region to that page. For region type, select Chart (Figure 2-7).

Select as Region Type: Chart

Figure 2-7. Select as Region Type: Chart

On the next page of the wizard, go with Flash Chart. Note that in APEX 4.0 there is no way to create an SVG chart anymore, as there was in APEX 3.x (Figure 2-8).

Select Flash Chart

Figure 2-8. Select Flash Chart

You'll see that the progress indicator of the wizard on the left-hand side has changed and now asks you to select the chart types you want to use (Figure 2-9).

Select a chart type

Figure 2-9. Select a chart type

One of the great new enhancements in the APEX 4.0 charts wizard is that you can see how the chart type looks like without having to click the Update button, as you had to do in APEX 3.x.

In APEX 4.0 there are more types to choose from, and they have a fresher look and have more options. The Chart wizard in APEX 4.0 also categorizes the charts nicely: you first select the main chart type and then get the choice to select the subtype if that is available. For example, the Line chart type doesn't have a subtype whereas the Column chart type has eight subtypes (Figure 2-10).

Column subcharts

Figure 2-10. Column subcharts

Clicking the subtype brings you to the Create Region screen, which is not different than any other Region screen in APEX (Figure 2-11). By default the region template is Chart Region, but you can choose any you like. Now give the region a title and click Next.

Create Region

Figure 2-11. Create Region

The next screen defines the look and feel of the chart and which options you want to include (Figure 2-12). You can go with the defaults during creation and adapt them later on or, if you already know exactly what you want, you can make the changes immediately. For example, if you want to include a legend, select the position where you'd like to see that (Left, Right, Top, Bottom, Float).

In APEX 4.0 there are a lot more Animations to choose from than there were in APEX 3.x. Also, the ability to include scrollbars is completely new in APEX 4.0. Scrollbars are particularly handy when you have large sets of data and you still want to have a good view.

We'll come back to the different attributes in the "Understanding the Chart Attributes" section.

Define the chart attributes

Figure 2-12. Define the chart attributes

Previously, we defined how the chart would look, but we didn't define the source of the chart yet. What data does the chart need to show? You'll need to add a SQL query that will be used to feed the chart with data (Figure 2-13). The SQL query syntax varies depending on the chart type you select.

Most of the charts have a query like this:

select link, label, value
from   table
order by label

where

  • link is a URL.

  • label is the text that displays in the chart.

  • value is the numeric column that defines the size of the chart type.

Define the SQL query of the chart

Figure 2-13. Define the SQL query of the chart

As said before, the query of the chart depends on the type of chart you selected. We'll come back to the different select statements for the different chart types in the section "Understanding the Chart Attributes."

The Result

Once the Chart region is created, it will appear on the page with a chart icon in the Tree view (Figure 2-14). Drilling into the chart region shows the series which contains the SQL statement to provide the chart with data.

Chart region in Tree view of the page

Figure 2-14. Chart region in Tree view of the page

Before you adapt the chart and look at what is happening behind the scenes, you just run the page to see what it looks like (Figure 2-15).

The chart displayed on the page

Figure 2-15. The chart displayed on the page

Understanding the Chart Region

When editing the chart region (double-click the region or right-click and select Edit) and looking at the region definition, you might be surprised at first as there is only some HTML code in the Region Source (Figure 2-16). But remember, APEX has to include a Flash object in the page, and the way you do that is to use exactly that HTML code.

The region source consists of an object tag and an embed tag, which both have some parameters. If you look a bit deeper in that code you see the parameters of the object and embed tag are almost the same. When I first saw this code I wondered why you would want to include the same code twice. The answer is browser compatibility. In the knowledge base of Adobe (owner of Flash) it is explained well. The OBJECT tag is used by Internet Explorer on Windows and the EMBED is used by Netscape-like browsers (Macintosh and Windows) and Internet Explorer (Macintosh) to direct the browser to load the Flash Player. Internet Explorer on Windows uses an ActiveX control to play Flash content while all other browser and platform combinations use the Netscape plug-in technology to play Flash content. This explains the need for the two tags.

The region definition of the chart

Figure 2-16. The region definition of the chart

In the parameters of the object and embed tags you find parameters for quality, width, height, name, scale, and so on. The parameters either have a static value assigned to them (for example, quality="high") or a token (for example, width="#WIDTH#"). APEX replaces these tokens when it renders the page. You can change the value of these tokens in the Chart Attributes tab (see further on). Normally you won't change these parameters, unless you want to make the chart more dynamic and, for example, let the user define a custom loading message or change the width or height of the chart. In that case, you would replace the token with "&PAGE_ITEM.", a reference to a page item. You are responsible for giving your page item a value before APEX renders the chart, for example, by using a computation or a page process.

The region definition of the chart line by line

Figure 2-17. The region definition of the chart line by line

Figure 2-17 provides a detailed explanation of the region definition:

  • Line 1 and 2 (IE) and line 23 (non-IE): Define the object classid and codebase used by Internet Explorer (IE) to identify the object and recognize it as a Flash object. The classid identifies the ActiveX control for the browser (IE). The codebase (IE) and pluginspage (non-IE) identifies the location of the Flash Player ActiveX control (IE) or plug-in (non-IE) so that the browser can automatically download it if it is not already installed. The #HOST_PROTOCOL# is either http or https, depending on the settings in Manage Instance - Security of your Oracle APEX instance.

  • Line 3 and 4 (IE), line 16 and 17 (non-IE): Define the width and height of the Flash object in pixels or % of browser window. The #WIDTH# and #HEIGHT# tokens are replaced by the value defined in the Chart Attributes.

  • Line 5 (IE) and line 18 (non-IE): Define the id of the object tag in IE and the name attribute for the embed tag in non-IE. The #CHART_NAME# is replaced by c concatenated with the region id. (See Oracle APEX view: APEX_APPLICATION_PAGE_FLASH5.)

  • Line 6 (IE) and line 20 (non-IE): Define the alignment of the Flash object.

  • Line 7 (IE) and line 14 (non IE): The movie parameter in IE and the src parameter in the embed tag for non-IE browsers specifies the location (URL) of the chart to load.

  • APEX ships with the AnyChart files that Oracle licensed, and this is the location they are in:

    • #IMAGE_PREFIX# is defined in the Application Attributes and is most likely /i/.

    • #CHART_TYPE# gets replaced by the chart type (for example, OracleAnyChart.swf).

    • #HOST# gets replaced by the webserver address.

    • #REGION_ID# is the region id the chart is in.

  • Line 8 (IE) and line 15 (non-IE): The quality parameter can have these values: low, autolow, autohigh, medium, high, best. Oracle APEX sets it to high by default.

    • Low: Favors playback speed over appearance and never uses anti-aliasing.

    • Autolow: Emphasizes speed at first but improves appearance whenever possible. Playback begins with anti-aliasing turned off. If the Flash Player detects that the processor can handle it, anti-aliasing is turned on.

    • Autohigh: Emphasizes playback speed and appearance equally at first but sacrifices appearance for playback speed if necessary. Playback begins with anti-aliasing turned on. If the actual frame rate drops below the specified frame rate, anti-aliasing is turned off to improve playback speed. Use this setting to emulate the View

      The region definition of the chart line by line
    • Medium: Applies some anti-aliasing and does not smooth bitmaps. It produces a better quality than the Low setting, but lower quality than the High setting.

    • High: Favors appearance over playback speed and always applies anti-aliasing. If the object does not contain animation, bitmaps are smoothed; if the object has animation, bitmaps are not smoothed.

    • Best: Provides the best display quality and does not consider playback speed. All output is anti-aliased and all bitmaps are smoothed.

  • Line 9 (IE) and line 21 (non-IE): AllowScriptAccess controls the ability of that SWF file to call JavaScript code. AllowScriptAccess has three possible values:

    • always: Unconditionally turns JavaScript access on.

    • never: Unconditionally turns JavaScript access off.

    • sameDomain: Turns JavaScript access on only if the SWF file is served from the same domain and hostname as the Oracle APEX page itself.

  • Line 10 (IE) and line 22 (non-IE): allowNetworking controls a SWF file's access to network functionality. Possible values are all, internal and none. The default is all and you don't want to change that in your APEX application.

  • Line 11 (IE) and line 19 (non-IE): scale defines if the Flash object can scale. Possible values:

    • default (Show all) makes the entire Flash object visible in the specified area without distortion, while maintaining the original aspect ratio of the object. Borders can appear on two sides of the object.

    • noborder scales the object to fill the specified area, without distortion but possibly with some cropping, while maintaining the original aspect ratio of the object.

    • exactfit makes the entire object visible in the specified area without trying to preserve the original aspect ratio. Distortion sometimes occurs.

    • noscale prevents the Flash object from scaling when the Flash Player window is resized. This is the default in Oracle APEX.

  • Line 12 (IE) and line 25 (non-IE): wmode sets the Window Mode property of the Flash object for transparency, layering, and positioning in the browser.

  • Line 13 (IE) and line 26 (non-IE): FlashVars is used to send root level variables to the AnyChart Flash object. If you want to change the messages, for example, when there is no data, you do that here. These are the default messages Oracle APEX uses for the tokens:

    • #FLASH_INIT#: Initializing...

    • #FLASH_LOADING#: Loading data...

    • #FLASH_RESOURCES#: Loading resources...

    • #FLASH_NO_DATA#: No data found.

    • #FLASH_WAITING#: Loading data. Please wait.

    • #FLASH_TEMPLATES#: Loading templates...

  • Line 23 (non-IE): type defines the Internet Media (MIME) type, in this case application/x-shockwave-Flash.

  • Line 27 (non-IE) and 28 (IE) are the closing tags of embed and object.

  • Line 29 (IE and non-IE): #CHART_REFRESH# will be replaced by some JavaScript to refresh the chart. More information about that can be found in "Understanding the Chart Attributes".

Understanding the Chart Attributes

The previous section covered the region definition, but more importantly, if you want to change the appearance and behavior of a chart, this can be done via the Chart Attributes (second tab on the Edit Region page or right-click in page Tree view and Edit Chart).

Depending on the chart type chosen, you have different sections in the chart attributes (Figure 2-18):

  • Chart Settings

  • Chart Series

  • Display Settings

  • Axes Settings (not for 3D Pie, 2D Pie, 2D Doughnut)

  • Gantt Settings (only for Gantt charts)

  • Legend Settings (not for Dial or Gantt charts)

  • Font Settings

  • Chart XML

  • Refresh

The different sections of the chart attributes

Figure 2-18. The different sections of the chart attributes

The Chart Settings allow you to change the chart type, the title, the size of the chart and the look and feel. Figure 2-19 shows the settings, which you can use as follows:

  • Chart Type: Enables you to change between chart types in a given family. For example, you can change between 3D Stacked Column, 3D Bar Chart, 3D Stacked Bar Chart, and so forth.

  • Chart Width and Height: Specify the size of the region in which the chart is rendered.

  • Chart Margin: Lets you specify the amount of blank space surrounding the chart. Values are in pixels.

  • Color Scheme: Lets you select one of the built-in color schemes for your chart. Single-series charts use a different color for each data point. Multiple-series charts use a different color for each series. Select the Custom option to define your own color scheme.

  • Hatch Pattern: Allows you to toggle hatch patterns off and on. In a multi-series bar chart for example, you can show one series as bars with lines in them, another series as bars with stripes, and so forth.

The main settings of the chart in Chart Settings

Figure 2-19. The main settings of the chart in Chart Settings

The Chart Series holds the select queries which are used to feed the chart with data. You can have one or more series defined. To edit an existing series you click the Edit icon, while to add a new series you click the Add Series button (Figure 2-20). In the next section, "Adding Multiple Series," we go into more detail about the series.

One or more series per chart in chart series

Figure 2-20. One or more series per chart in chart series

In the Display Settings you define the main look and feel of the chart and the different features you want to enable. Figure 2-21 shows the following settings that you can control:

  • Animation controls the initial appearance of this chart. There are thirty different types of animation available, for example, Side from Left, Scale Y Top, etc.

  • Marker is an object with a specified shape, size, and color used to mark and to identify values on your chart. There are 14 different types of Marker, for example, including Cross, Triangle Up, Triangle Down, etc.

Warning

At the time of writing, Oracle APEX 4.0.2.00.07 does not support the display of markers on a bar or column chart. The workaround to include the markers is to adapt the XML manually and change marker type="None" to the marker you want (for example, marker type="Cross").

  • Style defines the visual appearance of the data element, which is most apparent in 2D Bar and Column charts. There are four different styles available in APEX 4.0: Default, Aqua Dark, Aqua Light, and Silver.

  • Background Type has three choices. Transparent makes the chart background transparent. Solid Color uses the color specified in Background Color 1 for the background of the chart. Gradient uses Background Color 1 and 2 and fades between them depending the gradient angle specified lower down in Gradient Angle.

  • Include on Chart allows you to select the options you want to display on your chart. Depending on the chart type, some options might not be available. Following are the options:

    • Hints: Check this box if you want to see the label and value when you hover your cursor over the chart.

    • Values: Check this box if you want to show the values next to your chart data.

    • Labels: Check this box if you want to see the labels along the chart axis.

    • Group by Series: Check this box if you want to see your series split. Instead of seeing your data grouped by column (Allen: SAL, COMM – Blake: SAL, COMM – Clark: SAL, COMM), you will see it grouped by series first and after that by column.

    • Major Ticks: Check this box if you want to see the big tick marks in a gauge or dial chart.

    • Minor Ticks: Check this box if you want to see the small tick marks between the big tick marks on your gauge (or dial) chart.

    • Tick Labels: Check this box if you want to see the values corresponding to the tick marks.

    • Multiple Y-Axes: Check the box if you want to see an extra Y-Axis positioned opposite to the existing Y-Axis on the chart. On a multi-series chart, the extra Y-Axis will be associated with the second series of the chart.

    • Invert X-Axis Scale: Check this box if you want the sorting to be reversed. For example, Adams – Ward becomes Ward – Adams.

    • Invert Y-Axis Scale: Check this box if you want the Y-Axis scale in an inverted mode. For example, checking the box will cause a bar chart to go down instead of up.

    • Invert Scale: Check this box if you want the numbers to start from high to low on a Gauge (or Dial) chart.

  • Show Scrollbars controls whether a scrollbar will be displayed on your chart. You can show a scrollbar on the X-Axis, the Y-Axis, or on both.

  • Show Grid controls whether a value grid will be displayed on your chart. You can show the grid for the X-Axis, the Y-Axis, or for both.

  • Gradient Angle defines the angle for the background type of Gradient. A value of 0 degrees results in a horizontal gradient with the first background color on the left and the second background color on the right. A value of 90 degrees results in a vertical gradient with first background color at the top and the second background color at the bottom.

Warning

At the time of writing, APEX 4.0.2.00.07 has a bug where the gradient angle is not rendered correctly as degrees. The current workaround is to change the XML manually to include the angle you want: <gradient angle="90" type="Linear"> (if you want the angle to be 90 degrees).

  • X-Axis Label, Y-Axis Label, and Values Rotation define the amount of rotation, in degrees, for the chart labels. Positive values indicate clockwise rotation. Negative values indicate counter-clockwise rotation. The Font Face setting for labels does not apply to rotated text. If the Y Axis Title contains non-ASCII characters, make sure you don't have a value specified in the Y-Axis Label Rotation.

Define the main look and feel of the chart in display settings.

Figure 2-21. Define the main look and feel of the chart in display settings.

In the Axes Settings shown in Figure 2-22, you define the title of the Axis, the interval, and the format of the values.

  • X-Axis Title and Y-Axis Title are used to describe the labels along the horizontal and vertical axis of your chart.

  • X-Axis Min and Max, and Y-Axis Min and Max, define the smallest and largest data value you want to appear on the corresponding Axis. You see these items depending on the chart type, for example, Column Chart.

Warning

Oracle APEX 4.0.2.00.07 has a bug where the X-Axis Min and Max items are visible for bar charts, instead of the Y-Axis Min and Max items. To define a data range for a bar chart, Y-Axis Min and Max values should be supplied. Values defined in the X-Axis Min and Max items are not taken into account for bar charts. The workaround is to set your chart type to Column Chart first, define the value for the Y-Axis, apply the changes, and edit the chart again to set the chart type back to Bar Chart. If you use Scrollbars, make sure there is no value defined in the hidden value for the X or Y-Axis Min.

  • X-Axis Prefix and Y-Axis Prefix define text to display before values on the corresponding axes. This text prefix will appear before grid labels, value labels, and hint text. For example, you can enter a currency symbol as a prefix.

  • X-Axis Postfix and Y-Axis Postfix define text to display after values on the corresponding axes. This text postfix will appear after grid labels, value labels and hint text. For example, you can enter a percentage symbol as a postfix.

  • X-Axis Minor and Major Interval, and Y-Axis Minor and Major Interval settings control the minor and major scale steps, used for the axis labels, the tick marks, and the grid on your chart. If not set, the steps are calculated automatically. Values entered must be positive. These settings will only be used when Show Grid in Display Settings is set.

  • Decimal Places defines the number of decimal places to be used in the Y Axis values.

Note

All these settings are static, so you can't use page items to dynamically set them. However, if you want to set, for example, the Y Axis Min value dynamically depending the data you return, you can set Custom XML to Yes on the Chart XML page, and include your substitution strings there (for example, &PAGE_ITEM).

The Axes Settings

Figure 2-22. The Axes Settings

In the Legend Settings (see Figure 2-23) you specify whether you want a legend and where it should appear and what the look and feel of it is.

  • Show Legend specifies whether a legend is displayed on your chart. Possible positions are: Left, Right, Top, Bottom or Float.

  • The Legend Title is the title of the Legend. If no Legend Title is entered, the title will be empty.

  • Legend Element Layout defines if the items of the legend will appear next to each other or under each other. The Legend Element Layout is only applicable when Show Legend is set to Top or Bottom.

  • Show Legend Background specifies whether the legend background (white) is visible on your chart or that the legend is transparent.

Define where the legend should appear

Figure 2-23. Define where the legend should appear

In the Font Settings you define the font face, font size, and font color of the different labels, values, hints, legend, and titles (Figure 2-24).

Warning

At the moment of writing, Oracle APEX 4.0.2.00.07 has a bug where the Grid Label items should not be visible. The X Axis Labels and Y Axis Labels items can be used to control the appearance of the labels on the respective chart axes.

The font settings of the different text on the chart

Figure 2-24. The font settings of the different text on the chart

The Chart XML page shows the XML that APEX will send to the AnyChart SWF file (more on that in the section "Behind the Scenes". See Figure 2-25.)

Based on the previous settings, APEX will generate XML, so any change you make in the chart settings will be translated into some XML. At any time you can overwrite the generated XML of APEX by setting the Use Custom XML setting to Yes. If you select to use custom XML, attributes under Display Settings, Axes Settings, Legend Settings, Font Settings, and Chart Title are not used and are made hidden. If you set Use Custom XML back to No, all the settings will appear again as they were last saved.

For a complete reference of the XML that can be used and a detailed explanation, see the AnyChart website at http://www.anychart.com/products/anychart/docs/xmlReference/index.html.

The Chart XML

Figure 2-25. The Chart XML

In the Refresh section, you can set Asynchronous Update to Yes to give the chart new data at an interval you specify (Figure 2-26). This is very useful if you always have the same page open with a dashboard, and want to see the latest data updated every few seconds without having to reload the page. You can enter the interval in seconds between chart updates, but Updates Intervals less than 2 seconds are discouraged as that would mean APEX has to constantly retrieve the data. The maximum value for this setting is 99999.

The region definition of the chart line by line

Figure 2-26. The region definition of the chart line by line

When the page is run the #CHART_REFRESH# token from the Region Attributes will be replaced by the following JavaScript:

<script type="text/javascript" language="javascript">
function chart_r10604411968639592_InitRefresh(pNow) {
  setTimeout("chart_r10604411968639592_InitRefresh(true)",10000);
  if (pNow){apex_RefreshFlashChart (2, '10604411968639592', 'en'),}
}
apex_SWFFormFix('c10604411968639592'),
addLoadEvent(chart_r10604411968639592_InitRefresh(false))
</script>

The big number is the id of the chart and you will only see the addLoadEvent when the Asynchronous Update select list is set to Yes. The addLoadEvent enables the function. In the section "Customizing Charts by using Custom XML, Dynamic Actions and JavaScript" we will customize this JavaScript.

You can now apply what you know and change some settings of the chart to include a pattern on the bars (hatch), get a smoother look (Aqua style), have a gradient background, have different colors and rotate the labels, play with the axes and add a legend:

  • Color Scheme: Look 7

  • Hatch Pattern: Yes

  • Style: Aqua Light

  • Background Type: Gradient with Background colors: #CCCCFF and #CCFFCC

  • Include on Chart: Hints, Values, Labels, Multiple Y-Axes, Invert Y-Axis Scale

  • Show Scrollbars: X-Axis

  • Gradient Angle: 0 Degrees

  • X-Axis Label Rotation: 45 Degrees

  • Values Rotation: 90 Degrees

  • Y Axis: Min: 200

  • Y Axis: Prefix: $

  • Y-Axis: Major Interval: 400 and Minor Interval: 200

  • Decimal Places: 2

  • Show Legend: Left

  • Legend Title: Legend

  • Legend Element Layout: Vertical

  • Show Legend Background: checked

  • Font Settings: a different color starting with #000011 end with #0000FF

The result is shown in Figure 2-27.

An example of a modified chart

Figure 2-27. An example of a modified chart

Adding Multiple Series and Combined Charts

In Figure 2-20 in the previous section, we could see the Series in the Chart Attributes. If you create a new Series or edit an existing Series a new tab will open called Chart Series (Figure 2-28).

Chart Series tab

Figure 2-28. Chart Series tab

The Series Attributes section lets you define a name, type, and sequence for the series of that Chart Type. In the Series Name you enter a name for this series. For Scatter Marker and Range charts, the Series Name is used to identify the series in hint and label text. Depending on the chart type chosen, you may able to change the Series Types. There are three options: Bar, Line and Marker. For example, if you want to combine a line chart with a bar chart, you could have a main chart type of 2D Line and then define the Series Type for one of the chart series to be Bar. We will cover combined charts in the next section. Lastly, the sequence determines the order of evaluation.

The next section in Chart Series holds the Series Query. The Query Source Type can be of type SQL Query or Function Returning SQL Query. Most of the time the Query Source Type will be SQL Query but if you need to run a different query depending some values on the page, the Function Returning SQL Query type will probably be the one to pick in that case.

In SQL, you enter the SQL statement or function that will return the data to display this Flash chart's series. Depending on the chart type you choose, a different query may be necessary. If you are unsure about which columns go first and which ones the chart type expects in the query, it's good to use the Build Query button, as that will go through a wizard to define the query (Figure 2-29).

The Build Query wizard

Figure 2-29. The Build Query wizard

Once the query is defined, you can still adapt it to your needs.

For more experienced developers, it might be useful to create the SQL statement first in SQL Developer or a similar application. That allows you to see if the query is returning the data you want and, in the case of a really complex statement, create a view or function first and base the SQL statement on that view or function.

The SQL query syntax for the various chart types is as follows:

  • Most of the charts have a SQL query with the following syntax:

    select link, label, value
    from   ...
  • In one query you can also define multiple values which will all be another series (also called Multiple Series Syntax):

    select link, label, series_1_value [, series_2_value [, ...]]
    from   ...
  • Dial Charts have this syntax:

    select value, maximum_value [, low_value [, high_value] ]
    from   ...
  • Range Charts have this syntax:

    select link, label, low_value, high_value
    from   ...
  • Scatter Charts have this syntax:

    select link, label, x_value, y_value
    from   ...
  • Candlestick Charts have this syntax:

    select link, label, open, low, high, close
    from   ...

Warning

At the time of this writing, Oracle APEX 4.0.2.00.07 has a bug in the Build Query wizard when adding a new series. The third step of the wizard only allows for the specification of the label, which results in an invalid query. Also when you create a chart based on two queries, the first being a multi-series query, using one query with multiple series syntax (see Multiple Series Syntax above), and the second a single series query, it appears that the Series Type (Bar, Line, Marker) isn't applied correctly to the multi-series query.

Maximum Rows contains the maximum number of rows you want to use to display the chart. For pie charts, you are restricted to displaying less than 50 rows; for the other charts, the number is unlimited, but the more rows you have the longer it takes to render the chart.

Figure 2-30 shows an example of a multiple series chart that combines Lines, Markers, and Bars. The chart shows the salary and commission for the employee as a column (bar), the minimum salary across employees as a marker, and a line with the average salary. It also added the Legend to show what color corresponds with what value.

Chart with Multiple Series

Figure 2-30. Chart with Multiple Series

Looking a bit closer into the series that are defined (Figure 2-31), the first series calculates the minimum salary and has a series type of Marker and contains a SQL query. The second series calculates the average salary and has a series type of Line and its Query Source Type is a Function Returning SQL Query. Editing the series shows the content a bit better (Figure 2-32). The last series contains the salary and commission and uses the multiple series syntax, so one query actually contains two series: salary and commission. This series is of type Bar. Also note that there is an NVL function call on commission in the SQL query.

Warning

It is my recommendation that you suppress nulls as some chart types may show up differently than expected. For example, when you don't suppress null values in a line chart, the line will be interrupted where null values are and empty spaces will appear in the line. If you put NVL around the column, in case of a null value, it will draw the line correctly but you will see the null values as the value 0. Putting a WHERE clause in the SQL statement to suppress the nulls, for example where comm is not null, will not show any value for that person.

Different Chart Series

Figure 2-31. Different Chart Series

Query Source Type of Function Returning SQL Query

Figure 2-32. Query Source Type of Function Returning SQL Query

Different Flash Chart Types

APEX ships with many different chart types. To use them in your application, you just select the chart type you like from the Flash Chart wizard. Oracle licenses these chart types from AnyChart, so you can use them freely anywhere in APEX. The following main- and subchart types are natively available in APEX 4.0 by using the wizard:

  • Column

    • 3D Column

    • 3D Range Column

    • 3D Stacked Column

    • 3D Stacked Column (Percent)

    • 2D Column

    • 2D Range Column

    • 2D Stacked Column

    • 2D Stacked Column (Percent)

  • Horizontal Bar

    • 3D Bar Chart

    • 3D Range Bar Chart

    • 3D Stacked Bar Chart

    • 3D Stacked Bar Chart (Percent)

    • 2D Bar Chart

    • 2D Range Bar Chart

    • 2D Stacked Bar Chart

    • 2D Stacked Bar Chart (Percent)

  • Pie & Doughnut

    • 3D Pie

    • 2D Pie

    • 2D Doughnut

  • Scatter Marker

  • 2D Line

  • Candlestick

  • Circular Gauges

    • Dial

    • Dial (Percent)

  • Gantt

    • Project Gantt

    • Resource Gantt

If there is a chart type you want to use, but you don't see it listed above (for example, a bubble chart), then you can get a separate license from AnyChart or you can buy AnyChart for APEX, which gives you a license to use any chart type you like. Figure 2-33 gives an overview of the chart types that come with APEX (most of them are available in 2D and 3D) on the left-hand side and, on the right-hand side, the extra chart types that are available in the AnyChart for APEX Integration Kit. APEX Evangelists partnered with AnyChart to create an AnyChart Integration Kit for APEX, which provides you with a license for all available AnyChart 5.1 chart types. APEX plug-ins can also be used to integrate these different charts into your application. More details and pricing information on the AnyChart Integration Kit for APEX can be found at http://anychart.apex-evangelists.com.

Comparison of the out-of-the-box charts in APEX with all available AnyChart charts

Figure 2-33. Comparison of the out-of-the-box charts in APEX with all available AnyChart charts

Behind the Scenes

As we have seen in the "Understanding the Chart Region" section, Oracle APEX generates the HTML to call the AnyChart Flash object which is located in #IMAGE_PREFIX#flashchart/anychart_5/swf/ (#IMAGE_PREFIX# is usually /i/). Most charts will use OracleAnyChart.swf. When Oracle APEX generates the call to the specific AnyChart object it also passes parameters with it. The most important parameter is XMLFile (for example, #HOST#apex_util.flash?p=&APP_ID.:4:&APP_SESSION.:FLOW_FLASH_CHART5_R#REGION_ID#) which is actually a call to a procedure called apex_util.flash which has some parameters (Figure 2-34). This procedure is not included in the documentation, so to find the definition of this procedure you have to look in the source code of the package, which you find under the user APEX_040000.

Flash procedure in the apex_util (htmldb_util) package

Figure 2-34. Flash procedure in the apex_util (htmldb_util) package

When calling the AnyChart objects, AnyChart might append various parameters to the XML file. These parameters are there to influence the behavior of the Flash objects. For example, XMLCallDate is used to make sure every call is unique and the browser is not caching the result. APEX_UTIL is actually a synonym for the HTMLDB_UTIL package. The flash procedure in the apex_util package can accept all these parameters. There is one important parameter called p, which is the URL the AnyChart object has to call back to get the data. The URL in the p parameter includes the application, page, and region so Oracle APEX knows which data (XML) it needs to generate for that specific chart.

More graphically presented, the flow is like that shown in Figure 2-35.

Graphical representation of the flow to generate the chart

Figure 2-35. Graphical representation of the flow to generate the chart

The following is an explanation of the steps shown in Figure 2-35:

  1. User requests a page with a chart, so the browser sends a request to APEX to retrieve the page.

  2. APEX handles the request and sends back the HTML for that page which includes the tag to include the Flash file.

  3. The browser shows the HTML page and renders the Flash object which will do a request back to APEX to get the data for the chart.

  4. APEX retrieves the request and sends back the XML for the data of the chart.

Looking at a real case when a user requests a page that holds a chart:

  1. User clicks on tab which does a call with this url: http://webserver/pls/apex/f?p=40:15:2887089650234857:::::.

  2. APEX searches for Application 40, Page 15 (and the Session is 2887089650234857). If you want more information about an Oracle APEX URL, click the Help in Oracle APEX and go to Home

    Graphical representation of the flow to generate the chart
    Source of Chart Region

    Figure 2-36. Source of Chart Region

    HTML of Chart Region generated by APEX

    Figure 2-37. HTML of Chart Region generated by APEX

  3. The page is shown in the browser and the AnyChart Flash object will request the data it needs to display. While it's getting the data you will see a loading animation (Figure 2-38).

    Rendered HTML and call for data of Flash objects

    Figure 2-38. Rendered HTML and call for data of Flash objects

  4. To verify the request, it's best to use a tool like Firebug (an add-on for Firefox). As you can see in that tool, the request that is called by the Flash object is GET http://webserver/pls/apex/apex_util.flash?p=40:15:2887089650234857:FLOW_FLASH_CHART5_R23967225268238782_en&XMLCallDate=1299428439349APEX_UTIL.FLASH. It will, based on the parameters, generate the XML of the chart. In this case it will look at the Chart Attributes and the Series (Figure 2-39 and Figure 2-40) and generate the XML (Figure 2-41) that the AnyChart Flash object understands. Note that all the tokens were replaced by values defined in the Chart Attributes and the #DATA# token was replaced by the output of the select statement defined in the Series. The generated XML is used by the AnyChart Flash object to draw the chart (Figure 2-42).

First part of Chart Attributes

Figure 2-39. First part of Chart Attributes

Last part of Chart Attributes, which shows the XML APEX will use

Figure 2-40. Last part of Chart Attributes, which shows the XML APEX will use

The XML that APEX produced based on the Chart Attributes

Figure 2-41. The XML that APEX produced based on the Chart Attributes

Chart completely drawn when the XML is retrieved

Figure 2-42. Chart completely drawn when the XML is retrieved

Debug and Performance

Debugging Flash Charts is done differently than debugging other components in APEX (for more information on debugging, see Chapter 6). After reading how these Flash Charts work behind the scenes, you know that there are different components and requests going on for a single chart. There is the HTML for the Region of the Chart (Region Template), the HTML to include the AnyChart Flash Object (Region Source), the call for the data (XML) for the chart and the generation of the chart itself.

When you run your page in Debug Mode, you see one line in the debug output for the chart region (Figure 2-43). That gives you an idea how long it took to generate the chart region, but only the HTML part. In the user's perspective it might be very different, as the Flash object still needs to be called by another process and the XML still has to be generated. Any performance issues are not really seen in the debug output. (In the next two figures, we show more about performance and how to really track how long it took to generate the chart.) But running the page in Debug Mode has another component that is very valuable. In the page itself, next to the chart, a Show XML link will appear. (See Figure 2-44.)

Debug information for a Chart

Figure 2-43. Debug information for a Chart

Extra Show XML link when running the page in Debug Mode

Figure 2-44. Extra Show XML link when running the page in Debug Mode

The Show XML link will show the XML output that was generated by APEX for the chart (Figure 2-45). Having this information is really important as the chart you see is defined by this XML. AnyChart has a complete XML reference in their documentation which explains every node. The URL to the AnyChart XML reference can be found in the "Resources" section later in the chapter (Figure 2-46).

XML behind the chart after clicking the Show XML link

Figure 2-45. XML behind the chart after clicking the Show XML link

XML Reference by AnyChart

Figure 2-46. XML Reference by AnyChart

To see exactly what is happening in the browser you need to use an external tool, such as Firebug. Other browsers also have developer tools which can do the same.

The Net Panel in Firefox is most important for seeing what's going on behind the scenes (Figure 2-47). The main purpose of the Net Panel is to monitor HTTP traffic initiated by a web page and simply present all collected and computed information to the user. Its content is composed of a list of entries where each entry represents one request/response round trip made by the page. You can see the requests, the status, the size of what is returned, and the time it took.

The Net Panel in Firebug/Firefox

Figure 2-47. The Net Panel in Firebug/Firefox

The first request is the request for the APEX page. The next nine requests are to get some CSS and JavaScript files. The eleventh request is to include the SWF and the last request is the call to apex_util.flash to retrieve the data (xml).

Hovering over the request shows you the complete URL and clicking on it slides open other options, for example, Params, Headers, and Cache. Clicking on the Params tab shows you all the parameters the URL has. In the case of Figure 2-48 it shows the URL that the AnyChart Flash object (OracleAnyChart.swf) will call.

The Params tab of a request in the Net Panel in Firebug/Firefox

Figure 2-48. The Params tab of a request in the Net Panel in Firebug/Firefox

Clicking the Response of the last request, which is calling the Flash procedure in the apex_util package, shows you the XML that Oracle APEX produced based on the settings in Chart Attributes for that chart.

If you have an issue with your chart, the first thing you should check is the response and the XML (Figure 2-49). In 90% of cases there is something awkward going on in the output, which explains why something is not behaving in the chart as you expect. For example, a tag may not be closed correctly, or some special characters can make the XML invalid, or the wrong syntax is used in the XML. Referring to the AnyChart documentation would be the next step to solve your problem.

The Response tab of a request in the Net Panel in Firebug/Firefox

Figure 2-49. The Response tab of a request in the Net Panel in Firebug/Firefox

If you find that some parts take a long time to load, you can investigate by hovering over the bar and more information will be shown (Figure 2-50).

Hovering over the timeline gives more information.

Figure 2-50. Hovering over the timeline gives more information.

If you need to go even further in debugging and want to actually debug things within Flash, you can download the Flash Player Debug version. There are tools like Flash Tracer for Firebug that integrate nicely with the Flash debug output. In my experience, it is seldom necessary to do this. Usually AnyChart will investigate the issue if you report a bug in the charting engine.

If you encounter performance issues and your charts become slow the first thing you need to look at is the Net Panel in Firebug and check the Timeline. That will tell you exactly where you are losing most of the time. Usually you will find that the last step (the generation of the XML) takes most of the time.

The more series you have, the longer it may take to see the data in the chart. If you can combine multiple series into one, you will gain performance. If you need multiple series it's best to try them first in SQL Developer or SQL Workshop to see how fast the results arrive. If the query is slow in that environment, it will be slow in the chart too. (Tuning the SQL statements falls outside the boundaries of this chapter.)

Upgrading Oracle APEX 3.x Flash and SVG Charts

If you initially developed your application in an earlier version of APEX and you used SVG or Flash charts, you might want to upgrade them to the new charts in APEX 4.0. As previously mentioned, AnyChart 5 charts are integrated withAPEX 4.0, which are so much nicer, faster, and have more options than the earlier version of AnyChart charts.

To upgrade an existing SVG or Flash chart to the latest AnyChart Flash charts engine, follow these steps:

  1. Open the page you have the chart on.

  2. Navigate to the Page Definition.

  3. Access the Region definition:

    • If you use the Tree view: Under Page Rendering, double-click the region name.

    • If you use the Component view: Under Region, select the region name.

  4. From the Tasks list, click the Upgrade to New Flash Chart link (Figure 2-51).

  5. Click Upgrade (Figure 2-52).

Upgrade existing chart to new Flash chart

Figure 2-51. Upgrade existing chart to new Flash chart

Final step to upgrade an existing chart

Figure 2-52. Final step to upgrade an existing chart

If you have more charts in your application and don't want to upgrade them one by one, there is an option in the Utilities section to upgrade all previous Flash and SVG charts to the new ones.

Follow these steps to upgrade all existing Flash and SVG Charts to the latest AnyChart Flash charts engine:

  1. Go to the Application home page.

  2. Click Utilities and then click Upgrade Application (Figure 2-53). The Upgrade Application Summary report appears (Figure 2-54).

  3. Look for Upgrade SVG Charts to Flash Chart 5 and Upgrade Flash Charts to Flash Chart 5, and click the number of candidate objects.

  4. Select the objects to upgrade and click Upgrade (Figure 2-55).

Utilities section in APEX 4.0

Figure 2-53. Utilities section in APEX 4.0

Upgrade Application Summary—Candidates of charts to Upgrade to Flash Chart 5

Figure 2-54. Upgrade Application Summary—Candidates of charts to Upgrade to Flash Chart 5

Select candidates to upgrade

Figure 2-55. Select candidates to upgrade

Note that SVG charts can be upgraded with the following restrictions:

  • Only number formats defined in axis format strings will be migrated. Date and time formats will be ignored.

  • Number format elements containing the following will be migrated: 0,9,D,G,, (comma),. (period),$,C,L,FM.

  • The label for each series in the Flash chart will be derived from each series' column alias. This differs from SVG charts, where the label for each series was derived from the Series Name attribute.

  • Flash Dial charts display actual values instead of percentages.

  • In SVG charts, only the labels for the first series are used for the x-axis. In Flash charts, this has been enhanced so that all data appears, even if the data's label does not occur in the first series.

Screen Reader Mode and Charts

APEX 4 allows you to run APEX itself and your own application in Screen Reader Mode. The Screen Reader Mode improves usability of Application Express applications with a screen reader. A screen reader is a software application that attempts to identify and interpret what is being displayed on the screen. This interpretation is then re-presented to the user with text-to-speech, sound icons, or a Braille output device.

There are three ways you can enable/disable Screen Reader Mode in your own application:

  • Add the #SCREEN_READER_TOGGLE# substitution string to the footer of your page template. Doing so results in a link on your pages that viewers can use to toggle the screen reader mode on and off.

  • Use the screen-reader APIs documented in the Oracle Application Express API Reference. Using the APIs is more work than adding the substitution string to your page footer, but they do provide you with more control.

  • Create links that enable and disable screen reader mode by executing f?p session requests. For example:

    <a href="f?p=&APP_ID.:&APP_PAGE_ID.:&APP_SESSION.:SET_SESSION_SCREEN_READER_ON">Reader
    Screen Reader Mode and Charts
    Mode On</a> <a href="f?p=&APP_ID.:&APP_PAGE_ID.:&APP_SESSION.:SET_SESSION_SCREEN_READER_OFF">Reader
    Screen Reader Mode and Charts
    Mode Off</a>

APEX Flash charts are not currently accessible to screen readers, therefore when running in screen reader mode the user will get a report representation of the information conveyed in the chart. A separate report will be generated for each series of a multiple-series chart if the series were defined as separate series. If the multiple series were defined in a single query, only one report will be generated (Figure 2-56). Note that this feature only works with the new Flash Charts in APEX 4, based on AnyChart 5.

When running in screen reader mode (Figure 2-57), these data tables contain descriptive text, in the following format:

  • Summary Text: In Application Builder, a combination of the chart title and chart series title are used.

  • Column Headers: In Application Builder, the column name/alias in the chart series query is used to identify the columns in the report.

Chart when NOT in Screen Reader Mode

Figure 2-56. Chart when NOT in Screen Reader Mode

Chart when running in Screen Reader Mode

Figure 2-57. Chart when running in Screen Reader Mode

Extending Flash Charts

In the previous topics you saw how to create charts through the APEX wizard and how these charts work behind the scenes. If you understand how the charts work and how they are implemented in APEX you should be able to do anything you like. This section will give some examples of extending the existing charting possibilities of APEX by stepping outside the APEX wizards.

Note

All the tables, data and code used in this chapter are available to download from the Apress website. Import the application export (the sql file you download) in your workspace and install the Supporting Objects which will create the tables and data. The application contains all examples covered in this book, so you can see everything working immediately and can copy the code straight from within the application.

Customizing Charts by Using Custom XML

A manager wants to see how sales are going based on her forecast and targets she previously set. Showing the budget can easily be done with a column chart, but showing the forecast and target lines is something that is not natively available (through the wizards) in APEX (unless you create another series for the line, but that is not quite the same). Below are the steps to add a 2D column chart and two trend lines, one for the forecast and one for the target:

  1. If you already have some experience with AnyChart XML and what each node is used for, go to the AnyChart Reference Documentation (you will find the URL in the "Resources" section).

  2. If you are less experienced, go to the AnyChart Gallery and click the 2D Column charts examples. Luckily there is something very similar to this above example in the gallery called Trend Lines and Axis Ranges Demo. Click that example and a popup will appear with an example chart in one tab (Figure 2-58) and the XML code that was used in the other tab (Figure 2-59).

AnyChart Gallery example of trend lines

Figure 2-58. AnyChart Gallery example of trend lines

XML code behind the example in the AnyChart Gallery

Figure 2-59. XML code behind the example in the AnyChart Gallery

  1. If APEX does not support a feature through the wizard, but you know AnyChart supports it (by finding an example or looking at the XML), you can adapt the XML for the chart in APEX to manually implement the feature. To customize the XML follow these steps:

    1. Create a normal 2D column chart

    2. Click the Tree view on the region and select Edit Chart. It will open the Chart Attributes.

    3. Navigate to the bottom of the page and set the dropdown for Use Custom XML to Yes. That will make the Custom XML text area editable.

  2. Note that the settings of the chart disappear and you now have to manually adapt the XML to make changes to the chart (Figure 2-60).

    Use Custom XML in APEX

    Figure 2-60. Use Custom XML in APEX

    1. Looking at the existing example of AnyChart or at the documentation, to add a trend line you would add the Axis Markers node. As you want a line to go horizontally, add the marker to the Y-axis. Locate the end of the Y-axis node (<y_axis>) and just before that add the following:

      <axis_markers>
      <lines>
          <line value="&P17_TARGET." thickness="2" color="Rgb(200,30,30)" caps="Square">
            <label enabled="True" multi_line_align="Center">
              <font color="Rgb(200,30,30)" />
              <format>Forecast: ${%Value}{numDecimals:0} </format>
            </label>
          </line>
          <line value="&P17_FORECAST." thickness="2" color="Green" caps="Square">
            <label enabled="True" multi_line_align="Center">
              <font color="Green" />
              <format>Target: ${%Value}{numDecimals:0}</format>
            </label>
          </line>
        </lines>
      </axis_markers>
    2. In the code we use &P17_TARGET. and &P17_FORECAST. which are substitution strings for the respective page items. You can dynamically set these items through, for example, a computation, so you can calculate the line from a select statement or PL/SQL procedure. If the values are always fixed, you can just replace the substitution strings with a numeric value.

  3. Saving the chart and running the APEX page gives the result as seen in Figure 2-61.

Result of adding an Axis marker manually to the chart in APEX

Figure 2-61. Result of adding an Axis marker manually to the chart in APEX

This example shows how you can customize the XML of a chart to add features that APEX doesn't allow by using the wizard or chart attributes. It's useful to read the AnyChart documentation and review the XML Reference to know what is possible. The principle is always the same: once you know what XML to include, you change the XML by setting Use Custom XML to yes in the Chart Attributes and, presto, you extend your chart!

Customizing Charts by Using Custom XML, Dynamic Actions, and JavaScript

Customizing the XML is one way to get more out of charts, but sometimes even that is not enough and you need to take an extra step. To illustrate this we will look at the use case where the manager of the previous example now wants to see which employees brought in a lot of sales, who performed well, and who did not. She could just look at the chart and do the math in her head, but giving colors to the columns (Good = green, Normal = yellow, Bad = red) would make the job easier (Figure 2-62). It would mean we define thresholds, sales numbers below a certain number (red), between numbers (yellow) and over a certain number (green).

Column chart with custom XML and Dynamic Action to show thresholds

Figure 2-62. Column chart with custom XML and Dynamic Action to show thresholds

These are the steps to create a chart with thresholds:

  1. Create a normal 2D column chart based on the following SQL statement:

    SELECT NULL LINK,
           ENAME LABEL,
           SAL VALUE
    FROM   EMP
    ORDER  BY ENAME
  2. Click right in the Tree view on the region and select Edit Chart. It will open the Chart Attributes.

  3. Navigate to the bottom of the page and set the dropdown for Use Custom XML to Yes. That will make the Custom XML text area editable. Note that the settings of the chart disappear and you now have to manually adapt the XML to make changes to the chart (Figure 2-60).

  4. The AnyChart XML Reference documentation (Figure 2-63) tells us we can use a threshold node (<threshold>). The following code needs to be added just after the </data_plot_settings> node (and before #DATA#):

    <thresholds>
      <threshold name="sales_threshold">
        <condition name="Bad" type="lessThan" value_1="{%Value}" value_2="1500" color="Red"/>
        <condition name="Normal" type="between" value_1="{%Value}" value_2="1500" value_3="2500"
    Column chart with custom XML and Dynamic Action to show thresholds
    color="Yellow"/>
        <condition name="Good" type="greaterThan" value_1="{%Value}" value_2="2500"
    Column chart with custom XML and Dynamic Action to show thresholds
    color="Green"/> </threshold> </thresholds>
  5. If you run the page now with the custom XML you don't see any difference, which is because the data node also needs to take the threshold into account. Now this isn't as straightforward as you might think. If you look at the XML you will find a #DATA# token that gets replaced on the fly by Oracle APEX based on the series. The SQL statement of the series gets translated into the correct XML. APEX doesn't support the threshold tag out-of-the-box, so you need to generate the correct XML so the thresholds are included manually.

  6. Create a Hidden Item on the page (right-click the chart region – Create Page Item – Hidden) and call it P18_CHART_XML (because we are on page 18). You will use this item to store the data part of the chart.

  7. In the Custom XML, replace #DATA# with &P18_CHART_XML. (note the . at the end), where P18_CHART_XML is the hidden page item. That item you will fill with the correct XML.

  8. To fill P18_CHART_XML with the XML, add an Advanced Dynamic Action to the page which generates the XML. Use the XMLDB feature of the database, which lets you create a select statement that generates XML. The Dynamic Action looks like this:

    • Event: Page Load

    • True Action: Execute PL/SQL Code

      declare
        l_xml clob;
      begin
        SELECT xmlelement("data", xmlattributes('sales_threshold' AS "threshold"),
      Column chart with custom XML and Dynamic Action to show thresholds
      xmlelement("series", xmlattributes('Series 1' AS "name"), xmlagg(
      Column chart with custom XML and Dynamic Action to show thresholds
      xmlelement("point",xmlattributes(ename AS "name", sal AS "y") ) ))).getClobVal() INTO l_xml FROM emp; :P18_CHART_XML := wwv_flow_utilities.clob_to_varchar2(l_xml); end;
    • Page Items to Submit: P18_CHART_XML

  9. If you want to add the Legend of the Thresholds you have to make another small change to the XML in Use Custom XML. You have to tell the legend the source is now thresholds instead of the items. Search for legend (only visible when you defined Show Legend before you set Use Custom XML) and change it to the following code. If you don't find the legend node, add it after the </axes> node.

<legend enabled="true" position="Bottom" align="Near" elements_layout="Horizontal"
Column chart with custom XML and Dynamic Action to show thresholds
ignore_auto_item="true" > <title enabled="true">
<text>Legend</text>
    <font family="Arial" size="10" color="0x000000" />
  </title>
  <font family="Arial" size="10" color="0x000000" />
  <items><item source="thresholds"/></items>
</legend>

Saving the chart and running the APEX page should give you the result shown in Figure 2-62.

If you have Asynchronous Update set to Yes, you will also need to change the Region and replace #CHART_REFRESH# with some custom JavaScript; instead of calling APEX's procedure to refresh the data, it needs to call your own. One way of doing that is by copying the Dynamic Action and assigning it to the change event of P18_CHART_XML.

  • Right-click the Dynamic Action – Copy

  • Event: Change

  • Selection Type: Item(s)

  • Item(s): P18_CHART_XML

  • Click the Copy Dynamic Action button

In the JavaScript you would trigger the change event on that item, so the Dynamic Action fires. Following JavaScript code does that:

<script type="text/javascript" language="JavaScript">
var chartName = '#CHART_NAME#';
chartName = chartName.substring(1);
function chart_r#CHART_NAME#_InitRefresh(pNow) {
  setTimeout("chart_r#CHART_NAME#_InitRefresh(true)",5000);
  if (pNow){
    apex_RefreshFlashChart (&APP_PAGE_ID., chartName, 'en-us'),
    $('#P18_CHART_XML').trigger('change'),
  }
}
apex_SWFFormFix('#CHART_NAME#'),
addLoadEvent(chart_r#CHART_NAME#_InitRefresh(false));
</script>

To get it working, replace the #CHART_REFRESH# token you find in the Region Definition of the chart by the above JavaScript.

AnyChart XML Reference documentation—thresholds node

Figure 2-63. AnyChart XML Reference documentation—thresholds node

Creating Charts Manually

When you want full control over everything, you can choose to create a chart completely manually. AnyChart allows you to add events to the chart to control every step, from rendering to moving the mouse and clicking on parts of the chart. In the following example we will create a multiseries chart with multiple axes and different tooltips per series. We will also make the width and height of the chart depend on what the user defined on the page. We will also discuss having null values in the resultset (see item 6 in this list).

Follow these steps to create a chart manually:

Create a page with an HTML region (in this example, page 7).

In the Region Source of the HTML region, add an empty div which will be filled with the chart by using JavaScript:

<div id="chartDiv"></div>

You will also create three Page Items:

  • One text item (Text Field) that defines the width of the chart: P7_CHART_WIDTH with a static value of 600 as the source.

  • One text item that defines the height of the chart: P7_CHART_HEIGHT with a static value of 400 as the source.

  • One hidden item where you store the XML data for the chart: P7_CHART_XML.

Because you will load the entire chart with JavaScript you need to add the JavaScript package that comes with AnyChart. Edit the Page and in the HTML Header put the following:

<script type="text/javascript"
src="#IMAGE_PREFIX#flashchart/anychart_5/js/AnyChart.js"></script>

Because we want to change the chart dynamically you need to make sure that the chart variable in JavaScript is accessible in the entire page. That is why you add in the Page Definition in Function and Global Variable Declaration the following variable declaration:

var chart;

You now need to initialize the chart by calling a specific AnyChart function and generate the data and give that to the chart. From APEX 4.0 onwards you should try to do as much JavaScript as possible through Dynamic Actions. Create a new Advanced Dynamic Action to generate the XML:

  • Name: Load Chart

  • Event: Page Load

  • True Actions:

  • Action: Set Value

  • Fire On Page Load: Yes

  • Set Type: PL/SQL Function Body

  • PL/SQL Function Body:

    declare
      l_chart varchar2(32767);
      l_xml   clob;
      l_data  varchar2(32767);
    begin
      l_chart := '<anychart>
      <settings>
        <animation enabled="True" />
      </settings>
      <charts>
        <chart plot_type="CategorizedVertical">
          <chart_settings>
            <title enabled="true">
              <text>Multi-Series: Multiple Y-Axes</text>
            </title>
            <axes>
              <x_axis tickmarks_placement="Center">
                <title enabled="true">
                  <text>Arguments</text>
                </title>
              </x_axis>
              <y_axis>
                <title enabled="true">
                  <text>Primary Y-Axis</text>
                  <font color="#135D8C" />
                </title>
                <labels align="Inside">
                  <font color="#135D8C" />
                </labels>
              </y_axis>
    <extra>
                <y_axis name="extra_y_axis_1" position="Right">
                  <minor_grid enabled="false" />
                  <major_grid enabled="false" />
                  <title enabled="true">
                    <text>Secondary Y-Axis</text>
                    <font color="#A4300B" />
                  </title>
                  <labels align="Inside">
                    <font color="#A4300B" />
                  </labels>
                </y_axis>
              </extra>
            </axes>
          </chart_settings>
          <data_plot_settings default_series_type="Line">
            <line_series>
              <label_settings enabled="true">
                <background enabled="false" />
                <font color="Rgb(45,45,45)" bold="true" size="9">
                  <effects enabled="true">
                    <glow enabled="true" color="White" opacity="1" blur_x="1.5" blur_y="1.5"
    Creating Charts Manually
    strength="3" /> </effects> </font> <format>{%YValue}{numDecimals:0}</format> </label_settings> <tooltip_settings enabled="true"> <format> Value: {%YValue}{numDecimals:2} Argument: {%Name} </format> <background> <border type="Solid" color="DarkColor(%Color)" /> </background> <font color="DarkColor(%Color)" /> </tooltip_settings> <marker_settings enabled="true" /> <line_style> <line thickness="3" /> </line_style> </line_series> </data_plot_settings> <data> #DATA# </data> </chart> </charts> </anychart>'; SELECT xmlelement("series", xmlattributes('Series 1' AS "name"), xmlagg( xmlelement
    Creating Charts Manually
    ("point", xmlattributes(ename AS "name", sal AS "y") ) )).getClobVal()
    INTO l_xml
      FROM emp;
    
      l_data := l_data || wwv_flow_utilities.clob_to_varchar2(l_xml);
    
      SELECT xmlelement("series", xmlattributes('Series 2' AS "name", 'extra_y_axis_1' AS
    Creating Charts Manually
    "y_axis"), xmlagg( xmlelement("point", xmlattributes(ename AS "name", nvl(comm,0) AS "y")
    Creating Charts Manually
    ) )).getClobVal() INTO l_xml FROM emp; l_data := l_data || wwv_flow_utilities.clob_to_varchar2(l_xml); l_chart := replace(l_chart, '#DATA#', l_data); return l_chart; end;
  • Escape Special Characters: No

  • Affected Elements – Selection Type: Item(s)

  • Item(s): P7_CHART_XML

We use the same XML DB features of the database to generate the data part. We also have a variable to store the XML definition of the chart. Note that the above example only works with datasets that are less than 32K because there is currently a limitation in APEX that you can assign a maximum of 32K to a Page Item. If you need to work with big datasets you need to slightly change the code. Later in this chapter, we will generate a dashboard and use the other technique which supports XML bigger than 32K. Also note that we used NVL(comm,0) for the value in the second series. If you don't use NVL the line will be incomplete as the y value in the XML will contain an empty string and your result might not be correct. So either you use NVL, which gives empty strings the value of 0, so every record will show up in the chart as a point, or you define a WHERE clause where you specify comm is not null; that means not every record will be shown, but your line will be complete.

A second True Actions to load the chart:

  • Action: Execute JavaScript Code

  • Fire When Event Result Is: True

  • Code:

    chart = new AnyChart('#IMAGE_PREFIX#flashchart/anychart_5/swf/OracleAnyChart.swf',
    Creating Charts Manually
    '#IMAGE_PREFIX#flashchart/anychart_5/swf/Preloader.swf'), chart.width = $v('P7_CHART_WIDTH'), chart.height = $v('P7_CHART_HEIGHT'), chart.setData( $v('P7_CHART_XML') ); chart.write('chartDiv'),

The chart JavaScript object we defined on the page level. The above code initiates a new AnyChart chart. The object can have different properties and events; in this case we used the width and height to define that at runtime based on the value in the page item. The setdata event gives the XML it finds in P7_CHART_XML to the chart and finally the write event will write the chart to the div.

Warning

Make sure you adapt the code to use your item names. For example, if you are on page 1 in the Dynamic Action you probably want to use P1_CHART_WIDTH.

Running the page gives the result as shown in Figure 2-64.

A chart manually created with JavaScript

Figure 2-64. A chart manually created with JavaScript

You also want to change the tooltip of Series 2 to have a custom message. To achieve that, follow these steps:

Edit the Dynamic Action "Load Chart" - "Set Value" in the True Action. Replace the existing SQL statement of Series 2 with the following code:

SELECT xmlelement("series", xmlattributes('Series 2' AS "name", 'extra_y_axis_1' AS
A chart manually created with JavaScript
"y_axis"), xmlagg( xmlelement("point", xmlattributes(ename AS "name", nvl(comm,0) AS "y"),
A chart manually created with JavaScript
xmlelement("tooltip", xmlattributes('true' as "enabled"), xmlelement("format", 'Job: '
A chart manually created with JavaScript
|| job)) ) )).getClobVal() INTO l_xml FROM emp;

In the point node you now added a tooltip node. The XML that gets generated looks like this:

<series name="Series 2" y_axis="extra_y_axis_1">
    <point name="SMITH" y="0">
        <tooltip enabled="true">
            <format>Job: CLERK</format>
        </tooltip>
    </point>
    <point name="ALLEN" y="300">
        <tooltip enabled="true">
            <format>Job: SALESMAN</format>
        </tooltip>
    </point>
    ...
    <point name="FORD" y="0">
        <tooltip enabled="true">
            <format>Job: ANALYST</format>
        </tooltip>
    </point>
    <point name="MILLER" y="0">
        <tooltip enabled="true">
            <format>Job: CLERK</format>
        </tooltip>
    </point>
</series>

To let the user define the width and height of the chart, you need to add two other dynamic actions that fire when the user changes the width and height text items. Here are the steps to do this:

Add a new Advanced Dynamic Action with the name: Change Chart Width

  • Event: Change

  • Selection Type: Item(s)

  • Item(s): P7_CHART_WIDTH

  • True Actions

  • Action: Execute JavaScript Code

  • Fire When Event Result is: True

  • Fire On Page Load: No

  • Code:

    chart.width = $v('P7_CHART_WIDTH'),
    chart.write('chartDiv'),

Add a new Dynamic Action with the name: Change Chart Height

  • Event: Change

  • Selection Type: Item(s)

  • Item(s): P7_CHART_HEIGHT

  • True Actions

  • Action: Execute JavaScript Code

  • Fire When Event Result is: True

  • Fire On Page Load: No

  • Code:

    chart.height = $v('P7_CHART_HEIGHT'),
    chart.write('chartDiv'),

When you manually create a chart for the first time it might be difficult to understand, but it comes down to going to the AnyChart Chart Gallery, finding an example you like, or looking into the documentation to know what XML and JavaScript you need to call. Next, you need to translate that logic into APEX components. Only by looking at the previous examples, trying things yourself, and gaining experience will this task become clear (if it is not already). After a while, the steps you have to take to create a chart completely manually will become trivial.

Drill-Down Charts, Dashboards, and Interactivity

In this section we will look more at combining different charts on the same page and letting them work nicely together. You will create a page that will provide an instant snapshot of your business information, by combining different reports and charts on a dashboard. With drill-down capabilities, the charts on your dashboard can show different results based on the user interaction with the page. There are many different techniques to create dashboard pages in APEX, from very simple examples using the built-in functionalities in APEX to very complex dashboards using actions and events that come with the full license of AnyChart charts.

Simple Dashboard with Submit

In this first example a manager wants to have an overview of the salaries he's giving to the respective departments and employees. To fullfill the manager's dream, we will create a page with one region and three subregions which hold the different charts, so it looks like the charts are in one region (Figure 2-65):

  • A pie chart with the salary by department

  • A 2D column chart that shows the average, minimum and maximum salary by department

  • Another 2D column with the salary by employee

A dashboard with three charts: one pie and two 2D column charts

Figure 2-65. A dashboard with three charts: one pie and two 2D column charts

Next, we want to allow the manager to select a department in the pie chart, and automatically update the other charts to only show information for the selected department (drill-down). Figure 2-66 represents the expected result when the manager clicks on the Sales (green) slice of the pie chart.

Dashboard chart drilled-down to the Sales department

Figure 2-66. Dashboard chart drilled-down to the Sales department

Behind the scenes, we used the wizard to create three different charts:

  • The pie chart that shows the salary by department uses the following query:

    SELECT 'f?p=&APP_ID.:&APP_PAGE_ID.:&APP_SESSION.::::P8_DEPTNO:'||d.deptno LINK,
           d.dname LABEL,
           sum(e.SAL) sal
    FROM   emp e, dept d
    where e.deptno = d.deptno
    group by 'f?p=&APP_ID.:&APP_PAGE_ID.:&APP_SESSION.::::P8_DEPTNO:'||d.deptno, d.dname
    ORDER  BY d.dname
  • The 2D column that shows the average, minimum, and maximum salaries by department uses this query:

    SELECT NULL LINK,
           d.dname LABEL,
           avg(e.SAL) as "Average Salary",
           min(e.SAL) as "Minimum Salary",
           max(e.SAL) as "Maximum Salary"
    FROM
           emp e, dept d
    where e.deptno = d.deptno
       and d.deptno = nvl(:P8_DEPTNO, d.deptno)
    group by d.dname
    ORDER  BY d.dname
  • The 2D Column that shows the salary by employee uses this query:

    SELECT NULL LINK,
    ENAME LABEL,
           SAL VALUE
    FROM   EMP
    where deptno = nvl(:P8_DEPTNO, deptno)
    ORDER  BY ENAME

If you want to create the above example yourself while you are reading, have a look at Figure 2-67, which shows all the regions, buttons and items behind the scenes and how they are laid out. If you downloaded the application that belongs to this chapter, you should have a look at page 8.

Note that the pie chart has a link defined. That link will submit the page and set the item P8_DEPTNO, a hidden item we created in that region, with the value of the slice the user clicks.

We also use a button on the page called All Departments which redirects to the same page and clears the cache. When creating the button for the action, select Redirect to Page in this Application, (the Page is 8 and Clear Cache is 8). Figure 2-67 shows how the rendering of page 8 looks, where no page processing has been defined.

Behind the scenes of the simple dashboard page with Submit

Figure 2-67. Behind the scenes of the simple dashboard page with Submit

This example is the simplest dashboard you can create. It uses charts created by the wizard and provides interactivity and drill-down capabilities by using the link in the series SQL statement. To achieve the dashboard look and feel, we created a parent region with three subregions for the charts. That way the charts look like they are combined. The above example has one big drawback: whenever the manager clicks on a link the entire page gets submitted, which isn't a nice effect and doesn't flow that well.

Simple Dashboard with JavaScript

This example will expand on the previous example, extending it to include a report on the employee data. Rather than doing a submit of the entire page, we will just refresh the necessary regions so the manager gets a nicer user experience.

We will copy the page of the previous example to page 10 and keep everything we did. We will add another report which will show the data of the employees. If the manager selects a specific department, the report only has to show the data for that department. So we add a Classic SQL Report to the page with the following SELECT statement:

select EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM
 from emp
where deptno = nvl(:P10_DEPTNO, deptno)

To remove the submit event of the page when the manager clicks on the pie chart, you need to change the link in the pie chart. We will set the value of P10_DEPTNO dynamically with JavaScript (by using $s(), a built-in function in APEX) so no submit happens. The select statement of the pie chart becomes:

SELECT 'javascript:$s("P10_DEPTNO",'||d.deptno||')' LINK,
       d.dname LABEL,
       sum(e.SAL) sal
FROM   emp e, dept d
where e.deptno = d.deptno
group by  'javascript:$s("P10_DEPTNO",'||d.deptno||')', d.dname
ORDER  BY d.dname

Now, when the manager clicks on a slice in the pie chart the hidden item will get a value (note that this value is not yet in session state as it has not been submitted yet, but is available through JavaScript). The issue now is that the other charts won't drill-down yet as they were not yet refreshed, which happened automatically before when the entire page was reloaded due to the submit event of the page. To refresh the other charts, you could set the Asynchronous Update in the Chart Attributes to 5 seconds, which will refresh the chart every 5 seconds. However, this is not a recommended way of handling the chart refresh in this scenario, because the refresh would always happen, even if the manager does not click on a slice. It also doesn't work for the report on the page, as you cannot define an Asynchronous Update like you could in the chart.

To solve the refresh issue, you use a Dynamic Action in APEX. Our dynamic action will refresh the two charts and the report. The Dynamic Action will fire whenever the value of the hidden item P10_DEPTNO gets changed. This is how our dynamic action is defined:

  • Event: Change

  • Selection Type: Item(s)

  • Item(s): P10_DEPTNO

  • True Actions

  • Action 1

    • Action: Execute PL/SQL Code

    • Fire When Event Result is: True

    • Fire On Page Load: No

    • PL/SQL Code:

      null;
    • Page Items to Submit: P10_DEPTNO

  • Action 2

    • Action: Execute JavaScript Code

    • Fire When Event Result is: True

    • Fire On Page Load: No

    • Code:

      apex_RefreshFlashChart ($v('pFlowStepId'), chartNameAvg.substring(1), 'en-us'),
      apex_SWFFormFix(chartNameAvg);
      apex_RefreshFlashChart ($v('pFlowStepId'), chartNameSal.substring(1), 'en-us'),
      apex_SWFFormFix(chartNameSal);
  • Action 3

    • Action: Refresh

    • Fire When Event Result is: True

    • Fire On Page Load: No

    • Selection Type: Region

    • Region: Salary by Employees (Report)

If you are not familiar with Dynamic Actions, you will find more information in Chapter 7. The following is a brief explanation of what our dynamic actions do. We first need to get the value of P10_DEPTNO into session state; one of the techniques to do that is used in Action 1. Action 2 will refresh the two charts. To know which chart it needs to refresh, we add the following code to the Region Definition of the chart with the average, maximum, and minimum salary:

<script type="text/javascript" language="javascript">
var chartNameAvg = '#CHART_NAME#';
</script>

to the chart with the salary by employee we add:

<script type="text/javascript" language="javascript">
var chartNameSal = '#CHART_NAME#';
</script>

The #CHART_NAME# token gets replaced at runtime by the chart name that APEX is using, and gets assigned to a global JavaScript value that we can reuse in the dynamic action. You need to use the apex_SWFFormFix to make it Internet Explorer–compatible as Internet Explorer has issues with objects that get changed on the fly.

Action 3 is a built-in dynamic action that refreshes the report.

Finally, you can change the button for seeing all departments to Redirect to Url. Use the following for the URL: javascript:$s('P10_DEPTNO',''). This basically empties out the hidden item.

Figure 2-68 represents the result of the manager clicking on a slice of the pie chart.

Dashboard chart and report drilled-down to Sales department (with JavaScript)

Figure 2-68. Dashboard chart and report drilled-down to Sales department (with JavaScript)

As you can see, the Sales slice in the pie chart is moved out from the rest of the chart. This "explode" action is a feature of AnyChart when you click on something in the chart, but you didn't see this in the first example because the entire page was submitted and rerendered. Figure 2-69 shows a behind-the-scenes view of the page.

Behind the scenes of the simple dashboard page with JavaScript

Figure 2-69. Behind the scenes of the simple dashboard page with JavaScript

Complex Dashboard with Actions

This example is completely different from previous examples and takes us beyond APEX. In this example, the manager wants to know how well his products have sold, broken down by state, and how many products every salesperson has sold. The manager also wants drill-down capabilities so that if he clicks on a state he can see how the products sold for only that state (Figure 2-70).

A complex dashboard using the full AnyChart capabilities

Figure 2-70. A complex dashboard using the full AnyChart capabilities

This example hardly uses any built-in features of APEX. The only thing you need is an HTML region where you define the <div> tag that holds the dashboard and a dynamic action to load the data for the dashboard (Figure 2-71). Unlike in the previous examples, this dashboard only consists of one Flash object, but inside that one Flash object three different charts are defined. The first one is a map, the second one a 2D bar chart, and the third one a 2D column chart.

Behind the scenes of the complex dashboard

Figure 2-71. Behind the scenes of the complex dashboard

The definition of the HTML Region is

<div id="chartDiv"></div>

And this is how the Dynamic Action is defined:

  • Event: Page Load

  • True Actions

  • Action 1:

    • Action: Execute JavaScript Code

    • Fire When Event Result is: True

    • Fire On Page Load: No

    • Code:

      chart = new AnyChart('#IMAGE_PREFIX#flashchart/anychart_5/swf/OracleAnyChart.swf',
      Behind the scenes of the complex dashboard
      '#IMAGE_PREFIX#flashchart/anychart_5/swf/Preloader.swf'), chart.width = 800; chart.height = 500; chart.setXMLFile('#OWNER#.GET_DASHBOARD_XML_PRC?p_param1=Full'), chart.write('chartDiv'),

As you can see, there is almost no complex structure to the page. The Dynamic Action runs on Page Load and will create a chart in the <div> tag. The only magic piece in the JavaScript is the call to setXMLFile which gets the XML for the chart. In this case we didn't use a hidden item to store the XML as that would give a problem for large datasets (more than 32K). Assigning a value to a page item is limited to 32K, but because the dashboard we want to create is based on three different charts, passing the information for all three charts will exceed that 32K limit. The setXMLFile calls a procedure on the server called GET_DASHBOARD_XML_PRC. The #OWNER# will get replaced by the default parsing schema defined in your workspace. The procedure has two parameters to pass extra information to the chart or change behavior based on the user interaction, but there is another parameter called XMLCallDate which you need to include because AnyChart is attaching extra parameters to the call. XMLCallDate is used by AnyChart to make sure every call is unique, otherwise the browser might cache the result and you might get incorrect results. You don't have to do anything special for that—AnyChart handles everything for you. You just need to make sure you accept these extra parameters in your procedure. The procedure looks like this:

create or replace procedure get_dashboard_xml_prc(
    p_param1 varchar2 default null,
    XMLCallDate IN NUMBER DEFAULT NULL)
is
  -- limit of 32K in single byte characterset, for UTF8 devide by 4 −1
  l_amt    number default 8191;
  l_offset number default 1;
  l_length number default 0;
  l_chart clob;
  l_chart_v varchar2(32767);
  l_chart_data clob;
begin
  dbms_lob.createtemporary( l_chart, FALSE, dbms_lob.session );
  dbms_lob.open( l_chart, dbms_lob.lob_readwrite );

  l_chart_v := '<anychart>
    <settings>
        <animation enabled="True"/>
    </settings>
    <dashboard>
        <view type="Dashboard">
            <title padding="2">
                <text>USA Sales Map</text>
            </title>
            <background>
                <inside_margin all="3" top="10"/>
            </background>
            <vbox width="100%" height="100%">
                <margin all="0"/>
                <hbox width="100%" height="60%">
                    <margin all="0"/>
                    <view type="Chart" source="mapChart" width="100%" height="100%"/>
                </hbox>
                <hbox width="100%" height="40%">
                    <margin all="0"/>
                    <view name="productsView" type="Chart" source="productsChart"
Behind the scenes of the complex dashboard
width="50%" height="100%"/> <view name="personsView" type="Chart" source="personsChart"
Behind the scenes of the complex dashboard
width="50%" height="100%"/> </hbox> </vbox> </view> </dashboard> <charts> <chart plot_type="Map" name="mapChart"> <chart_settings>
<controls>
                    <label inside_dataplot="True" position="Bottom" align="Near"
Behind the scenes of the complex dashboard
text_align="Center"> <text>Click on a state to see sales splitted by Products and Sales Representatives</text> </label> </controls> <title enabled="False"/> <chart_background> <border type="Solid" color="#CCCCCC" thickness="1"/> <corners type="Square"/> <effects enabled="false"/> <inside_margin all="10" top="5"/> </chart_background> <data_plot_background enabled="False"/> <legend enabled="True" ignore_auto_item="True" inside_dataplot="True"
Behind the scenes of the complex dashboard
rows_padding="0" align="Far"> <title enabled="False"/> <format>{%Icon} - ${%RangeMin}{numDecimals:0,scale:(1000)|(k)} -
Behind the scenes of the complex dashboard
{%RangeMax}{numDecimals:0,scale:(1000)|(k)}</format> <items> <item source="Thresholds"/> </items> </legend> </chart_settings> <data_plot_settings enable_3d_mode="False"> <map_series source="usa/country/states_48.amap"> <grid> <parallels enabled="False"> <labels enabled="False"/> </parallels> <meridians enabled="False"> <labels enabled="False"/> </meridians> <background enabled="False"/> </grid> <defined_map_region> <tooltip_settings enabled="True"> <font bold="True"/> <format> {%REGION_NAME} ${%Value}{numDecimals:1} </format> </tooltip_settings> <label_settings enabled="True"> <format>{%REGION_ID}</format> <background> <corners type="Rounded" all="2"/> </background> </label_settings>
<map_region_style>
                          <fill type="Gradient" color="%Color" opacity="0.75">
                            <gradient angle="45">
                              <key position="0" color="%Color" opacity="1"/>
                              <key position="1" color="Blend(DarkColor(%Color),%Color,0.4)"
Behind the scenes of the complex dashboard
opacity="1"/> </gradient> </fill> <border color="White"/> <states> <pushed> <fill type="Gradient" color="%Color" opacity="0.75"> <gradient angle="45"> <key position="0" color="%Color" opacity="1"/> <key position="1" color="Blend(DarkColor(%Color),
Behind the scenes of the complex dashboard
%Color,0.4)" opacity="1"/> </gradient> </fill> </pushed> </states> </map_region_style> </defined_map_region> </map_series> </data_plot_settings> <palettes> <palette name="salesPalette"> <item color="Red"/> <item color="Yellow"/> <item color="Green"/> </palette> </palettes> <thresholds> <threshold name="thrSales" type="Quantiles" range_count="5"
Behind the scenes of the complex dashboard
palette="salesPalette" /> </thresholds> <data> <series name="Region Sales" threshold="thrSales"> <actions> <action type="updateView" view="productsView"
Behind the scenes of the complex dashboard
source_mode="internalData" source="productsChart"> <replace token="{$ProductASales}">{%PR_A}{enabled:False}</replace> <replace token="{$ProductBSales}">{%PR_B}{enabled:False}</replace> <replace token="{$ProductCSales}">{%PR_C}{enabled:False}</replace> </action> <action type="updateView" view="personsView"
Behind the scenes of the complex dashboard
source_mode="internalData" source="personsChart"> <replace token="{$kateSales}">
Behind the scenes of the complex dashboard
{%KATE_SALES}{enabled:False}</replace> <replace token="{$jacksonSales}">
Behind the scenes of the complex dashboard
{%JACKSON_SALES}{enabled:False}</replace>
                            <replace token="{$adamSales}">
Behind the scenes of the complex dashboard
{%ADAM_SALES}{enabled:False}</replace>
                            <replace token="{$brentSales}">
Behind the scenes of the complex dashboard
{%BRENT_SALES}{enabled:False}</replace> </action> </actions>'; dbms_lob.writeappend( l_chart, length(l_chart_v), l_chart_v); select xmlagg( xmlelement("point", xmlattributes(p.c1 as "name", p.c2 as "y"), (select xmlelement("attributes", xmlagg( xmlelement("attribute", xmlattributes
Behind the scenes of the complex dashboard
(t.c3 as "name"), t.c4))) from salespp t where t.c1=p.c1))).getclobval() into l_chart_data from (select distinct c1,c2 from salespp) p; dbms_lob.append(l_chart, l_chart_data); l_chart_v := ' </series> </data> </chart> <chart plot_type="CategorizedHorizontal" name="productsChart"> <chart_settings> <title> <text>By Products</text> </title> <axes> <y_axis position="Opposite"> <title enabled="False"/> <labels> <format>${%Value}{scale:(1000)|(k),numDecimals:0}</format> </labels> </y_axis> <x_axis> <title enabled="False"/> </x_axis> </axes> <chart_background> <border type="Solid" color="#CCCCCC" thickness="1"/> <corners type="Square"/> <effects enabled="false"/> <inside_margin all="10" top="5"/> </chart_background> </chart_settings> <data_plot_settings> <bar_series> <tooltip_settings enabled="True"> <format> {%Name} ${%Value}{numDecimals:2} </format>
</tooltip_settings>
                    <label_settings enabled="True">
                        <format>${%Value}{numDecimals:1,scale:(1000)|(k)}</format>
                        <font bold="False"/>
                        <background enabled="True">
                            <fill enabled="True" color="White" opacity="0.3"/>
                            <inside_margin all="0"/>
                            <corners type="Rounded" all="2"/>
                        </background>
                    </label_settings>
                </bar_series>
            </data_plot_settings>
            <data>
                <series>
                    <point name="Product A" y="{$ProductASales}"/>
                    <point name="Product B" y="{$ProductBSales}"/>
                    <point name="Product C" y="{$ProductCSales}"/>
                </series>
            </data>
        </chart>
        <chart plot_type="CategorizedVertical" name="personsChart">
            <chart_settings>
                <title>
                    <text>By Sales Representative</text>
                </title>
                <chart_background>
                    <border type="Solid" color="#CCCCCC" thickness="1"/>
                    <corners type="Square"/>
                    <effects enabled="false"/>
                    <inside_margin all="10" top="5"/>
                </chart_background>
                <axes>
                    <y_axis>
                        <title enabled="False"/>
                        <labels>
                            <format>${%Value}{numDecimals:0,scale:(1000)|(k)}</format>
                        </labels>
                    </y_axis>
                    <x_axis>
                        <title enabled="False"/>
                    </x_axis>
                </axes>
            </chart_settings>
            <data_plot_settings>
                <bar_series group_padding="0.3">
                    <tooltip_settings enabled="True">
<format>
{%Name}
${%Value}{numDecimals:2}
</format>
                    </tooltip_settings>
                    <label_settings enabled="True">
<format>${%Value}{numDecimals:1,scale:(1000)|(k)}</format>
                        <font bold="False"/>
                        <background enabled="True">
                            <fill enabled="True" color="White" opacity="0.3"/>
                            <inside_margin all="0"/>
                            <corners type="Rounded" all="2"/>
                        </background>
                    </label_settings>
                </bar_series>
            </data_plot_settings>
            <data>
                <series palette="Default">
                    <point name="Kate" y="{$kateSales}"/>
                    <point name="Jackson" y="{$jacksonSales}"/>
                    <point name="Adam" y="{$adamSales}"/>
                    <point name="Brent" y="{$brentSales}"/>
                </series>
            </data>
        </chart>
    </charts>
</anychart>';
  dbms_lob.writeappend( l_chart, length(l_chart_v), l_chart_v);
  dbms_lob.close( l_chart );
  --
  owa_util.mime_header('text/xml', FALSE, 'utf-8'),
  owa_util.http_header_close;
  l_length := dbms_lob.getlength(l_chart);
  if l_length > 0 then
     while ( l_offset < l_length )
     loop
          htp.prn(dbms_lob.substr(l_chart, l_amt, l_offset) );
          l_offset := l_offset + l_amt;
     end loop;
  end if;
  --
  if l_chart is not null then
      dbms_lob.freetemporary(l_chart);
  end if;
end;

When you look at this code for the first time it might look challenging, but it comes down to generating the correct XML that AnyChart requires to render a dashboard. You would need to look into the AnyChart Gallery and Documentation to know what XML is expected.

In this case we hardcode many things—for example, the title and the persons—but you can make this procedure as dynamic as you like by using more parameters or building more queries to retrieve the data. Because there is a limit in htp.prn, you have to write a loop to pass the XML back in chunks. The look and feel of the chart in the above example is defined by a string, the data is retrieved from the salespp table, and you build the XML using the XML DB feature as we have done in previous examples.

Looking closer into the XML of the dashboard, AnyChart supports interactivity by defining Actions. We defined an action when a user clicks on the map to refresh the two detail charts of the products and persons. In a dashboard, AnyChart calls them views. So there is only one Flash Object, but because the View type is Dashboard and we defined how these views look, AnyChart will render multiple charts into one.

There are many more options in AnyChart; for example, using specific events to refresh one particular view of the dashboard (setViewData in JavaScript) or letting the chart behave completely differently when the user is hovering over and clicking the chart.

The possibilities are endless and we can't show every possible feature of AnyChart, but by understanding how AnyChart works behind the scenes and by looking at the different techniques used throughout this chapter, you should be able to build your dream chart.

Most Common Issues

This section explains some issues people frequently seem to have and how they can be solved.

Search for a Specific Feature

Looking at the Oracle APEX Forum, most of the requests there are about how to do a certain thing in a chart. In some cases, people don't know where to add a link or what every option in the APEX wizard means. In other cases it wasn't supported by an option in the APEX screens and a change had to be made in the XML, by using Custom XML and/or some JavaScript to generate the correct XML data. And in still other cases, people wanted to produce a chart that was not licensed by Oracle, so they had to get a valid license of AnyChart for APEX on the AnyChart website.

All the above questions have been answered in this chapter and you now have a good understanding of how charts work in APEX and how you can enhance them. It's a matter of reading the AnyChart documentation and finding the correct XML syntax and/or JavaScript to produce the chart you want.

Invalid #HOST# with Reverse Proxy or HTTPS

Sometimes people say they don't see the chart. In that case it might be that they have issues with the #HOST# substitution string that APEX is using in the region definition of the chart:

"#IMAGE_PREFIX#flashchart/anychart_5/swf/#CHART_TYPE#.swf?XMLFile=#HOST#apex_util.flash?p=
Invalid #HOST# with Reverse Proxy or HTTPS
&APP_ID.:&FLOW_PAGE_ID.:&APP_SESSION.:FLOW_FLASH_CHART5_R#REGION_ID#"

APEX might replace the #HOST# substitution string incorrectly. Many people running a reverse proxy or running in https seem to initially have this problem. To solve this issue, you have a few options:

  • Hard-code the correct value for your environment or use a substitution string or application item to pass the correct host value.

  • Pass through the host and port to your mod_plsql environment. For example:

    PlsqlCGIEnvironmentList    HTTP_HOST=<public hostname>:<public_port>
  • Use Virtual Hosts. For example:

    <VirtualHost *:80>
    # normal
    ServerName myserver.com
    ServerAlias myserver.com
    DocumentRoot /home/myserver
    Port 7777
    ...
    # in case of a Proxy
    ProxyPass http://www.myserver.com:8080/apex
    ProxyPassReverse http://www.myserver.com:8080/apex
    </VirtualHost

With the following command you can verify if the host name and port are set correctly:

select owa_util.get_cgi_env('HTTP_HOST') from dual;

Flash Security Error

On some occasions you might receive the following error:

Flash Security Error:
AnyChart can not be launched due to Flash Security Settings violation.
Please refer to Security Error Article in AnyChart Documentation to fix this issue.

This error is linked to the previous error with the #HOST#, but this error is a more global security error that any Flash object might have. You receive this error when the AnyChart SWF and the data for the SWF are on a different domain. In some cases you might access APEX through one web server, while your data comes from another. In this case the #HOST# is different if you use the standard way to generate the XML for the chart, or you might have decided to call a procedure on another server, but this is something that Flash doesn't allow unless you specify a cross-domain policy file. Another issue might be that the SWF is loaded from http while the data comes from https.

The solution is, you use the same domain and protocol (http, https) or you tell Flash the other domain is a trusted location. In the documentation of AnyChart you will find an example of a policy file (AnyChart Documentation

Flash Security Error

Charts in the Future

Charts are becoming more and more important in new websites and applications. They provide a quick overview of a situation at any moment. Business Intelligence is already widely adopted, but having charts in your APEX application gives you an advantage.

The charting world is rapidly changing. Column and bar charts have been around for a long time, and will exist in the future, but as data grows exponentially, time-based charts become more and more important. Being able to quickly navigate through a large volume of time-based data in a user-friendly way will be a challenge. For example, AnyChart has created a new product called AnyStock, which allows the creation of time-based and financial charts, but not all chart types are supported by the product yet.

Because applications need to run from anywhere and at anytime, Flash chart technology will probably need a facelift. Adobe, the owner of Flash, is working hard to translate Flash objects on the fly into native HTML5 code, which every future browser will be able to run. Flash is currently faced with the issue that it doesn't run on devices that don't have or support a Flash plug-in, so a browser is not enough to run these charts. As people expect to see and use their applications anywhere and anytime, non-Flash charts will become more and more common in the future.

Other elements of the future of charting solutions will include user interaction like zooming, drag-drop, different information depending on user interaction, and the like. Allowing the user to do things in an innovative and intuitive way will become increasingly important and will decide if your application is "wow", or just okay.

We'll see how far Oracle will be able to follow these new charting trends in APEX, but it looks like they intend to keep up with the future. Oracle has indicated that future versions of APEX will be able to generate non-Flash charts. But as the AnyChart release schedule does not coincide with Oracle's APEX releases, it's more than likely that new third-party APEX plug-ins will become available to support the latest and greatest in charting. One of the companies that has already started to do this is mine (APEX Evangelists): we already offer non-Flash charts, time-based charts (based on AnyStock), and upgrade kits for the current charting engines in APEX. You can find more information about our charting solutions at http://www.apex-evangelists.com.

Resources

Below is a list of resources linked to using charts in a web environment and Oracle Application Express. You might find them useful if you need more information or examples:

  • The APEX application used in this book:

    http://examples.apex-evangelists.com/pls/apex/f?p=APEX_EXPERT_CHART
  • Blog posts related to mentioned bugs:

    http://dgielis.blogspot.com/2011/02/apex-4-bug-add-marker-to-your-chart.html
    http://dgielis.blogspot.com/2011/02/apex-4-bug-gradient-in-charts.html
    http://dgielis.blogspot.com/2011/02/apex-4-bug-axes-in-charts.html
    http://dgielis.blogspot.com/2011/02/apex-4-bug-font-grid-label-in-charts.html
    http://dgielis.blogspot.com/2011/02/apex-4-bug-chart-attributes-add-series.html
    http://dgielis.blogspot.com/2011/02/apex-4-bug-series-type-bar-line-marker.html
  • APEX Documentation, Accessibility in Oracle Application Express:

    http://download.oracle.com/docs/cd/E17556_01/doc/install.40/e15513/accessibility.htm#sthref285
  • Adobe knowledge base:

    • About Object/Embed tag:

      http://kb2.adobe.com/cps/415/tn_4150.html
    • Possible parameters for Object/Embed tag:

      http://kb2.adobe.com/cps/127/tn_12701.html
      http://kb2.adobe.com/cps/403/kb403183.html
    • AnyChart User's Guide:

      http://www.anychart.com/products/anychart/docs/users-guide/index.html
    • AnyChart XML Reference:

      http://www.anychart.com/products/anychart/docs/xmlReference/index.html
    • AnyChart Gallery with many examples of charts:

      http://www.anychart.com/products/anychart/gallery/
    • AnyChart Integration Kit for APEX:

      http://anychart.apex-evangelists.com
    • AnyGantt XML Reference:

      http://www.anychart.com/products/anygantt/docs/xmlReference/index.html
    • AnyGantt Gallery:

      http://www.anychart.com/products/anygantt/gallery/
    • Hilary Farrell from the APEX Development Team also has a sample chart application with many demos and tips:

      http://apex.oracle.com/pls/apex/f?p=36648
    • Firebug for Firefox:

      http://getfirebug.com

Conclusion

We started this chapter with an overview of the charting possibilities in Oracle APEX. There are two big charting types in APEX 4.0: HTML Charts and Flash Charts. We looked at both charting types and learned that HTML charts are more limited than Flash Charts.

Flash Charts give you a lot more possibilities to let the chart behave as you want. We explained in great detail how the charts are working behind the scenes so you can identify quickly how to do something or where to look in case of unexpected behavior.

We saw how you can customize the AnyChart XML and enhance the charting by using Dynamic Actions and by creating charts and dashboards manually.

Using charts in APEX is a great way for your users to visualize the data they work with day-in and day-out. APEX and AnyChart have everything on board to fulfill your charting dreams, and there is more to come in the future. If the current implementation of charting doesn't include a particular feature, there are already many extensions and plug-ins available that give you that functionality today.

Good luck with charting and enjoy this wonderful technology!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset