in Sencha Touch 2.1 how can I load the chart dynamically from json, also with dynamic fields store, chart axes, and chart series,
I know maybe this is too much, but I need to display many kind of data, If I create 1 chart component for each display means I have to create more than 15 chart component, I'm afraid it get bloated
I did not complete this dynamically, but I made it seem dynamic.
I first request a user to fill out a form.
I also have multiple panels that holds charts with empty stores, in the form of several different layouts.
Based on the user's form, I show and hide panels, or chart when they need to be displayed only after loading the store with the required data.
yes it is bulky, and they are static, but I found it slightly easier to handle than dynamically loading.
EDIT
After thinking,
have you tried a function like
function dynamiccharts(var1, var2, var3){
return Ext.chart.Chart({
....
})
}
variables would include things like data, url, store or etc.
This is my example creating a chart on controller inside a panel: axis, series, store fields, url are became parameters, PAR_FORM is global variable showing the difference between views, I'm using this code for another chart (Column, Pie)
Ext.define("Geis.controller.app", {
extend: "Ext.app.Controller",
config: {
refs: {
mainview: 'mainview',
barchartview: 'barchartview',
btnShowChartAnggaran: '#btnShowChartAnggaran'
},
control: {
'btnShowChartAnggaran': {
tap: 'onShowChartAnggaran'
}
}
}
createBarChart: function(fields, series_xfield, series_yfield, url) {
this.getBarchartview().add(new Ext.chart.CartesianChart({
id: 'barchartgenerateview',
store: {
fields: fields,
proxy: {
type: 'jsonp',
url: url
}
},
background: 'white',
flipXY: true,
colors: Geis.view.ColorPatterns.getBaseColors(),
interactions: [
{
type: 'panzoom',
axes: {
"left": {
allowPan: true,
allowZoom: true
},
"bottom": {
allowPan: true,
allowZoom: true
}
}
},
'itemhighlight'
],
series: [{
type: 'bar',
xField: series_xfield,
yField: series_yfield,
highlightCfg: {
strokeStyle: 'red',
lineWidth: 3
},
style: {
stroke: 'rgb(40,40,40)',
maxBarWidth: 30
}
}],
axes: [{
type: 'numeric',
position: 'bottom',
fields: series_yfield,
grid: {
odd: {
fill: '#e8e8e8'
}
},
label: {
rotate: {
degrees: -30
}
},
maxZoom: 1
},
{
type: 'category',
position: 'left',
fields: series_xfield,
maxZoom: 4
}]
}));
Ext.getCmp('barchartgenerateview').getStore().load();
},
onShowChartAnggaran: function() {
this.getBarchartview().remove(Ext.getCmp('barchartgenerateview'), true);
if (PAR_FORM == 'Dana Anggaran') {
this.createBarChart(['kode', 'keterangan', 'nilai'], 'keterangan', 'nilai',
Geis.util.Config.getBaseUrl() + 'anggaran/laporan/json/get_dana_anggaran_json/');
} else if (PAR_FORM == 'Alokasi Anggaran') {
this.createBarChart(['kode', 'keterangan', 'belanja_pegawai', 'belanja_barang', 'belanja_modal'],
'keterangan', ['belanja_pegawai', 'belanja_barang', 'belanja_modal'],
Geis.util.Config.getBaseUrl() + 'anggaran/laporan/json/get_alokasi_json/');
}
this.getMainview().animateActiveItem(1, {type:'slide', direction:'left'});
}
});
base on my experiment if you want to activate the interactions features you need to set the chart id dynamically too, for example by creating Global Counter Variable
Related
I am trying to display my header name in a new line, but i am unable to do it.
Version of ag-grid-vue: 6.12.0
Here is what i tried but it did not work out:
defaultColDef: {
sortable: true,
editable: true,
resizable: true,
suppressMenu: true
},
columnDefs: [
{
headerName: 'Average low ', // This value is displayed in a single line
field: 'average_low',
width: 200,
},
{
headerName: 'Average high ', // Even this value is displayed in a single line
field: 'average_high',
width: 200,
},
...
}
I tried something like this to display the headerName in new line:
{
headerName: 'Avg. \n low ', // This value is displayed in a single line
field: 'average_low',
width: 200,
},
{
headerName: 'Avg. </br> high ', // Even this value is displayed in a single line
field: 'average_high',
width: 200,
},
I want to display something like this:
Please tell me how i can do this. Here is the officially documentation:
https://www.ag-grid.com/documentation/vue/component-header/
and here is the plunker which shows the example and can be used to workout:
https://plnkr.co/edit/QGopxrvIoTPu2vkZ
EDIT: here is a working solution >> https://plnkr.co/edit/Lr6cneCFiT91lCOD
Adapt it to your liking with the according theme (alpine, balham and so on) and the height that you wish or any other CSS structure that you have.
As told below, this inspired by this guy's work.
A working solution can be done with the script below
const MIN_HEIGHT = 80; // this line is the one you're looking for !
function autosizeHeaders(event) {
if (event.finished !== false) {
event.api.setHeaderHeight(MIN_HEIGHT);
const headerCells = document.querySelectorAll('#myGrid .ag-header-cell-label');
let minHeight = MIN_HEIGHT;
headerCells.forEach(cell => {
minHeight = Math.max(minHeight, cell.scrollHeight);
});
event.api.setHeaderHeight(minHeight);
}
}
(function() {
document.addEventListener('DOMContentLoaded', function() {
var gridDiv = document.querySelector('#myGrid');
var gridOptions = {
enableColResize: true,
enableSorting: true,
onColumnResized: autosizeHeaders,
onGridReady: autosizeHeaders,
columnDefs: [
{
headerName: 'Header with a very long description',
field: 'name',
headerClass: 'multiline'
},
{
headerName: 'Another long header title',
field: 'role',
headerClass: 'multiline'
}
],
rowData: [
{name: 'Niall', role: 'Developer'},
{name: 'Eamon', role: 'Manager'},
{name: 'Brian', role: 'Musician'},
{name: 'Kevin', role: 'Manager'}
]
};
new agGrid.Grid(gridDiv, gridOptions);
});
})();
There is a github issue here with a Stackoverflow thread with a lot of hacky (but working) solutions. It looks like there is no official support for this, so your best bet would be to check there and try out the various CSS solutions.
If you have a hosted example that we can play with, I may help more but right now, I can only recommend reading the various comments and try to tinker the CSS with your dev tools ! :)
I'm creating an overview of features and their feature dependencies (not user stories).
I'm fetching the wsapi store filtered on release in step 1 and in step 2 I'm fetching the predecessor and successor collections in order to display their values.
I would like to use this wsapi store directly in a grid, but when performing an onScopeChange (release filtered app) the rendering of the grid happens before my loading of predecessor + successor collections. Thus, I'm trying to store the data in a custom.store to use in the grid - so far so good.
My issue is that I need to do all (most) formatting in the grid on my own. I'm setting the custom store model to PortfolioItem/Feature and would expect this to be used on the grid, but it just doesn't. Is this possible? If so, what am I doing wrong?
Custom store
_getViewStore: function () {
var me = this;
/*
Extract data from featureStore
*/
var records = me.myFeatureStore.getRecords();
/*
Create new, update, store for adding into grid
*/
if (!me.myViewStore) {
me.myViewStore = Ext.create('Rally.data.custom.Store', {
model: 'PortfolioItem/Feature',
data: records,
});
} else {
me.myViewStore.removeAll();
me.myViewStore.add(records);
}
},
Grid
_createGrid: function () {
var me = this;
me.myGrid = Ext.create('Ext.Container', {
items: [{
xtype: 'rallygrid',
store: me.myViewStore,
columnCfgs: [{
xtype: 'gridcolumn',
align: 'left',
tpl: Ext.create('Rally.ui.renderer.template.FormattedIDTemplate'),
text: 'Predecessors',
dataIndex: 'Predecessors',
width: 200,
renderer: function (value, metaData, record) {
var mFieldOutputPre = '';
var records = record.predecessorStore.getRecords();
_.each(records, function (feature) {
mFieldOutputPre += Rally.nav.DetailLink.getLink({
record: feature,
text: feature.get('FormattedID'),
showTooltip: true
});
// Add the feature name and a line break.
mFieldOutputPre += ' - ' + feature.get('Name') + '<br>';
}); //_.each
return mFieldOutputPre;
},
},
{
text: 'FormattedID',
dataIndex: 'FormattedID',
xtype: 'templatecolumn',
tpl: Ext.create('Rally.ui.renderer.template.FormattedIDTemplate')
},
{
text: 'Name',
dataIndex: 'Name',
flex: 1
},
{
text: 'Release',
dataIndex: 'Release',
flex: 1
},
{
text: 'State',
dataIndex: 'State',
flex: 1
},
{ // Column 'Successors'
xtype: 'templatecolumn',
align: 'left',
tpl: Ext.create('Rally.ui.renderer.template.FormattedIDTemplate'),
text: 'Successors',
dataIndex: 'Successors',
width: 200,
renderer: function (value, metaData, record) {
var mFieldOutputSuc = '';
var records = record.successorStore.getRecords();
_.each(records, function (feature) {
//console.log('feature = ', feature);
mFieldOutputSuc += Rally.nav.DetailLink.getLink({
record: feature,
text: feature.get('FormattedID'),
showTooltip: true
});
// Add the feature name and a line break.
mFieldOutputSuc += ' - ' + feature.get('Name') + '<br>';
});
return mFieldOutputSuc;
},
}
]
}],
renderTo: Ext.getBody()
});
me.add(me.myGrid);
}
The Release + State fields does not display data correct when using my custom store, but if I use my wsapi (feature) store that are formatted correctly.
Thank you in advance
I'd probably load all the stores first and then add the rallygrid configured with your already loaded feature store. Then you don't have to worry about the timing issues. I'm guessing you already found this example in the docs for loading the child collections?
https://help.rallydev.com/apps/2.1/doc/#!/guide/collections_in_v2-section-collection-fetching
This example is also pretty helpful, as it shows how to load hierarchical data much like you're doing, and uses promises to help manage all of that and then do something when everything has finished loading:
https://help.rallydev.com/apps/2.1/doc/#!/guide/promises-section-retrieving-hierarchical-data
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();
}
});
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.
I am using a grid panel in which I need to make a column as a link(It should look like link-with no action). I am using listener in the gridpanel and on click of a cell its working fine. Only thing is 1st column should look like a link. But how to put href="#" I am not sure. This is my code:
var addressDetailsStore = Ext.create('Ext.data.Store', {
id:'addressDetailsStore',
autoLoad: true,
fields:
[
'addressType',
'street1',
'street2',
'province',
'city',
'country'
],
proxy: {
type: 'ajax',
url: 'resources/json/addressDetails.json', // url that will load data with respect to start and limit params
reader: {
type: 'json',
root: 'items',
}
}
});
Ext.define('iOMS.view.common.addressView', {
extend: 'Ext.grid.Panel',
alias: 'widget.AddressViewPanel',
layout: 'fit',
collapsible: true,
title:'Address',
store: addressDetailsStore,
listeners:{
cellclick:function (iView, iCellEl, iColIdx, iRecord, iRowEl, iRowIdx, iEvent){
// Getting the event and I am doing logic here..
}
I just want 'addressType' columns appear like a link and I dont know where to put href...
Thanks for your responses.
-Praveen
You could also use a template column:
columns: [
{ text: 'External Link', xtype: 'templatecolumn', tpl: '{title}'}
]
You can specify the columns you want, and for the column with just a link, add a renderer. This example might help you.
var template = new Ext.XTemplate(
' ').compile();
columns:[
{
header: "",
renderer: function () {
return template.applyTemplate();
}
},
You can use renderer function like as follow
columns: [
{
header: 'number',
dataIndex: 'number',
flex: 1,
renderer: function(number) {
return Ext.String.format('{0}', number);
}
},