Skip to Content
Author's profile photo Basar Ozgur Kahraman

Mobilize ALV Reports – Part 3 Visualize ALV Data with Highcharts for iPad

In my previous blog post, we created a mobile application to show ALV data. Now we will visualize data with Highcharts .

Before begin, i recommend you to read previous posts.

Part 1 – Create RESTful service

Part 2 – Create JQueryMobile Web Application with Datatables plugin

Pre-requisites:

  1. Check over Highcharts documentation

Steps:

  1. Modify index.html for charting
  2. Create charting rule selections dynamicly based on ALV Metadata
  3. Create chart data according to rule selections
  4. Initialize highcharts

index.html

<!DOCTYPE html>

<html>

    <!–<html manifest=”app.appcache”>–>

    <head>

    <title></title>

    <meta http-equiv=”Content-Type” content=”text/html; charset=UTF-8″>   

    <meta name=”apple-mobile-web-app-capable” content=”yes”/>

    <meta name=”viewport” content=”width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no” />

    <link rel=”shortcut icon” href=”images/mysapreport.jpg” />

    <link rel=”stylesheet” href=”css/jqm/jquery.mobile-1.1.1.min.css” />

    <!– DataTables CSS     –>

    <link rel=”stylesheet” type=”text/css” href=”css/datatables/jquery.dataTables.css”/>  

    <link rel=”stylesheet” type=”text/css” href=”css/datatables/ColVisAlt.css”/>

    <script src=”js/jqm/jquery-1.7.2.min.js”></script>

    <script src=”js/jqm/jquery.mobile-1.1.1.min.js”></script>

    <!– DataTables –>

    <script type=”text/javascript” src=”js/datatables/jquery.dataTables.min.js”></script>              

    <script type=”text/javascript” src=”js/datatables/ColVis.min.js”></script>    

    <script type=”text/javascript” src=”js/datatables/TableTools.min.js”></script>    

    <script type=”text/javascript” src=”js/settings.js”></script>

    <script type=”text/javascript” src=”js/table.js”></script>

    <script type=”text/javascript” src=”js/chart.js”></script>   

    <script>

        $.support.cors = true;

        jQuery.support.cors = true;                 

    </script>

</head>

<body>

<div data-role=”page” id=”alv” data-theme=”e”>

    <div data-role=”header” data-position=”fixed”>

        <h1>MySapReport</h1>

        <a href=”#settings”  data-role=”button” data-icon=”gear” data-theme=”b”>Settings</a>

    </div>

    <div data-role=”content” >

        <div data-role=”fieldcontain”>

            <label for=”transaction”>Transaction:</label>

            <input type=”text” name=”transaction” id=”transaction” value=”” />      

        </div>

        <div data-role=”fieldcontain”>

            <label for=”variant”>Variant:</label>

            <input type=”text” name=”variant” id=”variant” value=”” />

        </div>

        <a href=”javascript:getALV()”  data-role=”button” data-icon=”grid” data-theme=”b”>Call Report</a>

        <a href=”javascript:getDemoData()”  data-role=”button” data-icon=”grid” data-theme=”b”>Demo</a>      

        <br>

    </div>

</div>

<div data-role=”dialog” id=”settings”>

    <div data-role=”content” >

        <label for=”connectUrl”>Connect to:</label>

        <input type=”url” name=”connectUrl” id=”connectUrl” value=”” data-mini=”true” />

        <label for=”username”>Username:</label>

        <input type=”text” name=”username” id=”username” value=”” data-mini=”true” />

        <label for=”password”>Password:</label>

        <input type=”password” name=”password” id=”password” value=”” data-mini=”true” />

        <br>

        <a href=”javascript:exitSettings()” data-role=”button” data-icon=”delete”>Exit</a>

        <a href=”javascript:saveSettings()” data-role=”button” data-icon=”check” data-theme=”b”>Save</a>               

    </div>

</div>

<div data-role=”page” id=”showDatatable” data-theme=”e” data-add-back-btn=”true” data-dom-cache=”true”>

    <div data-role=”header” data-position=”fixed”>

        <h1 id=”datatableHeader”>ALV</h1>

        <div class=”ui-btn-right”>          

            <a href=”#chartRules” data-role=”button” data-icon=”star” data-theme=”e” data-back=”true”>Chart</a>          

        </div>

    </div>

    <div data-role=”content”>

        <div id=”dynamicDatatableDIV” >          

            <!–<table id=”dynamicDatatable” class=”tbl_basket_style”></table>–>

        </div>

    </div>

</div>

<div id=”chartRules” data-role=”dialog”>

    <div data-role=”header”>

        <h1>Chart Rules</h1>

    </div>

    <section data-role=”content”>

        <div data-role=”fieldcontain”>

            <label for=”select-choice-ctype” class=”select”>Chart Type</label>          

            <select name=”select-choice-ctype” id=”select-choice-ctype” data-native-menu=”false”>                              

                <option value=”line”>Basic Line</option>                    

                <option value=”area”>Basic Area</option>              

                <option value=”bar”>Basic Bar</option>              

                <option value=”column”>Basic Column</option>             

                <option value=”pie”>Pie chart</option>              

            </select>

            <label for=”select-choice-x” class=”select”>X-Axis</label>          

            <select name=”select-choice-x” id=”select-choice-x” data-native-menu=”false”></select>

            <label for=”select-choice-y” class=”select”>Y-Axis</label>

            <select name=”select-choice-y” id=”select-choice-y” data-native-menu=”false”></select>

            <label for=”select-choice-b” class=”select”>Series</label>

            <select name=”select-choice-b” id=”select-choice-b” data-native-menu=”false”></select>

            <label for=”select-choice-f” class=”select”>Series Filter</label>

            <select name=”select-choice-f” id=”select-choice-f” multiple=”multiple” data-native-menu=”false”></select>

        </div>

        <a href=”#pageChart” data-role=”button” data-icon=”grid” data-theme=”e” data-back=”true”>Show Chart</a>                                       

    </section>

</div>

<div id=”pageChart” data-role=”page” data-add-back-btn=”true” data-theme=”b”>

    <header data-role=”header” data-position=”fixed”>

        <h1>Chart</h1>

    </header>

    <section data-role=”content”>

        <div id=”chartContainer” style=”width: 100%; min-width: 400px; height: 100%; margin: 0 auto”></div>

        <div id=”myChart” ></div>      

    </section>

</div>

<script type=”text/javascript” src=”js/highcharts/highcharts.js”></script>

<script type=”text/javascript” src=”js/highcharts/modules/exporting.js”></script>

<script type=”text/javascript” src=”js/highcharts/themes/gray.js”></script>

</body>

</html>

Create charting rule selections

function fillChartingRules(){

    var outputx = [];

    var outputy = [];

    var outputb = [];

    if (!$(‘#select-choice-x’).is(‘:empty’)){

        return;

    }

    outputx.push(‘<option>X-Axis</option>’);      

    outputy.push(‘<option>Y-Axis</option>’);      

    outputb.push(‘<option>Base</option>’);      

    for(i=0;i<alvMetadata.length;i++){

        if (alvMetadata[i].inttype === ‘P’ || alvMetadata[i].inttype === ‘I’ ||

            alvMetadata[i].inttype === ‘F’ || alvMetadata[i].inttype === ‘b’ ||

            alvMetadata[i].inttype === ‘s’){             

            outputy.push(‘<option value=”‘ + alvMetadata[i].fieldname.toLowerCase() + ‘”>’ + alvMetadata[i].coltext + ‘</option>’);  

        }else{                          

            outputx.push(‘<option value=”‘ + alvMetadata[i].fieldname.toLowerCase() + ‘”>’ + alvMetadata[i].coltext + ‘</option>’);      

            outputb.push(‘<option value=”‘ + alvMetadata[i].fieldname.toLowerCase() + ‘”>’ + alvMetadata[i].coltext + ‘</option>’);          

        }

    }     

    $(‘#select-choice-x’).empty();

    $(‘#select-choice-y’).empty();

    $(‘#select-choice-b’).empty();   

    $(‘#select-choice-f’).empty();

    $(‘#select-choice-x’).append(outputx.join(”));

    $(‘#select-choice-y’).append(outputy.join(”));

    $(‘#select-choice-b’).append(outputb.join(”));

    try{

        $(‘#select-choice-x’).selectmenu(“refresh”);

        $(‘#select-choice-y’).selectmenu(“refresh”);

        $(‘#select-choice-b’).selectmenu(“refresh”);

        $(‘#select-choice-f’).selectmenu(“refresh”);

    }catch(err){ }

}

function fillSeriesFilterData(){

    var outputf = [];

    var optionf;                

    outputf.push(‘<option>Base Filter</option>’);       

    for(i=0;i<alvData.length;i++){

        optionf = ‘<option value=”‘ + alvData[i][$(“#select-choice-b”).val()] + ‘”>’ + alvData[i][$(“#select-choice-b”).val()] + ‘</option>’;

        if (jQuery.inArray(optionf, outputf) === -1)

            outputf.push(optionf);              

    }

    outputf.sort(function(a,b) {

        return (a > b) ? 1 : ((b > a) ? -1 : 0);

    } );       

    $(‘#select-choice-f’).empty();

    $(‘#select-choice-f’).append(outputf.join(”));  

    $(‘#select-choice-f’).selectmenu(‘refresh’, true);

}

Create chart data

function setXaxisCategories(pOptions){

    alvData.sort(function(a,b) {

        return (a[$(“#select-choice-x”).val()] > b[$(“#select-choice-x”).val()]) ? 1 : ((b[$(“#select-choice-x”).val()] > a[$(“#select-choice-x”).val()]) ? -1 : 0);

    } );

    for(i=0;i<alvData.length;i++){

        if (jQuery.inArray(alvData[i][$(“#select-choice-x”).val()], pOptions.xAxis.categories) === -1)

            pOptions.xAxis.categories.push(alvData[i][$(“#select-choice-x”).val()]);       

    }

}

function setSeries(pOptions){

    var seriesData = [];

    var seriesFilter = $(“#select-choice-f”).val() || [];

    var hasFilter = false;

    var _series = {

        name:””,

        data:[]

    };

    //initialize data array for each category

    var _initData = [];

    for(i=0;i<pOptions.xAxis.categories.length;i++){

        _initData.push(0);

    }       

    if (seriesFilter.length < 1){

        _series.name = “”;

        _series.data = _initData.slice();

        seriesData.push(_series);

    }else{

        hasFilter = true;

        for(i=0;i<seriesFilter.length;i++){       

            var _seriesF = {

                name:””,

                data:[]

            };

            _seriesF.name = seriesFilter[i];

            _seriesF.data = _initData.slice();

            seriesData.push(_seriesF);

        }

    }

    var xValue;

    var yValue;

    var _index;

    var _seriesindex;

    var _filter;

    for(i=0;i<alvData.length;i++){

        xValue = alvData[i][$(“#select-choice-x”).val()];

        yValue = alvData[i][$(“#select-choice-y”).val()];

        _index = jQuery.inArray(xValue, pOptions.xAxis.categories);

        _seriesindex = 0;

        if (hasFilter) {

            _filter = alvData[i][$(“#select-choice-b”).val()];

            if (jQuery.inArray(_filter, seriesFilter) !== -1){

                for(j=0;j<seriesData.length;j++){

                    if (_filter === seriesData[j].name){

                        _seriesindex = j;

                        break;

                    }                                              

                }     

            }else{

                continue;

            }

        }

        if (isNaN(seriesData[_seriesindex].data[_index]))

            seriesData[_seriesindex].data[_index] = parseFloat(yValue); 

        else

            seriesData[_seriesindex].data[_index] = seriesData[_seriesindex].data[_index] + parseFloat(yValue);

        //set 2 decimal point

        seriesData[_seriesindex].data[_index] = parseFloat(seriesData[_seriesindex].data[_index].toFixed(2));

    }

    pOptions.series = seriesData;

}

Initialize Highcharts

function basicChart(){

    var options = {

        chart: {

            renderTo: ‘chartContainer’,

            defaultSeriesType: $(“#select-choice-ctype”).val()//pie, column, bar, line          

        },

        title: {

            text: reportDescription          

        },

        subtitle: {

            text: $(‘#select-choice-x option:selected’).text() + ‘ / ‘ + $(‘#select-choice-y option:selected’).text()          

        },

        legend: {

            layout: ‘vertical’,

            align: ‘right’,

            verticalAlign: ‘top’,

            x: -10,

            y: 100,

            borderWidth: 0

        },

        xAxis: {

            categories: [],

            labels: {

                rotation: -45,

                align: ‘right’,

                style: {

                    fontSize: ’13px’,

                    fontFamily: ‘Verdana, sans-serif’

                }

            },

            title: {

                text: $(‘#select-choice-x option:selected’).text()

            }

        },

        yAxis: {

            title: {

                text: $(‘#select-choice-y option:selected’).text()

            }

        },

        series: []

    };

    setXaxisCategories(options);

    setSeries(options);

    // Create chart

    var chart = new Highcharts.Chart(options);                   

}

Test

You may use MySapReport for testing.

Rule definions of chart;

  1. Chart Type (Mandatory): There are 5 kind of charts predefined (Line, Area, Bar, Column, Pie).
  2. X-Axis       (Mandatory): Used as category axis. Only non-numerical alv columns can be chosen.
  3. Y-Axis       (Mandatory): Used as value type axis. Only numeric alv columns can be chosen.
  4. Series          (Optional): Used as collection of datapoints in category axis.
  5. Series Filter (Optional): Used as filter for series, filled by selection event of Series and values are derived dynamicly from alv data.

You can find all sources codes on https://github.com/basarozgur/MySapReport

Screen Shots:

    Chart rule definition

/wp-content/uploads/2012/10/cr_142034.jpg

   Basic Line

/wp-content/uploads/2012/10/bl_142035.jpg

   Basic Area

/wp-content/uploads/2012/10/ba_142036.jpg

    Basic Bar

/wp-content/uploads/2012/10/bb_142037.jpg

    Basic Column

/wp-content/uploads/2012/10/bc_142038.jpg

    Pie

/wp-content/uploads/2012/10/pie_142039.jpg


Assigned Tags

      1 Comment
      You must be Logged on to comment or reply to a post.
      Author's profile photo Former Member
      Former Member

      Thank you very much Basar for posting such advanced concept in reporting. I find it very helpful as I am exploring on this topic these days.

      Regards,

      Rashmith.