Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
christopha1
Explorer
0 Kudos

In this post I will describe how you can easily insert any custom chart control in a SAPUI5 Mobile app.

In this particular example I am going to use a SplitApp and  D3 as charting library however the steps apply also to other libraries and controls. Please find the comple source code on GitHub.


Let´s start by creating a simple SplitApp with two detail pages:



var oSplitApp = new sap.m.SplitApp("mySplitApp")
          .addMasterPage(new sap.m.Page("master2", {
              title: "Master2",
              navButtonPress: function () {
                  oSplitApp.backMaster();
              },
              content: [new sap.m.List({
                  mode: "SingleSelectMaster",
                  select: function (oEv) {
                      if (oEv.getParameter("listItem").getId() == "listDetail2") {
                          oSplitApp.toDetail("detail2");
                      } else {
                          oSplitApp.toDetail("detail1");
                      }
                  },
                  items: [new sap.m.StandardListItem("listDetail2", {
                      title: "To Detail 2"
                  }), new sap.m.StandardListItem("listDetail", {
                      title: "To Detail 1"
                  })]
              })]
          }))
         .addDetailPage(new sap.m.Page("detail1", {
             title: "Detail 1"
         }))
         .addDetailPage(new sap.m.Page("detail2", {
             title: "Detail 2",
         })).placeAt("content");







Now we want to place a chart control on both detail pages. The chart will be drawn by the  function shown in the snippet below that is taken from this D3 example. That function is passed the DOM element that will contain the chart.

My first idea was to just use jQuerys document.ready function and just add the chart in here. However there is one big issue with that approach as only the first detail page is available in the DOM once the document.ready function gets called. So DetailPage1 will contain the chart, DetailPage2 won´t. See it in action here.


$(document).ready(function () {
            drawChart(jQuery.sap.byId("detail1")[0]);
            drawChart(jQuery.sap.byId("detail2")[0]);
        });





So the problem here is basically that SAPUI5 is clever enough to lazy load components and only insert them into the DOM once they are actually needed.

In order to draw the chart in a SAPUI5 conforming way we will just create a simple custom control and make use of its onAfterRendering function. So the final SplitApp looks like below (see it in action here) .


    sap.ui.core.Control.extend("chris.Chart", {
            renderer: function (oRm, oControl) {
                oRm.write("<div");
                oRm.writeControlData(oControl);
                oRm.write("</div>");
            },
            onAfterRendering: function (eeee) {
                drawChart(eeee.srcControl.$()[0]);
            }
        });
        var oSplitApp = new sap.m.SplitApp("mySplitApp")
         .addMasterPage(new sap.m.Page("master", {
             title: "Master",
             navButtonPress: function () {
                 oSplitApp.backMaster();
             },
             content: [new sap.m.List({
                 mode: "SingleSelectMaster",
                 select: function (oEv) {
                     if (oEv.getParameter("listItem").getId() == "listDetail2") {
                         oSplitApp.toDetail("detail2");
                     } else {
                         oSplitApp.toDetail("detail1");
                     }
                 },
                 items: [new sap.m.StandardListItem("listDetail2", {
                     title: "To Detail 2"
                 }), new sap.m.StandardListItem("listDetail", {
                     title: "To Detail 1"
                 })]
             })]
         }))
        .addDetailPage(new sap.m.Page("detail1", {
            title: "Detail 1",
            content: [new chris.Chart()]
        }))
        .addDetailPage(new sap.m.Page("detail2", {
            title: "Detail 2",
            content: [new chris.Chart()]
        })).placeAt("content");




DrawChart Function:


function drawChart(element) {
            var margin = { top: 20, right: 20, bottom: 70, left: 40 },
    width = 600 - margin.left - margin.right,
    height = 300 - margin.top - margin.bottom;
            // Parse the date / time
            var parseDate = d3.time.format("%Y-%m").parse;
            var x = d3.scale.ordinal().rangeRoundBands([0, width], .05);
            var y = d3.scale.linear().range([height, 0]);
            var xAxis = d3.svg.axis()
                .scale(x)
                .orient("bottom")
                .tickFormat(d3.time.format("%Y-%m"));
            var yAxis = d3.svg.axis()
                .scale(y)
                .orient("left")
                .ticks(10);
            var svg =
                d3
                .select(element)
                //.select("#detail1")
                .append("svg")
                .attr("width", width + margin.left + margin.right)
                .attr("height", height + margin.top + margin.bottom)
              .append("g")
                .attr("transform",
                      "translate(" + margin.left + "," + margin.top + ")");
            var data = [
                {
                    date: "2013-01",
                    value: "53"
                },
                 {
                     date: "2013-02",
                     value: "153"
                 },
            ];
            data.forEach(function (d) {
                d.date = parseDate(d.date);
                d.value = +d.value;
            });
            x.domain(data.map(function (d) { return d.date; }));
            y.domain([0, d3.max(data, function (d) { return d.value; })]);
            svg.append("g")
                .attr("class", "x axis")
                .attr("transform", "translate(0," + height + ")")
                .call(xAxis)
              .selectAll("text")
                .style("text-anchor", "end")
                .attr("dx", "-.8em")
                .attr("dy", "-.55em")
                .attr("transform", "rotate(-90)");
            svg.append("g")
                .attr("class", "y axis")
                .call(yAxis)
              .append("text")
                .attr("transform", "rotate(-90)")
                .attr("y", 6)
                .attr("dy", ".71em")
                .style("text-anchor", "end")
                .text("Value ($)");
            svg.selectAll("bar")
                .data(data)
              .enter().append("rect")
                .style("fill", "steelblue")
                .attr("x", function (d) { return x(d.date); })
                .attr("width", x.rangeBand())
                .attr("y", function (d) { return y(d.value); })
                .attr("height", function (d) { return height - y(d.value); });
        }






Labels in this area