Use components to render charts
This commit is contained in:
parent
a3bb27109d
commit
8976f4d15c
|
|
@ -12,6 +12,18 @@ use Kanboard\Core\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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -5,25 +5,25 @@
|
|||
<?php if (empty($metrics)): ?>
|
||||
<p class="alert"><?= t('Not enough data to show the graph.') ?></p>
|
||||
<?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">
|
||||
<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>
|
||||
|
||||
<p class="alert alert-info">
|
||||
<?= t('This chart show the average time spent into each column for the last %d tasks.', 1000) ?>
|
||||
</p>
|
||||
</section>
|
||||
<p class="alert alert-info">
|
||||
<?= t('This chart show the average time spent into each column for the last %d tasks.', 1000) ?>
|
||||
</p>
|
||||
<?php endif ?>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,11 @@
|
|||
<?php if (! $display_graph): ?>
|
||||
<p class="alert"><?= t('You need at least 2 days of data to show the chart.') ?></p>
|
||||
<?php else: ?>
|
||||
<section id="analytic-burndown">
|
||||
<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>
|
||||
</section>
|
||||
<?= $this->app->component('chart-burndown', array(
|
||||
'metrics' => $metrics,
|
||||
'labelTotal' => t('Total for all columns'),
|
||||
'dateFormat' => e('%%Y-%%m-%%d'),
|
||||
)) ?>
|
||||
<?php endif ?>
|
||||
|
||||
<hr/>
|
||||
|
|
|
|||
|
|
@ -5,9 +5,10 @@
|
|||
<?php if (! $display_graph): ?>
|
||||
<p class="alert"><?= t('You need at least 2 days of data to show the chart.') ?></p>
|
||||
<?php else: ?>
|
||||
<section id="analytic-cfd">
|
||||
<div id="chart" data-metrics='<?= json_encode($metrics, JSON_HEX_APOS) ?>' data-date-format="<?= e('%%Y-%%m-%%d') ?>"></div>
|
||||
</section>
|
||||
<?= $this->app->component('chart-cumulative-flow', array(
|
||||
'metrics' => $metrics,
|
||||
'dateFormat' => e('%%Y-%%m-%%d'),
|
||||
)) ?>
|
||||
<?php endif ?>
|
||||
|
||||
<hr/>
|
||||
|
|
|
|||
|
|
@ -12,29 +12,30 @@
|
|||
<?php if (empty($metrics)): ?>
|
||||
<p class="alert"><?= t('Not enough data to show the graph.') ?></p>
|
||||
<?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">
|
||||
<?= $this->form->date(t('Start date'), 'from', $values) ?>
|
||||
</div>
|
||||
<div class="form-inline-group">
|
||||
<?= $this->form->date(t('End date'), 'to', $values) ?>
|
||||
</div>
|
||||
|
||||
<div class="form-inline-group">
|
||||
<?= $this->form->date(t('End date'), 'to', $values) ?>
|
||||
</div>
|
||||
<div class="form-inline-group">
|
||||
<button type="submit" class="btn btn-blue"><?= t('Execute') ?></button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="form-inline-group">
|
||||
<button type="submit" class="btn btn-blue"><?= t('Execute') ?></button>
|
||||
</div>
|
||||
</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>
|
||||
<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>
|
||||
<?php endif ?>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@
|
|||
<?php if (empty($metrics)): ?>
|
||||
<p class="alert"><?= t('Not enough data to show the graph.') ?></p>
|
||||
<?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">
|
||||
<tr>
|
||||
|
|
|
|||
|
|
@ -15,13 +15,13 @@
|
|||
<?php if ($paginator->isEmpty()): ?>
|
||||
<p class="alert"><?= t('No tasks found.') ?></p>
|
||||
<?php elseif (! $paginator->isEmpty()): ?>
|
||||
<chart-project-time-comparison
|
||||
:metrics='<?= json_encode($metrics, JSON_HEX_APOS)?>'
|
||||
label-spent="<?= t('Hours Spent') ?>"
|
||||
label-estimated="<?= t('Hours Estimated') ?>"
|
||||
label-closed="<?= t('Closed') ?>"
|
||||
label-open="<?= t('Open') ?>">
|
||||
</chart-project-time-comparison>
|
||||
<?= $this->app->component('chart-project-time-comparison', array(
|
||||
'metrics' => $metrics,
|
||||
'labelSpent' => t('Hours Spent'),
|
||||
'labelEstimated' => t('Hours Estimated'),
|
||||
'labelClosed' => t('Closed'),
|
||||
'labelOpen' => t('Open'),
|
||||
)) ?>
|
||||
|
||||
<table class="table-fixed table-small table-scrolling">
|
||||
<tr>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@
|
|||
<?php if (empty($metrics)): ?>
|
||||
<p class="alert"><?= t('Not enough data to show the graph.') ?></p>
|
||||
<?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">
|
||||
<tr>
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -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
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
|
|
@ -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', {
|
||||
props: ['metrics'],
|
||||
template: '<div id="chart"></div>',
|
||||
ready: function () {
|
||||
KB.component('chart-project-task-distribution', function (containerElement, options) {
|
||||
|
||||
this.render = function () {
|
||||
var columns = [];
|
||||
|
||||
for (var i = 0; i < this.metrics.length; i++) {
|
||||
columns.push([this.metrics[i].column_title, this.metrics[i].nb_tasks]);
|
||||
for (var i = 0; i < options.metrics.length; i++) {
|
||||
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({
|
||||
data: {
|
||||
columns: columns,
|
||||
type : 'donut'
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,17 +1,18 @@
|
|||
Vue.component('chart-project-time-comparison', {
|
||||
props: ['metrics', 'labelSpent', 'labelEstimated', 'labelClosed', 'labelOpen'],
|
||||
template: '<div id="chart"></div>',
|
||||
ready: function () {
|
||||
var spent = [this.labelSpent];
|
||||
var estimated = [this.labelEstimated];
|
||||
KB.component('chart-project-time-comparison', function (containerElement, options) {
|
||||
|
||||
this.render = function () {
|
||||
var spent = [options.labelSpent];
|
||||
var estimated = [options.labelEstimated];
|
||||
var categories = [];
|
||||
|
||||
for (var status in this.metrics) {
|
||||
spent.push(this.metrics[status].time_spent);
|
||||
estimated.push(this.metrics[status].time_estimated);
|
||||
categories.push(status === 'open' ? this.labelOpen : this.labelClosed);
|
||||
for (var status in options.metrics) {
|
||||
spent.push(options.metrics[status].time_spent);
|
||||
estimated.push(options.metrics[status].time_estimated);
|
||||
categories.push(status === 'open' ? options.labelOpen : options.labelClosed);
|
||||
}
|
||||
|
||||
KB.el(containerElement).add(KB.el('div').attr('id', 'chart').build());
|
||||
|
||||
c3.generate({
|
||||
data: {
|
||||
columns: [spent, estimated],
|
||||
|
|
@ -32,5 +33,5 @@ Vue.component('chart-project-time-comparison', {
|
|||
show: true
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,18 +1,19 @@
|
|||
Vue.component('chart-project-user-distribution', {
|
||||
props: ['metrics'],
|
||||
template: '<div id="chart"></div>',
|
||||
ready: function () {
|
||||
KB.component('chart-project-user-distribution', function (containerElement, options) {
|
||||
|
||||
this.render = function () {
|
||||
var columns = [];
|
||||
|
||||
for (var i = 0; i < this.metrics.length; i++) {
|
||||
columns.push([this.metrics[i].user, this.metrics[i].nb_tasks]);
|
||||
for (var i = 0; i < options.metrics.length; i++) {
|
||||
columns.push([options.metrics[i].user, options.metrics[i].nb_tasks]);
|
||||
}
|
||||
|
||||
KB.el(containerElement).add(KB.el('div').attr('id', 'chart').build());
|
||||
|
||||
c3.generate({
|
||||
data: {
|
||||
columns: columns,
|
||||
type : 'donut'
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -180,20 +180,6 @@ Kanboard.App.prototype.hideLoadingIcon = function() {
|
|||
$("#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() {
|
||||
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 KB = {
|
||||
components: {}
|
||||
components: {},
|
||||
utils: {}
|
||||
};
|
||||
|
||||
KB.component = function (name, object) {
|
||||
|
|
@ -109,3 +110,17 @@ KB.el = function (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";
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue