Related
I'm using ExtJS 4 with MVC. I have a chart with two series: line and column. When clicking a column I need to trigger an event.
In the controller, I used the following query to match the column series, but doesn't work.
this.control({
'#companyChartItemId[series[type=column]]': {
itemmouseup:this.onItemMouseUp
}
});
Any thoughts how could I match it?
Below is my code:
app/view/company/Chart.js
Ext.define('Market.view.company.Chart', {
extend: 'Ext.chart.Chart',
xtype: 'companyChart',
requires: ['Market.store.HistoricalMarketData'],
theme: 'Category1',
store:'HistoricalMarketData',
initComponent: function() {
this.callParent();
},
axes: [{
type: 'Numeric',
position: 'left',
fields: ['close'],
title: 'Price',
grid: true
}, {
type: 'Numeric',
position: 'right',
fields: ['volume'],
title: 'Volume',
grid: true
}, {
type: 'Category',
position: 'bottom',
fields: ['time'],
title: 'Month of the Year'
}],
series: [{
type: 'column',
axis: 'right',
xField: 'time',
yField: 'volume',
highlight: true,
markerConfig: {
type: 'cross',
size: 3
}
}, {
type: 'line',
axis: 'left',
smooth: false,
fill: false,
fillOpacity: 0.8,
xField: 'time',
yField: 'close'
}]
});
app/controller/ChartController.js
Ext.define('Market.controller.ChartController', {
extend:'Ext.app.Controller',
stores:['MarketData'],
init: function() {
this.control({
'#companyChartItemId[series[type=column]]': {
itemmouseup:this.onItemMouseUp
}
});
},
onItemMouseUp: function (item) {
//do something
}
});
I would just configure the listener/response function where you define your series. You can add listeners as a config in your series, check out the doc:
http://docs.sencha.com/extjs/4.2.1/#!/api/Ext.chart.series.Series-cfg-listeners
I'm pretty new to web development and ExtJS, I've looked around for tutorials on more complex concepts but they are hard to find (Yes I've found the Sencha documentation but the only provide simple concepts)
I'm trying to make a dashboard for my application, in this dashboard I want a chart
that gives a detailed overview of my statistics. In order to accomplish this I am trying to add a custom filter for the chart by making a seperate list with that holds all the instances of the key, when selecting said instances from a list I want the chart to only display those selected instances.
The chart I made:
Ext.define('view.chart.LocationStatisticsPerMonth', {
extend: 'Ext.chart.Chart',
alias: 'widget.LocationStatisticsPerMonthChart',
requires: [
'store.LocationStatisticsStore',
'store.TemplateStore',
'view.TitleToolbar'
],
constructor: function () {
this.store = Ext.create('store.LocationStatisticsStore', {
autoLoad: true, sorters: [{
property: 'YearMonth',
direction: 'ASC'
}]
});
this.store.getProxy().api.read = ServerControllers.Dashboard.LocationStatisticsPerMonth;
this.callParent(arguments);
},
animate: true,
shadow: true,
border: true,
legend: {
position: 'right'
},
axes: [{
type: 'Numeric',
position: 'left',
fields: ['TotalCount'],
title: false,
grid: true,
label: {
renderer: function (v) {
return String(v);
}
}
}, {
type: 'Category',
position: 'bottom',
fields: ['Location_Id'],
title: false,
label: {
rotate: {
degrees: 315
}
}
}],
series: [{
type: 'column',
axis: 'left',
gutter: 80,
xField: ['Location_Id'],
yField: ['TotalCount'],
tips: {
trackMouse: true,
width: 125,
height: 28,
renderer: function(storeItem, item) {
this.setTitle(String('Visitors: '+item.value[1]));
}
}
}]
});
My Store
Ext.define('store.LocationStatisticsStore', {
extend: 'Ext.data.Store',
requires: ['model.LocationStatistics'],
model: 'model.LocationStatistics',
autoLoad: false,
remoteSort: false,
remoteFilter: false,
filterOnLoad: true,
sorters: [{
property: ['YearMonth' , 'Location_Id'],
direction: 'DESC'
}],
proxy: {
type: 'direct',
paramOrder: [],
api: {
read: ServerControllers.Reports.GetLocationStatisticsPerMonth
},
reader: {
type: 'json',
root: 'data',
totalProperty: 'totalRecords',
successProperty: 'success',
messageProperty: 'msg'
}
}
});
My Model:
Ext.define('model.LocationStatistics', {
extend: 'Ext.data.Model',
idProperty: ['Location_Id'],
fields: [
{ name: 'YearMonth', type: 'string' },
{ name: 'Location_Id', type: 'int' },
{ name: 'Year', type: 'int' },
{ name: 'Month', type: 'int' },
{ name: 'TotalCount', type: 'int' },
{ name: 'AverageCountPerDay', type: 'int' }
]
});
Would anyone be so kind as to explain this concept to me, link a tutorial or provide me an example of how to go about doing this?
Help is greatly appreciated.
EDIT: the panel that this is contained in:
Ext.define('view.panel.DashboardStatisticsPanel', {
extend : 'Ext.panel.Panel',
alias : 'widget.DashboardStatisticsPanel',
requires : [
'Ext.layout.container.Column',
'view.chart.LocationStatisticsPerMonth'
],
plain: true,
border: false,
layout: {
type: 'hbox',
padding: '10 10 10 10'
},
items: [{
xtype: 'panel',
layout: 'fit',
border: true,
flex: 1,
items: [{
xtype: 'panel',
layout: 'anchor',
border: true,
overflowX: 'scroll',
height: 400,
dockedItems: [{
xtype: 'toolbar',
dock: 'top',
items: [{
xtype: 'label',
text: 'Select Date',
padding: '0 0 0 10'
},
{
xtype: 'combobox',
displayField: 'YearMonth',
emptyText: 'Select Date ',
queryMode: 'local',
padding: '0 0 0 10',
store: function (btn) {
btn.up('panel').down('LocationStatisticsPerMonthChart').getStore();
},
valueField: 'YearMonth',
}]
}]
/*tbar: [{
text: 'September Only',
handler: function (btn) {
var store = btn.up('panel').down('LocationStatisticsPerMonthChart').getStore();
store.clearFilter();
Ext.defer(function (btn) {
store.filter("Month", 9);
}, 300);
}
}]*/,
items: [{
xtype: 'LocationStatisticsPerMonthChart',
itemId: 'LocationStatisticsPerMonthChart',
anchor: '2000, -10',
//height: 400,
// width: 2000,
}]
}],
dockedItems: [{
xtype: 'TitleToolbar',
dock: 'top',
title: Resources.t('RegistrationsPerUnit'),
items: ['->', {
iconCls: 'iconRefresh',
itemId: 'refresh',
scope: this,
handler: function (btn) {
var store = btn.up('panel').down('LocationStatisticsPerMonthChart').getStore();
//store.removeAll();
store.load();
}
}]
}]
}]
});
The best way is to use a function, I'll give you an example:
We have a store, let's call it StoreA, and another store StoreB
var storeA = something.getStore();
var storeB = somethingElse.getStore();
storeA.filterBy(function(record) {
return storeB.find("name", record.data.name) != -1;
});
So basicly in this example, if the name is in storeB (find returns an index), it will filter it out from storeA's contents.
Unfortunately, you will have to re-do the exact same filter every time a new record is added or updated... so what I do is bind a function that does this to the load, update, delete, etc.. events.
You only need to filter the related data store. To accomplish this use the filter method as follows:
chart.store.filter("Month", 10);
You can always remove the filtering on the store by calling clearFilter store's method,
chart.store.clearFilter();
Take into account that you need to remove previous filters when applying new ones otherwise the each new applied filter will stack with the current ones
You can see a small example based on your code here. Hope it helps you to solve your problem.
Similar to this post in the Sencha forums, how do I get the labels in this (image below) to show up vertically and line up with the grid? Seems like this should be charting basics, but maybe I missed something.
Here is the jsFiddle with the code: http://jsfiddle.net/wilsjd/kg6Ps/8/
Ext.require('Ext.chart.*');
Ext.require(['Ext.Window', 'Ext.fx.target.Sprite', 'Ext.layout.container.Fit', 'Ext.window.MessageBox']);
Ext.define('CPI', {
extend: 'Ext.data.Model',
fields: [{
name: 'ReportingPeriod',
type: 'string'
}, {
name: 'PeriodAmount',
type: 'decimal'
}, {
name: 'CumulativeAmount',
type: 'decimal'
}]
});
var store1 = Ext.create('Ext.data.Store', {
model: 'CPI',
data: [{
ReportingPeriod: 'Period1',
PeriodAmount: 1,
CumulativeAmount: 1.2,
Target: 1
}, {
ReportingPeriod: 'Period2',
PeriodAmount: 1.2,
CumulativeAmount: .2,
Target: 1
}, {
ReportingPeriod: 'Period9',
PeriodAmount: 1.5,
CumulativeAmount: 0.8,
Target: 1
}]
});
var chart = Ext.create('Ext.chart.Chart', {
style: 'background:#fff',
animate: true,
theme: 'Category1',
store: store1,
width: 300,
height: 300,
renderTo: 'chart',
axes: [{
type: 'Numeric',
position: 'left',
fields: ['PeriodAmount', 'CumulativeAmount'],
title: 'CPI'
},{
type: 'Category',
position: 'bottom',
fields: ['ReportingPeriod'],
title: 'Reporting Period',
label : {
rotation:{degrees:270}
}
}],
series: [{
type: 'column',
axis: 'left',
xField: 'ReportingPeriod',
yField: 'PeriodAmount',
renderer: function(sprite, record, attr, index, store) {
var value = 0;
if(record.get('PeriodAmount')>=1){
value = 0;
}else{
value = 1;
}
var color = ['rgb(127, 255, 127)',
'rgb(255, 0, 50)'
][value];
return Ext.apply(attr, {
fill: color
});
}
}, {
type: 'line',
axis: 'left',
xField: 'ReportingPeriod',
yField: 'CumulativeAmount',
markerConfig: {
type: 'circle',
size: 4,
radius: 4,
'stroke-width': 0,
}
}]
});
chart.show();
I changed rotation to rotate and it works.
label:{
rotate:{degrees:270}
}
Per usual, the people at sencha's forum are as helpful as a punch to the throat: http://www.sencha.com/forum/showthread.php?156746-line-chart-time-axis-label-rotate-issue&p=678586&viewfull=1#post678586
It appears to be set via dy attribute in the html:
<tspan x="96" dy="3.75">Period1</tspan>
Altering dy will move the h-pos left or right. Unfortunately, there doesn't seem to be an inbuilt way to do it though.
Bottom line: it might be a bug (as a dev mentions in the above link -- but helpfully doesn't expand upon).
Suppose I have some data that I want to display on an Ext.js bar chart and I want my data to revolve around a custom value, "1.0" for example, on the y-axis (versus traditionally "0.0").
Meaning, the picture below has negative values represented with inverted bars, I would like values less than "1.0" to show as an inverted bar on the chart.
Is there a setting that I can set to acheive this? If so, would it be in the series and the axis definition? Maybe the chart itself?
The code for the chart displayed is below:
Ext.require('Ext.chart.*');
Ext.require(['Ext.Window', 'Ext.fx.target.Sprite', 'Ext.layout.container.Fit', 'Ext.window.MessageBox']);
Ext.define('CPI', {
extend: 'Ext.data.Model',
fields: [{
name: 'ReportingPeriod',
type: 'string'
}, {
name: 'CPI_P',
type: 'decimal'
}, {
name: 'CPI_C',
type: 'decimal'
}]
});
var store1 = Ext.create('Ext.data.Store', {
model: 'CPI',
data: [{
ReportingPeriod: 'Period1',
CPI_P: '1.9',
CPI_C: '1.2'
}, {
ReportingPeriod: 'Period2',
CPI_P: '1.2',
CPI_C: '1.1'
}, {
ReportingPeriod: 'Period3',
CPI_P: '0.1',
CPI_C: '0.5'
}, {
ReportingPeriod: 'Period4',
CPI_P: '-0.5',
CPI_C: '0.6'
}, {
ReportingPeriod: 'Period5',
CPI_P: '-0.9',
CPI_C: '0.8'
}, {
ReportingPeriod: 'Period6',
CPI_P: '-1.0',
CPI_C: '-0.6'
}, {
ReportingPeriod: 'Period7',
CPI_P: '-1.1',
CPI_C: '-0.7'
}, {
ReportingPeriod: 'Period8',
CPI_P: '-1.5',
CPI_C: '-0.8'
}]
});
var chart = Ext.create('Ext.chart.Chart', {
style: 'background:#fff',
animate: true,
theme: 'Category1',
store: store1,
width: 300,
height: 300,
renderTo: 'chart',
axes: [{
type: 'Numeric',
position: 'left',
fields: ['CPI_P', 'CPI_C'],
title: 'CPI',
grid: true
}, {
type: 'Category',
position: 'bottom',
fields: ['ReportingPeriod'],
title: 'Reporting Period'
}],
series: [{
type: 'column',
axis: 'left',
xField: 'ReportingPeriod',
yField: 'CPI_P',
markerConfig: {
type: 'cross',
size: 3
},
renderer: function(sprite, record, attr, index, store) {
var value = (record.get('CPI_P') >> 2) % 2;
var color = ['rgb(213, 70, 121)',
'rgb(44, 153, 201)'
][value];
return Ext.apply(attr, {
fill: color
});
}
}]
});
chart.show();
UPDATE
If I add a minimum to y-axis I get closer (sort of)
...
axes: [{
type: 'Numeric',
position: 'left',
fields: ['CPI_P', 'CPI_C'],
title: 'CPI',
grid: true,
minimum: 1,
}....
It's the right idea, because the bars now are relevant to the number 1, but I obviously need to keep the bars on the graph.
What has seemed to work is subtracting 1 from my data and adding 1 to the labels.
axes: [{
type: 'Numeric',
position: 'left',
grid: true,
maximum: 1.0, //will render to 2.0
fields: ['PeriodAmount', 'CumulativeAmount'],
label:{
renderer:function(v){
return (v+1).toFixed(2);
}
}
}...]
This is a viable work around for me, but I wouldn't consider this an elegant answer since it isn't very configurable for custom values. For example, changing this to -1 or 2 would require more work than just changing a simple setting.
I'm migrating ExtJs 3 application to ExtJs 4. One of the component that I need to change is a chart that has series of bars and lines on it. It displays the data for previous and current years. Beside the chart there is a checkbox "Compare to previous year". When it checked all line series should be visible and hidden when it is not checked.
In ExtJs 3 I did this task by setting visibility:hidden for series styles this way: chart.setSeriesStyles(...). But in ExtJs 4 this function is absent and I can't find any other way to hide series on demand.
Here is the code of my chart:
var store = Ext.create('Ext.data.Store', {
fields: [
'month','data1','data2','data3','prev_data1','prev_data2','prev_data3'
],
proxy: {
type: 'ajax',
url: '/getmonthlystats.php'
}
});
this.statChart = Ext.create('Ext.chart.Chart', {
flex: 1,
store: store,
axes: [{
type: 'Numeric',
position: 'left',
minimum: 0,
maximum: 100,
fields: [
'data1',
'data2',
'data3',
'prev_data1',
'prev_data2',
'prev_data3'
],
label: {
renderer: Ext.util.Format.numberRenderer('0,0')
},
grid: true
},{
type: 'Category',
position: 'bottom',
fields: ['month'],
label: {
rotate: {
degrees: 315
}
}
}],
series: [{
type: 'column',
yField: ['data1','data2','data3'],
xField: 'month'
},
{
type: 'line',
yField: 'prev_data1',
xField: 'month'
},{
type: 'line',
yField: 'prev_data2',
xField: 'month'
},{
type: 'line',
yField: 'prev_data3',
xField: 'month'
}]
});
So, the lines prev_data1, prev_data2, prev_data3 should be shown or hidden when needed (depending on the checkbox state). Does anyone know the way to do that?
Thanx.
Try this (sample from my code):
handler: function (checkbox, checked) {
if (checked)
chart.series.getAt(index).showAll();
else
chart.series.getAt(index).hideAll();
}
For ExtJS 4.2.x
If you use 'legend' with your charts, this code will be better for you:
var chart = Ext.getCmp(chartId);
var series = chart.series.getAt(seriesIndex);
if (value) {
series.showInLegend = true;
series.showAll();
} else {
series.showInLegend = false;
series.hideAll();
}
chart.redraw();