ExtJS5 Charts - Extending Cartesian Chart - extjs

Below, there are two examples (A and B). The first, A, works corectly, but the chart is managed by a container. I feel that this isn't necessary. I want to directly extend the Cartesian chart instead of adding it to a
Container. I have tried to do so in the second Example, B, but I have been unsuccessful.
Example A
This example works just fine. It is derived from Sencha's ExtJS5 Multi-axis column chart example of their kitchen sink.
Demo # JSFiddle
var climateData = getClimateData();
Ext.define('ChartApp.mixins.reader.DynamicReaderMixin', {
extend : 'Ext.Mixin',
readRecords : function(data) {
var me = this;
var rootData = data;
console.log(data);
this.callParent(arguments);
}
});
Ext.define('ChartApp.data.reader.DynamicChartReader', {
extend : 'Ext.data.reader.Json',
alias : 'widget.dynamicChartReader',
xtype : 'dynamicChartReader',
mixins : {
dynamicReader : 'ChartApp.mixins.reader.DynamicReaderMixin'
},
config : {
xField : null
},
readRecords : function(data) {
console.log('Reading records...');
if (data.metaData == null) {
data = this.mixin.dynamicReader.readRecords.call(this, data);
}
return this.callParent([data]);
}
});
Ext.define("ChartApp.model.Climate", {
extend: "Ext.data.Model",
fields: ["month", "high", "low", {
name: "highF",
calculate: function (b) {
return toFaherenheit(b.high);
}
}, {
name: "lowF",
calculate: function (b) {
return toFaherenheit(b.low);
}
}],
});
Ext.define("ChartApp.store.Climate", {
extend: "Ext.data.Store",
alias: "store.climate",
model : "ChartApp.model.Climate",
counter: 0,
generateData: function () {
var h = this.config.data,
e, j, g = [];
for (e = 0; e < h.length; e++) {
g.push({
month: h[e].month,
high: 20 + Math.random() * 20,
low: Math.random() * 20
})
}
return g
},
refreshData: function () {
this.setData(this.generateData())
}
});
Ext.define('ChartApp.view.charts.column.MultiAxis', {
extend: 'Ext.container.Container',
xtype: 'column-multi-axis',
width: 650,
height: 500,
initComponent: function () {
var me = this;
var highSeries = {
type: 'line',
xField: 'month',
yField: ['highF'],
yAxis: 'fahrenheit-axis',
style: {
lineWidth: 2,
fillStyle: '#115fa6',
strokeStyle: '#115fa6',
fillOpacity: 0.6,
miterLimit: 3,
lineCap: 'miter'
},
colors : [ '#115fa6' ],
title : ['High'],
tooltip: {
trackMouse: true,
style: 'background: #444; color: #FFF',
renderer: function(storeItem, item) {
var title = item.series.getTitle()[0];
this.setHtml(title + ' for '
+ storeItem.get('month') + ': '
+ storeItem.get(item.field).toFixed(2) + '°');
}
}
},
lowSeries = Ext.apply({}, {
yField: ['lowF'],
style: {
lineWidth: 2,
fillStyle: '#ff8800',
strokeStyle: '#884400',
fillOpacity: 0.6,
miterLimit: 3,
lineCap: 'miter'
},
colors : [ '#ff8800' ],
title : ['Low'],
}, highSeries);
me.items = [{
xtype: 'cartesian',
legend : {
hidden : true
},
store: {
type: 'climate',
reader: {
xtype : 'dynamicChartReader'
}
},
insetPadding: 10,
innerPadding: {
left: 20,
right: 20
},
interactions: 'crosszoom',
axes: [{
type: 'numeric',
id: 'fahrenheit-axis',
adjustByMajorUnit: true,
position: 'left',
titleMargin: 20,
minimum: 32,
grid: true,
title: {
text: 'Temperature in °F',
fontSize: 14
},
listeners: {
rangechange: function (range) {
var cAxis = this.getChart().getAxis('celsius-axis');
if (cAxis) {
cAxis.setMinimum(toCelcius(range[0]));
cAxis.setMaximum(toCelcius(range[1]));
}
}
}
}, {
id: 'celsius-axis',
type: 'numeric',
titleMargin: 20,
position: 'right',
title: {
text: 'Temperature in °C',
fontSize: 14,
fillStyle: 'red'
}
}, {
id: 'months-axis',
type: 'category',
position: 'bottom',
title: {
text: 'Months'
}
}, {
position: 'top',
linkedTo: 'months-axis',
title: {
text: 'Climate data for Redwood City, California',
fontSize: 16,
fillStyle: 'green'
},
titleMargin: 20
}],
series: [ highSeries, lowSeries ]
}];
this.callParent();
},
getChart : function() {
return this.down('cartesian');
},
getStore : function() {
return this.getChart().getStore();
},
getLegendStore : function() {
return this.getChart().getLegendStore();
}
});
Ext.define('ChartApp.chart.Legend', {
extend : 'Ext.chart.Legend',
xtype: 'extendedlegend',
docked : 'left',
tpl: [
'<div class="', Ext.baseCSSPrefix, 'legend-container">',
'<tpl for=".">',
'<div class="', Ext.baseCSSPrefix, 'legend-item">',
'<input type="checkbox" class="', Ext.baseCSSPrefix, 'legend-item-check" checked="true" />',
'<span ',
'class="', Ext.baseCSSPrefix,
'legend-item-marker {[ values.disabled ? Ext.baseCSSPrefix + \'legend-inactive\' : \'\' ]}" ',
'style="background:{mark};">',
'</span>{name}',
'</div>',
'</tpl>',
'</div>'
],
initComponent : function() {
var me = this;
me.callParent(arguments);
},
onItemClick: function (record, item, index, e) {
var target = e.getTarget();
var disabled = record.get('disabled');
if (this.isCheckBox(target)) {
target.checked = !disabled;
console.log(target.checked);
this.callParent(arguments);
}
},
isCheckBox : function(element) {
return element && element.tagName.toLowerCase() === 'input' && element.type === 'checkbox';
}
});
Ext.define('ChartApp.components.ChartContainer', {
extend : 'Ext.container.Container',
alias : 'widget.chartcontainer',
referenceHolder: true,
height : 600,
width : 800,
layout: 'border',
items: [{
region : 'west',
title : 'Legend',
items : [{
xtype : 'extendedlegend',
reference : 'chartLegend',
}],
width : 180,
minHeight : 550,
collapsible : true,
collasped : false,
split : true,
animCollapse : true
}, {
region : 'center',
reference : 'chartWrapper',
layout : 'fit',
margins : '5 5 0 0',
items : [{
xtype : 'column-multi-axis',
reference : 'chart',
layout : 'fit'
}]
}],
initComponent : function() {
var me = this;
me.callParent(arguments);
var chart = me.lookupReference('chart');
chart.getStore().loadData(climateData);
var legend = me.lookupReference('chartLegend');
legend.setStore(chart.getLegendStore());
}
});
Ext.onReady(function() {
Ext.create('Ext.panel.Panel', {
title : 'Dual Axis Example',
layout : 'fit',
items : [{
xtype : 'chartcontainer'
}],
renderTo: Ext.getBody(),
});
});
function toCelcius(faherenheit) {
return (faherenheit - 32) / 1.8;
};
function toFaherenheit(celcius) {
return (celcius * 1.8) + 32;
};
function getClimateData() {
return [
{ month: "Jan", high: 14.7, low: 5.6 },
{ month: "Feb", high: 16.5, low: 6.6 },
{ month: "Mar", high: 18.6, low: 7.3 },
{ month: "Apr", high: 20.8, low: 8.1 },
{ month: "May", high: 23.3, low: 9.9 },
{ month: "Jun", high: 26.2, low: 11.9 },
{ month: "Jul", high: 27.7, low: 13.3 },
{ month: "Aug", high: 27.6, low: 13.2 },
{ month: "Sep", high: 26.4, low: 12.1 },
{ month: "Oct", high: 23.6, low: 9.9 },
{ month: "Nov", high: 17.0, low: 6.8 },
{ month: "Dec", high: 14.7, low: 5.8 }
];
}
Example B
In this example the column-multi-axis directly extend the cartesian chart. For some reason unknown to me, in the chartcontainer's initComponent, after the call to this.callParent(), the store is still a config on the chart.
Demo # JSFiddle
var climateData = getClimateData();
Ext.define('ChartApp.mixins.reader.DynamicReaderMixin', {
extend : 'Ext.Mixin',
readRecords : function(data) {
var me = this;
var rootData = data;
console.log(data);
this.callParent(arguments);
}
});
Ext.define('ChartApp.data.reader.DynamicChartReader', {
extend : 'Ext.data.reader.Json',
alias : 'widget.dynamicChartReader',
xtype : 'dynamicChartReader',
mixins : {
dynamicReader : 'ChartApp.mixins.reader.DynamicReaderMixin'
},
config : {
xField : null
},
readRecords : function(data) {
console.log('Reading records...');
if (data.metaData == null) {
data = this.mixin.dynamicReader.readRecords.call(this, data);
}
return this.callParent([data]);
}
});
Ext.define("ChartApp.model.Climate", {
extend: "Ext.data.Model",
fields: ["month", "high", "low", {
name: "highF",
calculate: function (b) {
return toFaherenheit(b.high);
}
}, {
name: "lowF",
calculate: function (b) {
return toFaherenheit(b.low);
}
}],
});
Ext.define("ChartApp.store.Climate", {
extend: "Ext.data.Store",
alias: "store.climate",
model : "ChartApp.model.Climate",
counter: 0,
generateData: function () {
var h = this.config.data,
e, j, g = [];
for (e = 0; e < h.length; e++) {
g.push({
month: h[e].month,
high: 20 + Math.random() * 20,
low: Math.random() * 20
})
}
return g
},
refreshData: function () {
this.setData(this.generateData())
}
});
Ext.define('ChartApp.view.charts.column.MultiAxis', {
extend: 'Ext.chart.CartesianChart',
xtype: 'column-multi-axis',
width: 650,
height: 500,
initComponent: function () {
var me = this;
var highSeries = {
type: 'line',
xField: 'month',
yField: ['highF'],
yAxis: 'fahrenheit-axis',
style: {
lineWidth: 2,
fillStyle: '#115fa6',
strokeStyle: '#115fa6',
fillOpacity: 0.6,
miterLimit: 3,
lineCap: 'miter'
},
colors : [ '#115fa6' ],
title : ['High'],
tooltip: {
trackMouse: true,
style: 'background: #444; color: #FFF',
renderer: function(storeItem, item) {
var title = item.series.getTitle()[0];
this.setHtml(title + ' for '
+ storeItem.get('month') + ': '
+ storeItem.get(item.field).toFixed(2) + '°');
}
}
},
lowSeries = Ext.apply({}, {
yField: ['lowF'],
style: {
lineWidth: 2,
fillStyle: '#ff8800',
strokeStyle: '#884400',
fillOpacity: 0.6,
miterLimit: 3,
lineCap: 'miter'
},
colors : [ '#ff8800' ],
title : ['Low'],
}, highSeries);
Ext.apply(me, {
legend : {
hidden : true
},
store: {
type: 'climate',
reader: {
xtype : 'dynamicChartReader'
}
},
insetPadding: 10,
innerPadding: {
left: 20,
right: 20
},
interactions: 'crosszoom',
axes: [{
type: 'numeric',
id: 'fahrenheit-axis',
adjustByMajorUnit: true,
position: 'left',
titleMargin: 20,
minimum: 32,
grid: true,
title: {
text: 'Temperature in °F',
fontSize: 14
},
listeners: {
rangechange: function (range) {
var cAxis = this.getChart().getAxis('celsius-axis');
if (cAxis) {
cAxis.setMinimum(toCelcius(range[0]));
cAxis.setMaximum(toCelcius(range[1]));
}
}
}
}, {
id: 'celsius-axis',
type: 'numeric',
titleMargin: 20,
position: 'right',
title: {
text: 'Temperature in °C',
fontSize: 14,
fillStyle: 'red'
}
}, {
id: 'months-axis',
type: 'category',
position: 'bottom',
title: {
text: 'Months'
}
}, {
position: 'top',
linkedTo: 'months-axis',
title: {
text: 'Climate data for Redwood City, California',
fontSize: 16,
fillStyle: 'green'
},
titleMargin: 20
}],
series: [ highSeries, lowSeries ]
});
this.callParent();
}
});
Ext.define('ChartApp.chart.Legend', {
extend : 'Ext.chart.Legend',
xtype: 'extendedlegend',
docked : 'left',
tpl: [
'<div class="', Ext.baseCSSPrefix, 'legend-container">',
'<tpl for=".">',
'<div class="', Ext.baseCSSPrefix, 'legend-item">',
'<input type="checkbox" class="', Ext.baseCSSPrefix, 'legend-item-check" checked="true" />',
'<span ',
'class="', Ext.baseCSSPrefix,
'legend-item-marker {[ values.disabled ? Ext.baseCSSPrefix + \'legend-inactive\' : \'\' ]}" ',
'style="background:{mark};">',
'</span>{name}',
'</div>',
'</tpl>',
'</div>'
],
initComponent : function() {
var me = this;
me.callParent(arguments);
},
onItemClick: function (record, item, index, e) {
var target = e.getTarget();
var disabled = record.get('disabled');
if (this.isCheckBox(target)) {
target.checked = !disabled;
console.log(target.checked);
this.callParent(arguments);
}
},
isCheckBox : function(element) {
return element && element.tagName.toLowerCase() === 'input' && element.type === 'checkbox';
}
});
Ext.define('ChartApp.components.ChartContainer', {
extend : 'Ext.container.Container',
alias : 'widget.chartcontainer',
referenceHolder: true,
height : 600,
width : 800,
layout: 'border',
items: [{
region : 'west',
title : 'Legend',
items : [{
xtype : 'extendedlegend',
reference : 'chartLegend',
}],
width : 180,
minHeight : 550,
collapsible : true,
collasped : false,
split : true,
animCollapse : true
}, {
region : 'center',
reference : 'chartWrapper',
layout : 'fit',
margins : '5 5 0 0',
items : [{
xtype : 'column-multi-axis',
reference : 'chart',
layout : 'fit'
}]
}],
initComponent : function() {
var me = this;
me.callParent(arguments);
var chart = me.lookupReference('chart');
console.log(chart.getStore()); // Still a config
chart.getStore().loadData(climateData);
var legend = me.lookupReference('chartLegend');
legend.setStore(chart.getLegendStore());
}
});
Ext.onReady(function() {
Ext.create('Ext.panel.Panel', {
title : 'Dual Axis Example',
layout : 'fit',
items : [{
xtype : 'chartcontainer'
}],
renderTo: Ext.getBody(),
});
});
function toCelcius(faherenheit) {
return (faherenheit - 32) / 1.8;
};
function toFaherenheit(celcius) {
return (celcius * 1.8) + 32;
};
function getClimateData() {
return [
{ month: "Jan", high: 14.7, low: 5.6 },
{ month: "Feb", high: 16.5, low: 6.6 },
{ month: "Mar", high: 18.6, low: 7.3 },
{ month: "Apr", high: 20.8, low: 8.1 },
{ month: "May", high: 23.3, low: 9.9 },
{ month: "Jun", high: 26.2, low: 11.9 },
{ month: "Jul", high: 27.7, low: 13.3 },
{ month: "Aug", high: 27.6, low: 13.2 },
{ month: "Sep", high: 26.4, low: 12.1 },
{ month: "Oct", high: 23.6, low: 9.9 },
{ month: "Nov", high: 17.0, low: 6.8 },
{ month: "Dec", high: 14.7, low: 5.8 }
];
}

Store does not yet exist at this point - better to say there was no attempt to run setStore() yet. If you really need it at that point try to call:
chart.setStore(chart.getStore());
That should call the underlying setter's methods that are responsible for store creation.

Related

custom ticks based on selected range from rangeSelector in Highstock

I am trying to get my Highcharts/Highstock chart to display a custom tick when the rangeSelector is set to All, I have it setup this way, but is throwing me errors when I try to use the interactive portion of the graph
Received below answer from Highstock Change tick interval on range selector change
componentDidMount() {
// Timezone Offset for PST standard is UTC timezone
Highcharts.setOptions({
global: {
timezoneOffset: 8 * 60
},
lang: {
thousandsSep: ','
}
});
Highcharts.stockChart('chart', {
chart: {
backgroundColor:'rgba(255, 255, 255, 0.0)',
height: 400,
zoomType: 'xy'
},
title: {
text: 'Bitcoin Chart',
style: {
color: 'white'
}
},
navigator: {
trigger: "navigator",
triggerOp: "navigator-drag",
rangeSelectorButton: undefined,
handles: {
backgroundColor: 'white',
borderColor: 'black'
}
},
scrollbar: {
enabled: false
},
rangeSelector: {
buttons: [{
type: 'day',
count: 1,
text: '1d'
}, {
type: 'day',
count: 7,
text: '7d'
}, {
type: 'month',
count: 1,
text: '1m'
}, {
type: 'month',
count: 3,
text: '3m'
}, {
type: 'year',
count: 1,
text: '1y'
}, {
type: 'all',
text: 'All'
}],
selected: 6,
// styles for the buttons
buttonTheme: {
fill: 'black',
// stroke: 'none',
'stroke-width': 0,
r: 8,
style: {
color: 'white',
fontWeight: 'bold'
},
states: {
hover: {
},
select: {
fill: 'white',
style: {
color: 'black'
}
}
}
},
// Date Selector box
inputBoxBorderColor: 'black',
inputBoxWidth: 120,
inputBoxHeight: 18,
inputStyle: {
color: 'black',
fontWeight: 'bold'
},
labelStyle: {
color: 'silver',
fontWeight: 'bold'
},
},
series: [{
name: 'Bitcoin Price',
color: 'black',
data: this.props.data.all_price_values,
type: 'area',
threshold: null,
tooltip: {
valuePrefix: '$',
valueSuffix: ' USD',
valueDecimals: 2
}
}],
plotOptions: {
series: {
fillColor: {
linearGradient: [0, 0, 0, 0],
stops: [
[0, '#FF9900'],
[1, Highcharts.Color(Highcharts.getOptions().colors[0]).setOpacity(0).get('rgba')]
]
}
}
},
xAxis: {
events: {
setExtremes: function(e) {
if (e.trigger === "rangeSelectorButton" && e.rangeSelectorButton.text === "All") {
var range = e.max - e.min;
// ticks spaced by one day or one hour
var ticksSpacing = range >= 86400 * 1000 ? 86400 : 3600;
this.update({
tickPositioner: function() {
var positions = [],
info = this.tickPositions.info;
for (var x = this.dataMin; x <= this.dataMax; x += ticksSpacing * 1000) { // Seconds * 1000 for ticks
positions.push(x);
};
positions.info = info;
return positions;
}
}, false);
}
}
},
title: {
enabled: true,
text: 'Date (Timezone: PST)',
style: {
color: 'white'
}
},
labels: {
style: {
color: 'white'
}
},
type: 'datetime',
dateTimeLabelFormats: {
day: '%b %e, %Y'
},
tickInterval: 1
},
yAxis: {
floor: 0,
labels: {
formatter: function () {
return '$' + this.axis.defaultLabelFormatter.call(this);
},
format: '{value:,.0f}',
align: 'left',
style: {
color: 'white'
},
},
},
// Mobile Design
responsive: {
rules: [{
condition: {
maxWidth: 600
},
chartOptions: {
chart: {
height: 400
},
subtitle: {
text: null
},
navigator: {
enabled: false
}
}
}]
}
});
}
I am talking about the blue highlighted section, when I move it, it throws an error
I am trying to get the charts to have 2 plots per day on ALL rangeSelector, displaying the first point in the day and the last point in a day. What am I doing wrong?
EDIT 1 : Updated to full config, X Axis is now being disrupted by the original answer, ticks on custom range selector is still in works. Added images to show what's going on
The setExtremes event is raised each time you change the range to be displayed on the graph. It can have several origins:
A button click in the range selector
An handle drag in the navigator
etc..
The actual properties of the event depend on its origin. If you output the event with console.log(e), you'll see that it's not the same for these two origins:
Button click in the range selector
{
trigger: "rangeSelectorButton",
rangeSelectorButton: {
text: "2Hour",
type: "hour",
count: 2,
},
...
}
Handle drag in the navigator
{
trigger: "navigator",
triggerOp: "navigator-drag",
rangeSelectorButton: undefined
}
If you drag the handle in the navigator, there's no rangeSelectorButton attached to the event, because it doesn't make sense: in that case, no button is pressed.
To fix your error, you can add a check on the trigger property:
xAxis: {
events: {
setExtremes: function(e) {
if (e.trigger === "rangeSelectorButton" && e.rangeSelectorButton.text === "All") {
...
}
}
}
How to solved the actual issue
Now, the REAL issue. You want to change the ticks based on what is displayed: either the beginning and end of each day, or hours if not a complete day. You can do that with e.min and e.max, that represent the selected time range.
Like so:
setExtremes: function(e) {
var range = e.max - e.min;
// ticks spaced by one day or one hour
var ticksSpacing = range >= 86400 * 1000 ? 86400 : 3600;
this.update({
tickPositioner: function() {
var positions = [],
info = this.tickPositions.info;
for (var x = this.dataMin; x <= this.dataMax; x += ticksSpacing * 1000) { // Seconds * 1000 for ticks
positions.push(x);
};
positions.info = info;
return positions;
}
}, false);
}

How to display content $scope in HighCharts?

I'm doing a statistical graph using angularJs and highChartsJS.
Here is the code angularJS:
app.controller("StatController",function($scope,$http,fileUpload,$window, $filter)
{
var ids=location.search; // id ressource
$scope.FindStats=function(){
$http.get(url+"/Stats"+ids)
.success(function(data){
$scope.Stat = data;
console.log(JSON.stringify($scope.Stat));//{"idStat":21,"nbrBoks":7,"nbSection":5,"total":135,"resCon":0.0518519,"resNotCon":0.037037}
}).error(function(err,data){
console.log("error:"
+data);
});
};
$scope.FindStats();
});
Html code:
<div>
{{Stat}}
<!--{"idStat":21,"nbrBoks":7,"nbSection":5,"total":135,"resCon":0.0518519,"resNotCon":0.037037} -->
</div>
<script type="text/javascript">
Highcharts.chart('container', {
chart: {
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false,
type: 'pie'
},
title: {
text: 'Browser market shares January, 2015 to May, 2015'
},
tooltip: {
pointFormat: '{series.name}: <b>{point.percentage:.2f}%</b>'
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: true,
format: '<b>{point.name}</b>: {point.percentage:.2f} %',
style: {
color: (Highcharts.theme && Highcharts.theme.contrastTextColor) || 'black'
}
}
}
},
series: [{
name: 'Brands',
colorByPoint: true,
data: [{
name: 'Result of books',
y: '{Stat.resNotCon}', // error is here
color: '#00c853',
},{
name: 'Result of section',
y:'{Stat.resCon}', //error is here
color: '#b71c1c',
}]
}]
});
</script>
After a test of the code, I have a problem :
Uncaught Error: Highcharts error #14: www.highcharts.com/errors/14
at Object.a.error (http://code.highcharts.com/highcharts.js:10:49)
at k.setData (http://code.highcharts.com/highcharts.js:289:213)
at k.init (http://code.highcharts.com/highcharts.js:282:174)
at a.Chart.initSeries (http://code.highcharts.com/highcharts.js:248:70)
at http://code.highcharts.com/highcharts.js:271:370
at Array.forEach (native)
at a.each (http://code.highcharts.com/highcharts.js:27:360)
at a.Chart.firstRender (http://code.highcharts.com/highcharts.js:271:341)
at a.Chart.init (http://code.highcharts.com/highcharts.js:247:444)
at a.Chart.getArgs (http://code.highcharts.com/highcharts.js:246:307)
So the problem is with the format of the data in highCharts.js:
Highcharts Error #14
String value sent to series.data, expected Number
This happens if you pass in a string as a data point, for example in a
setup like this:
series: [{ data: ["3", "5", "1", "6"] }] Highcharts expects the data
values to be numbers. The most common reason for this is that data is
parsed from CSV or from a XML source, and the implementer forgot to
run parseFloat on the parsed value.
For performance reasons internal type casting is not performed, and
only the first value is checked (since 2.3).
Edit1:
data: [{
name: 'Result of books',
color: '#00c853',
y: {Stat.resNotCon} // error is here
},{
name: 'Result of section',
color: '#b71c1c',
y: {Stat.resCon} //error is here
}]
Error of edit1:
Uncaught SyntaxError: Unexpected token. in y: {Stat.resNotCon}
Edit2:
$scope.FindStats=function(){
$http.get(url+"/Stats"+ids)
.success(function(data){
$scope.Stat = data;
console.log(JSON.stringify($scope.Stat));//{"idStat":21,"nbrBoks":7,"nbSection":5,"total":135,"resCon":0.0518519,"resNotCon":0.037037}
}).error(function(err,data){
console.log("error:"
+data);
});
};
$scope.FindStats();
console.log("$scope "+$scope.Stat); //it's empty
var Stat=$scope.Stat;
console.log("after "+Stat); // it's empty
How to format data for highCharts.JS?
Thank you,
The problem is resolved through the following code:
var app = angular.module('myApp',[]);
app.controller("StatController",function($scope,$http,$window, $filter,$RootScope)
{
$RootScope.FindStats = function() {
$scope.Stat = {
"idStat": 21,
"nbrBoks": 7,
"nbSection": 5,
"total": 135,
"resCon": 0.0518519,
"resNotCon": 0.037037
};
Highcharts.chart('container', {
chart: {
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false,
type: 'pie'
},
title: {
text: 'Browser market shares January, 2015 to May, 2015'
},
tooltip: {
pointFormat: '{series.name}: <b>{point.percentage:.2f}%</b>'
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: true,
format: '<b>{point.name}</b>: {point.percentage:.2f} %',
style: {
color: (Highcharts.theme && Highcharts.theme.contrastTextColor) || 'black'
}
}
}
},
series: [{
name: 'Brands',
colorByPoint: true,
data: [{
name: 'Result of books',
y: Stat.resNotCon,
color: '#00c853',
},{
name: 'Result of section',
y:Stat.resCon,
color: '#b71c1c',
}]
}]
});
}
$scope.FindStats();
});
You just have to store the value of Stat in variable and not bind it to scope.
var app = angular.module('myApp',[]);
app.controller("StatController",function($scope,$http,$window, $filter)
{
$scope.FindStats = function() {
$scope.Stat = {
"idStat": 21,
"nbrBoks": 7,
"nbSection": 5,
"total": 135,
"resCon": 0.0518519,
"resNotCon": 0.037037
};
}
$scope.FindStats();
var Stat = $scope.Stat;
Highcharts.chart('container', {
chart: {
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false,
type: 'pie'
},
title: {
text: 'Browser market shares January, 2015 to May, 2015'
},
tooltip: {
pointFormat: '{series.name}: <b>{point.percentage:.2f}%</b>'
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: true,
format: '<b>{point.name}</b>: {point.percentage:.2f} %',
style: {
color: (Highcharts.theme && Highcharts.theme.contrastTextColor) || 'black'
}
}
}
},
series: [{
name: 'Brands',
colorByPoint: true,
data: [{
name: 'Result of books',
y: Stat.resNotCon, // error is here
color: '#00c853',
},{
name: 'Result of section',
y:Stat.resCon, //error is here
color: '#b71c1c',
}]
}]
});
});
Working Example
http://jsfiddle.net/ADukg/11648/

Filter by range date for angular-nvd3 directive?

I create an nvd3 graph with the angular-nvd3 directive:
<nvd3 id="analytics-community" options="vm.community.options" data="vm.community.data" config="vm.graphConfig" class="with-3d-shadow with-transitions"></nvd3>
However it does not seem possible to filter the data attribute using |filter:something as it ends up looping infinitely and angular breaks with infinite loop error.
Graph options are setup with:
vm.graphOptions = {
chart: {
type: 'lineChart',
height: 300,
margin : {
top: 50,
right: 50,
bottom: 50,
left: 50
},
x: function(d) {
return d3.time.format.iso.parse(d.key);
},
y: function(d) {
return d.value;
},
useInteractiveGuideline: false,
dispatch: {
stateChange: function(e) { },
changeState: function(e) { },
tooltipShow: function(e) { },
tooltipHide: function(e) { }
},
xScale: d3.time.scale(),
xAxis: {
axisLabel: 'Date',
tickFormat: function (d) {
return d3.time.format('%b %Y')(new Date(d));
}
},
yAxis: {
axisLabel: 'Count',
tickFormat: function(d) {
return d;
}
}
}
};
And the data is set-up with:
vm.community.data = [
{
key: 'Members',
values: vm.statsModel.registeredMembers
},
{
key: 'Students',
values: vm.statsModel.registeredStudents
},
{
key: 'Alumni',
values: vm.statsModel.registeredAlumni
}
];
Where vm.statsModel.registeredMembers is like:
[
{
key: "2015-06-15",
value: 458
},
{
key: "2015-06-23",
value: 459
},
{
key: "2015-06-27",
value: 460
}
]
Any ideas?
Setting the xDomain in vm.graphOptions.chart worked:
vm.graphOptions.chart.xDomain = [new Date(vm.selectedItem.date), dateToday]
Where vm.selectedItem.date = new Date().setMonth(new Date().getMonth() - 6) for 6 months ago... and dateToday = new Date()
So I just $watch for changes on vm.selectedItem which changes with a select box and update xDomain.

Jointjs and angular : ng click doesn't work

I am creating an element with joint js and putting it inside a paper. The element has an ng-click directive in a pencil. However when I click on the element
The element
joint.shapes.flowie.Rect = joint.shapes.basic.Generic.extend(_.extend({}, joint.shapes.basic.PortsModelInterface, {
markup: '<g class="rotatable" ><g class="scalable"><rect class="body"/></g><text class="label"/><text region="" transform="translate(40,10)" ng-init="alert()" ng-click="loadStep(workflow.steps[this.stepName])" class="fa edit fa-pencil"></text><g class="inPorts"/><g class="outPorts"/></g>',
portMarkup: '<g class="port port<%= id %>"><circle class="port-body"/><text class="port-label"/></g>',
defaults: joint.util.deepSupplement({
type: 'devs.Model',
size: { width: 1, height: 1 },
inPorts: [],
outPorts: [],
attrs: {
'.': { magnet: false },
'.body': {
width: 150, height: 350,
stroke: '#000000'
},
'.port-body': {
r: 8,
magnet: true,
stroke: '#000000'
},
text: {
// 'pointer-events': 'none'
},
'.label': { text: 'Model', 'ref-x': .5, 'ref-y': 10, ref: '.body', 'text-anchor': 'middle', fill: '#000000' },
'.inPorts .port-label': { x:-15, dy: 4, 'text-anchor': 'end', fill: '#000000'},
".inPorts circle": {type:"input", magnet:"passive" },
'.outPorts .port-label':{ x: 15, dy: 4, fill: '#000000',type:"output" }
}
}, joint.shapes.basic.Generic.prototype.defaults),
getPortAttrs: function(portName, index, total, selector, type) {
var attrs = {};
var portClass = 'port' + index;
var portSelector = selector + '>.' + portClass;
var portLabelSelector = portSelector + '>.port-label';
var portBodySelector = portSelector + '>.port-body';
attrs[portLabelSelector] = { text: portName };
attrs[portBodySelector] = { port: { id: portName || _.uniqueId(type) , type: type } };
attrs[portSelector] = { ref: '.body', 'ref-y': (index + 0.5) * (1 / total) };
if (selector === '.outPorts') { attrs[portSelector]['ref-dx'] = 0; }
return attrs;
}
}));
There is a saveStep function triggered by saving a form. The form contains some metadata for each element
I then do the following to add the step to the graph
shape = new joint.shapes.flowie.Start({
position: { x: 10, y: 10 },
size: { width: 100, height: 30 },
attrs: { rect: { fill: 'blue' }, '.label': { text: step.stepName, fill: 'white' } },
stepName:name
});
shape.set('inPorts', []);
shape.set('outPorts', ['OUT']);
graph.addCells([shape])
I have heard of the compile directive but can't figure out a way to use it.

Want to call a function when chart is loaded rally

Want to call a function when chart is loaded, written that function in listeners, but its getting called before the chart is displayed, any idea which event should I listen to chartRendered or any other
getChartConfig: function(project_oid) {
that = this;
var chart = Ext.getCmp('mychart');
if (chart) {
chart.destroy();
}
return {
xtype:'rallychart',
id: 'mychart',
storeConfig: {
find: {
'_ProjectHierarchy': project_oid,
"$or": [
{"_TypeHierarchy": "HierarchicalRequirement"},
{"_TypeHierarchy": "Defect"}
],
'Children': null
},
fetch: ['PlanEstimate','_TypeHierarchy','ObjectID', 'ScheduleState', '_ValidFrom', '_ValidTo', '_PreviousValues'],
hydrate: ['ScheduleState', '_TypeHierarchy'],
sort: { '_ValidFrom': 1 }
,
/*find: {
'_ProjectHierarchy': project_oid,
"_TypeHierarchy": {
"$in": ['HierarchicalRequirement', 'Defect']
},
'Children': null
},
fetch: ['PlanEstimate','_TypeHierarchy','ObjectID', 'ScheduleState', '_ValidFrom', '_ValidTo', '_PreviousValues'],
hydrate: ['ScheduleState', '_TypeHierarchy'],
sort: { '_ValidFrom': 1 }*/
},
calculatorType: 'CycleCalculator',
chartColors: [ "#6AB17D", "#F47168", "#000000"],
calculatorConfig: {
startDate: Rally.util.DateTime.format(new Date(this._startDate), 'Y-m-d'),
endDate: Rally.util.DateTime.format(new Date(this._endDate), 'Y-m-d'),
startState: this._startState,
endState: this._endState
//granularity: 'week'
},
chartConfig: {
chart: {
type: 'line',
},
title: { text: 'Cycle/Lead Time' },
border: 1,
plotOptions: {
series: {
connectNulls: true,
marker: {
enabled:false
}
}
},
xAxis: {
//tickmarkPlacement: 'on',
tickInterval: 10,
title: {
text: 'Months'
}
},
yAxis: [
{
title: {
text: 'Average Days'
}
}
]
},
listeners: {
snapshotsAggregated: this.showStats,
scope: this
}
}
},
below the is function I want to call
And in showStats() function I want use chart object,,,,please help..thanks in advance
showStats: function(chart) {
console.log("chart values", chart);
var average = Ext.Array.mean(chart.calculator.globalVar);
var average = Ext.Number.toFixed(average, 2);
var min = Ext.Array.min(chart.calculator.globalVar);
var max = Ext.Array.max(chart.calculator.globalVar);
var count = Ext.Array.sum(chart.calculator.globalVar);
console.log("field value", average, min, max, count);
//field.fieldLabel = average;
var stdDev = this.standardDeviation(average, chart.calculator.globalVar);
var stdDev = Ext.Number.toFixed(stdDev, 2);
this.down('#averageId').setText("Average " + average);
this.down('#countId').setText("Count " + count);
this.down('#minId').setText("Minimum " + min);
this.down('#maxId').setText("Maximum " + max);
this.down('#stdDevId').setText("Std Deviation " + stdDev);
},
Your choice of chartRendered is correct- that is the last one to fire.
If it is fires before the chart is fully rendered, it is a bug, but from my tests it looks like it fires at the right time. I do not know what data is stored in your globalVar and how you arrive at it. Perhaps the problem is somewhere else other then the timing of the chartRendered event.
When I modify this example by adding chartRendered event listener, visually the console.log may log a little faster than the chart animation entirely completes, but the chart data is already fully loaded by then, and all the data is complete. I verified that by building a table with a few stats that you use. Here is the full code:
Ext.define('Rally.example.BurnCalculator', {
extend: 'Rally.data.lookback.calculator.TimeSeriesCalculator',
config: {
completedScheduleStateNames: ['Accepted']
},
constructor: function(config) {
this.initConfig(config);
this.callParent(arguments);
},
getDerivedFieldsOnInput: function() {
var completedScheduleStateNames = this.getCompletedScheduleStateNames();
return [
{
"as": "Planned",
"f": function(snapshot) {
if (snapshot.PlanEstimate) {
return snapshot.PlanEstimate;
}
return 0;
}
},
{
"as": "PlannedCompleted",
"f": function(snapshot) {
if (_.contains(completedScheduleStateNames, snapshot.ScheduleState) && snapshot.PlanEstimate) {
return snapshot.PlanEstimate;
}
return 0;
}
}
];
},
getMetrics: function() {
return [
{
"field": "Planned",
"as": "Planned",
"display": "line",
"f": "sum"
},
{
"field": "PlannedCompleted",
"as": "Completed",
"f": "sum",
"display": "column"
}
];
}
});
var PI_OID = 12483739639; //The ObjectID of the PI on which to burn
Ext.define('Rally.example.BurnChart', {
extend: 'Rally.app.App',
requires: [
'Rally.example.BurnCalculator'
],
launch: function() {
this.add({
xtype: 'rallychart',
storeType: 'Rally.data.lookback.SnapshotStore',
storeConfig: this._getStoreConfig(),
calculatorType: 'Rally.example.BurnCalculator',
calculatorConfig: {
completedScheduleStateNames: ['Accepted', 'Released']
},
chartConfig: this._getChartConfig(),
listeners:{
chartRendered: this._getStats,
scope: this
}
});
},
/**
* Generate the store config to retrieve all snapshots for all leaf child stories of the specified PI
*/
_getStoreConfig: function() {
return {
find: {
_ItemHierarchy: PI_OID,
_TypeHierarchy: 'HierarchicalRequirement',
Children: null
},
fetch: ['ScheduleState', 'PlanEstimate'],
hydrate: ['ScheduleState'],
sort: {
_ValidFrom: 1
},
context: this.getContext().getDataContext(),
limit: Infinity
};
},
/**
* Generate a valid Highcharts configuration object to specify the chart
*/
_getChartConfig: function() {
return {
chart: {
defaultSeriesType: 'area',
zoomType: 'xy'
},
title: {
text: 'PI Burnup'
},
xAxis: {
categories: [],
tickmarkPlacement: 'on',
tickInterval: 5,
title: {
text: 'Date',
margin: 10
}
},
yAxis: [
{
title: {
text: 'Points'
}
}
],
tooltip: {
formatter: function() {
return '' + this.x + '<br />' + this.series.name + ': ' + this.y;
}
},
plotOptions: {
series: {
marker: {
enabled: false,
states: {
hover: {
enabled: true
}
}
},
groupPadding: 0.01
},
column: {
stacking: null,
shadow: false
}
}
};
},
_getStats:function(chart){
var stats = [];
console.log(chart);
var series = chart.chartData.series;
_.each(series, function(s){
stats.push({
name : s.name,
average : Ext.Number.toFixed(Ext.Array.mean(s.data), 2),
min : Ext.Array.min(s.data),
max : Ext.Array.max(s.data),
count : Ext.Array.sum(s.data)
});
});
this._showStats(stats);
},
_showStats: function(stats) {
console.log(stats);
this.add({
xtype: 'rallygrid',
store: Ext.create('Rally.data.custom.Store', {
data: stats
}),
columnCfgs: [
{
text: 'Name',
dataIndex: 'name'
},
{
text: 'Average',
dataIndex: 'average'
},
{
text: 'Min',
dataIndex: 'min'
},
{
text: 'Max',
dataIndex: 'max'
},
{
text: 'Count',
dataIndex: 'count'
}
]
});
}
});

Resources