drupal-civicrm/sites/all/modules/civicrm/ang/crmMailingAB/Stats.js
2018-01-14 13:10:16 +00:00

281 lines
9.6 KiB
JavaScript

(function (angular, $, _) {
// FIXME: This code is long and hasn't been fully working for me, but I've moved it into a spot
// where it at least fits in a bit better.
// example: <div crm-mailing-ab-stats="{split_count: 6, criteria:'Open'}" crm-abtest="myabtest" />
// options (see also: Mailing.graph_stats API)
// - split_count: int
// - criteria: string
// - target_date: string, date
// - target_url: string
angular.module('crmMailingAB').directive('crmMailingAbStats', function (crmApi, $parse) {
return {
scope: {
crmMailingAbStats: '@',
crmAbtest: '@'
},
template: '<div class="crm-mailing-ab-stats"></div>',
link: function (scope, element, attrs) {
var abtestModel = $parse(attrs.crmAbtest);
var optionModel = $parse(attrs.crmMailingAbStats);
var options = angular.extend({}, optionModel(scope.$parent), {
criteria: 'Open', // e.g. 'Open', 'Total Unique Clicks'
split_count: 5
});
scope.$watch(attrs.crmAbtest, refresh);
function refresh() {
var abtest = abtestModel(scope.$parent);
if (!abtest) {
console.log('failed to draw stats - missing abtest');
return;
}
scope.graph_data = [
{},
{},
{},
{},
{}
];
var keep_cnt = 0;
for (var i = 1; i <= options.split_count; i++) {
var result = crmApi('MailingAB', 'graph_stats', {
id: abtest.ab.id,
target_date: abtest.ab.declare_winning_time ? abtest.ab.declare_winning_time : 'now',
target_url: null, // FIXME
criteria: options.criteria,
split_count: options.split_count,
split_count_select: i
});
/*jshint -W083 */
result.then(function (data) {
var temp = 0;
keep_cnt++;
for (var key in data.values.A) {
temp = key;
}
var t = data.values.A[temp].time.split(" ");
var m = t[0];
var year = t[2];
var day = t[1].substr(0, t[1].length - 3);
var t1, hur, hour, min;
if (_.isEmpty(t[3])) {
t1 = t[4].split(":");
hur = t1[0];
if (t[5] == "AM") {
hour = hur;
if (hour == 12) {
hour = 0;
}
}
if (t[5] == "PM") {
hour = parseInt(hur) + 12;
}
min = t1[1];
}
else {
t1 = t[3].split(":");
hur = t1[0];
if (t[4] == "AM") {
hour = hur;
if (hour == 12) {
hour = 0;
}
}
if (t[4] == "PM") {
hour = parseInt(hur) + 12;
}
min = t1[1];
}
var month = 0;
switch (m) {
case "January":
month = 0;
break;
case "February":
month = 1;
break;
case "March":
month = 2;
break;
case "April":
month = 3;
break;
case "May":
month = 4;
break;
case "June":
month = 5;
break;
case "July":
month = 6;
break;
case "August":
month = 7;
break;
case "September":
month = 8;
break;
case "October":
month = 9;
break;
case "November":
month = 10;
break;
case "December":
month = 11;
break;
}
var tp = new Date(year, month, day, hour, min, 0, 0);
scope.graph_data[temp - 1] = {
time: tp,
x: data.values.A[temp].count,
y: data.values.B[temp].count
};
if (keep_cnt == options.split_count) {
scope.graphload = true;
data = scope.graph_data;
// set up a colour variable
var color = d3.scale.category10();
// map one colour each to x, y and z
// keys grabs the key value or heading of each key value pair in the json
// but not time
color.domain(d3.keys(data[0]).filter(function (key) {
return key !== "time";
}));
// create a nested series for passing to the line generator
// it's best understood by console logging the data
var series = color.domain().map(function (name) {
return {
name: name,
values: data.map(function (d) {
return {
time: d.time,
score: +d[name]
};
})
};
});
// Set the dimensions of the canvas / graph
var margin = {
top: 30,
right: 20,
bottom: 40,
left: 75
},
width = 550 - margin.left - margin.right,
height = 350 - margin.top - margin.bottom;
// Set the ranges
//var x = d3.time.scale().range([0, width]).domain([0,10]);
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(10);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
// Define the line
// Note you plot the time / score pair from each key you created earlier
var valueline = d3.svg.line()
.x(function (d) {
return x(d.time);
})
.y(function (d) {
return y(d.score);
});
// Adds the svg canvas
var svg = d3.select($('.crm-mailing-ab-stats', element)[0])
.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 + ")");
// Scale the range of the data
x.domain(d3.extent(data, function (d) {
return d.time;
}));
// note the nested nature of this you need to dig an additional level
y.domain([
d3.min(series, function (c) {
return d3.min(c.values, function (v) {
return v.score;
});
}),
d3.max(series, function (c) {
return d3.max(c.values, function (v) {
return v.score;
});
})
]);
svg.append("text") // text label for the x axis
.attr("x", width / 2)
.attr("y", height + margin.bottom)
.style("text-anchor", "middle")
.text("Time");
svg.append("text") // text label for the x axis
.style("text-anchor", "middle")
.text(scope.winnercriteria).attr("transform",function (d) {
return "rotate(-90)";
}).attr("x", -height / 2)
.attr("y", -30);
// create a variable called series and bind the date
// for each series append a g element and class it as series for css styling
series = svg.selectAll(".series")
.data(series)
.enter().append("g")
.attr("class", "series");
// create the path for each series in the variable series i.e. x, y and z
// pass each object called x, y nad z to the lne generator
series.append("path")
.attr("class", "line")
.attr("d", function (d) {
// console.log(d); // to see how d3 iterates through series
return valueline(d.values);
})
.style("stroke", function (d) {
return color(d.name);
});
// Add the X Axis
svg.append("g") // Add the X Axis
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.attr("transform", function (d) {
return "rotate(-30)";
});
// Add the Y Axis
svg.append("g") // Add the Y Axis
.attr("class", "y axis")
.call(yAxis);
}
});
}
}
} // link()
};
});
})(angular, CRM.$, CRM._);