Add graph for user repartition

This commit is contained in:
Frédéric Guillot
2014-11-13 20:37:37 -05:00
parent e4efc73a90
commit 1487cb2763
22 changed files with 234 additions and 15 deletions

View File

@@ -27,11 +27,11 @@ class Analytic extends Base
} }
/** /**
* Show task distribution graph * Show tasks distribution graph
* *
* @access public * @access public
*/ */
public function repartition() public function tasks()
{ {
$project = $this->getProject(); $project = $this->getProject();
$metrics = $this->projectAnalytic->getTaskRepartition($project['id']); $metrics = $this->projectAnalytic->getTaskRepartition($project['id']);
@@ -46,11 +46,39 @@ class Analytic extends Base
)); ));
} }
else { else {
$this->response->html($this->layout('analytic/repartition', array( $this->response->html($this->layout('analytic/tasks', array(
'project' => $project, 'project' => $project,
'metrics' => $metrics, 'metrics' => $metrics,
'title' => t('Task repartition for "%s"', $project['name']), 'title' => t('Task repartition for "%s"', $project['name']),
))); )));
} }
} }
/**
* Show users repartition
*
* @access public
*/
public function users()
{
$project = $this->getProject();
$metrics = $this->projectAnalytic->getUserRepartition($project['id']);
if ($this->request->isAjax()) {
$this->response->json(array(
'metrics' => $metrics,
'labels' => array(
'user' => t('User'),
'nb_tasks' => t('Number of tasks'),
)
));
}
else {
$this->response->html($this->layout('analytic/users', array(
'project' => $project,
'metrics' => $metrics,
'title' => t('User repartition for "%s"', $project['name']),
)));
}
}
} }

View File

@@ -573,4 +573,6 @@ return array(
// 'Analytics' => '', // 'Analytics' => '',
// 'Subtask' => '', // 'Subtask' => '',
// 'My subtasks' => '', // 'My subtasks' => '',
// 'User repartition' => '',
// 'User repartition for "%s"' => '',
); );

View File

@@ -573,4 +573,6 @@ return array(
// 'Analytics' => '', // 'Analytics' => '',
// 'Subtask' => '', // 'Subtask' => '',
// 'My subtasks' => '', // 'My subtasks' => '',
// 'User repartition' => '',
// 'User repartition for "%s"' => '',
); );

View File

@@ -573,4 +573,6 @@ return array(
// 'Analytics' => '', // 'Analytics' => '',
// 'Subtask' => '', // 'Subtask' => '',
// 'My subtasks' => '', // 'My subtasks' => '',
// 'User repartition' => '',
// 'User repartition for "%s"' => '',
); );

View File

@@ -573,4 +573,6 @@ return array(
// 'Analytics' => '', // 'Analytics' => '',
// 'Subtask' => '', // 'Subtask' => '',
// 'My subtasks' => '', // 'My subtasks' => '',
// 'User repartition' => '',
// 'User repartition for "%s"' => '',
); );

View File

@@ -573,4 +573,6 @@ return array(
'Analytics' => 'Analytique', 'Analytics' => 'Analytique',
'Subtask' => 'Sous-tâche', 'Subtask' => 'Sous-tâche',
'My subtasks' => 'Mes sous-tâches', 'My subtasks' => 'Mes sous-tâches',
'User repartition' => 'Répartition des utilisateurs',
'User repartition for "%s"' => 'Répartition des utilisateurs pour « %s »',
); );

View File

@@ -573,4 +573,6 @@ return array(
// 'Analytics' => '', // 'Analytics' => '',
// 'Subtask' => '', // 'Subtask' => '',
// 'My subtasks' => '', // 'My subtasks' => '',
// 'User repartition' => '',
// 'User repartition for "%s"' => '',
); );

View File

@@ -573,4 +573,6 @@ return array(
// 'Analytics' => '', // 'Analytics' => '',
// 'Subtask' => '', // 'Subtask' => '',
// 'My subtasks' => '', // 'My subtasks' => '',
// 'User repartition' => '',
// 'User repartition for "%s"' => '',
); );

View File

@@ -573,4 +573,6 @@ return array(
// 'Analytics' => '', // 'Analytics' => '',
// 'Subtask' => '', // 'Subtask' => '',
// 'My subtasks' => '', // 'My subtasks' => '',
// 'User repartition' => '',
// 'User repartition for "%s"' => '',
); );

View File

@@ -573,4 +573,6 @@ return array(
// 'Analytics' => '', // 'Analytics' => '',
// 'Subtask' => '', // 'Subtask' => '',
// 'My subtasks' => '', // 'My subtasks' => '',
// 'User repartition' => '',
// 'User repartition for "%s"' => '',
); );

View File

@@ -573,4 +573,6 @@ return array(
// 'Analytics' => '', // 'Analytics' => '',
// 'Subtask' => '', // 'Subtask' => '',
// 'My subtasks' => '', // 'My subtasks' => '',
// 'User repartition' => '',
// 'User repartition for "%s"' => '',
); );

View File

@@ -573,4 +573,6 @@ return array(
// 'Analytics' => '', // 'Analytics' => '',
// 'Subtask' => '', // 'Subtask' => '',
// 'My subtasks' => '', // 'My subtasks' => '',
// 'User repartition' => '',
// 'User repartition for "%s"' => '',
); );

View File

@@ -573,4 +573,6 @@ return array(
// 'Analytics' => '', // 'Analytics' => '',
// 'Subtask' => '', // 'Subtask' => '',
// 'My subtasks' => '', // 'My subtasks' => '',
// 'User repartition' => '',
// 'User repartition for "%s"' => '',
); );

View File

@@ -573,4 +573,6 @@ return array(
// 'Analytics' => '', // 'Analytics' => '',
// 'Subtask' => '', // 'Subtask' => '',
// 'My subtasks' => '', // 'My subtasks' => '',
// 'User repartition' => '',
// 'User repartition for "%s"' => '',
); );

View File

@@ -41,7 +41,7 @@ class Acl extends Base
'task' => array('show', 'create', 'save', 'edit', 'update', 'close', 'open', 'duplicate', 'remove', 'description', 'move', 'copy', 'time'), 'task' => array('show', 'create', 'save', 'edit', 'update', 'close', 'open', 'duplicate', 'remove', 'description', 'move', 'copy', 'time'),
'category' => array('index', 'save', 'edit', 'update', 'confirm', 'remove'), 'category' => array('index', 'save', 'edit', 'update', 'confirm', 'remove'),
'action' => array('index', 'event', 'params', 'create', 'confirm', 'remove'), 'action' => array('index', 'event', 'params', 'create', 'confirm', 'remove'),
'analytic' => array('repartition'), 'analytic' => array('tasks', 'users'),
); );
/** /**

View File

@@ -11,7 +11,7 @@ namespace Model;
class ProjectAnalytic extends Base class ProjectAnalytic extends Base
{ {
/** /**
* Get task repartition * Get tasks repartition
* *
* @access public * @access public
* @param integer $project_id Project id * @param integer $project_id Project id
@@ -40,4 +40,41 @@ class ProjectAnalytic extends Base
return $metrics; return $metrics;
} }
/**
* Get users repartition
*
* @access public
* @param integer $project_id Project id
* @return array
*/
public function getUserRepartition($project_id)
{
$metrics = array();
$total = 0;
$tasks = $this->taskFinder->getAll($project_id);
$users = $this->projectPermission->getMemberList($project_id);
foreach ($tasks as $task) {
$user = $users[$task['owner_id']];
$total++;
if (! isset($metrics[$user])) {
$metrics[$user] = array(
'nb_tasks' => 0,
'percentage' => 0,
'user' => $user,
);
}
$metrics[$user]['nb_tasks']++;
}
foreach ($metrics as &$metric) {
$metric['percentage'] = round(($metric['nb_tasks'] * 100) / $total, 2);
}
return array_values($metrics);
}
} }

View File

@@ -2,7 +2,10 @@
<h2><?= t('Reportings') ?></h2> <h2><?= t('Reportings') ?></h2>
<ul> <ul>
<li> <li>
<?= Helper\a(t('Task distribution'), 'analytic', 'repartition', array('project_id' => $project['id'])) ?> <?= Helper\a(t('Task distribution'), 'analytic', 'tasks', array('project_id' => $project['id'])) ?>
</li>
<li>
<?= Helper\a(t('User repartition'), 'analytic', 'users', array('project_id' => $project['id'])) ?>
</li> </li>
</ul> </ul>
</div> </div>

View File

@@ -1,9 +1,9 @@
<div class="page-header"> <div class="page-header">
<h2><?= t('Task distribution') ?></h2> <h2><?= t('Task distribution') ?></h2>
</div> </div>
<section id="analytic-repartition"> <section id="analytic-task-repartition">
<div id="chart" data-url="<?= Helper\u('analytic', 'repartition', array('project_id' => $project['id'])) ?>"></div> <div id="chart" data-url="<?= Helper\u('analytic', 'tasks', array('project_id' => $project['id'])) ?>"></div>
<table> <table>
<tr> <tr>

View File

@@ -0,0 +1,29 @@
<div class="page-header">
<h2><?= t('User repartition') ?></h2>
</div>
<section id="analytic-user-repartition">
<div id="chart" data-url="<?= Helper\u('analytic', 'users', array('project_id' => $project['id'])) ?>"></div>
<table>
<tr>
<th><?= t('User') ?></th>
<th><?= t('Number of tasks') ?></th>
<th><?= t('Percentage') ?></th>
</tr>
<?php foreach ($metrics as $metric): ?>
<tr>
<td>
<?= Helper\escape($metric['user']) ?>
</td>
<td>
<?= $metric['nb_tasks'] ?>
</td>
<td>
<?= n($metric['percentage']) ?>%
</td>
</tr>
<?php endforeach ?>
</table>
</section>

View File

@@ -25,7 +25,7 @@
</li> </li>
<li> <li>
<i class="fa fa-line-chart fa-fw"></i> <i class="fa fa-line-chart fa-fw"></i>
<?= Helper\a(t('Analytics'), 'analytic', 'repartition', array('project_id' => $project['id'])) ?> <?= Helper\a(t('Analytics'), 'analytic', 'tasks', array('project_id' => $project['id'])) ?>
</li> </li>
<?php if (Helper\is_admin()): ?> <?php if (Helper\is_admin()): ?>
<li><i class="fa fa-cog fa-fw"></i> <li><i class="fa fa-cog fa-fw"></i>

View File

@@ -4,15 +4,18 @@ Kanboard.Analytic = (function() {
return { return {
Init: function() { Init: function() {
if (Kanboard.Exists("analytic-repartition")) { if (Kanboard.Exists("analytic-task-repartition")) {
Kanboard.Analytic.Repartition.Init(); Kanboard.Analytic.TaskRepartition.Init();
}
else if (Kanboard.Exists("analytic-user-repartition")) {
Kanboard.Analytic.UserRepartition.Init();
} }
} }
}; };
})(); })();
Kanboard.Analytic.Repartition = (function() { Kanboard.Analytic.TaskRepartition = (function() {
function fetchData() function fetchData()
{ {
@@ -56,3 +59,48 @@ Kanboard.Analytic.Repartition = (function() {
}; };
})(); })();
Kanboard.Analytic.UserRepartition = (function() {
function fetchData()
{
jQuery.getJSON($("#chart").attr("data-url"), function(data) {
drawGraph(data.metrics, data.labels);
});
}
function drawGraph(metrics, labels)
{
var series = prepareSeries(metrics, labels);
var svg = dimple.newSvg("#chart", 700, 350);
var chart = new dimple.chart(svg, series);
chart.addMeasureAxis("p", labels["nb_tasks"]);
var ring = chart.addSeries(labels["user"], dimple.plot.pie);
ring.innerRadius = "50%";
chart.addLegend(0, 0, 100, 100, "left");
chart.draw();
}
function prepareSeries(metrics, labels)
{
var series = [];
for (var i = 0; i < metrics.length; i++) {
var serie = {};
serie[labels["nb_tasks"]] = metrics[i]["nb_tasks"];
serie[labels["user"]] = metrics[i]["user"];
series.push(serie);
}
return series;
}
return {
Init: fetchData
};
})();

View File

@@ -273,15 +273,18 @@ Kanboard.Analytic = (function() {
return { return {
Init: function() { Init: function() {
if (Kanboard.Exists("analytic-repartition")) { if (Kanboard.Exists("analytic-task-repartition")) {
Kanboard.Analytic.Repartition.Init(); Kanboard.Analytic.TaskRepartition.Init();
}
else if (Kanboard.Exists("analytic-user-repartition")) {
Kanboard.Analytic.UserRepartition.Init();
} }
} }
}; };
})(); })();
Kanboard.Analytic.Repartition = (function() { Kanboard.Analytic.TaskRepartition = (function() {
function fetchData() function fetchData()
{ {
@@ -324,6 +327,51 @@ Kanboard.Analytic.Repartition = (function() {
Init: fetchData Init: fetchData
}; };
})();
Kanboard.Analytic.UserRepartition = (function() {
function fetchData()
{
jQuery.getJSON($("#chart").attr("data-url"), function(data) {
drawGraph(data.metrics, data.labels);
});
}
function drawGraph(metrics, labels)
{
var series = prepareSeries(metrics, labels);
var svg = dimple.newSvg("#chart", 700, 350);
var chart = new dimple.chart(svg, series);
chart.addMeasureAxis("p", labels["nb_tasks"]);
var ring = chart.addSeries(labels["user"], dimple.plot.pie);
ring.innerRadius = "50%";
chart.addLegend(0, 0, 100, 100, "left");
chart.draw();
}
function prepareSeries(metrics, labels)
{
var series = [];
for (var i = 0; i < metrics.length; i++) {
var serie = {};
serie[labels["nb_tasks"]] = metrics[i]["nb_tasks"];
serie[labels["user"]] = metrics[i]["user"];
series.push(serie);
}
return series;
}
return {
Init: fetchData
};
})(); })();
// Initialization // Initialization
$(function() { $(function() {