Files
nairobi/app/assets/javascripts/dashboard_graphs.js
2019-09-11 01:56:27 +02:00

309 lines
8.0 KiB
JavaScript

//= require d3
//= require c3
//= require c3ext
// TODO: This module is complex enough to require its own tests. Rewrite it using Ecma6 class syntax and
// write tests for this feature after consul has been migrated to Rails 5.1
(function(){
'use strict';
var ProposalGraph = function(url) {
this.url = url;
this.successfulProposalDataUrl = null;
this.proposalAchievementsUrl = null;
this.targetId = null;
this.groupBy = null;
this.proposalSuccess = null;
this.maximumValue = 0;
this.progressLabel = 'Progress';
this.supportsLabel = 'Supports';
this.successLabel = 'Success';
this.goals = null;
this.achievements = null;
this.xColumnValues = null;
this.progressColumnValues = null;
this.resourcesUrl = null;
};
ProposalGraph.prototype.refresh = function() {
this.refreshGoals()
.then(this.refreshData.bind(this))
.then(this.refreshSuccessfulData.bind(this))
.then(this.refreshAchievements.bind(this))
.done(this.draw.bind(this));
};
ProposalGraph.prototype.refreshGoals = function () {
return $.ajax({
url: this.resourcesUrl,
cache: false,
success: function(data) {
this.parseGoals(data);
}.bind(this)
});
};
ProposalGraph.prototype.parseGoals = function(data) {
var i, l;
this.goals = [];
for (i = 0, l = data.length; i < l; i += 1) {
this.goals.push({
value: data[i].required_supports,
text: data[i].title
});
}
};
ProposalGraph.prototype.refreshData = function () {
return $.ajax({
url: this.url,
cache: false,
success: function (data) {
this.parseData(data);
}.bind(this),
data: {
group_by: this.groupBy
}
});
};
ProposalGraph.prototype.parseData = function(data) {
var key;
this.xColumnValues = [ ];
this.progressColumnValues = [ this.progressLabel ];
for (key in data) {
if (data.hasOwnProperty(key)) {
this.xColumnValues.push(key);
this.progressColumnValues.push(data[key]);
if (this.maximumValue < data[key]) {
this.maximumValue = data[key];
}
}
}
};
ProposalGraph.prototype.refreshSuccessfulData = function() {
return $.ajax({
url: this.successfulProposalDataUrl,
cache: false,
success: function (data) {
this.parseSuccessfulProposalData(data);
}.bind(this),
data: {
group_by: this.groupBy
}
});
};
ProposalGraph.prototype.parseSuccessfulProposalData = function(data) {
var key;
this.successfulColumnValues = [ this.successLabel ];
for (key in data) {
if (data.hasOwnProperty(key)) {
this.addXColumnValue(key);
this.successfulColumnValues.push(data[key]);
}
}
};
ProposalGraph.prototype.refreshAchievements = function() {
return $.ajax({
url: this.proposalAchievementsUrl,
cache: false,
success: function (data) {
this.parseAchievements(data);
}.bind(this),
data: {
group_by: this.groupBy
}
});
};
ProposalGraph.prototype.parseAchievements = function(data) {
var group;
this.achievements = [];
for (group in data) {
if (data.hasOwnProperty(group)) {
this.addXColumnValue(group);
this.achievements.push({
value: this.formatGroup(group),
text: data[group].title,
position: 'start'
});
}
}
};
ProposalGraph.prototype.addXColumnValue = function (value) {
if (this.xColumnValues.indexOf(value) === -1) {
this.xColumnValues.push(value);
}
};
ProposalGraph.prototype.draw = function() {
var colors = {},
maximumValue = this.maximumValue === 0 ? this.proposalSuccess : Math.round(this.maximumValue * 1.10);
this.formatXColumnValues();
colors[this.progressColumnValues[0]] = '#004a83';
colors[this.successfulColumnValues[0]] = '#ff7f0e';
c3.generate({
bindto: '#' + this.targetId,
data: {
x: 'x',
columns: [
this.xColumnValues,
this.progressColumnValues,
this.successfulColumnValues
],
colors: colors,
color: function (color, d) {
var achievement;
if (d.id === this.successfulColumnValues[0] || !d.hasOwnProperty('x')) {
return color;
}
achievement = this.achievements.find(function (element) {
return element.value === this.xColumnValues[d.index + 1];
}.bind(this));
if (achievement !== undefined) {
return '#ff0000';
}
return color;
}.bind(this)
},
axis: {
y: {
tick: {
values: this.tickYValues()
},
min: (this.maximumValue === 0 ? Math.round(this.proposalSuccess * 0.10) : 0),
max: maximumValue,
label: {
text: this.supportsLabel,
position: 'outer-middle'
}
},
x: {
type: 'category',
tick: {
values: this.tickXValues(),
centered: true
}
}
},
grid: {
y: {
lines: this.goals
}
},
zoom: {
enabled: true
},
tooltip: {
format: {
title: function (d) {
var achievement = this.achievements.find(function (element) {
return element.value === this.xColumnValues[d + 1];
}.bind(this));
if (achievement !== undefined) {
return this.xColumnValues[d + 1] + ': ' + achievement.text;
}
return this.xColumnValues[d + 1];
}.bind(this)
}
}
});
};
ProposalGraph.prototype.tickYValues = function () {
var i,
tick = [0],
maximumValue = this.maximumValue === 0 ? this.proposalSuccess : Math.round(this.maximumValue * 1.10),
step = maximumValue <= 10 ? 1 : Math.round(maximumValue / 10);
for (i = step; i < maximumValue; i += step) {
tick.push(i);
}
tick.push(maximumValue);
return tick;
};
ProposalGraph.prototype.tickXValues = function () {
var i,
l,
tick = [],
step = this.xColumnValues.length < 13 ? 1 : Math.round((this.xColumnValues.length - 1) / 12);
if (this.xColumnValues.length > 1) {
tick.push(0);
for(i = step, l = this.xColumnValues.length - 1; i < l; i += step) {
tick.push(i);
}
}
return tick;
};
ProposalGraph.prototype.formatXColumnValues = function () {
var i, l;
this.xColumnValues = this.xColumnValues.sort();
if (this.isDailyGrouped()) {
for (i = 0, l = this.xColumnValues.length; i < l; i += 1) {
this.xColumnValues[i] = this.formatGroup(this.xColumnValues[i]);
}
}
this.xColumnValues.unshift('x');
};
ProposalGraph.prototype.formatGroup = function(group) {
if (this.isDailyGrouped()) {
var parts = group.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/);
return parts[2] + "/" + parts[3];
}
return group;
};
ProposalGraph.prototype.isDailyGrouped = function() {
return this.groupBy === undefined || this.groupBy === '' || this.groupBy === null;
};
$(document).ready(function () {
$('[data-proposal-graph-url]').each(function () {
var graph = new ProposalGraph($(this).data('proposal-graph-url'));
graph.successfulProposalDataUrl = $(this).data('successful-proposal-graph-url');
graph.proposalAchievementsUrl = $(this).data('proposal-achievements-url');
graph.targetId = $(this).attr('id');
graph.groupBy = $(this).data('proposal-graph-group-by');
graph.progressLabel = $(this).data('proposal-graph-progress-label');
graph.supportsLabel = $(this).data('proposal-graph-supports-label');
graph.successLabel = $(this).data('proposal-graph-success-label');
graph.proposalSuccess = parseInt($(this).data('proposal-success'), 10);
graph.resourcesUrl = $(this).data('proposal-resources-url');
graph.refresh();
});
});
})();