Not sure if this is possible. In my example I am using json as the source but this could be any size. In my example on fiddle I would use this data in a shared fashion by only binding two columns ProductFamily (xAxis) and Value (yAxis) but I would like to be able to group the columns by using an aggregate.
In this example without the grouping it shows multiple columns for FamilyA. Can this be grouped into ONE column and the values aggregated regardless of the amount of data?
So the result will show one column for FamilyA of Value 4850 + 4860 = 9710 etc.?
A problem with all examples online is that there is always the correct amount of data for each category. Not sure if this makes sense?
http://jsfiddle.net/jqIndy/ZPUr4/3/
//Sample data (see fiddle for complete sample)
[{
"Client":"",
"Date":"2011-06-01",
"ProductNumber":"5K190",
"ProductName":"CABLE USB",
"ProductFamily":"FamilyC",
"Status":"OPEN",
"Units":5000,
"Value":5150.0,
"ShippedToDestination":"CHINA"
}]
var productDataSource = new kendo.data.DataSource({
data: dr,
//group: {
// field: "ProductFamily",
//},
sort: {
field: "ProductFamily",
dir: "asc"
},
//aggregate: [
// { field: "Value", aggregate: "sum" }
//],
//schema: {
// model: {
// fields: {
// ProductFamily: { type: "string" },
// Value: { type: "number" },
// }
// }
//}
})
$("#product-family-chart").kendoChart({
dataSource: productDataSource,
//autoBind: false,
title: {
text: "Product Family (past 12 months)"
},
seriesDefaults: {
overlay: {
gradient: "none"
},
markers: {
visible: false
},
majorTickSize: 0,
opacity: .8
},
series: [{
type: "column",
field: "Value"
}],
valueAxis: {
line: {
visible: false
},
labels: {
format: "${0}",
skip: 2,
step: 2,
color: "#727f8e"
}
},
categoryAxis: {
field: "ProductFamily"
},
legend: {
visible: false
},
tooltip: {
visible: true,
format: "Value: ${0:N0}"
}
});
The Kendo UI Chart does not support binding to group aggregates. At least not yet.
My suggestion is to:
Move the aggregate definition, so it's calculated per group:
group: {
field: "ProductFamily",
aggregates: [ {
field: "Value",
aggregate: "sum"
}]
}
Extract the aggregated values in the change handler:
var view = products.view();
var families = $.map(view, function(v) {
return v.value;
});
var values = $.map(view, function(v) {
return v.aggregates.Value.sum;
});
Bind the groups and categories manually:
series: [ {
type: "column",
data: values
}],
categoryAxis: {
categories: families
}
Working demo can be found here: http://jsbin.com/ofuduy/5/edit
I hope this helps.
Related
I am using rally lookback API and creating a defect trend chart. I need to filter defects that do not have a tag "xyz".
Using the following:
this.myTrendChart = Ext.create('Rally.ui.chart.Chart', {
storeType: 'Rally.data.lookback.SnapshotStore',
storeConfig: {
find: {
_TypeHierarchy: "Defect",
State: { $lt: "Closed"},
Tags.Name: { $nin: ["xyz"] },
_ProjectHierarchy: projectOid,
_ValidFrom: {$gte: startDateUTC}
}
},
calculatorType: 'Calci',
calculatorConfig: {},
chartConfig: {
chart: {
zoomType: 'x',
type: 'line'
},
title: {
text: 'Defect trend'
},
xAxis: {
type: 'datetime',
minTickInterval: 7
},
yAxis: {
title: {
text: 'Number of Defects'
}
}
}
});
This does not return any data. Need help with the filter for tags.
Tags is a collection of tag-oids so you'll need to find and use the oid of the tag vs the name, at which point it'll just be Tags: { $nin: [oid] }. Caveat: technically, due to how expensive it is, $nin is unsupported (https://rally1.rallydev.com/analytics/doc/#/manual/48e0589f681160fc316a8a4802dc389f)...but it doesn't throw an error so maybe it works anyway.
I am trying to setup a filter that is similar to a defect view within a Trend chart. The filter in the defect view is:
(State < Closed) AND (Severity <= Major) AND (Tags !contains Not a Stop Ship)
I cannot seem to get the Tags find to work correctly. Any suggestions?
this.myTrendChart = Ext.create('Rally.ui.chart.Chart', {
storeType: 'Rally.data.lookback.SnapshotStore',
storeConfig: {
find: {
_TypeHierarchy: "Defect",
State: {
$lt: "Closed"
},
Severity: {
$lte: "Major"
},
Tags: {
$ne: "Not a Stop Ship"
},
_ProjectHierarchy: ProjectOid
},
hydrate: ["Priority"],
fetch: ["_ValidFrom", "_ValidTo", "ObjectID", "Priority"]
},
calculatorType: 'My.TrendCalc',
calculatorConfig: {},
chartConfig: {
chart: {
zoomType: 'x',
type: 'line'
},
title: {
text: 'Defects over Time'
},
xAxis: {
type: 'datetime',
minTickInterval: 3
},
yAxis: {
title: {
text: 'Number of Defects'
}
}
}
});
Based on reviewing the JSON messages, I figured out the tag needed to be the ObjectId. Once I found this, I replaced "Not a Stop Ship" with the ObjectId value and the filter worked correctly.
How do I control how many rows appear in a kendo grid? Real Estate is limited, so I need to have a lot of info in a pretty compact space. I'm trying to pack everything in my grid in a 300-pixel high area.
The issue I'm having is that all 200-plus rows of data that are being returned from my MVC JsonResult in my controller are displaying at once, on a single page. Not quite exactly what I'm looking for.
Code is below, if someone a little more knowledgeable about formatting a kendo grid could help out, I'd appreciate it.
Thanks!
-RC
{}
var RemoteJsonData_Call = new kendo.data.DataSource({
transport:
{
read: {
type: "GET",
dataType: "json",
url: resourceURL_Call
},
pageSizes: 8,
serverPaging: true
},
schema: {
model: {
ScheduleData: {
extensionDataField: {
fields: {
ScheduleDate: { type: "date" },
ScheduleAmount: { type: "number" },
SchedulePrice: { type: "number" },
ScheduleNotes: { type: "string" }
}
}
}
}
}
})
$('#callSched').kendoGrid({
height: '300',
sortable: true,
reorderable: true,
resizable: true,
pageable: {
numeric: true,
refresh: true,
pageSizes: true,
previousNext: true,
input: true,
info: true
},
columns: [
{
field: "ScheduleDate",
title: "Date",
template: "#= kendo.toString(kendo.parseDate(ScheduleDate, 'MM-dd-yyyy'), 'MM-dd-yyyy') #"
},
{
field: "ScheduleAmount",
title: "Amount",
},
{
field: "SchedulePrice",
title: "Price"
},
{
field: "ScheduleNotes",
title: "Notes"
}
], dataSource: RemoteJsonData_Call
});
{}
The problem is that you have defined that the paging is done in the server when it is not. You should say:
serverPaging: false
or just nothing since the default value is false.
With this you should have a grid with the number of pixels specified in the height option (in your example 300 pixels). Other options in you example are correct.
You have server paging and page size set up incorrectly here:
var RemoteJsonData_Call = new kendo.data.DataSource({
transport:
{
read: {
type: "GET",
dataType: "json",
url: resourceURL_Call
},
pageSizes: 8,
serverPaging: true
},
It should be:
var RemoteJsonData_Call = new kendo.data.DataSource({
transport:
{
read: {
type: "GET",
dataType: "json",
url: resourceURL_Call
}
},
pageSize: 8,
serverPaging: true
The config options were in the wrong place, and "pageSizes" was misspelled, it should be "pageSize" with no "s" on the end.
http://docs.telerik.com/kendo-ui/api/javascript/data/datasource#configuration-pageSize
I see that Hierarchical trees are labeled as experimental on the Rally site (https://help.rallydev.com/apps/2.0rc3/doc/#!/api/Rally.ui.grid.TreeGrid). I wanted to build an app using the hierarchical tree and I had a few questions about the features. Is it possible to filter the tree or no? Also can i add up the totals of the tasks for a given userstory (estimate, todo, actual, etc) and list that total as the userstory value? Is there another way to get a list of the userstories with the tasks in a list beneath it?
A not-treegrid example: this app that uses group and summary features in a grid of tasks in current iteration grouped by workproduct (user story), where Estimate values of individual tasks are summed up. Full code is in this github repo.
launch: function() {
var that = this;
var today = new Date().toISOString();
var stories = Ext.create('Rally.data.wsapi.Store', {
model: 'UserStory',
fetch: ['Tasks'],
filters: [
{
property: 'Iteration.StartDate',
operator: '<=',
value: today
},
{
property: 'Iteration.EndDate',
operator: '>=',
value: today
}
]
});
stories.load().then({
success: this.loadTasks,
scope: this
}).then({
success:function(results) {
that.makeGrid(results);
},
failure: function(){
console.log("oh noes!")
}
});
},
loadTasks: function(stories){
console.log("load tasks",stories)
var promises = [];
_.each(stories, function(story){
var tasks = story.get('Tasks');
if (tasks.Count > 0) {
tasks.store = story.getCollection('Tasks',{fetch:['Name','FormattedID','Estimate','State','Blocked','WorkProduct']});
promises.push(tasks.store.load());
}
});
return Deft.Promise.all(promises);
},
makeGrid: function(results){
var tasks = _.flatten(results);
var data = [];
_.each(tasks, function(task){
data.push(task.data);
})
_.each(data, function(record){
record.Story = record.WorkProduct.FormattedID + " " + record.WorkProduct.Name;;
})
this.add({
xtype: 'rallygrid',
showPagingToolbar: true,
showRowActionsColumn: true,
editable: false,
store: Ext.create('Rally.data.custom.Store', {
data: data,
groupField: 'Story',
}),
features: [{ftype:'groupingsummary'}],
columnCfgs: [
{
xtype: 'templatecolumn',text: 'ID',dataIndex: 'FormattedID',width: 100,
tpl: Ext.create('Rally.ui.renderer.template.FormattedIDTemplate'),
summaryRenderer: function() {
return "Estimate Total";
}
},
{
text: 'Name',dataIndex: 'Name',
},
{
text: 'State',dataIndex: 'State',xtype: 'templatecolumn',
tpl: Ext.create('Rally.ui.renderer.template.ScheduleStateTemplate',
{
states: ['Defined', 'In-Progress', 'Completed'],
field: {
name: 'State'
}
})
},
{
text: 'Estimate',dataIndex: 'Estimate',
summaryType: 'sum',
},
{
text: 'WorkProduct',dataIndex: 'WorkProduct',
renderer: function(val, meta, record) {
return '' + record.get('WorkProduct').FormattedID + '';
}
},
]
});
}
Update: If you want to filter the task store include a filter here:
tasks.store = story.getCollection('Tasks',{fetch:['Name','FormattedID','Estimate','State','Blocked','WorkProduct'],filters:{property: 'State',operator: '<',value: 'Completed'}});
A treegrid example: Rally.ui.grid.TreeGrid you referred is still a work in progress. I have not seen a working example of a story hierarchy using a treegrid but it does not mean it's impossible.
When I tested a story hierarchy, child stories did not appear under epic stories, however a story/task hierarchy worked. The filtering worked too. Here is an example:
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
launch:function(){
Ext.create('Rally.data.wsapi.TreeStoreBuilder').build({
models: ['userstory'],
autoLoad: true,
filters:[
{
property: 'Name',
operator: 'contains',
value: 'story'
}
],
enableHierarchy: true
}).then({
success: function(store) {
var grid = Ext.create('Ext.Container', {
items: [{
xtype: 'rallytreegrid',
columnCfgs: [
'Name',
'Owner'
],
store: store
}]
});
that.add(grid);
}
});
}
The screenshot below shows that tasks are nested under a child story as expected,but the child story is not nested under parent. The grid is filtered by Name as expected:
I want to create a chart of how many tasks are in a given Schedule State during the length of the sprint. Is it possible to call WsapiDataStore on each day?
What you are looking for is a lookback Snapshot Store , using the Lookback API - this allows you to specify a date or a point in time that you want to query by.
A typical use looks like this:
Ext.create('Rally.data.lookback.SnapshotStore', {
pageSize : 10000,
fetch : ['fetch'],
filters : [{
property : '__At',
value : 'current'
},{
property : '_ItemHierarchy',
value : 'HierarchicalRequirement'
}]
}).load({
callback : function(records) {
Ext.Array.each(records, function(record) {
// do something with each record
});
}
});
WsapiDataStore is not intended for historic data. You need to use Rally.data.lookback.SnapshotStore which retrieves data from the Lookback API.
Lookback API allows to see what any work item or collection of work items looked like in the past. This is different from using WS API directly (or via WsapiDataStore) which can provide you with the current state of objects, but does not have historical data.
LBAPI documentation is available here
As far as Rally release object's attributes see WS API object model here. But it is not clear from your comment what you mean by data for the entire release. If you are interested in getting back user stories assigned to a specific release then your query object should be hierarchical requirement and not release, and you may filter by release.
Here is an app that builds a chart using a Release dropdown. Based on the selection in the dropdown the chart is refreshed (it is destroyed and added):
Ext.define('CustomApp', {
extend: 'Rally.app.TimeboxScopedApp',
componentCls: 'app',
scopeType: 'release',
comboboxConfig: {
fieldLabel: 'Select a Release:',
labelWidth: 100,
width: 300
},
addContent: function() {
this._makeStore();
},
onScopeChange: function() {
this._makeStore();
},
_makeStore: function() {
Ext.create('Rally.data.WsapiDataStore', {
model: 'UserStory',
autoLoad: true,
filters: [this.getContext().getTimeboxScope().getQueryFilter()],
listeners: {
load: this._onDataLoaded,
scope: this
}
});
},
_onDataLoaded: function(store, data) {
var records = [];
var scheduleStateGroups = ["Defined","In-Progress","Completed","Accepted"]
// State count variables
var definedCount = 0;
var inProgressCount = 0;
var completedCount = 0;
var acceptedCount = 0;
// Loop through returned data and group/count by ScheduleState
Ext.Array.each(data, function(record) {
//Perform custom actions with the data here
//Calculations, etc.
scheduleState = record.get('ScheduleState');
switch(scheduleState)
{
case "Defined":
definedCount++;
break;
case "In-Progress":
inProgressCount++;
break;
case "Completed":
completedCount++;
break;
case "Accepted":
acceptedCount++;
}
});
if (this.down('#myChart')) {
this.remove('myChart');
}
this.add(
{
xtype: 'rallychart',
height: 400,
itemId: 'myChart',
chartConfig: {
chart: {
},
title: {
text: 'User Story Schedule State Counts',
align: 'center'
},
xField : 'ScheduleState',
xAxis: [
{
//categories: scheduleStateGroups,
title: {
text: 'ScheduleState'
}
}
],
yAxis: {
title: {
text: 'Count'
}
},
plotOptions : {
column: {
color: '#F00'
},
series : {
animation : {
duration : 2000,
easing : 'swing'
}
}
}
},
chartData: {
categories: scheduleStateGroups,
series: [
{
type: 'column',
data: [definedCount, inProgressCount, completedCount, acceptedCount]
}
]
}
}
);
this.down('#myChart')._unmask();
}
});