Skip to Content
Technical Articles
Author's profile photo Yogesh Kumar

Printing Charts / Graphs on Smart Forms Dynamically

In many requirement graphical charts are required by the clients since a graph is much more appealing to the user. As graphs enables a better analysis of data to the user. It is however quite simple to provide the same functionality for building graphical charts in your ABAP report itself by using CL_IGS_CHART_ENGINE.

Recently I had the requirement of printing Charts on Smart forms. In Smart forms we can print the image if the image is already uploaded to the Form Graphics (SE78). I search through the SCN but doesn’t find the solution of printing the charts on Smart forms. Then I had an idea of uploading the graphical image generated by CL_IGS_CHART_ENGINE dynamically to Form Graphics (SE78).  I have used the same functionality as used in Form Graphics (SE78) import to upload the image dynamically in Form Graphics.

Solution:

Create a Sample smart-Form to display the Graphical Chart generated by the custom function module.

TD_NAME is the name of the graphical chart generated dynamically by the custom function module YTESTCHART.

 

Delete the graphics after printing.

 

Print Preview of the Smart Form

 

FUNCTION ytestchart.
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     REFERENCE(IM_TDNAME) TYPE  STXBITMAPS-TDNAME
*"  EXPORTING
*"     VALUE(EX_STXBITMAPS) TYPE  STXBITMAPS
*"----------------------------------------------------------------------

  " IM_TDNAME         Image name to be printed on smartforms
  " EX_STXBITMAPS     Image reference data generated dynamically

  " Call This FM in the smartforms to generate image

  DATA: xt_sflight            TYPE flighttab,
        g_ixml                TYPE REF TO if_ixml,

        x_ixml_data_doc       TYPE REF TO if_ixml_document,
        x_ixml_custom_doc     TYPE REF TO if_ixml_document,
        x_cl_igs_chart_engine TYPE REF TO cl_igs_chart_engine,
        x_image_mime          TYPE w3mimetabtype,
        x_image_size          TYPE w3param-cont_len,
        x_image_type          TYPE w3param-cont_type,

        width_tw              LIKE  stxbitmaps-widthtw,
        height_tw             LIKE  stxbitmaps-heighttw,
        width_pix             LIKE  stxbitmaps-widthpix,
        height_pix            LIKE  stxbitmaps-heightpix,
        dpi                   LIKE  stxbitmaps-resolution,
        bds_bytecount         TYPE  i,
        bitmap_file_bds       TYPE sbdst_content,

        lo_bds_object         TYPE REF TO cl_bds_document_set,
        xt_bds_components     TYPE sbdst_components,
        x_bds_components      TYPE bapicompon,
        xt_bds_signature      TYPE sbdst_signature,
        x_bds_signature       TYPE bapisignat,
        xt_bds_properties     TYPE sbdst_properties,
        x_bds_properties      TYPE bapiproper,
        x_stxbitmaps          TYPE stxbitmaps,
        x_object_key          TYPE sbdst_object_key.



  " Get Sample Data For the Chart/Graph

  SELECT * FROM sflight INTO TABLE xt_sflight.

  g_ixml = cl_ixml=>create( ).

  " Generate XML for the chart

  PERFORM create_data_demo USING x_ixml_data_doc xt_sflight
                        CHANGING g_ixml.

  PERFORM create_custom_demo USING x_ixml_custom_doc
                          CHANGING g_ixml.

" Generate Image Using CL_IGS_CHART_ENGINE

  x_cl_igs_chart_engine = NEW #( ).

  CALL METHOD x_cl_igs_chart_engine->set_data
    EXPORTING
      data_doc = x_ixml_data_doc.
  CALL METHOD x_cl_igs_chart_engine->set_customizing
    EXPORTING
      custom_doc = x_ixml_custom_doc.

  CALL METHOD x_cl_igs_chart_engine->execute
    EXCEPTIONS
      OTHERS = 1.

  IF sy-subrc IS INITIAL.

 " Get Image  to upload to SE78



    CALL METHOD x_cl_igs_chart_engine->get_image
      IMPORTING
        image      = x_image_mime
        image_size = x_image_size
        image_type = x_image_type.

    CALL FUNCTION 'SAPSCRIPT_CONVERT_BITMAP_BDS'
      EXPORTING
        color                    = 'X'
        format                   = 'BMP'
        resident                 = ' '
        bitmap_bytecount         = x_image_size
        compress_bitmap          = ' '
      IMPORTING
        width_tw                 = width_tw
        height_tw                = height_tw
        width_pix                = width_pix
        height_pix               = height_pix
        dpi                      = dpi
        bds_bytecount            = bds_bytecount
      TABLES
        bitmap_file              = x_image_mime
        bitmap_file_bds          = bitmap_file_bds
      EXCEPTIONS
        format_not_supported     = 1
        no_bmp_file              = 2
        bmperr_invalid_format    = 3
        bmperr_no_colortable     = 4
        bmperr_unsup_compression = 5
        bmperr_corrupt_rle_data  = 6
        OTHERS                   = 7.



*     Save bitmap in BDS
    lo_bds_object = NEW #( ).

    x_bds_components-doc_count  = '1'.
    x_bds_components-comp_count = '1'.
    x_bds_components-mimetype   = 'application/octet-stream'.
    x_bds_components-comp_size  = bds_bytecount.
    APPEND x_bds_components TO xt_bds_components.

    x_bds_signature-doc_count = '1'.
    APPEND x_bds_signature TO xt_bds_signature.

    CALL METHOD lo_bds_object->create_with_table
      EXPORTING
        classname  = 'DEVC_STXD_BITMAP'
        classtype  = 'OT'
        components = xt_bds_components
        content    = bitmap_file_bds
      CHANGING
        signature  = xt_bds_signature
        object_key = x_object_key
      EXCEPTIONS
        OTHERS     = 1.

* Save bitmap header in Database Table STXBITPMAPS
    x_stxbitmaps-tdname     = im_tdname.
    x_stxbitmaps-tdobject   = 'GRAPHICS'.
    x_stxbitmaps-tdid       = 'BMAP'.
    x_stxbitmaps-tdbtype    = 'BCOL'.
    x_stxbitmaps-docid      = xt_bds_signature[ 1 ]-doc_id.
    x_stxbitmaps-widthpix   = width_pix. " Width and hights can be changed
    x_stxbitmaps-heightpix  = height_pix.
    x_stxbitmaps-widthtw    = width_tw.
    x_stxbitmaps-heighttw   = height_tw.
    x_stxbitmaps-resolution = '075'.
*    x_stxbitmaps-resident   = 'X'.
    x_stxbitmaps-autoheight = 'X'.
*    x_stxbitmaps-bmcomp     = 'X'.
    INSERT INTO stxbitmaps VALUES x_stxbitmaps.
    IF sy-subrc <> 0.
      UPDATE stxbitmaps FROM x_stxbitmaps.
    ENDIF.

    ex_stxbitmaps = x_stxbitmaps.

    x_bds_properties-prop_name  = 'DESCRIPTION'.
    x_bds_properties-prop_value = 'Charts'.
    APPEND x_bds_properties TO xt_bds_properties.

    CALL METHOD lo_bds_object->change_properties
      EXPORTING
        classname  = 'DEVC_STXD_BITMAP'
        classtype  = 'OT'
        object_key = x_object_key
        doc_id     = xt_bds_signature[ 1 ]-doc_id
        doc_ver_no = '1'
        doc_var_id = '1'
      CHANGING
        properties = xt_bds_properties
      EXCEPTIONS
        OTHERS     = 1.

  ENDIF.

ENDFUNCTION.

**----------------------------------------------------------------------*
****INCLUDE LYTESTCHARTF01.
**----------------------------------------------------------------------*
*&---------------------------------------------------------------------*
*&      Form  CREATE_DATA_DEMO
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
*      -->P_X_IXML_DATA_DOC  text
*      -->P_XT_SFLIGHT  text
*      <--P_G_IXML  text
*----------------------------------------------------------------------*
FORM create_data_demo  USING p_ixml_doc TYPE REF TO if_ixml_document
                             pt_sflight TYPE flighttab
                    CHANGING p_ixml TYPE REF TO if_ixml.

  DATA: l_simplechartdata TYPE REF TO if_ixml_element,
        l_categories      TYPE REF TO if_ixml_element,
        l_series          TYPE REF TO if_ixml_element,
        l_element         TYPE REF TO if_ixml_element,
        l_encoding        TYPE REF TO if_ixml_encoding,
        l_value           TYPE string.

  p_ixml_doc = p_ixml->create_document( ).
* Set encoding to UTF-8
  l_encoding = p_ixml->create_encoding(
  byte_order = if_ixml_encoding=>co_little_endian
  character_set = 'utf-8' ).
  p_ixml_doc->set_encoding( l_encoding ).
* Populate Chart Data
  l_simplechartdata = p_ixml_doc->create_simple_element(
  name = 'SimpleChartData' parent = p_ixml_doc ).
* Populate X-Axis Values i.e. Categories and Series
  l_categories = p_ixml_doc->create_simple_element(
  name = 'Categories' parent = l_simplechartdata ).
* Here you can populate the category labels. First you need
* to create all the labels and only then you can populate
* values for these labels.
  LOOP AT pt_sflight ASSIGNING FIELD-SYMBOL(<sflight>).
    l_element = p_ixml_doc->create_simple_element(
    name = 'C' parent = l_categories ).
    CONCATENATE <sflight>-carrid <sflight>-connid INTO l_value.
* Populate the category value which you want to display here.
* This will appear in the X-axis.
    l_element->if_ixml_node~set_value( l_value ).
    CLEAR l_value.
  ENDLOOP.
* Create an element for Series and then populate it's values.
  l_series = p_ixml_doc->create_simple_element(
  name = 'Series' parent = l_simplechartdata ).
* You can set your own label for X-Axis here e.g. Airline
  l_series->set_attribute( name = 'label' value = 'Price' ).
  LOOP AT pt_sflight ASSIGNING <sflight>.
    l_element = p_ixml_doc->create_simple_element(
    name = 'S' parent = l_series ).
* Populate the Value for each category you want to display from
* your internal table.
    l_value = <sflight>-price.
    l_element->if_ixml_node~set_value( l_value ).
    CLEAR l_value.
  ENDLOOP.
* Similarly you can have number of Categories
*  and values for each category
* based on your requirement
  l_series = p_ixml_doc->create_simple_element(
  name = 'Series' parent = l_simplechartdata ).
  l_series->set_attribute( name = 'label' value = 'Max Capacity' ).
  LOOP AT pt_sflight ASSIGNING <sflight>.
    l_element = p_ixml_doc->create_simple_element(
    name = 'S' parent = l_series ).
* Populate value for another category here.
    l_value = <sflight>-seatsmax.
    l_element->if_ixml_node~set_value( l_value ).
    CLEAR l_value.
  ENDLOOP.

ENDFORM.
*&---------------------------------------------------------------------*
*&      Form  CREATE_CUSTOM_DEMO
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
*      -->P_L_IXML_CUSTOM_DOC  text
*----------------------------------------------------------------------*
FORM create_custom_demo USING p_ixml_doc TYPE REF TO if_ixml_document
                     CHANGING p_ixml     TYPE REF TO if_ixml.
  DATA: l_root           TYPE REF TO if_ixml_element,
        l_globalsettings TYPE REF TO if_ixml_element,
        l_default        TYPE REF TO if_ixml_element,
        l_elements       TYPE REF TO if_ixml_element,
        l_chartelements  TYPE REF TO if_ixml_element,
        l_title          TYPE REF TO if_ixml_element,
        l_text           TYPE REF TO if_ixml_element,
        l_element        TYPE REF TO if_ixml_element,
        l_chartaxes      TYPE REF TO if_ixml_element,
        l_categoryaxis   TYPE REF TO if_ixml_element,
        l_line           TYPE REF TO if_ixml_element,
        l_encoding       TYPE REF TO if_ixml_encoding.

  p_ixml_doc = p_ixml->create_document( ).
  l_encoding = p_ixml->create_encoding(
  byte_order = if_ixml_encoding=>co_little_endian
  character_set = 'utf-8' ).
  p_ixml_doc->set_encoding( l_encoding ).
  l_root = p_ixml_doc->create_simple_element(
  name = 'SAPChartCustomizing' parent = p_ixml_doc ).
  l_root->set_attribute( name = 'version' value = '1.1' ).
  l_globalsettings = p_ixml_doc->create_simple_element(
  name = 'GlobalSettings' parent = l_root ).
  l_element = p_ixml_doc->create_simple_element(
  name = 'FileType' parent = l_globalsettings ).
  l_element->if_ixml_node~set_value( 'BMP' ).
* Here you can give the Chart Type i.e. 2D, 3D etc
  l_element = p_ixml_doc->create_simple_element(
  name = 'Dimension' parent = l_globalsettings ).
* For 2 Dimensional Graph write - PseudoTwo
* For 2 Dimensional Graph write - PseudoThree
  l_element->if_ixml_node~set_value( 'PseudoThree' ).
* Here you can give the chart type
  l_element = p_ixml_doc->create_simple_element(
  name = 'ChartType'
  parent = l_globalsettings ).
* For Bar Char write - Columns
* For Pie Chart write - Pie etc
  l_element->if_ixml_node~set_value('Columns'). "( 'Speedometer' ).
  l_element = p_ixml_doc->create_simple_element(
  name = 'FontFamily' parent = l_default ).
  l_element->if_ixml_node~set_value( 'Arial' ).
  l_elements = p_ixml_doc->create_simple_element(
  name = 'Elements' parent = l_root ).
  l_chartelements = p_ixml_doc->create_simple_element(
  name = 'ChartElements' parent = l_elements ).
  l_title = p_ixml_doc->create_simple_element(
  name = 'Title' parent = l_chartelements ).
* Give the desired caption for the chart here
  l_element =
  p_ixml_doc->create_simple_element( name = 'Caption' parent = l_title ).
  l_element->if_ixml_node~set_value( 'Airline Details' ).

ENDFORM.

 

Conclusion: –

Now we can print any type of charts using CL_IGS_CHART_ENGINE on smart-forms dynamically. we just need to change the XML for changing the chart.

I hope that makes drawing graphs/charts with ABAP complete and easily achievable.

Thanks for reading this blog post. I would like to see your comments and would like to answer questions which u can post at Q&A tag area: https://answers.sap.com/tags/66233466-fcd6-45d2-a9ae-2cba38c72e19

 

Assigned tags

      2 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Florian Henninger
      Florian Henninger

       

      Hi Yogesh,

      First question which come to my mind... you link to a S/4 space and writing about smartforms... so what's the reason for that.

      There is this brandnew.. errm new.. ermm in 2006 presented technology called IFbA which make such requirements a little easier to solve..

      So, everyone who wants to print today anything out of SAP.. expecially in the context of S/4 I recommend to have a look  what IFbA can do for you and why it's the recommended way to print anything. But if you want to use smartforms or Sapscript you can.. but should you?!

      Next to that, examples with form-routines developed in 2021.. don't add anything here.

      ~Florian

       

      ~Florian

      Author's profile photo kunal khullar
      kunal khullar

      Thanks for the post Yogesh.

      We are utilizing Smartforms for our major number of print outs in our organization and also looking for similar provision for our analytical dashboards.

      Please also let us know for analytical tools like time series (Laplace and fourier series) in case we are running our utilities solutions.

      KK