Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 

I got an issue to create a PDF form with charts. Those charts are not static of course.

So, we are to use the Adobe LiveCycle Designer and CL_IGS_CHART_ENGINE.

First of all I’ve tried to create a simple report that can create an image file with chart.

The easiest way to create a chart – is to use a functional module PIG_EZ_CHART. It has a very simple interface:


CALL FUNCTION 'PIG_EZ_CHART'
EXPORTING
*   FORMAT               = 0
*   WIDTH                = 320
*   HEIGHT               = 200
*   USE_DB               = ' '
*   TYP                  = 'PIE'
*   TITLE                = ''
*   LEGEND               = 'DEFAULT'
*   SCHEME               = 'DEFAULT'
values              
=
*   TITLE_CAT            = ''
*   TITLE_VAL            = ''
* IMPORTING
*   CONTENT_TYPE         =
*   CONTENT_LENGTH       =
*   CONTENT_ID           =
* TABLES
*   CONTENT              =
*   IMAGEMAP             =
.


The only one field we need to pass is values string. It’s a charlike string where lines separated by ‘@.’ and field values separated by ‘@,’.

Here is the simple short code to get a chart image:


DATA: lv_data    TYPE pig_data-char30k,
lt_content
TYPE TABLE OF w3mime,
lv_filename
TYPE string VALUE 'C:\Temp\MyFirstChart.jpg'.

lv_data
= 'First_line@,Label1@,12@.Second_line@,Label2@,4'.

CALL FUNCTION 'PIG_EZ_CHART'
EXPORTING
values 
= lv_data
*    typ     = 'BARS_STACKED'
TABLES
content
= lt_content.

CALL METHOD cl_gui_frontend_services=>gui_download
EXPORTING
filename
= lv_filename
filetype
= 'BIN'
CHANGING
data_tab
= lt_content
EXCEPTIONS
OTHERS   = 24.

Here we’re trying to get 2 lines somewhere and 2 labels for them with different values. Here is the result:

Here is just one label and there are no lines presented! And where are my values?

But you can see I’ve commented one short line with passing parameter ‘TYP’. Here is a list of values for this parameter (INCLUDE LSGRAPHICSTOP):

constants:
* presentation type:
sgma_prestype_trend
(20)           type c value 'TREND',

sgma_prestype_lines
(20)           type c value 'LINES',
sgma_prestype_lines_3d
(20)        type c value 'LINES_3D',

sgma_prestype_area
(20)            type c value 'AREA',
sgma_prestype_area_3d
(20)         type c value 'AREA_3D',
sgma_prestype_area_stacked
(20)    type c value 'AREA_STACKED',
sgma_prestype_area_stacked_3d
(20) type c value 'AREA_STACKED_3D',

sgma_prestype_bars
(20)            type c value 'BARS',
sgma_prestype_bars_3d
(20)         type c value 'BARS_3D',
sgma_prestype_bars_stacked
(20)    type c value 'BARS_STACKED',
sgma_prestype_bars_stacked_3d
(20) type c value 'BARS_STACKED_3D',

sgma_prestype_cols
(20)            type c value 'COLUMNS',
sgma_prestype_cols_3d
(20)         type c value 'COLUMNS_3D',
sgma_prestype_cols_stacked
(20)    type c value 'COLUMNS_STACKED',
sgma_prestype_cols_stacked_3d
(20) type c
value 'COLUMNS_STACKED_3D',

Let’s try with
typ     = 'BARS_STACKED'
Here is a result:


Definitely better!

It’s rather simple. But we have some limitations on influencing customizations. Try to change background color or scales representation. For these purposes we have a Chart Designer (http://www.sdn.sap.com/irj/scn/downloads?rid=/library/uuid/e0a9ba90-0201-0010-d3a2-9cb376b5e181) and also we have a report GRAPHICS_GUI_CE_DEMO that allow creating and saving customizations.

Customization is a XML file. It describes almost all parameters of your chart. So you can create any customization and same it as a XSL-transformation. We will need to change a caption of our chart, so there is a little need to change content of this static xml.

I found that it is good idea to leave data filling as it is. I mean it’s a simple string with all data separated by signs ‘@,’ and ‘@.’ We will have at least one method to get desired chart.

To use CL_IGS_CHART_ENGINE we will need to pass two XML structures:

  1. Customizing structure (set_customizing method)
  2. Data structure (set_data method)

The first structure we can get and pass to Chart Engine by following code:

DATA: m_ixml     TYPE REF TO if_ixml,
m_ixml_sf 
TYPE REF TO if_ixml_stream_factory,
lv_data   
TYPE string,
lref_chart
TYPE REF TO cl_igs_chart_engine,
l_istream 
TYPE REF TO if_ixml_istream,
l_document
TYPE REF TO if_ixml_document.

m_ixml
= cl_ixml=>create( ).
m_ixml_sf
= m_ixml->create_stream_factory( ).
*  Call XSL-transformation to get customization
CALL TRANSFORMATION (YOUR_XSL_TRANSFORMATION)
SOURCE caption
= iv_text   "Desired  caption
height 
= iv_height "Desired Height
RESULT XML lv_data
.
*  Prepare XML data for parsing
l_istream
= m_ixml_sf->create_istream_cstring(
string
= lv_data ).
l_document
= m_ixml->create_document( ).
l_parser
= m_ixml->create_parser(
stream_factory
= m_ixml_sf
istream       
= l_istream
document      
= l_document ).
l_result
= l_parser->parse( ).
CHECK l_result IS INITIAL.
*  Create chart engine instance
CREATE OBJECT lref_chart.
*  Pass Customization
lref_chart
->set_customizing( custom_doc = l_document ).


And finally we need to pass data to our chart instance.

As soon as I’ve decided to leave data filling as it is I have to create a method to get structures back from single string:

METHOD get_categories_n_series.
TYPES: BEGIN OF gty_category,
text TYPE string,
END OF gty_category,
BEGIN OF gty_value,
value TYPE dmbtr,
END OF gty_value,
gty_value_tab
TYPE TABLE OF gty_value,
BEGIN OF gty_series,
text   TYPE  string_unicode,
values
TYPE  gty_value_tab,
END OF gty_series.
DATA: lt_lines TYPE TABLE OF string,
lv_category
TYPE string,
lv_xval
TYPE string,
lv_yval
TYPE char100,
lv_rest
TYPE string,
lv_categ
TYPE TABLE OF gty_category.
FIELD-SYMBOLS:
<line>
TYPE string,
<seria>
TYPE gty_series,
<value>
TYPE gty_value.
SPLIT iv_data AT c_line_delimiter INTO TABLE lt_lines.
LOOP AT lt_lines ASSIGNING <line>..
SPLIT <line> AT c_field_delimiter INTO
lv_category lv_xval lv_yval lv_rest
.
lv_categ
-text = lv_xval.
COLLECT lv_categ INTO et_cteg.
READ TABLE et_series ASSIGNING <seria>
WITH KEY text = lv_category.
IF sy-subrc <> 0.
APPEND INITIAL LINE TO et_series ASSIGNING <seria>.
<seria>
-text = lv_category.
ENDIF.
APPEND INITIAL LINE TO <seria>-values ASSIGNING <value>.
REPLACE ALL OCCURRENCES OF ',' IN lv_yval WITH '.'.
CONDENSE lv_yval.
REPLACE ALL OCCURRENCES OF '-' IN lv_yval WITH ''.
<value>-value = lv_yval.
ENDLOOP.
ENDMETHOD.

Now we need to pass these data to our chart instance.

l_document = m_ixml->create_document( ).
*  Prepare XML header with encoding
l_encoding
= m_ixml->create_encoding(
byte_order
= if_ixml_encoding=>co_little_endian
character_set
= 'utf-8' ).
l_document
->set_encoding( l_encoding ).
*  Create a root element (see documentation for Chart Designer)
l_simplechartdata
= l_document->create_simple_element(
name
= 'ChartData' parent = l_document ).
* Create node to fill categories
l_categories
= l_document->create_simple_element(
name
= 'Categories' parent = l_simplechartdata ).
* For each category calculated - need to create node
LOOP AT lt_categories ASSIGNING <category_line>.
l_element
= l_document->create_simple_element(
name
= 'Category' parent = l_categories ).
l_element
->if_ixml_node~set_value( <category_line>-text ).
ENDLOOP.
* It's for just this task - determine one of two series
lv_first
= abap_true.
LOOP AT lt_series ASSIGNING <seria>.
l_series
= l_document->create_simple_element(
name
= 'Series' parent = l_simplechartdata ).
IF lv_first = abap_true.
*    Customizing - is an attribute influencing on apperiance of
*    separeted column or bar or etc.
l_series
->set_attribute( name = 'customizing' value = 'Series1' ).
CLEAR lv_first.
ELSE.
l_series
->set_attribute( name = 'customizing' value = 'Series2' ).
ENDIF.
*  Fill name
l_series
->set_attribute( name = 'label' value = <seria>-text ).

LOOP AT <seria>-values ASSIGNING <chart_value>.
*    Create a Point node see documentation for Chart Designer
l_element
= l_document->create_simple_element(
name
= 'Point' parent = l_series ).
l_point
= l_document->create_simple_element(
name
= 'Value' parent = l_element ).
*    Here we fill just Y value
l_point
->set_attribute( name = 'type' value = 'y' ).
lv_string
= <chart_value>-value.
l_point
->if_ixml_node~set_value( lv_string ).
ENDLOOP.
ENDLOOP.
lref_chart
->set_data( l_document ).
*    Call Chart Engine
CALL METHOD lref_chart->execute
EXCEPTIONS
OTHERS = 1.

IF sy-subrc = 0.
CLEAR lt_mime.
CALL METHOD lref_chart->get_image
IMPORTING
image
= lt_mime.
CLEAR lv_result.
*    lv_result type xstring
*    Collect all data into single XSTRING

LOOP AT lt_mime ASSIGNING <mime>.
lv_result
= lv_result && <mime>-line.
ENDLOOP.
*    Get STRING from XSTRING to pass into PDF form
CALL FUNCTION 'SSFC_BASE64_ENCODE'
EXPORTING
bindata                 
= lv_result
IMPORTING
b64data                 
= rv_result
EXCEPTIONS
OTHERS                   = 8.
ENDIF.

Now let’s imagine we’ve completed all duties on charts well. As a result we got a string with image for our PDF. There we’re to create a field of type Image Field with binding to our string calculated.

And we will get something like this:


18 Comments