Merge pull request #19632 from colemanw/afformDateRange
[civicrm-core.git] / ang / crmMailingAB / Stats.js
1 (function (angular, $, _) {
2
3
4 // FIXME: This code is long and hasn't been fully working for me, but I've moved it into a spot
5 // where it at least fits in a bit better.
6
7 // example: <div crm-mailing-ab-stats="{split_count: 6, criteria:'Open'}" crm-abtest="myabtest" />
8 // options (see also: Mailing.graph_stats API)
9 // - split_count: int
10 // - criteria: string
11 // - target_date: string, date
12 // - target_url: string
13 angular.module('crmMailingAB').directive('crmMailingAbStats', function (crmApi, $parse) {
14 return {
15 scope: {
16 crmMailingAbStats: '@',
17 crmAbtest: '@'
18 },
19 template: '<div class="crm-mailing-ab-stats"></div>',
20 link: function (scope, element, attrs) {
21 var abtestModel = $parse(attrs.crmAbtest);
22 var optionModel = $parse(attrs.crmMailingAbStats);
23 var options = angular.extend({}, optionModel(scope.$parent), {
24 criteria: 'Open', // e.g. 'Open', 'Total Unique Clicks'
25 split_count: 5
26 });
27
28 scope.$watch(attrs.crmAbtest, refresh);
29 function refresh() {
30 var abtest = abtestModel(scope.$parent);
31 if (!abtest) {
32 console.log('failed to draw stats - missing abtest');
33 return;
34 }
35
36 scope.graph_data = [
37 {},
38 {},
39 {},
40 {},
41 {}
42 ];
43 var keep_cnt = 0;
44
45 for (var i = 1; i <= options.split_count; i++) {
46 var result = crmApi('MailingAB', 'graph_stats', {
47 id: abtest.ab.id,
48 target_date: abtest.ab.declare_winning_time ? abtest.ab.declare_winning_time : 'now',
49 target_url: null, // FIXME
50 criteria: options.criteria,
51 split_count: options.split_count,
52 split_count_select: i
53 });
54 /*jshint -W083 */
55 result.then(function (data) {
56 var temp = 0;
57 keep_cnt++;
58 for (var key in data.values.A) {
59 temp = key;
60 }
61 var t = data.values.A[temp].time.split(" ");
62 var m = t[0];
63 var year = t[2];
64 var day = t[1].substr(0, t[1].length - 3);
65 var t1, hur, hour, min;
66 if (_.isEmpty(t[3])) {
67 t1 = t[4].split(":");
68 hur = t1[0];
69 if (t[5] == "AM") {
70 hour = hur;
71 if (hour == 12) {
72 hour = 0;
73 }
74 }
75 if (t[5] == "PM") {
76 hour = parseInt(hur) + 12;
77 }
78 min = t1[1];
79 }
80 else {
81 t1 = t[3].split(":");
82 hur = t1[0];
83 if (t[4] == "AM") {
84 hour = hur;
85 if (hour == 12) {
86 hour = 0;
87 }
88 }
89 if (t[4] == "PM") {
90 hour = parseInt(hur) + 12;
91 }
92 min = t1[1];
93 }
94 var month = 0;
95 switch (m) {
96 case "January":
97 month = 0;
98 break;
99 case "February":
100 month = 1;
101 break;
102 case "March":
103 month = 2;
104 break;
105 case "April":
106 month = 3;
107 break;
108 case "May":
109 month = 4;
110 break;
111 case "June":
112 month = 5;
113 break;
114 case "July":
115 month = 6;
116 break;
117 case "August":
118 month = 7;
119 break;
120 case "September":
121 month = 8;
122 break;
123 case "October":
124 month = 9;
125 break;
126 case "November":
127 month = 10;
128 break;
129 case "December":
130 month = 11;
131 break;
132
133 }
134 var tp = new Date(year, month, day, hour, min, 0, 0);
135 scope.graph_data[temp - 1] = {
136 time: tp,
137 x: data.values.A[temp].count,
138 y: data.values.B[temp].count
139 };
140
141 if (keep_cnt == options.split_count) {
142 scope.graphload = true;
143 data = scope.graph_data;
144
145 // set up a colour variable
146 var color = d3.scale.category10();
147
148 // map one colour each to x, y and z
149 // keys grabs the key value or heading of each key value pair in the json
150 // but not time
151 color.domain(d3.keys(data[0]).filter(function (key) {
152 return key !== "time";
153 }));
154
155 // create a nested series for passing to the line generator
156 // it's best understood by console logging the data
157 var series = color.domain().map(function (name) {
158 return {
159 name: name,
160 values: data.map(function (d) {
161 return {
162 time: d.time,
163 score: +d[name]
164 };
165 })
166 };
167 });
168
169 // Set the dimensions of the canvas / graph
170 var margin = {
171 top: 30,
172 right: 20,
173 bottom: 40,
174 left: 75
175 },
176 width = 550 - margin.left - margin.right,
177 height = 350 - margin.top - margin.bottom;
178
179 // Set the ranges
180 //var x = d3.time.scale().range([0, width]).domain([0,10]);
181 var x = d3.time.scale().range([0, width]);
182 var y = d3.scale.linear().range([height, 0]);
183
184 // Define the axes
185 var xAxis = d3.svg.axis().scale(x)
186 .orient("bottom").ticks(10);
187
188 var yAxis = d3.svg.axis().scale(y)
189 .orient("left").ticks(5);
190
191 // Define the line
192 // Note you plot the time / score pair from each key you created earlier
193 var valueline = d3.svg.line()
194 .x(function (d) {
195 return x(d.time);
196 })
197 .y(function (d) {
198 return y(d.score);
199 });
200
201 // Adds the svg canvas
202 var svg = d3.select($('.crm-mailing-ab-stats', element)[0])
203 .append("svg")
204 .attr("width", width + margin.left + margin.right)
205 .attr("height", height + margin.top + margin.bottom)
206 .append("g")
207 .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
208
209 // Scale the range of the data
210 x.domain(d3.extent(data, function (d) {
211 return d.time;
212 }));
213
214 // note the nested nature of this you need to dig an additional level
215 y.domain([
216 d3.min(series, function (c) {
217 return d3.min(c.values, function (v) {
218 return v.score;
219 });
220 }),
221 d3.max(series, function (c) {
222 return d3.max(c.values, function (v) {
223 return v.score;
224 });
225 })
226 ]);
227 svg.append("text") // text label for the x axis
228 .attr("x", width / 2)
229 .attr("y", height + margin.bottom)
230 .style("text-anchor", "middle")
231 .text("Time");
232
233 svg.append("text") // text label for the x axis
234 .style("text-anchor", "middle")
235 .text(scope.winnercriteria).attr("transform",function (d) {
236 return "rotate(-90)";
237 }).attr("x", -height / 2)
238 .attr("y", -30);
239
240 // create a variable called series and bind the date
241 // for each series append a g element and class it as series for css styling
242 series = svg.selectAll(".series")
243 .data(series)
244 .enter().append("g")
245 .attr("class", "series");
246
247 // create the path for each series in the variable series i.e. x, y and z
248 // pass each object called x, y nad z to the lne generator
249 series.append("path")
250 .attr("class", "line")
251 .attr("d", function (d) {
252 // console.log(d); // to see how d3 iterates through series
253 return valueline(d.values);
254 })
255 .style("stroke", function (d) {
256 return color(d.name);
257 });
258
259 // Add the X Axis
260 svg.append("g") // Add the X Axis
261 .attr("class", "x axis")
262 .attr("transform", "translate(0," + height + ")")
263 .call(xAxis)
264 .selectAll("text")
265 .attr("transform", function (d) {
266 return "rotate(-30)";
267 });
268
269 // Add the Y Axis
270 svg.append("g") // Add the Y Axis
271 .attr("class", "y axis")
272 .call(yAxis);
273 }
274 });
275 }
276 }
277 } // link()
278 };
279 });
280 })(angular, CRM.$, CRM._);