Create a PDF form with charts
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:
- Customizing structure (set_customizing method)
- 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:
Thanks for the Information..
You're welcome! π
thanks, but I have a question: how do you make your charts look like in your last picture? When I'm creating bar charts with the ChartDesigner, they look more like this:
You can try to change my data line from:
lv_data = 'First_line@,Label1@,12@.Second_line@,Label2@,4'.
To:
lv_data = 'First_line@,Label1@,12@.Second_line@,Label1@,4'.
And see: https://dl.dropboxusercontent.com/u/89537103/MyFirstChart11.jpg
Sorry, I think you didn't understand my question.
I mean the last picture in your blog entry (the charts with the blue bars) - where did you get the picture from? Is this a SAP chart, made with the CL_IGS_CHART_ENGINE? Or is it a HTML chart? Because it looks completely different than my charts in SAP.
It's mady by CL_IGS_CHART_ENGINE of course. You can try to use a customization here: https://dl.dropboxusercontent.com/u/89537103/XSLT_for_charts.txt It's an XSL-transformation used to get these charts.
Did you try to use a report GRAPHICS_GUI_CE_DEMO to save a customization? Actually there is a standalone program ChartDesigner but it doesn't work properly. So the only way I found to customize Charts is that report.
Ah thanks, now I can reproduce your chart.
What do you mean, the ChartDesigner doesn't work properly? I always use the ChartDesigner - you just have to save the customizing as an xml document and import the file into the MIME repository, where you can load it from your ABAP program.
Ich loaded your customizing into the ChartDesigner and it works. I can see and change the customizing from here and export it as xml file again.
Thanks again!
I'm happy that you achieved desired results. I mean that when I push the button 'Next' it crushes down. Perhaps it's an undocumented feature π
And of course, you're welcome!
Ah yes, ChartDesigner can load and save customizations. So you're right.
Maybe you should reinstall the ChartDesigner, because (as I mentioned before) it works for me. I can create the whole customizing and save it as xml file. I think your installation is broken...
Hi,
My requirment is to add chart in ADOBE form can you please share your full code if it is possible... Because here some code are not fully attached.
Thanks in advance for your reply.
Regards,
Ravi Shankar.L
Nice Document..Kindly help me to implement the same by sharing the code thanks for your help in advance.
Regards,
Ravi Shankar.L
Can you please let me know which part you need to be explained? What is the main problem to implement this solution into PDF? Is it about creating XSL transformation with customization or it's about getting xml with data? Or something else? Regards, Alex
Following are my doubts,
I am new in these using classes if anything asked silly means please ignoring it. But your document is the best solution to bring data in PDF π
Regards,
Ravi Shankar.L
I see π
Well, we can go from the very end. What do we need? Just a string with a JPG content. That's why rv_string is:
DATA: rv_string type string.
This step is to run the chart engine. It will generate an image:
CALL METHOD lref_chart->execute
EXCEPTIONS
OTHERS = 1.
IF sy-subrc = 0.
CLEAR lt_mime.
*Here we're to get that image
* lt_mime type W3MIMETABTYPE. "You can learn it from se24->CL_IGS_CHART_ENGINE
CALL METHOD lref_chart->get_image
IMPORTING
image = lt_mime.
CLEAR lv_result.
*Get desired string as xstring.
* lv_result type xstring
* Collect all data into single XSTRING
LOOP AT lt_mime ASSIGNING <mime>.
lv_result = lv_result && <mime>-line.
ENDLOOP.
And now two points more difficult:
1. Create XSLT for customization. And send it as a costomization to the Chart engine.
2. Create xml with our data to transfer values.
1.
So the first can be done by downloading desired customization from the Chart Designer. Then you can simply create XSL transformation at t-code strans. You can copy-paste the whole content of that customization into the transformation.
I gave the whole code for this part in the text. From the line "The first structure we can get and pass to Chart Engine by following code:"
2.
I decided to store all the data as described in the example: lv_data = 'First_line@,Label1@,12@.Second_line@,Label2@,4'.
This allow us using both methods: the simple one and the difficult one. At the same time we can't transfer this line into the Chart Engine. We have to translate it into the xml format. That's why I created a method METHOD get_categories_n_series.
So we're to pass there a line and to get back tables with categories and series. The method call would look like:
get_categories_n_series( exporting iv_data = {your line with data}
importing et_cteg = lt_categories
et_series = lt_series ).
By the way. Types described in the method are global. So your lt_categories type gty_value_tab and your lt_series type table of gty_series.
I found a mistake in my method: lv_categ TYPE TABLE OF gty_category. should be
lv_categ TYPE gty_category.
Now we have two tables:
1. Categories texts and
2. Series with their values
So we are to compose the xml structure. It's described after the line "Now we need to pass these data to our chart instance."
And you asked about types... I went trough the text and found that it may be unreadable π Sorry. So you can read the main method from the line "The first structure we can get and pass to Chart Engine by following code:"
Then you can skip method get_categories_n_series and continue from the line "Now we need to pass these data to our chart instance."
That mean you will have:
1. Chart Engine instance created.
2. Customization paased there.
3.
4. Data transformed into the xml structure.
You can see that I skipped point 3. Here you are to pass your data line to the method get_categories_n_series
I hope this will help you! Unfortunatelly I can't give you the source code as soon as I have no connection to that system.
Kindest regards
Alex
To your question about
"l_result = l_parser->parse( )."
You can find:
l_parser = m_ixml->create_parser(
stream_factory = m_ixml_sf
istream = l_istream
document = l_document ).
So l_parser is:
data: l_parser type ref to IF_IXML_PARSER.
BR,
Alex
Thanks for your reply I will try this and let you know...... Thanks a lot...... π
Hello Alex,
I have a requirement to display tabular data in first half page and in the second half 4 statistical graph charts based on the tabular data. Main challenge is to download the output with all graph charts to PDF.
My requirement is to display different data ( both tabular & Form sharing the first half screen) in an ALV report and in the second bottom half of the same output to display 4 different statistical graph charts based on the above data. No dynamic but static based on First half screen data. I think it is possible to do the above requirement with multiple ALV containers.
I could achieve this by creating a screen (ex: screen 100) with 2 containers - CNT1 for ALV data in tabular and form page display, and in CNT2 for statistical graphs referring to cl_gui_chart_engine.
Other requirement is to download the above output data with all tabular alv data and the 4 graphical charts to the PDF on user desktop in the same way as it display on SAP output screen. This is little doubt ful as i never converted output with graph charts sending to spool and convert otf to pdf. Not sure whether graph chart can convert into pdf and other concern is the data and graphs will be scrolled on the sap output to view all.
Users simply given me an excel file designed with colorful and asked to create an ABAP Report in the same fashion.
Similar requirement was asked in the past in below link but not answered.
https://archive.sap.com/discussions/thread/1224950
Appreciate if anyone did this kind of requirement and share with me detail code.
following are my queries:1. Is it possible to get the report data in tabular format into excel and add the graph as an image below that table.2. The top container creates scroll bars if the ALV lines go beyond its defined height.3. I guess cl_gui_chart_engine has methods that can convert the graph into an image format...