+ Start a Discussion
George AdamsGeorge Adams 

How to Dynamically Create and Assign Constructors? (plotting line chart)

I'm very new to VF and Apex. I'm plotting a list of values on a time-series chart, but am having trouble handling the dynamic nature of the number/names of the multiple series on the x-axis of the plot.

Here is the controller:
public class BarChartController {
    // Return a list of data points for a chart
    public List<Data> getData() {
        return BarChartController.getChartData();
    }
    
    // Make the chart data available via JavaScript remoting
    @RemoteAction
    public static List<Data> getRemoteData() {
        return BarChartController.getChartData();
    }
    
    // The actual chart data; needs to be static to be
    // called by a @RemoteAction method
    public static List<Data> getChartData() {
        List<Data> data = new List<Data>();
        List<CM_Group_Tracking__c> allData = new List<CM_Group_Tracking__c>([SELECT Id, Action__c, Email__c, DateTime__c, Group__c
                                                                             FROM CM_Group_Tracking__c
                                                                             ORDER BY DateTime__c ASC NULLS LAST]);
        Set<String> groupNamesSet = new Set<String>();
        List<String> last30days = new List<String>();
        Map<String, Map<String, Integer>> groupNamesMap = new Map<String, Map<String, Integer>>();
        
        //create set of all existing group names
        for (CM_Group_Tracking__c st : allData) {
            try {
                groupNamesSet.add(st.Group__c);
            } catch (Exception e) {
                system.debug('%%% exception adding group name to set: ' + e);
            }
        }
        
        //loop through last 30 days (including today) as i
        for (Integer i = 30; i >0; i--) {
            last30days.add(string.valueOf(datetime.now().addDays(-i).format('MMM-d')));
            //setup map for holding values
            for (String s : groupNamesSet) {
                Map<String,Integer> tmpMap = New Map<String,Integer>();
                groupNamesMap.put(string.valueOf(datetime.now().addDays(-i).format('MMM-d')), tmpMap);
                groupNamesMap.get(string.valueOf(datetime.now().addDays(-i).format('MMM-d'))).put(s, 0);
            }
            
        }
                
        //add each stat to the correct map and submap
        for (CM_Group_Tracking__c st : allData) {
            
            //format and get date of current stat
            string statDay;
            if (st.DateTime__c != null) {statDay = st.DateTime__c.format('MMM-d');}            
            
            boolean hasTimeAndAction = st.DateTime__c != null && st.Action__c != null;
            
            //for each stat, loop through all group names and add it to the corresponding one
            for (String days30 : last30days) {
                if (hasTimeAndAction && statDay == days30) {
                    integer myint;
                    if (groupNamesMap.get(days30).get(st.Group__c) == null) {
                        myint = 0;
                    } else {
                    	myint = groupNamesMap.get(days30).get(st.Group__c);
                    }
                    
                    groupNamesMap.get(days30).put(st.Group__c, myint+1);
                    
                } else {
                    system.debug('%%% NULL FOUND & FILTERED ---------------------- ' + string.ValueOf(st.Id));
                }
            }
        }        
        
        //create new data objects based on map and submap values
        for (String s : last30days) {
            data.add(new Data(s, groupNamesMap.get(s).get('CM_Group_NameExample1'), groupNamesMap.get(s).get('CM_Group_NameExample2'), 0));
            
        }
        
        return data;
    }
    
    // Wrapper class
    public class Data {
        public String name { get; set; }
        public Integer data1 { get; set; }
        public Integer data2 { get; set; }
        public Integer data3 { get; set; }
        public Data(String name, Integer data1, Integer data2, Integer data3) {
            this.name = name;
            this.data1 = data1;
            this.data2 = data2;
            this.data3 = data3;
        }
    }
}
And here is the VF page:
<apex:page controller="BarChartController">
    <apex:chart height="400" width="700" data="{!data}">
        <apex:legend position="right"/>
        <apex:axis type="Numeric" position="left" fields="data1,data2" 
                   title="MyDataTitleHere" grid="true" minimum="0"/>
        <apex:axis type="Category" position="bottom" fields="name" 
                   title="Date (last 30 days)" minimum="0">
            <apex:chartLabel rotate="330"/>
        </apex:axis>
        <apex:lineSeries axis="left" fill="false" xField="name" yField="data1"
                         markerType="circle" markerSize="4" markerFill="#FF0000" />
        <apex:lineSeries axis="left" fill="false" xField="name" yField="data2"
                         markerType="cross" markerSize="5" markerFill="#FF0000" />
    </apex:chart>
</apex:page>

What I need the code to do (I think) is generate the constructors in the wrapper using the values present in groupNamesSet. From there, I need the code in the section "//create new data objects based..." to basically do this (to dynamically create Data objects and fill in the constructors by getting values from the map using the names from the groupNamesSet, which the values are already keyed by in the map):
data.add(new Data(s, groupNamesMap.get(s).get(groupNamesSet[0]), groupNamesMap.get(s).get(groupNamesSet[1], groupNamesMap.get(s).get(groupNamesSet[3], ETC)));
How can I achieve this?

Or, are there other methods that I should use to deal with the problem of a dynamic list of values to plot like in this example (where groupNamesSet could have any number of different values depending on the underlying data)?

Thanks!