Use components to render charts
This commit is contained in:
@@ -12,6 +12,18 @@ use Kanboard\Core\Base;
|
|||||||
*/
|
*/
|
||||||
class AppHelper extends Base
|
class AppHelper extends Base
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Render Javascript component
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param array $params
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function component($name, array $params = array())
|
||||||
|
{
|
||||||
|
return '<div class="js-'.$name.'" data-params=\''.json_encode($params, JSON_HEX_APOS).'\'></div>';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get config variable
|
* Get config variable
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -5,25 +5,25 @@
|
|||||||
<?php if (empty($metrics)): ?>
|
<?php if (empty($metrics)): ?>
|
||||||
<p class="alert"><?= t('Not enough data to show the graph.') ?></p>
|
<p class="alert"><?= t('Not enough data to show the graph.') ?></p>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<section id="analytic-avg-time-column">
|
<?= $this->app->component('chart-avg-time-column', array(
|
||||||
|
'metrics' => $metrics,
|
||||||
|
'label' => t('Average time spent'),
|
||||||
|
)) ?>
|
||||||
|
|
||||||
<div id="chart" data-metrics='<?= json_encode($metrics, JSON_HEX_APOS) ?>' data-label="<?= t('Average time spent') ?>"></div>
|
<table class="table-striped">
|
||||||
|
<tr>
|
||||||
|
<th><?= t('Column') ?></th>
|
||||||
|
<th><?= t('Average time spent') ?></th>
|
||||||
|
</tr>
|
||||||
|
<?php foreach ($metrics as $column): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?= $this->text->e($column['title']) ?></td>
|
||||||
|
<td><?= $this->dt->duration($column['average']) ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</table>
|
||||||
|
|
||||||
<table class="table-striped">
|
<p class="alert alert-info">
|
||||||
<tr>
|
<?= t('This chart show the average time spent into each column for the last %d tasks.', 1000) ?>
|
||||||
<th><?= t('Column') ?></th>
|
</p>
|
||||||
<th><?= t('Average time spent') ?></th>
|
|
||||||
</tr>
|
|
||||||
<?php foreach ($metrics as $column): ?>
|
|
||||||
<tr>
|
|
||||||
<td><?= $this->text->e($column['title']) ?></td>
|
|
||||||
<td><?= $this->dt->duration($column['average']) ?></td>
|
|
||||||
</tr>
|
|
||||||
<?php endforeach ?>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p class="alert alert-info">
|
|
||||||
<?= t('This chart show the average time spent into each column for the last %d tasks.', 1000) ?>
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|||||||
@@ -5,9 +5,11 @@
|
|||||||
<?php if (! $display_graph): ?>
|
<?php if (! $display_graph): ?>
|
||||||
<p class="alert"><?= t('You need at least 2 days of data to show the chart.') ?></p>
|
<p class="alert"><?= t('You need at least 2 days of data to show the chart.') ?></p>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<section id="analytic-burndown">
|
<?= $this->app->component('chart-burndown', array(
|
||||||
<div id="chart" data-metrics='<?= json_encode($metrics, JSON_HEX_APOS) ?>' data-date-format="<?= e('%%Y-%%m-%%d') ?>" data-label-total="<?= t('Total for all columns') ?>"></div>
|
'metrics' => $metrics,
|
||||||
</section>
|
'labelTotal' => t('Total for all columns'),
|
||||||
|
'dateFormat' => e('%%Y-%%m-%%d'),
|
||||||
|
)) ?>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|||||||
@@ -5,9 +5,10 @@
|
|||||||
<?php if (! $display_graph): ?>
|
<?php if (! $display_graph): ?>
|
||||||
<p class="alert"><?= t('You need at least 2 days of data to show the chart.') ?></p>
|
<p class="alert"><?= t('You need at least 2 days of data to show the chart.') ?></p>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<section id="analytic-cfd">
|
<?= $this->app->component('chart-cumulative-flow', array(
|
||||||
<div id="chart" data-metrics='<?= json_encode($metrics, JSON_HEX_APOS) ?>' data-date-format="<?= e('%%Y-%%m-%%d') ?>"></div>
|
'metrics' => $metrics,
|
||||||
</section>
|
'dateFormat' => e('%%Y-%%m-%%d'),
|
||||||
|
)) ?>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|||||||
@@ -12,29 +12,30 @@
|
|||||||
<?php if (empty($metrics)): ?>
|
<?php if (empty($metrics)): ?>
|
||||||
<p class="alert"><?= t('Not enough data to show the graph.') ?></p>
|
<p class="alert"><?= t('Not enough data to show the graph.') ?></p>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<section id="analytic-lead-cycle-time">
|
<?= $this->app->component('chart-lead-cycle-time', array(
|
||||||
|
'metrics' => $metrics,
|
||||||
|
'labelCycle' => t('Cycle Time'),
|
||||||
|
'labelTime' => t('Lead Time'),
|
||||||
|
)) ?>
|
||||||
|
|
||||||
<div id="chart" data-metrics='<?= json_encode($metrics, JSON_HEX_APOS) ?>' data-label-cycle="<?= t('Cycle Time') ?>" data-label-lead="<?= t('Lead Time') ?>"></div>
|
<form method="post" class="form-inline" action="<?= $this->url->href('AnalyticController', 'leadAndCycleTime', array('project_id' => $project['id'])) ?>" autocomplete="off">
|
||||||
|
|
||||||
<form method="post" class="form-inline" action="<?= $this->url->href('AnalyticController', 'leadAndCycleTime', array('project_id' => $project['id'])) ?>" autocomplete="off">
|
<?= $this->form->csrf() ?>
|
||||||
|
|
||||||
<?= $this->form->csrf() ?>
|
<div class="form-inline-group">
|
||||||
|
<?= $this->form->date(t('Start date'), 'from', $values) ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-inline-group">
|
<div class="form-inline-group">
|
||||||
<?= $this->form->date(t('Start date'), 'from', $values) ?>
|
<?= $this->form->date(t('End date'), 'to', $values) ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-inline-group">
|
<div class="form-inline-group">
|
||||||
<?= $this->form->date(t('End date'), 'to', $values) ?>
|
<button type="submit" class="btn btn-blue"><?= t('Execute') ?></button>
|
||||||
</div>
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
<div class="form-inline-group">
|
<p class="alert alert-info">
|
||||||
<button type="submit" class="btn btn-blue"><?= t('Execute') ?></button>
|
<?= t('This chart show the average lead and cycle time for the last %d tasks over the time.', 1000) ?>
|
||||||
</div>
|
</p>
|
||||||
</form>
|
|
||||||
|
|
||||||
<p class="alert alert-info">
|
|
||||||
<?= t('This chart show the average lead and cycle time for the last %d tasks over the time.', 1000) ?>
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|||||||
@@ -5,7 +5,9 @@
|
|||||||
<?php if (empty($metrics)): ?>
|
<?php if (empty($metrics)): ?>
|
||||||
<p class="alert"><?= t('Not enough data to show the graph.') ?></p>
|
<p class="alert"><?= t('Not enough data to show the graph.') ?></p>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<chart-project-task-distribution :metrics='<?= json_encode($metrics, JSON_HEX_APOS) ?>'></chart-project-task-distribution>
|
<?= $this->app->component('chart-project-task-distribution', array(
|
||||||
|
'metrics' => $metrics,
|
||||||
|
)) ?>
|
||||||
|
|
||||||
<table class="table-striped">
|
<table class="table-striped">
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -15,13 +15,13 @@
|
|||||||
<?php if ($paginator->isEmpty()): ?>
|
<?php if ($paginator->isEmpty()): ?>
|
||||||
<p class="alert"><?= t('No tasks found.') ?></p>
|
<p class="alert"><?= t('No tasks found.') ?></p>
|
||||||
<?php elseif (! $paginator->isEmpty()): ?>
|
<?php elseif (! $paginator->isEmpty()): ?>
|
||||||
<chart-project-time-comparison
|
<?= $this->app->component('chart-project-time-comparison', array(
|
||||||
:metrics='<?= json_encode($metrics, JSON_HEX_APOS)?>'
|
'metrics' => $metrics,
|
||||||
label-spent="<?= t('Hours Spent') ?>"
|
'labelSpent' => t('Hours Spent'),
|
||||||
label-estimated="<?= t('Hours Estimated') ?>"
|
'labelEstimated' => t('Hours Estimated'),
|
||||||
label-closed="<?= t('Closed') ?>"
|
'labelClosed' => t('Closed'),
|
||||||
label-open="<?= t('Open') ?>">
|
'labelOpen' => t('Open'),
|
||||||
</chart-project-time-comparison>
|
)) ?>
|
||||||
|
|
||||||
<table class="table-fixed table-small table-scrolling">
|
<table class="table-fixed table-small table-scrolling">
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -5,7 +5,9 @@
|
|||||||
<?php if (empty($metrics)): ?>
|
<?php if (empty($metrics)): ?>
|
||||||
<p class="alert"><?= t('Not enough data to show the graph.') ?></p>
|
<p class="alert"><?= t('Not enough data to show the graph.') ?></p>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<chart-project-user-distribution :metrics='<?= json_encode($metrics, JSON_HEX_APOS) ?>'></chart-project-user-distribution>
|
<?= $this->app->component('chart-project-user-distribution', array(
|
||||||
|
'metrics' => $metrics,
|
||||||
|
)) ?>
|
||||||
|
|
||||||
<table class="table-striped">
|
<table class="table-striped">
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
4
assets/js/app.min.js
vendored
4
assets/js/app.min.js
vendored
File diff suppressed because one or more lines are too long
41
assets/js/components/chart-avg-time-column.js
Normal file
41
assets/js/components/chart-avg-time-column.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
KB.component('chart-avg-time-column', function (containerElement, options) {
|
||||||
|
|
||||||
|
this.render = function () {
|
||||||
|
var metrics = options.metrics;
|
||||||
|
var plots = [options.label];
|
||||||
|
var categories = [];
|
||||||
|
|
||||||
|
for (var column_id in metrics) {
|
||||||
|
plots.push(metrics[column_id].average);
|
||||||
|
categories.push(metrics[column_id].title);
|
||||||
|
}
|
||||||
|
|
||||||
|
KB.el(containerElement).add(KB.el('div').attr('id', 'chart').build());
|
||||||
|
|
||||||
|
c3.generate({
|
||||||
|
data: {
|
||||||
|
columns: [plots],
|
||||||
|
type: 'bar'
|
||||||
|
},
|
||||||
|
bar: {
|
||||||
|
width: {
|
||||||
|
ratio: 0.5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axis: {
|
||||||
|
x: {
|
||||||
|
type: 'category',
|
||||||
|
categories: categories
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
tick: {
|
||||||
|
format: KB.utils.formatDuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
50
assets/js/components/chart-burndown.js
Normal file
50
assets/js/components/chart-burndown.js
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
KB.component('chart-burndown', function (containerElement, options) {
|
||||||
|
|
||||||
|
this.render = function () {
|
||||||
|
var metrics = options.metrics;
|
||||||
|
var columns = [[options.labelTotal]];
|
||||||
|
var categories = [];
|
||||||
|
var inputFormat = d3.time.format("%Y-%m-%d");
|
||||||
|
var outputFormat = d3.time.format(options.dateFormat);
|
||||||
|
|
||||||
|
for (var i = 0; i < metrics.length; i++) {
|
||||||
|
|
||||||
|
for (var j = 0; j < metrics[i].length; j++) {
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
columns.push([metrics[i][j]]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
columns[j + 1].push(metrics[i][j]);
|
||||||
|
|
||||||
|
if (j > 0) {
|
||||||
|
|
||||||
|
if (columns[0][i] == undefined) {
|
||||||
|
columns[0].push(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
columns[0][i] += metrics[i][j];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j == 0) {
|
||||||
|
categories.push(outputFormat(inputFormat.parse(metrics[i][j])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KB.el(containerElement).add(KB.el('div').attr('id', 'chart').build());
|
||||||
|
|
||||||
|
c3.generate({
|
||||||
|
data: {
|
||||||
|
columns: columns
|
||||||
|
},
|
||||||
|
axis: {
|
||||||
|
x: {
|
||||||
|
type: 'category',
|
||||||
|
categories: categories
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
49
assets/js/components/chart-cumulative-flow.js
Normal file
49
assets/js/components/chart-cumulative-flow.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
KB.component('chart-cumulative-flow', function (containerElement, options) {
|
||||||
|
|
||||||
|
this.render = function () {
|
||||||
|
var metrics = options.metrics;
|
||||||
|
var columns = [];
|
||||||
|
var groups = [];
|
||||||
|
var categories = [];
|
||||||
|
var inputFormat = d3.time.format("%Y-%m-%d");
|
||||||
|
var outputFormat = d3.time.format(options.dateFormat);
|
||||||
|
|
||||||
|
for (var i = 0; i < metrics.length; i++) {
|
||||||
|
|
||||||
|
for (var j = 0; j < metrics[i].length; j++) {
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
columns.push([metrics[i][j]]);
|
||||||
|
|
||||||
|
if (j > 0) {
|
||||||
|
groups.push(metrics[i][j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
columns[j].push(metrics[i][j]);
|
||||||
|
|
||||||
|
if (j == 0) {
|
||||||
|
categories.push(outputFormat(inputFormat.parse(metrics[i][j])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KB.el(containerElement).add(KB.el('div').attr('id', 'chart').build());
|
||||||
|
|
||||||
|
c3.generate({
|
||||||
|
data: {
|
||||||
|
columns: columns,
|
||||||
|
type: 'area-spline',
|
||||||
|
groups: [groups]
|
||||||
|
},
|
||||||
|
axis: {
|
||||||
|
x: {
|
||||||
|
type: 'category',
|
||||||
|
categories: categories
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
47
assets/js/components/chart-lead-cycle-time.js
Normal file
47
assets/js/components/chart-lead-cycle-time.js
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
KB.component('chart-lead-cycle-time', function (containerElement, options) {
|
||||||
|
|
||||||
|
this.render = function () {
|
||||||
|
var metrics = options.metrics;
|
||||||
|
var cycle = [options.labelCycle];
|
||||||
|
var lead = [options.labelLead];
|
||||||
|
var categories = [];
|
||||||
|
|
||||||
|
var types = {};
|
||||||
|
types[options.labelCycle] = 'area';
|
||||||
|
types[options.labelLead] = 'area-spline';
|
||||||
|
|
||||||
|
var colors = {};
|
||||||
|
colors[options.labelLead] = '#afb42b';
|
||||||
|
colors[options.labelCycle] = '#4e342e';
|
||||||
|
|
||||||
|
for (var i = 0; i < metrics.length; i++) {
|
||||||
|
cycle.push(parseInt(metrics[i].avg_cycle_time));
|
||||||
|
lead.push(parseInt(metrics[i].avg_lead_time));
|
||||||
|
categories.push(metrics[i].day);
|
||||||
|
}
|
||||||
|
|
||||||
|
KB.el(containerElement).add(KB.el('div').attr('id', 'chart').build());
|
||||||
|
|
||||||
|
c3.generate({
|
||||||
|
data: {
|
||||||
|
columns: [
|
||||||
|
lead,
|
||||||
|
cycle
|
||||||
|
],
|
||||||
|
types: types,
|
||||||
|
colors: colors
|
||||||
|
},
|
||||||
|
axis: {
|
||||||
|
x: {
|
||||||
|
type: 'category',
|
||||||
|
categories: categories
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
tick: {
|
||||||
|
format: KB.utils.formatDuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -1,18 +1,19 @@
|
|||||||
Vue.component('chart-project-task-distribution', {
|
KB.component('chart-project-task-distribution', function (containerElement, options) {
|
||||||
props: ['metrics'],
|
|
||||||
template: '<div id="chart"></div>',
|
this.render = function () {
|
||||||
ready: function () {
|
|
||||||
var columns = [];
|
var columns = [];
|
||||||
|
|
||||||
for (var i = 0; i < this.metrics.length; i++) {
|
for (var i = 0; i < options.metrics.length; i++) {
|
||||||
columns.push([this.metrics[i].column_title, this.metrics[i].nb_tasks]);
|
columns.push([options.metrics[i].column_title, options.metrics[i].nb_tasks]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KB.el(containerElement).add(KB.el('div').attr('id', 'chart').build());
|
||||||
|
|
||||||
c3.generate({
|
c3.generate({
|
||||||
data: {
|
data: {
|
||||||
columns: columns,
|
columns: columns,
|
||||||
type : 'donut'
|
type : 'donut'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
Vue.component('chart-project-time-comparison', {
|
KB.component('chart-project-time-comparison', function (containerElement, options) {
|
||||||
props: ['metrics', 'labelSpent', 'labelEstimated', 'labelClosed', 'labelOpen'],
|
|
||||||
template: '<div id="chart"></div>',
|
this.render = function () {
|
||||||
ready: function () {
|
var spent = [options.labelSpent];
|
||||||
var spent = [this.labelSpent];
|
var estimated = [options.labelEstimated];
|
||||||
var estimated = [this.labelEstimated];
|
|
||||||
var categories = [];
|
var categories = [];
|
||||||
|
|
||||||
for (var status in this.metrics) {
|
for (var status in options.metrics) {
|
||||||
spent.push(this.metrics[status].time_spent);
|
spent.push(options.metrics[status].time_spent);
|
||||||
estimated.push(this.metrics[status].time_estimated);
|
estimated.push(options.metrics[status].time_estimated);
|
||||||
categories.push(status === 'open' ? this.labelOpen : this.labelClosed);
|
categories.push(status === 'open' ? options.labelOpen : options.labelClosed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KB.el(containerElement).add(KB.el('div').attr('id', 'chart').build());
|
||||||
|
|
||||||
c3.generate({
|
c3.generate({
|
||||||
data: {
|
data: {
|
||||||
columns: [spent, estimated],
|
columns: [spent, estimated],
|
||||||
@@ -32,5 +33,5 @@ Vue.component('chart-project-time-comparison', {
|
|||||||
show: true
|
show: true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
Vue.component('chart-project-user-distribution', {
|
KB.component('chart-project-user-distribution', function (containerElement, options) {
|
||||||
props: ['metrics'],
|
|
||||||
template: '<div id="chart"></div>',
|
this.render = function () {
|
||||||
ready: function () {
|
|
||||||
var columns = [];
|
var columns = [];
|
||||||
|
|
||||||
for (var i = 0; i < this.metrics.length; i++) {
|
for (var i = 0; i < options.metrics.length; i++) {
|
||||||
columns.push([this.metrics[i].user, this.metrics[i].nb_tasks]);
|
columns.push([options.metrics[i].user, options.metrics[i].nb_tasks]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KB.el(containerElement).add(KB.el('div').attr('id', 'chart').build());
|
||||||
|
|
||||||
c3.generate({
|
c3.generate({
|
||||||
data: {
|
data: {
|
||||||
columns: columns,
|
columns: columns,
|
||||||
type : 'donut'
|
type : 'donut'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -180,20 +180,6 @@ Kanboard.App.prototype.hideLoadingIcon = function() {
|
|||||||
$("#app-loading-icon").remove();
|
$("#app-loading-icon").remove();
|
||||||
};
|
};
|
||||||
|
|
||||||
Kanboard.App.prototype.formatDuration = function(d) {
|
|
||||||
if (d >= 86400) {
|
|
||||||
return Math.round(d/86400) + "d";
|
|
||||||
}
|
|
||||||
else if (d >= 3600) {
|
|
||||||
return Math.round(d/3600) + "h";
|
|
||||||
}
|
|
||||||
else if (d >= 60) {
|
|
||||||
return Math.round(d/60) + "m";
|
|
||||||
}
|
|
||||||
|
|
||||||
return d + "s";
|
|
||||||
};
|
|
||||||
|
|
||||||
Kanboard.App.prototype.isVisible = function() {
|
Kanboard.App.prototype.isVisible = function() {
|
||||||
var property = "";
|
var property = "";
|
||||||
|
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
Kanboard.AvgTimeColumnChart = function(app) {
|
|
||||||
this.app = app;
|
|
||||||
};
|
|
||||||
|
|
||||||
Kanboard.AvgTimeColumnChart.prototype.execute = function() {
|
|
||||||
if (this.app.hasId("analytic-avg-time-column")) {
|
|
||||||
this.show();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Kanboard.AvgTimeColumnChart.prototype.show = function() {
|
|
||||||
var chart = $("#chart");
|
|
||||||
var metrics = chart.data("metrics");
|
|
||||||
var plots = [chart.data("label")];
|
|
||||||
var categories = [];
|
|
||||||
|
|
||||||
for (var column_id in metrics) {
|
|
||||||
plots.push(metrics[column_id].average);
|
|
||||||
categories.push(metrics[column_id].title);
|
|
||||||
}
|
|
||||||
|
|
||||||
c3.generate({
|
|
||||||
data: {
|
|
||||||
columns: [plots],
|
|
||||||
type: 'bar'
|
|
||||||
},
|
|
||||||
bar: {
|
|
||||||
width: {
|
|
||||||
ratio: 0.5
|
|
||||||
}
|
|
||||||
},
|
|
||||||
axis: {
|
|
||||||
x: {
|
|
||||||
type: 'category',
|
|
||||||
categories: categories
|
|
||||||
},
|
|
||||||
y: {
|
|
||||||
tick: {
|
|
||||||
format: this.app.formatDuration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
show: false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
Kanboard.BurndownChart = function(app) {
|
|
||||||
this.app = app;
|
|
||||||
};
|
|
||||||
|
|
||||||
Kanboard.BurndownChart.prototype.execute = function() {
|
|
||||||
if (this.app.hasId("analytic-burndown")) {
|
|
||||||
this.show();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Kanboard.BurndownChart.prototype.show = function() {
|
|
||||||
var chart = $("#chart");
|
|
||||||
var metrics = chart.data("metrics");
|
|
||||||
var columns = [[chart.data("label-total")]];
|
|
||||||
var categories = [];
|
|
||||||
var inputFormat = d3.time.format("%Y-%m-%d");
|
|
||||||
var outputFormat = d3.time.format(chart.data("date-format"));
|
|
||||||
|
|
||||||
for (var i = 0; i < metrics.length; i++) {
|
|
||||||
|
|
||||||
for (var j = 0; j < metrics[i].length; j++) {
|
|
||||||
|
|
||||||
if (i == 0) {
|
|
||||||
columns.push([metrics[i][j]]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
columns[j + 1].push(metrics[i][j]);
|
|
||||||
|
|
||||||
if (j > 0) {
|
|
||||||
|
|
||||||
if (columns[0][i] == undefined) {
|
|
||||||
columns[0].push(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
columns[0][i] += metrics[i][j];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (j == 0) {
|
|
||||||
categories.push(outputFormat(inputFormat.parse(metrics[i][j])));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c3.generate({
|
|
||||||
data: {
|
|
||||||
columns: columns
|
|
||||||
},
|
|
||||||
axis: {
|
|
||||||
x: {
|
|
||||||
type: 'category',
|
|
||||||
categories: categories
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
Kanboard.CumulativeFlowDiagram = function(app) {
|
|
||||||
this.app = app;
|
|
||||||
};
|
|
||||||
|
|
||||||
Kanboard.CumulativeFlowDiagram.prototype.execute = function() {
|
|
||||||
if (this.app.hasId("analytic-cfd")) {
|
|
||||||
this.show();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Kanboard.CumulativeFlowDiagram.prototype.show = function() {
|
|
||||||
var chart = $("#chart");
|
|
||||||
var metrics = chart.data("metrics");
|
|
||||||
var columns = [];
|
|
||||||
var groups = [];
|
|
||||||
var categories = [];
|
|
||||||
var inputFormat = d3.time.format("%Y-%m-%d");
|
|
||||||
var outputFormat = d3.time.format(chart.data("date-format"));
|
|
||||||
|
|
||||||
for (var i = 0; i < metrics.length; i++) {
|
|
||||||
|
|
||||||
for (var j = 0; j < metrics[i].length; j++) {
|
|
||||||
|
|
||||||
if (i == 0) {
|
|
||||||
columns.push([metrics[i][j]]);
|
|
||||||
|
|
||||||
if (j > 0) {
|
|
||||||
groups.push(metrics[i][j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
columns[j].push(metrics[i][j]);
|
|
||||||
|
|
||||||
if (j == 0) {
|
|
||||||
categories.push(outputFormat(inputFormat.parse(metrics[i][j])));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c3.generate({
|
|
||||||
data: {
|
|
||||||
columns: columns,
|
|
||||||
type: 'area-spline',
|
|
||||||
groups: [groups]
|
|
||||||
},
|
|
||||||
axis: {
|
|
||||||
x: {
|
|
||||||
type: 'category',
|
|
||||||
categories: categories
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
Kanboard.LeadCycleTimeChart = function(app) {
|
|
||||||
this.app = app;
|
|
||||||
};
|
|
||||||
|
|
||||||
Kanboard.LeadCycleTimeChart.prototype.execute = function() {
|
|
||||||
if (this.app.hasId("analytic-lead-cycle-time")) {
|
|
||||||
this.show();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Kanboard.LeadCycleTimeChart.prototype.show = function() {
|
|
||||||
var chart = $("#chart");
|
|
||||||
var metrics = chart.data("metrics");
|
|
||||||
var cycle = [chart.data("label-cycle")];
|
|
||||||
var lead = [chart.data("label-lead")];
|
|
||||||
var categories = [];
|
|
||||||
|
|
||||||
var types = {};
|
|
||||||
types[chart.data("label-cycle")] = 'area';
|
|
||||||
types[chart.data("label-lead")] = 'area-spline';
|
|
||||||
|
|
||||||
var colors = {};
|
|
||||||
colors[chart.data("label-lead")] = '#afb42b';
|
|
||||||
colors[chart.data("label-cycle")] = '#4e342e';
|
|
||||||
|
|
||||||
for (var i = 0; i < metrics.length; i++) {
|
|
||||||
cycle.push(parseInt(metrics[i].avg_cycle_time));
|
|
||||||
lead.push(parseInt(metrics[i].avg_lead_time));
|
|
||||||
categories.push(metrics[i].day);
|
|
||||||
}
|
|
||||||
|
|
||||||
c3.generate({
|
|
||||||
data: {
|
|
||||||
columns: [
|
|
||||||
lead,
|
|
||||||
cycle
|
|
||||||
],
|
|
||||||
types: types,
|
|
||||||
colors: colors
|
|
||||||
},
|
|
||||||
axis: {
|
|
||||||
x: {
|
|
||||||
type: 'category',
|
|
||||||
categories: categories
|
|
||||||
},
|
|
||||||
y: {
|
|
||||||
tick: {
|
|
||||||
format: this.app.formatDuration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -3,7 +3,8 @@
|
|||||||
var Kanboard = {};
|
var Kanboard = {};
|
||||||
|
|
||||||
var KB = {
|
var KB = {
|
||||||
components: {}
|
components: {},
|
||||||
|
utils: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
KB.component = function (name, object) {
|
KB.component = function (name, object) {
|
||||||
@@ -109,3 +110,17 @@ KB.el = function (tag) {
|
|||||||
|
|
||||||
return new DOMBuilder(tag);
|
return new DOMBuilder(tag);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
KB.utils.formatDuration = function(d) {
|
||||||
|
if (d >= 86400) {
|
||||||
|
return Math.round(d/86400) + "d";
|
||||||
|
}
|
||||||
|
else if (d >= 3600) {
|
||||||
|
return Math.round(d/3600) + "h";
|
||||||
|
}
|
||||||
|
else if (d >= 60) {
|
||||||
|
return Math.round(d/60) + "m";
|
||||||
|
}
|
||||||
|
|
||||||
|
return d + "s";
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user