Thursday, January 31, 2013

ADF Mobile - Create Drill Down Graph Reports

Drill Down Graph Report - Scenario here is to show all the cars sales report for this year in Pie Chart and when user click a individual car in pie chart slice, a drill through report opens, which accepts the car type as a parameter, and then displays car models sale in Bar Chart.

In ADF Mobile, "clickListener" method is not provided for DVT components. Click listener interface will receive click events on the gauge components and can do further data process in BC4J.  In ADF Mobile "Action" method is supported on DataItem in the graphs. Action defines a reference to the an action method sent by the command button component, or static outcome of an action. So in this article I'm explaining how to build drill down reports using <dvtm:pieChart> and <dvtm:barChart>.

Application screen looks like below when it deployed and run on Android Device/Emulator. Displays the Cars Sales Reports in first screen.


In above screen, slide the screen towards right. Notice only check boxes are displayed and attributes values(Legends) are not getting displayed for the pie chart slices, this could be an error. 

Next click on any pie chart slice and respective car models will be displayed in Bar Chart screen.


[Runs with Oracle JDeveloper 11.1.2.3.0]

Implementation Steps

Create an ADF Mobile Application, the application consists of two projects. Application Controller project of Application LifeCycle, Listeners, Device Features DataControl and ViewController project contains mobile features content like AMX Files, Task Flows and DataControl.

In ViewController project, locate and expand the Application Sources folder, create a Cars.java file and add the below code.
public class Cars {
    private String carName;
    private int carSalesCount;
    private transient PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);

    public Cars() {
        super();
    }

    public Cars(String carName, int carSalesCount) {
        this.carName = carName;
        this.carSalesCount = carSalesCount;
    }

    public void setCarName(String carName) {
        String oldCarName = this.carName;
        this.carName = carName;
        propertyChangeSupport.firePropertyChange("carName", oldCarName, carName);
    }

    public String getCarName() {
        return carName;
    }

    public void setCarSalesCount(int carSalesCount) {
        int oldCarSalesCount = this.carSalesCount;
        this.carSalesCount = carSalesCount;
        propertyChangeSupport.firePropertyChange("carSalesCount", oldCarSalesCount, carSalesCount);
    }

    public int getCarSalesCount() {
        return carSalesCount;
    }

    public void setPropertyChangeSupport(PropertyChangeSupport propertyChangeSupport) {
        this.propertyChangeSupport = propertyChangeSupport;
    }

    public PropertyChangeSupport getPropertyChangeSupport() {
        return propertyChangeSupport;
    }
}
Create CarModels.java file and add the below code.
public class CarModels extends Cars {
    private String modelName;
    private int modelSalesCount;
    private transient PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);

    public CarModels() {
        super();
    }

    public CarModels(String carName, String modelName, int modelSalesCount) {
        super();
        setCarName(carName);
        this.modelName = modelName;
        this.modelSalesCount = modelSalesCount;
    }

    public void setModelName(String modelName) {
        String oldModelName = this.modelName;
        this.modelName = modelName;
        propertyChangeSupport.firePropertyChange("modelName", oldModelName, modelName);
    }

    public String getModelName() {
        return modelName;
    }

    public void setModelSalesCount(int modelSalesCount) {
        int oldModelSalesCount = this.modelSalesCount;
        this.modelSalesCount = modelSalesCount;
        propertyChangeSupport.firePropertyChange("modelSalesCount", oldModelSalesCount, modelSalesCount);
    }

    public int getModelSalesCount() {
        return modelSalesCount;
    }

    public void setPropertyChangeSupport(PropertyChangeSupport propertyChangeSupport) {
        this.propertyChangeSupport = propertyChangeSupport;
    }

    public PropertyChangeSupport getPropertyChangeSupport() {
        return propertyChangeSupport;
    }
}
Create Generic.java file and add the below code, create DataControl based on Generic.java file.
public class Generic {
    private static List s_cars = null;
    private static List s_carModels = null;
    private static List s_filterCarModels = null;
    private transient ProviderChangeSupport providerChangeSupport = new ProviderChangeSupport(this);
    private transient PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);

    public Generic() {
        super();
        if (s_cars == null) {
            s_cars = new ArrayList();
            s_cars.add(new Cars("Audi", 2000));
            s_cars.add(new Cars("BMW", 2500));
            s_cars.add(new Cars("Honda", 5000));
            s_cars.add(new Cars("Mitsubishi", 1000));
            s_cars.add(new Cars("Toyota", 4000));
            s_cars.add(new Cars("Volkswagen", 3000));
        }
        if (s_carModels == null) {
            s_carModels = new ArrayList();
            s_carModels.add(new CarModels("Audi", "A3", 300));
            s_carModels.add(new CarModels("Audi", "A4", 1000));
            s_carModels.add(new CarModels("Audi", "Quattro", 700));
            s_carModels.add(new CarModels("BMW", "BMW128", 1000));
            s_carModels.add(new CarModels("BMW", "BMW528", 800));
            s_carModels.add(new CarModels("BMW", "Gran Coupe", 700));
            s_carModels.add(new CarModels("Honda", "Accord", 1200));
            s_carModels.add(new CarModels("Honda", "Civic", 2000));
            s_carModels.add(new CarModels("Honda", "Hybrid", 1800));
            s_carModels.add(new CarModels("Mitsubishi", "Lancer", 400));
            s_carModels.add(new CarModels("Mitsubishi", "Evolution", 300));
            s_carModels.add(new CarModels("Mitsubishi", "Outlander", 300));
            s_carModels.add(new CarModels("Toyota", "Camry", 1800));
            s_carModels.add(new CarModels("Toyota", "Corolla", 1200));
            s_carModels.add(new CarModels("Toyota", "Cruiser", 1000));
            s_carModels.add(new CarModels("Volkswagen", "Beetle", 1300));
            s_carModels.add(new CarModels("Volkswagen", "Jetta", 800));
            s_carModels.add(new CarModels("Volkswagen", "Tiguan", 900));
        }

    }

    public void addPropertyChangeListener(PropertyChangeListener l) {
        propertyChangeSupport.addPropertyChangeListener(l);
    }

    public void removePropertyChangeListener(PropertyChangeListener l) {
        propertyChangeSupport.removePropertyChangeListener(l);
    }

    public void addProviderChangeListener(ProviderChangeListener l) {
        providerChangeSupport.addProviderChangeListener(l);
    }

    public void removeProviderChangeListener(ProviderChangeListener l) {
        providerChangeSupport.removeProviderChangeListener(l);
    }

    /**
     * Method will populate the result list to s_cars.
     */
    public Cars[] getCars() {
        Cars c[] = null;
        c = (Cars[])s_cars.toArray(new Cars[s_cars.size()]);
        return c;
    }

    /**
     * Method will populate the result list to s_carModels.
     */
    public CarModels[] getCarModels() {
        CarModels cm[] = null;
        cm = (CarModels[])s_carModels.toArray(new CarModels[s_carModels.size()]);
        return cm;
    }

    /**
     * Method will filter the result from s_carModels list.
     */
    public CarModels[] filteredCarModels(String carType) {
        CarModels cm[] = null;
        s_filterCarModels = new ArrayList();
        for (Iterator i = s_carModels.iterator(); i.hasNext(); ) {
            CarModels curCM = (CarModels)i.next();
            if (curCM.getCarName().equals(carType)) {
                s_filterCarModels.add(new CarModels(curCM.getCarName(), curCM.getModelName(),
                                                    curCM.getModelSalesCount()));
            }
        }
        cm = (CarModels[])s_filterCarModels.toArray(new CarModels[s_filterCarModels.size()]);
        providerChangeSupport.fireProviderRefresh("carModels");
        return cm;
    }
}
In ViewController project. Locate and expand the Application Sources folder, then expand the META-INF folder. You will see the adfmf-feature.xml file, click on the adfmf-feature.xml file to launch the Feature editor. Add a new feature by clicking the green plus sign on the Features table near top of the editor this will launch the new Create ADF Mobile Feature dialog, modify the values as shown below.


In the Features table, select the newly created feature Graph. Under the Features table, click the Content tab, and locate the Content table. Notice that the content item Graph.1 is created by default. Next add a new file by clicking the green plus sign and select taskflow option, this will launch the new Create ADF Mobile Task Flow dialog, modify the value as shown below.


Click on the GraphTaskflow.xml to open the file in taskflow editor and follow the below steps.
1) Create two views and name them as carsView and carModelsView respectively.
 2) Draw the control flow case from carsView to carModelsView and Outcome as "carsModel", Behavior->Transition as "flipRight".
 3) Draw the control flow case from carModelsView to carsView and Outcome as "car", Behavior->Transition as "slideLeft".

Double click on carsView view will launch Create ADF Mobile AMX Page dialog. Open the carsView.amx page and to source tab and follow the below steps:

1) In Header facet, amx:outputText set the value as "Sales Report"
2) From DC palette drag and drop Generic->Cars->ADF Mobile Chart and in Component Gallery dialog, select Pie chart and click ok.
3) In Create Mobile Pie Chart dialog, select the values as shown in below image.


4) For dvtm:pieDataItem, set the action as "action" and drop amx:setPropertyListener and modify the values as shown in below code.
 <dvtm:pieChart var="row" value="#{bindings.cars.collectionModel}" id="pc1" animationOnDisplay="auto"
                       inlineStyle="width:400px; height:280px; float:left; background-color:white;" threeDEffect="on"
                       title="Car">
            <amx:facet name="dataStamp">
                <dvtm:pieDataItem sliceId="#{row.carName}" value="#{row.carSalesCount}" action="carsModel">
                    <amx:setPropertyListener from="#{row.carName}" to="#{pageFlowScope.carName}"/>
                </dvtm:pieDataItem>
            </amx:facet>
 </dvtm:pieChart>           
Double click on carModelsView view will launch Create ADF Mobile AMX Page dialog, in page facets select Header, Primary Action. Open the deptList.amx page and to source tab and follow the below steps:

1) In Header facet, amx:outputText set the value as "Sales Report"
2) In Seconday Action facet, for amx:commandButton modify the values text: Back, action: __back.
3) From DC palette drag and drop Generic->filteredCarModels->CarModels->ADF Mobile Chart and in Component Gallery dialog, select Bar chart and click ok.
4) In Create Mobile Bar Chart dialog, select the values as shown in below image.


Enter the carType parameter value as #{pageFlowScope.carName}.


Open the carModelsView.amx and modify the properties for dvtm:barChart as shown below.
<dvtm:barChart var="row" value="#{bindings.CarModels.collectionModel}" id="bc1"
      inlineStyle="width:400px; height:300px; float:left; background-color:white;"
      title="#{pageFlowScope.carName} Car Models">
 <amx:facet name="dataStamp">
  <dvtm:chartDataItem group="#{row.modelName}" value="#{row.modelSalesCount}" series="Sales Count"/>
 </amx:facet>
 <dvtm:legend position="end" id="l1"/>
</dvtm:barChart>
Click on Create Executable binding and select Invoke action and follow as shown in below image.


Edit invokeFilterdCarModels invoke actiion and set the Refresh to always, so when ever page loads employeesTotalRows method will get executed.

Note:- When the screen loads for the first time Bar Chart will get cached and for second time execution filteredCarModels method will not get executed at all even if the parameter value changed. To overcome this we have to set invoke Action for filteredCarModels method, this executes the  invokeAction every time a page is navigated to regardless of the state of the binding container.


Preview of the carsView.amx and carModelsView.amx will looks like below.


In the Application menu, select Deploy - New Deployment Profile to start the Create Deployment Profile dialog box. In the Profile Type drop-down list, ensure ADF Mobile for Android/IOS is selected and then click OK. Next select Deploy - New Deployment deployment profile. In the subsequent dialog box, select Deploy application to device/emulator/package, and click Finish.

5 comments:

  1. Hi Deepak,

    Thanks!!!It helps me a lot!!!!


    -Pradip

    ReplyDelete
  2. Really helpful material!! Thanks for sharing the code, It helped me alot!
    -Diego RFG.

    ReplyDelete
  3. Appreciate Your Efforts. Thanks alot..

    ReplyDelete
  4. INTERNATIONAL CONCEPT OF WORK FROM HOME
    Work from home theory is fast gaining popularity because of the freedom and flexibility that comes with it. Since one is not bound by fixed working hours, they can schedule their work at the time when they feel most productive and convenient to them. Women & Men benefit a lot from this concept of work since they can balance their home and work perfectly. People mostly find that in this situation, their productivity is higher and stress levels lower. Those who like isolation and a tranquil work environment also tend to prefer this way of working. Today, with the kind of communication networks available, millions of people worldwide are considering this option.

    Women & Men who want to be independent but cannot afford to leave their responsibilities at home aside will benefit a lot from this concept of work. It makes it easier to maintain a healthy balance between home and work. The family doesn't get neglected and you can get your work done too. You can thus effectively juggle home responsibilities with your career. Working from home is definitely a viable option but it also needs a lot of hard work and discipline. You have to make a time schedule for yourself and stick to it. There will be a time frame of course for any job you take up and you have to fulfill that project within that time frame.

    There are many things that can be done working from home. A few of them is listed below that will give you a general idea about the benefits of this concept.

    Baby-sitting
    This is the most common and highly preferred job that Women & Men like doing. Since in today's competitive world both the parents have to work they need a secure place to leave behind their children who will take care of them and parents can also relax without being worried all the time. In this job you don't require any degree or qualifications. You only have to know how to take care of children. Parents are happy to pay handsome salary and you can also earn a lot without putting too much of an effort.

    Nursery
    For those who have a garden or an open space at your disposal and are also interested in gardening can go for this method of earning money. If given proper time and efforts nursery business can flourish very well and you will earn handsomely. But just as all jobs establishing it will be a bit difficult but the end results are outstanding.

    Freelance
    Freelance can be in different wings. Either you can be a freelance reporter or a freelance photographer. You can also do designing or be in the advertising field doing project on your own. Being independent and working independently will depend on your field of work and the availability of its worth in the market. If you like doing jewellery designing you can do that at home totally independently. You can also work on freelancing as a marketing executive working from home. Wanna know more, email us on workfromhome.otr214426@gmail.com and we will send you information on how you can actually work as a marketing freelancer.


    Internet related work
    This is a very vast field and here sky is the limit. All you need is a computer and Internet facility. Whatever field you are into work at home is perfect match in the software field. You can match your time according to your convenience and complete whatever projects you get. To learn more about how to work from home, contact us today on workfromhome.otr214426@gmail.comand our team will get you started on some excellent work from home projects.


    Diet food
    Since now a days Women & Men are more conscious of the food that they eat hence they prefer to have homemade low cal food and if you can start supplying low cal food to various offices then it will be a very good source of income and not too much of efforts. You can hire a few ladies who will help you out and this can be a good business.

    Thus think over this concept and go ahead.

    ReplyDelete
  5. Hi,
    I am looking for a drillable option as with dvt:bargraph in dvt:barchart, barchart is introduced since 12c, chart components replaces the graph components in palette.
    Also the chart components do not make use of the graph model.
    Please let me know if there is a way to achieve drillable charts.
    Thanks in advance.

    ReplyDelete