Part 2: XML-based Gantt customizing
Part 3: ABAP-based Chart engine
After previously collecting the project data, we now need to convert it into an XML-based document. To realize this, standard iXML libraries come into play. For more information regarding iXML libraries, please refer to the following link.
The chart engine is represented in the system by a global ABAP class:
Also, in the types section:
types:
BEGIN OF s_category,
description TYPE string,
END OF s_category.
types:
t_category TYPE TABLE OF s_category.
types:
BEGIN OF s_series_gantt,
points TYPE yppm_tty_point,
label TYPE string,
customizing TYPE string,
END OF s_series_gantt.
types:
t_series_gantt TYPE TABLE OF s_series_gantt.
Additionally, a data dictionary structure (E.g. YPPM_STR_POINT) and it’s corresponding table type must be created:
Component | Type |
---|---|
START_VALUE | STRING |
END_VALUE | STRING |
TOOLTIP | STRING |
Using the project data from Part 2, we now call the FILL_CHART_CONTEXT method, passing the internal table as a parameter. We’ve used the following code to fill in class attributes MT_CATEGORY_GANTT and MT_SERIES_GANTT:
types:
begin of s_ms,
index type i,
start type datum,
end type datum,
end of s_ms,
t_ms type standard table of s_ms.
data:
ls_category type s_category, " found in the TYPES section
ls_series type s_series_gantt, " found in the TYPES section
lt_point_plan type yppm_tty_point,
lt_point_date type yppm_tty_point,
lt_point_ms type yppm_tty_point,
ls_point type yppm_str_point,
ls_ms type s_ms,
lt_ms type t_ms,
lv_date1 type string,
lv_date2 type string.
field-symbols:
<fs_data> like line of it_data[].
define convert_date.
concatenate &1+6(2) &1+4(2) &1(4) into lv_date1 separated by '.'.
concatenate &2+6(2) &2+4(2) &2(4) into lv_date2 separated by '.'.
if lv_date1 ne lv_date2.
concatenate &3 lv_date1 '-' lv_date2 into &4 separated by space.
else.
concatenate &3 lv_date1 into &4 separated by space.
endif.
end-of-definition.
" create all categories first
refresh mt_category_gantt[].
loop at it_data[] assigning <fs_data>.
ls_category-description = <fs_data>-object_desc.
append ls_category to mt_category_gantt[].
endloop.
" create points for each series
loop at it_data[] assigning <fs_data>.
ls_point-start_value = <fs_data>-date_start.
ls_point-end_value = <fs_data>-date_end.
convert_date ls_point-start_value ls_point-end_value 'Plan:' ls_point-tooltip.
append ls_point to lt_point_plan[]. clear ls_point.
ls_point-start_value = sy-datum.
ls_point-end_value = sy-datum.
convert_date ls_point-start_value ls_point-end_value 'Current Date:' ls_point-tooltip.
append ls_point to lt_point_date[]. clear ls_point.
do 5 times. " maximum number of milestones, can be a dynamic value
ls_ms-index = sy-index.
read table <fs_data>-ms[] index ls_ms-index into ls_ms-start.
if sy-subrc is initial.
ls_ms-end = ls_ms-start.
else.
clear:
ls_ms-start,
ls_ms-end.
endif.
append ls_ms to lt_ms[]. clear ls_ms.
enddo.
endloop.
" create all series
refresh mt_series_gantt[].
do 2 times.
case sy-index.
when 1.
" plan series
ls_series-customizing = 'Plan'.
ls_series-label = 'Plan'.
ls_series-points = lt_point_plan[].
when 2.
" line for current date
ls_series-customizing = 'ACTDATE'.
ls_series-points = lt_point_date[].
endcase.
append ls_series to mt_series_gantt[].
enddo.
" create milestones
do 5 times.
loop at lt_ms[] into ls_ms where index eq sy-index.
ls_point-start_value = ls_ms-start.
ls_point-end_value = ls_ms-end.
append ls_point to lt_point_ms[]. clear ls_point.
endloop.
ls_series-customizing = 'MS'.
ls_series-label = 'MS'.
ls_series-points = lt_point_ms[]. refresh lt_point_ms[].
append ls_series to mt_series_gantt[]. clear ls_series.
enddo.
The next step is to load and parse the XML-based customizing file and use it to fill the class attribute MT_CUSTOMIZING.
set_graphic_parameter( '/sap/public/ppm/ypdf/gantt_customizing.xml').
We do this by calling the method SET_GRAPHIC_PARAMETER using the MIME path as an import parameter. This method encapsulates the following code:
data:
lo_mime_repository type ref to if_mr_api,
lv_content type xstring,
lo_ixml type ref to if_ixml,
lo_stream_factory type ref to if_ixml_stream_factory,
lo_istream type ref to if_ixml_istream,
lo_document type ref to if_ixml_document,
lo_parser type ref to if_ixml_parser.
" get the .xml file from MIME
lo_mime_repository = cl_mime_repository_api=>if_mr_api~get_api( ).
lo_mime_repository->get( exporting i_url = iv_path
i_check_authority = abap_false
importing e_content = lv_content ).
if lv_content is initial.
" raise exception
endif.
" generate XML instance
lo_ixml = cl_ixml=>create( ).
lo_stream_factory = lo_ixml->create_stream_factory( ).
lo_istream = lo_stream_factory->create_istream_xstring( lv_content ).
lo_document = lo_ixml->create_document( ).
lo_parser = lo_ixml->create_parser(
document = lo_document
istream = lo_istream
stream_factory = lo_stream_factory ).
lo_parser->set_namespace_mode( mode = if_ixml_parser=>co_namespace_aware ).
lo_parser->set_validating( mode = if_ixml_parser=>co_validate_if_dtd ).
lo_parser->parse( ).
" save customizing
refresh mt_customizing[].
append lo_document to mt_customizing[].
At this point, we already have the XML-based customizing and the ready to use project data (still in ABAP format).
Now it’s time to convert the MT_CATEGORY_GANTT and MT_SERIES_GANTT internal tables into a XML-based document. We do this using method CREATE_CHART_DATA_XML, having the following source code:
data:
lo_ixml type ref to if_ixml,
lo_document type ref to if_ixml_document,
lo_encoding type ref to if_ixml_encoding,
lo_chartdata type ref to if_ixml_element,
lo_categories type ref to if_ixml_element,
lo_category type ref to if_ixml_element,
ls_category type s_category,
lo_series type ref to if_ixml_element,
ls_series type s_series_gantt,
lo_point type ref to if_ixml_element,
ls_point type yppm_str_point,
lo_element type ref to if_ixml_element,
lv_string type string value is initial.
" create document and set header data
lo_ixml = cl_ixml=>create( ).
lo_document = lo_ixml->create_document( ).
lo_encoding = lo_ixml->create_encoding( byte_order = if_ixml_encoding=>co_little_endian
character_set = 'utf-8' ).
lo_document->set_encoding( lo_encoding ).
" create main elements for chart data and categories
lo_chartdata = lo_document->create_simple_element( name = 'ChartData' parent = lo_document ).
lo_categories = lo_document->create_simple_element( name = 'Categories' parent = lo_chartdata ).
loop at mt_category_gantt[] into ls_category.
lv_string = ls_category-description.
lo_category = lo_document->create_simple_element( name = 'Category'
parent = lo_categories
value = lv_string ). clear lv_string.
endloop.
" build XML structure for each series
loop at mt_series_gantt[] into ls_series.
" create series elements
lo_series = lo_document->create_simple_element( name = 'Series' parent = lo_chartdata ).
lv_string = ls_series-label.
lo_series->set_attribute( name = 'label' value = lv_string ). clear lv_string.
lv_string = ls_series-customizing.
lo_series->set_attribute( name = 'customizing' value = lv_string ). clear lv_string.
" build XML structure for each point of each series
loop at ls_series-points[] into ls_point.
" create point elements
lo_point = lo_document->create_simple_element( name = 'Point' parent = lo_series ).
" create TIME VALUE start
lv_string = ls_point-start_value.
lo_element = lo_document->create_simple_element( name = 'Value'
parent = lo_point
value = lv_string ). clear lv_string.
lo_element->set_attribute( name = 'type' value = 'time' ).
" create TIME VALUE finish
lv_string = ls_point-end_value.
lo_element = lo_document->create_simple_element( name = 'Value'
parent = lo_point
value = lv_string ). clear lv_string.
lo_element->set_attribute( name = 'type' value = 'time' ).
endloop.
endloop.
mr_chart_data = lo_document.
The final step is the actual rendering of the graphic which will be covered in Part 4.