Flash in XFA — sample column chart

After posting about the new features arriving in Acrobat X / XFA 3.3 I received several requests for samples. So today we’ll have a look at a sample that uses a generic column chart to display form data.  If you have used flash inside Acrobat 9, the concepts here should be very familiar.  And before we go any further, I should remind you that you don’t (yet) have the tools to design this form yourselves.  You need to wait for the next version of LiveCycle Designer.  But in the meantime, you can look at the script and internals of the sample form using the current version of Designer.

First, here is the sample PDF, here is the flex project for the chart swf.

Some comments about how to use the form:

  1. In the "Type" field, select the column chart variation you want: clustered, overlaid or stacked.
  2. Edit the hex values in the color fields to choose the colors for the 5 data series that can be created
  3. Click "Start Chart" to create the chart with its first data series
  4. Click "Add Row" to add another row of dataa — and to include it in the chart. (the new row values are randomized)
  5. Edit some of the sales values in the table.  Notice how the chart reacts when you exit the field.

Now the nitty gritty:

A Generic Column Chart

If you use Flash Builder to create a column chart, it’s pretty easy to define it with declarative markup when the data source is well understood. In my case I wanted a skeletal chart definition and allow it to be modified by actionscript methods — which would in turn be called from the form JavaScript.

To achieve this, the sample column chart exposes three methods:

  • reset() — get rid of existing data and restart the chart
  • addSeries() — add a new data series to the chart
  • updateValue() — notify the chart that one of the values in its data series has changed

The actionscript in the sample chart calls ExternalInterface.addCallback() to register each of these methods.

These three methods provide all the parameters needed for the chart (title, data, colors, labels). There are plenty of other chart properties that could be exposed by an energetic developer who is a little more industrious than me.

A couple other pointers for developing flash for embedding in PDF:

  • Round-tripping the flash to test in Designer is cumbersome.  I’m continually exporting release builds from Flash Builder.  For expedient testing I added buttons to the chart sample to call the relevant methods so I can test from within flash builder.  Then when I’m happy with the result I comment out the buttons.
  • You need the right settings so that your embedded flash will respond to document zoom events.  The magic bit is this code in the application element:
    <mx:Application applicationComplete="stage.scaleMode=StageScaleMode.EXACT_FIT;" …>

Embedding the Flash

To embed the flash, I created a host field with the same aspect ratio as the flash application — in this case my flex specified: <mx:application width="675" height="450"/> so I made the dimensions of my host field: w=6.75in h=4.5in.

I specified a poster image to use when the flash is not active.  To get a suitable image, I took a screen shot of the empty chart, cropped it and saved as a jpg.

In order to pass in chart data and chart parameters, the form JavaScript calls methods on the flash object using the ‘invoke’ method on exObject:

chart.ui.exObject.invoke("reset", …);

Restoring the state of the flash object

When re-opening the form we need to restore the state of the embedded flash object.  If the flash were a simple widget with a data value, we’d likely use the multimedea calls to save/restore data:

ExternalInterface.call( “multimedia_saveSettingsString”, “…” );

state = ExternalInterface.call( “multimedia_loadSettingsString” );

If we called these methods, the widget data would be saved/restored from the form data associated with the host field.  However in the case of our chart, we want to restore the chart from the data in the table.

I failed in my first attempt to restore the flash data.  I called the chart reset() method from the docReady event.  The problem was that the flash object was not yet activated and the call was ignored.  The solution was to have the embedded chart call a script object method when it was activated. From actionscript this looked like:

ExternalInterface.call("chartHelper.initialize");

This calls the initialize() method on the chartHelper script object.  The initialize method then uses the reset() and addSeries() methods to re-populate the chart.

 

10 Responses to Flash in XFA — sample column chart

  1. Pingback: Final Post: XFA Tank Wars - Stefan Cameron on Forms

  2. Thanks John,

    This new feature in LC Designer/Acrobat X is going to be good and we are looking forward to working with it.

    I tried the sample in Reader X, but it failed to load the swz:

    http://blogs.adobe.com/formfeed/files/formfeed/PDFMedia000036/g/osmf_flex.4.0.0.13495.swz

    It may require Acrobat X. When I tried the url in a browser, I got a 404.

    I have been looking at the externalInterface on and off for a while now. Still getting my head around it. https://acrobat.com/#d=LFN07JAKvPMbaIif3ERJUw.

    Thanks for the information, script and example.

    Niall

    • John Brinkman says:

      Niall:

      You’re right. The sample appears to work only for Acrobat right now — not Reader.
      I suspect the problem is due to a dependency on a shared flex runtime library.
      I’ll try and resolve this soon…

      John

      • Niall:

        I’ve updated the content. Should work in reader now. The trick is in the flash builder build path settings to specify the Framework linkage: “merged into code”.

        thanks again for the heads up.

        John

  3. Hi John
    Great sample and information.
    I have a couple of questions (I really should stop being lazy and just work these out for myself, but you may just know the answers).
    1. What would we get if we rendered this in LiveCycle Output? (The poster image?)
    2. Are there any restrictions on what the “Flexlet” can do? Can it pop up a dialog, open a web page, call a web service, invoke LiveCycle Data services, etc?
    Many thanks,
    Howard

    • John Brinkman says:

      Howard:
      Good questions.
      1. Your guess is correct. LiveCycle output will render the poster image.
      2. Restrictions: The embedded flash must conform to the Reader security model. The biggest impact is that all http access goes through the Reader network stack — meaning that you can perform http-based operations; but they’ll have the same restrictions that you have in Reader. e.g. you may get the phone-home dialog.
      So specifically to your examples:
      dialog? yes. But note that when flex is launched in a floating window the window location is restricted to the document area of the Reader application.
      web page? Hyperlinks should work.
      Web service? yes.
      LCDS? Hmm. My guess is that we don’t support AMF protocol. But this is an area you might want to test yourself. The behaviour you get with flash in plain PDF should be the same as when embedded in XFA.

      John

      • Diego Silva says:

        Hi Howard,

        Regarding to your 1st question, if you use the importData from Form Data Integration service instead, you’d get the dynamic PDF with the chart running.

        Cheers!

        Diego

  4. Sorry about this John, but the URL appears to be pointing to a file now: file://PDFMedia002330/g/osmf_flex.4.0.0.13495.swz

    I’ll try again once I have Acrobat X installed.

    Thanks,

    Niall

    • John Brinkman says:

      Checking with Niall offline, it appears his problem was due to a stale browser cache.
      But more importantly, the original problem Niall reported has been acknowledged as a bug. We anticipate a fix in the first dot release of Reader.

  5. Hi John,

    will that function be available within the server products i.e. one could render a dynamic form including the chart using LiveCycle Forms? Any other ways in getting a SWF into a PDF on the server side?

    With kind regards

    Maruan