Commit | Line | Data |
---|---|---|
22bc3e48 | 1 | (function (angular, $, _) { |
22bc3e48 | 2 | |
360aaa75 TO |
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 | |
d3312ed5 | 13 | angular.module('crmMailingAB').directive('crmMailingAbStats', function (crmApi, $parse) { |
360aaa75 TO |
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() { | |
360aaa75 TO |
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, | |
d3312ed5 | 48 | target_date: abtest.ab.declare_winning_time ? abtest.ab.declare_winning_time : 'now', |
360aaa75 TO |
49 | target_url: null, // FIXME |
50 | criteria: options.criteria, | |
51 | split_count: options.split_count, | |
52 | split_count_select: i | |
53 | }); | |
175762a3 | 54 | /*jshint -W083 */ |
360aaa75 TO |
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); | |
f2bad133 | 65 | var t1, hur, hour, min; |
175762a3 | 66 | if (_.isEmpty(t[3])) { |
f2bad133 TO |
67 | t1 = t[4].split(":"); |
68 | hur = t1[0]; | |
360aaa75 TO |
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 | } | |
f2bad133 | 78 | min = t1[1]; |
360aaa75 TO |
79 | } |
80 | else { | |
f2bad133 TO |
81 | t1 = t[3].split(":"); |
82 | hur = t1[0]; | |
360aaa75 TO |
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 | } | |
f2bad133 | 92 | min = t1[1]; |
360aaa75 TO |
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; | |
f2bad133 | 143 | data = scope.graph_data; |
360aaa75 TO |
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 | |
e4f46be0 | 192 | // Note you plot the time / score pair from each key you created earlier |
360aaa75 TO |
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) { | |
f2bad133 | 236 | return "rotate(-90)"; |
360aaa75 TO |
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 | |
f2bad133 | 242 | series = svg.selectAll(".series") |
360aaa75 TO |
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 | }); | |
22bc3e48 | 280 | })(angular, CRM.$, CRM._); |