Highcharts - Lazy loading combined with SQL queries - sql

Based on the Lazy Loading Example I wanted to create the similar function for my Highcharts.StockChart. But with the aid of Ajax.
Some words about the database structure:
Tables contains the values of 1 month
Column 'tijd' contains a timestamp
Values are posted every minute to the database, resolution = 1 minute
Please focus on why the zoom function isn't updating the chart. This drives me #!#
For the first time generation of the chart I use this code, which works fine
JAVASCRIPT:
function generateChart(param, options)
{
// EERST DE GESELECTEERDE GEGEVENS GAAN OPVRAGEN
data = param.join();
console.log(data);
t_min = new Date(2015, 0, 1, 0, 0, 0, 0);
t_max = Date.now();
console.log(t_min, t_max);
console.log((t_max - t_min) / 1000);
$.ajax({
url: url,
data: { "data": data, "db": klantnummer, "t_min": t_min, "t_max": t_max },
type: "POST",
async: false,
cache: false,
success:
function (gegevens)
{
// GEGEVENS OPSLAAN IN DE OPTIE.SERIES
console.log('Gegevens:');
console.log(gegevens); //werkt!
options.series = gegevens;
}
});
//EFFECTIEF AANMAKEN VAN DE GRAFIEK
chart = new Highcharts.StockChart(options);
}
PHP:
// READ THE COLUMN NAMES
$data_in = $_POST['data'];
// DATA_IN to array
$name = explode(",", $data_in);
// count the amount of columns
$c_name = count($name);
$name_sql = implode(", ", $name);
//Connection with database
$klantnummer = $_POST['db'];
require 'connectie.php';
//ZOOM: min and max values are converterd to PHP UNIX EPOCH time
$t_min = ($_POST['t_min'])/1000;
$t_max = ($_POST['t_max'])/1000;
$range = $t_max - $t_min;
//Doesn't work, don't need it to load the chart
//$startTime = $t_min->format('m-d-Y H:i:s');
//$stopTime = $t_max->format('m-d-Y H:i:s');
//we only ask a query if there are enough columns
if ($c_name > 0) {
//Ask the names of the tables from the database
$sql = "SELECT TABLE_NAME FROM information_schema.tables WHERE TABLE_NAME LIKE 'T%' ORDER BY TABLE_NAME DESC";
$tableName = sqlsrv_query($conn, $sql);
if ( $tableName === false ) {
die(print_r(sqlsrv_errors(), true));
};
$t = array();
while ($row = sqlsrv_fetch_array($tableName)) {
array_push($t, $row['TABLE_NAME']);
};
// So we know the range, which filter should we apply?
if ($range < 14 * 24 *3600) { //2 weeks
$tijdspanne = 2; // load 2 tables
$filter = 1; // show every minute
} elseif ($range < 28 * 24 *3600) { //4 weeks
$tijdspanne = 2; // load 2 tables
$filter = 5; // show every 5 minutes
} elseif ($range < 3 * 28 * 24 *3600) { //3 months
$tijdspanne = 4; // load 4 months
$filter = 15; // show every 15 minutes
} else {
$tijdspanne = count($t); // load every table
$filter = 60; // show every 60 minutes
}
//Namen zijn gekend, nu in query steken om daarna op te vragen
$sql = "select tijd,".$name_sql." FROM ".$t[0]." where datepart(mi,tijd) % ".$filter." = 0";// AND tijd BETWEEN ".$startTime." AND ".$stopTime;
for ($x = 1; $x < count($t) and $x < $tijdspanne ; ++$x ) {
$sql .= " union all select tijd,".$name_sql." FROM ".$t[$x]." where datepart(mi,tijd) % ".$filter." = 0";// AND tijd BETWEEN ".$startTime." AND ".$stopTime;
};
$sql .= " ORDER BY tijd";
//DATA from MS SQL server, save to arrays
$stmt = sqlsrv_query($conn, $sql);
if ( $stmt === false ) {
die(print_r(sqlsrv_errors(), true));
}
while ($row = sqlsrv_fetch_array($stmt)) {
$tijd_U = $row["0"]->format("U");
$tijd = ($tijd_U) * 1000; //date format to javascript
for ($i = 0; $i < $c_name; ++$i) {
$j = $i +1;
$data[$i][]= array($tijd, $row[$j]);
}
}
// prepare JSON format
$data_output = array();
for ($i = 0; $i < $c_name; ++$i) {
$data_output[$i] = array('name' => $name[$i], 'data' => $data[$i]);
}
}
// admit we use JSON
header('Content-Type: application/json');
// send the data to the user
echo json_encode($data_output, JSON_NUMERIC_CHECK);
So this code works, but when the user zooms in. The graph doens't update.
JAVASCRIPT:
function afterSetExtremes(e)
{
console.log(Math.round(e.min));
chart.showLoading('Loading data from server...');
$.ajax({
url: url,
data: { "data": data, "db": klantnummer, "t_min": Math.round(e.min), "t_max": Math.round(e.max) },
type: "POST",
async: false,
cache: false,
success:
function (gegevens)
{
// GEGEVENS OPSLAAN IN DE OPTIE.SERIES
console.log('Gegevens:');
console.log(gegevens); //werkt!
options.series = gegevens;
}
});
chart.hideLoading();
}
With this set of options:
function generateChartOptions(div, ymax, ymin)
{
var options = {
navigator: {
adaptToUpdatedData: false,
series: {
includeInCSVExport: false
}
},
chart: {
renderTo: div,
type: 'line',
zoomType: 'x'
},
rangeSelector: {
buttons: [{
type: 'day',
count: 1,
text: '1d'
}, {
type: 'week',
count: 1,
text: '1w'
}, {
type: 'week',
count: 2,
text: '2w'
}, {
type: 'all',
text: 'All'
}],
selected: 4,
inputBoxWidth: 150,
inputDateFormat: '%d-%m-%Y %H:%M',
inputEditDateFormat: '%d-%m-%Y %H:%M'
},
legend: {
enabled: true
},
xAxis: {
type: 'datetime',
events: {
afterSetExtremes: afterSetExtremes,
setExtremes: function (e)
{
$('#testveld').html('<b>Set extremes:</b> e.min: ' + Highcharts.dateFormat(null, e.min) +
' | e.max: ' + Highcharts.dateFormat(null, e.max) + ' | e.trigger: ' + e.trigger);
}
},
minRange: 60 * 1000 //1 minuut
},
yAxis: {
opposite: false,
max: ymax,
min: ymin
},
plotOptions: {
line: {
tooltip: {
valueDecimals: 1
}
}
},
scrollbar: {
liveRedraw: false
},
series: [{}]
};
return options;
}

Related

How to add a subtotal column in Datatables

My last question was related to the sum of columns (vertically) and now I need to sum the values of the columns (horizontally)
What I've tried:
I've tried iterating all columns table.columns().data() and sum the values but I do not know how to "inject" the result of the sum in the last column.
Desired result:
Sub Total is the result of: 3+4+5+6+7+8+9+10+11+12
LIVE JS BIN
Here is your JS code with your old code. You can also see it from here
<script>
$(document).ready(function() {
var DT1 = $('#example').DataTable({
columnDefs: [{
orderable: false,
className: 'select-checkbox',
targets: 0,
}],
select: {
style: 'os',
selector: 'td:first-child'
},
order: [
[1, 'asc']
],
"language": {
"info": "Showing _START_ to _END_ of _TOTAL_ Projects",
"infoEmpty": "Showing 0 to 0 of 0 Projects",
"infoFiltered": "(filtered from _MAX_ total Projects)"
},
"pagingType": "numbers",
dom: 'rtip',
initComplete: function(settings, json) {
// calculate the sum when table is first created:
doSum();
}
});
$('#example').on('draw.dt', function() {
// re-calculate the sum whenever the table is re-displayed:
doSum();
});
$(".selectAll").on("click", function(e) {
if ($(this).is(":checked")) {
DT1.rows().select();
} else {
DT1.rows().deselect();
}
});
// This provides the sum of all records:
function doSum() {
// get the DataTables API object:
var table = $('#example').DataTable();
// set up the initial (unsummed) data array for the footer row:
var totals = ['', 'Total:', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
// iterate all rows - use table.rows( {search: 'applied'} ).data()
// if you want to sum only filtered (visible) rows:
totals = table.rows().data()
// sum the amounts:
.reduce(function(sum, record) {
for (let i = 2; i <= 12; i++) {
sum[i] = sum[i] + numberFromString(record[i]);
}
return sum;
}, totals);
// place the sum in the relevant footer cell:
for (let i = 1; i <= 12; i++) {
var column = table.column(i);
$(column.footer()).html(formatNumber(totals[i]));
}
$('#example > tbody > tr').each(function(index, tr) {
var rowSum = 0;
for (let j = 0; j < 12; j++) {
if (j >= 2) {
var tdCellValue = numberFromString(tr.cells[j].innerText);
rowSum = rowSum + tdCellValue;
}
if (j >= 11) {
tr.cells[12].innerText = rowSum;
}
}
});
$('#example > tfoot > tr').each(function(index, tr) {
var rowSum = 0;
for (let j = 0; j < 12; j++) {
if (j >= 2) {
var tdCellValue = numberFromString(tr.cells[j].innerText);
rowSum = rowSum + tdCellValue;
}
if (j >= 11) {
tr.cells[12].innerText = rowSum;
}
}
});
}
function numberFromString(s) {
return typeof s === 'string' ?
s.replace(/[\$,]/g, '') * 1 :
typeof s === 'number' ?
s : 0;
}
function formatNumber(n) {
return n.toLocaleString(); // or whatever you prefer here
}
});
</script>

setInterval doesn't fire in vue

im learning vue and setInterval doesn't work like in normal javascript? the problem is that my update function doesn't get fired.
start gets fired from a button, and hours/minutes/seconds are bound to input fields with v-model, i get all console.logs before the setInterval.
export default Vue.extend({
name: "timer-c",
data() {
return {
startDate: undefined,
hours: "",
minutes: "",
seconds: "",
timeLeft: undefined,
endDate: undefined,
interval: undefined,
text: "00:00:00",
sub: undefined,
};
},
methods: {
start: function() {
if (this.sub === undefined) {
let sum = 0;
if (this.seconds.match(/^\d+$/)) {
sum = sum + this.seconds * 1000;
console.log(sum);
}
if (this.minutes.match(/^\d+$/)) {
sum = sum + this.minutes * 60 * 1000;
}
if (this.hours.match(/^\d+$/)) {
sum = sum + this.hours * 60 * 60 * 1000;
}
if (sum === 0) {
console.log(this.$refs.br_start);
this.failed = true;
} else {
console.log(sum);
this.failed = false;
this.endDate = new Date(Date.now() + sum);
console.log(this.endDate);
this.startDate = new Date(Date.now());
console.log(this.startDate);
this.interval = setInterval(time => this.update, 1000);
//this.sub = this.interval.subscribe(time => this.update(time));
}
}
},
update: function() {
console.log('test');
const timeRemaining = Math.round((Date.now() - this.endDate) / 1000);
this.text = timeRemaining;
if (new Date(Date.now()) >= this.endDate) {
console.log("test");
}
},
Try to not return the function but execute it
this.interval = setInterval(time => { this.update(time) }, 1000);

Dynamically update lines in Highcharts time series chart

Here I'm working on Highcharts time series chart with live streaming data, based on the sample jsfiddle. In the fiddle there shows 4 lines named as input1, input2, input3, & input 4 and it is updated with live random data but in my actual project the input values are updated via MQTT. In actual project, sometimes, when we push streaming data, there will be increase or decrease in no: of inputs (such as input5, input6 like wise). So how can we add new line or remove line dynamically in time series chart with streaming data.
javascript code :
$(function() {
$(document).ready(function() {
Highcharts.setOptions({
global: {
useUTC: false
}
});
$('#container').highcharts({
chart: {
type: 'spline',
animation: Highcharts.svg, // don't animate in old IE
marginRight: 10,
events: {
load: function() {
// set up the updating of the chart each second
var series = this.series;
var length = series.length;
setInterval(function() {
var x = (new Date()).getTime(), // current time
a0 = Math.random();
a1 = Math.random();
a2 = Math.random();
series[0].addPoint([x, Math.random()], true, true);
for (var i = 1; i < length; i++) {
series[i].addPoint([x, Math.random()], false, true);
}
}, 1000);
}
}
},
title: {
text: 'Live random data'
},
legend: {
enabled: true
},
xAxis: {
type: 'datetime',
tickPixelInterval: 150
},
yAxis: {
title: {
text: 'Value'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
formatter: function() {
return '<b>' + this.series.name + '</b><br/>' +
Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) + '<br/>' +
Highcharts.numberFormat(this.y, 2);
}
},
exporting: {
enabled: false
},
series: [{
name: 'input1',
data: (function() {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
for (i = -19; i <= 0; i += 1) {
data.push({
x: time + i * 1000,
y: Math.random()
});
}
return data;
}())
}, {
name: 'input2',
data: (function() {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
for (i = -19; i <= 0; i += 1) {
data.push({
x: time + i * 1000,
y: Math.random()
});
}
return data;
}())
}, {
name: 'input3',
data: (function() {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
for (i = -19; i <= 0; i += 1) {
data.push({
x: time + i * 1000,
y: Math.random()
});
}
return data;
}())
}, {
name: 'input4',
data: (function() {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
for (i = -19; i <= 0; i += 1) {
data.push({
x: time + i * 1000,
y: Math.random()
});
}
return data;
}())
}]
});
});
});

Pivot data dynamically for google line chart

I want to display "population" of various countries through the years in the same line chart. The data displayed is based on selections from a multi-select dropdown "Countries". Underlying Data Table has 3 columns:
Year, Country, Population
2012,countryA,33
2013,countryA,35
2014,countryA,40
2012,countryB,65
2013,countryB,70
2014,countryB,75
2012,countryC,15
2013,countryC,20
2014,countryC,25
I am trying to create a pivoted Data View from the underlying Data Table
The code I am using is:
function drawLineChart() {
var arr = $('#country').val();
var lineChartJson = $.ajax({
url: "../json/lineChart.json",
dataType: "json",
async: false
}).responseText;
var lineChartData = new google.visualization.DataTable(lineChartJson);
var view = new google.visualization.DataView(lineChartData);
var viewCols = [0];
for(var i = 0; i < arr.length; i++) {
var viewCols1 = [{
type: 'number',
label: arr[i],
calc: function (dt, row) {
return (dt.getValue(row, 1) == arr[i]) ? dt.getValue(row, 2) : null;
}
}];
viewCols = viewCols.concat(viewCols1);
}
view.setColumns(viewCols);
var aggCols = [{
column: 1,
type: 'number',
label: view.getColumnLabel(1),
aggregation: google.visualization.data.sum
}];
for(var i = 2; i < 4; i++) {
var aggCols1 = [{
column: i,
type: 'number',
label: view.getColumnLabel(i),
aggregation: google.visualization.data.sum
}];
aggCols = aggCols.concat(aggCols1);
}
var pivotedData = google.visualization.data.group(view, [0], aggCols);
But this does not seem to work as expected and I just get 1 Line in the chart with values for all countries added up (although I can see the legend for 3 countries)
On the other hand if I set my View columns as below, it works as expected.
view.setColumns([0, {
type: 'number',
label: arr[0],
calc: function (dt, row) {
return (dt.getValue(row, 1) == arr[0]) ? dt.getValue(row, 2) : null;
}
}, {
type: 'number',
label: arr[1],
calc: function (dt, row) {
// return values of C only for the rows where B = "bar"
return (dt.getValue(row, 1) == arr[1]) ? dt.getValue(row, 2) : null;
}
}, {
type: 'number',
label: arr[2],
calc: function (dt, row) {
return (dt.getValue(row, 1) == arr[2]) ? dt.getValue(row, 2) : null;
}
}]);
What is going wrong in the loop? Is something wrong with "concat" in the loop where I am creating View Columns? I also saw the viewCols array by using console.log and it seems to have the right elements
I was trying to follow the below post:
Creating pivoted DataView from existing google charts DataTable object
the problem has to do with scope
arr[i] is undefined within calc: function (dt, row)
here is another way to pivot the data...
google.charts.load('current', {
callback: function () {
var arr = [
'countryA',
'countryB',
'countryC'
];
var lineChartData = google.visualization.arrayToDataTable([
['Year', 'Country', 'Population'],
[2012,'countryA',33],
[2013,'countryA',35],
[2014,'countryA',40],
[2012,'countryB',65],
[2013,'countryB',70],
[2014,'countryB',75],
[2012,'countryC',15],
[2013,'countryC',20],
[2014,'countryC',25]
]);
// sort by year
lineChartData.sort([{column: 0}]);
// get unique countries
var countryGroup = google.visualization.data.group(
lineChartData,
[1]
);
// build country data table
var countryData = new google.visualization.DataTable({
cols: [
{label: 'Year', type: 'number'},
]
});
// add column for each country
for (var i = 0; i < countryGroup.getNumberOfRows(); i++) {
countryData.addColumn(
{label: countryGroup.getValue(i, 0), type: 'number'}
);
}
// add row for each year / country
var rowYear;
var rowIndex;
for (var i = 0; i < lineChartData.getNumberOfRows(); i++) {
if (rowYear !== lineChartData.getValue(i, 0)) {
rowYear = lineChartData.getValue(i, 0);
rowIndex = countryData.addRow();
countryData.setValue(rowIndex, 0, rowYear);
}
for (var x = 1; x < countryData.getNumberOfColumns(); x++) {
if (countryData.getColumnLabel(x) === lineChartData.getValue(i, 1)) {
countryData.setValue(rowIndex, x, lineChartData.getValue(i, 2));
}
}
}
// draw agg table
new google.visualization.ChartWrapper({
chartType: 'Table',
containerId: 'table-div',
dataTable: countryData
}).draw();
// draw line chart
new google.visualization.ChartWrapper({
chartType: 'LineChart',
containerId: 'chart-div',
dataTable: countryData
}).draw();
},
packages: ['corechart', 'table']
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="table-div"></div>
<div id="chart-div"></div>
I could figure out the problem with my code above.
"calc" is the callback function in loop. So only last value of loop variable "i" is visible within the loop.
Putting a wrapper function fixes it:
for(var i = 0; i <= arr.length; i++)(function(i) {
var viewCols1 = [{
type: 'number',
label: arr[i],
calc: function (dt, row) {
return (dt.getValue(row, 1) == arr[i]) ? dt.getValue(row, 2) : null;
}
}];
viewCols = viewCols.concat(viewCols1);
})(i);

On my cardboard app trying to show total of all features actual points for each column(Release) on the header, but that is not getting displayed

On my cardboard app trying to show total of all features actual points for each column(Release) on the header, but that is not getting displayed.
See the image below the cards are my portfolioitem/feature, in particular release.
On each header with release information, below progress-bar I want to show total of all features actual points in that release.
Below is the code for that, I am not getting why actual_points are not getting displayed. I am doing something wrong, but I don't know where exactly it is
Ext.override(Rally.ui.cardboard.CardBoard,{
_buildColumnsFromModel: function() {
var me = this;
var model = this.models[0];
if (model) {
if ( this.attribute === "Release" ) {
var retrievedColumns = [];
retrievedColumns.push({
value: null,
columnHeaderConfig: {
headerTpl: "{name}",
headerData: {
name: "Backlog"
}
}
});
this._getLocalReleases(retrievedColumns, this.globalVar);
}
}
},
_getLocalReleases: function(retrievedColumns, today_iso) {
var me = this;
if (today_iso == undefined) {
today_iso = Rally.util.DateTime.toIsoString(new Date(),false);
}
var filters = [{property:'ReleaseDate',operator:'>',value:today_iso}];
var iteration_names = [];
Ext.create('Rally.data.WsapiDataStore',{
model:me.attribute,
autoLoad: true,
filters: filters,
context: { projectScopeUp: false, projectScopeDown: false },
sorters: [
{
property: 'ReleaseDate',
direction: 'ASC'
}
],
//limit: Infinity,
pageSize: 4,
//buffered: true,
//purgePageCount: 4,
fetch: ['Name','ReleaseStartDate','ReleaseDate','PlannedVelocity'],
listeners: {
load: function(store,records) {
Ext.Array.each(records, function(record){
console.log("records values", records);
var start_date = Rally.util.DateTime.formatWithNoYearWithDefault(record.get('ReleaseStartDate'));
var end_date = Rally.util.DateTime.formatWithNoYearWithDefault(record.get('ReleaseDate'));
//this._getMileStones(record.get('ReleaseStartDate'), record.get('ReleaseDate'), this.project);
iteration_names.push(record.get('Name'));
//iteration_names.push(record.get('ReleaseDate'));
retrievedColumns.push({
value: record,
_planned_velocity: 0,
_actual_points: 0,
_missing_estimate: false,
columnHeaderConfig: {
headerTpl: "{name}<br/>{start_date} - {end_date}",
headerData: {
name: record.get('Name'),
start_date: start_date,
end_date: end_date,
planned_velocity: 0,
actual_points: 0,
missing_estimate: false
}
}
});
});
this._getAllReleases(retrievedColumns,iteration_names);
},
scope: this
}
});
},
_getAllReleases: function(retrievedColumns,iteration_names, today_iso) {
var me = this;
if (today_iso == undefined) {
today_iso = Rally.util.DateTime.toIsoString(new Date(),false);
}
var filters = [{property:'ReleaseDate',operator:'>',value:today_iso}];
Ext.create('Rally.data.WsapiDataStore',{
model:me.attribute,
autoLoad: true,
filters: filters,
sorters: [
{
property: 'ReleaseDate',
direction: 'ASC'
}
],
fetch: ['Name','Project','PlannedVelocity'],
listeners: {
load: function(store,records) {
Ext.Array.each(records, function(record){
var planned_velocity = record.get('PlannedVelocity') || 0;
var actual_points = record.get('LeafStoryPlanEstimateTotal') || 0;
var index = Ext.Array.indexOf(iteration_names[0],record.get('Name'));
if (planned_velocity == 0 ) {
retrievedColumns[index+1]._missing_estimate = true;
}
retrievedColumns[index+1]._actual_points += actual_points;
retrievedColumns[index+1]._planned_velocity += planned_velocity;
});
this.fireEvent('columnsretrieved',this,retrievedColumns);
this.columnDefinitions = [];
_.map(retrievedColumns,this.addColumn,this);
this._renderColumns();
},
scope: this
}
});
}
});
Ext.define('Rally.technicalservices.plugin.ColumnHeaderUpdater', {
alias: 'plugin.tscolumnheaderupdater',
extend: 'Ext.AbstractPlugin',
config: {
/**
*
* #type {String} The name of the field holding the card's estimate
*
* Defaults to c_FeatureEstimate (try LeafStoryPlanEstimateTotal)
*/
field_to_aggregate: "planned_velocity",
/**
* #property {Number} The current count of feature estimates
*/
total_feature_estimate: 0,
fieldToDisplay: "actual_points",
/**
* #property {String|Ext.XTemplate} the header template to use
*/
headerTpl: new Rally.technicalservices.template.LabeledProgressBarTemplate({
fieldLabel: 'Features Planned vs Planned Velocity: ',
calculateColorFn: function(data) {
if ( data.percentDone > 0.9 ) {
return '#EDB5B1';
}
return '#99CCFF';
},
showDangerNotificationFn: function(data) {
return data.missing_estimate;
},
generateLabelTextFn: function(data) {
if ( data.percentDone === -1 ) {
return "No Planned Velocity";
} else {
var text_string = "";
if ( data.field_to_aggregate === "planned_velocity" ) {
text_string = this.calculatePercent(data) + '%';
} else {
text_string = 'By Story: ' + this.calculatePercent(data) + '%';
}
return text_string;
}
}
})
//headerTpl: '<div class="wipLimit">({total_feature_estimate} of {planned_velocity})</div>'
},
constructor: function(config) {
this.callParent(arguments);
if(Ext.isString(this.headerTpl)) {
this.headerTpl = Ext.create('Ext.XTemplate', this.headerTpl);
}
},
init: function(column) {
this.column = column;
if ( column.value === null ) {
this.headerTpl = new Ext.XTemplate('');
}
this.planned_velocity = this.column._planned_velocity;
this.missing_estimate = this.column._missing_estimate;
this.actual_points = this.column._actual_points;
this.column.on('addcard', this.recalculate, this);
this.column.on('removecard', this.recalculate, this);
this.column.on('storeload', this.recalculate, this);
this.column.on('afterrender', this._afterRender, this);
this.column.on('ready', this.recalculate, this);
this.column.on('datachanged', this.recalculate, this);
},
destroy: function() {
if(this.column) {
delete this.column;
}
},
_afterRender: function() {
if ( this.feature_estimate_container ) {
this.feature_estimate_container.getEl().on('click', this._showPopover, this);
}
},
recalculate: function() {
this.total_feature_estimate = this.getTotalFeatureEstimate();
this.refresh();
},
refresh: function() {
var me = this;
if (this.feature_estimate_container) {
this.feature_estimate_container.update(this.headerTpl.apply(this.getHeaderData()));
} else {
this.feature_estimate_container = Ext.widget({
xtype: 'container',
html: this.headerTpl.apply(this.getHeaderData())
});
this.column.getColumnHeader().getHeaderTitle().add(this.feature_estimate_container);
}
if ( this.feature_estimate_container && this.feature_estimate_container.getEl()) {
this.feature_estimate_container.getEl().on('click', this._showPopover, this);
}
},
_showPopover: function() {
var me = this;
if ( me.planned_velocity > 0 ) {
if ( this.popover ) { this.popover.destroy(); }
this.popover = Ext.create('Rally.ui.popover.Popover',{
target: me.column.getColumnHeader().getHeaderTitle().getEl(),
items: [ me.getSummaryGrid() ]
});
this.popover.show();
}
},
getSummaryGrid: function() {
var me = this;
var estimate_title = "Feature Estimates";
if ( this.field_to_aggregate !== "c_FeatureEstimate") {
estimate_title = "Story Estimates";
}
var store = Ext.create('Rally.data.custom.Store',{
data: [
{
'PlannedVelocity': me.planned_velocity,
'ActualPoints': me.actual_points,
'TotalEstimate': me.getTotalFeatureEstimate(),
'Remaining': me.getCapacity(),
'MissingEstimate': me.missing_estimate
}
]
});
var grid = Ext.create('Rally.ui.grid.Grid',{
store: store,
columnCfgs: [
{ text: 'Plan', dataIndex:'PlannedVelocity' },
{ text: estimate_title, dataIndex: 'TotalEstimate' },
{ text: 'Remaining', dataIndex: 'Remaining' },
{ text: 'Team Missing Plan?', dataIndex: 'MissingEstimate' }
],
showPagingToolbar: false
});
return grid;
},
getHeaderData: function() {
var total_feature_estimate = this.getTotalFeatureEstimate();
actual_points = 0;
var percent_done = -1;
planned_velocity = 20;
if ( planned_velocity > 0 ) {
percent_done = total_feature_estimate / 4;
}
return {
actual_points: actual_points,
total_feature_estimate: total_feature_estimate,
planned_velocity: planned_velocity,
percentDone: percent_done,
field_to_aggregate: this.field_to_aggregate,
missing_estimate: this.missing_estimate
};
},
getCapacity: function() {
return this.planned_velocity - this.getTotalFeatureEstimate();
},
getTotalFeatureEstimate: function() {
var me = this;
var total = 0;
var total_unaligned = 0;
var records = this.column.getRecords();
Ext.Array.each(records, function(record){
var total_points = record.get('AcceptedLeafStoryPlanEstimateTotal');
var feature_estimate = record.get(me.field_to_aggregate) || 0;
var unaligned_estimate = record.get('UnalignedStoriesPlanEstimateTotal') || 0;
total += parseFloat(total_points,10);
});
if ( me.field_to_aggregate !== "planned_velocity" ) {
total = total
}
return total;
}
});