Related
My React app uses react-chartjs-2 (which in turn uses the latest Chart.js 2.7.2). I'm trying to create stacked line charts with a differently styled section between the second-to-last and last x-axis labels, as shown in this example:
How can this be accomplished?
I solved it myself by separating the stacked line data into 2 datasets, to plot as separate stacked plots on the same figure/axes (by including the 2 separate datasets in a single chart's data object).
#Izzi (from comment) here is example:
Link with examle: https://www.chartjs.org/docs/latest/samples/area/line-boundaries.html
Paste this config into editor on the website linked above:
data
const data = {
labels: generateLabels(),
datasets: [
{
label: 'Data A',
data: [40.96,89.06,65.46,45.46,89.55,54.52,71.24,89.1],
borderColor: Utils.CHART_COLORS.red,
backgroundColor: Utils.CHART_COLORS.red,
// look at this setting
fill: 'origin'
},
{
label: 'Data B',
data: [20.96,65.06,15.46,34.46,53.55,24.52,31.24,59.1],
borderColor: Utils.CHART_COLORS.blue,
backgroundColor: Utils.CHART_COLORS.blue,
fill: 'origin'
},
{
label: 'Data C',
data: [20.96,65.06,15.46,34.46,53.55,24.52,31.24,59.1],
borderColor: Utils.CHART_COLORS.green,
backgroundColor: Utils.CHART_COLORS.green,
fill: 'origin'
}
]
};
config
const config = {
type: 'line',
data: data,
options: {
scales: {
y: {
// look at this setting
stacked: true,
}
},
plugins: {
filler: {
propagate: false,
},
title: {
display: true,
text: (ctx) => 'Fill: ' + ctx.chart.data.datasets[0].fill
}
},
interaction: {
intersect: false,
}
},
};
I have Flot line chart with two dataseries. I would like to edit the tooltips independently for each series. I have tried moving the tooltip settings to the dataset part but it didn't work.
Does anyone know a solution?
$(function () {
var barOptions = {
xaxis: {
tickDecimals: 0
},
yaxes: [{
position: "left"
}, {
position: "right"
}],
colors: ["#36c6d3"],
grid: {
color: "#888888"
},
tooltip: {
show: true,
content: "Uge %x, %s: %y"
}
};
var dataset = [{
data: occData.data,
label: occData.label,
yaxis: occData.yaxis,
lines: {
show: true,
lineWidth: 1,
}
}, {
data: houseData.data,
label: houseData.label,
yaxis: houseData.yaxis,
color: 'grey',
lines: {
show: true,
lineWidth: 1,
fill: false
}
}];
$("#flot-line-chart-past").plot(dataset, barOptions);
});
I'm going to presume that you are using flot.tooltip to provide the tooltips. In which case, the content property of the tooltip configuration object can be a function as well as a format string. I quote from the documentation for the plug-in:
you can pass a callback function(label, xval, yval, flotItem) that must return a string with the format described.
So write a function that distinguishes between each label you use for the two series, and return a different format string for each.
I have a bar chart with a legend in ExtJS 6.0.2.
I need to update the colors of the bars and of the legend when the user does an action (clicking on a pie slice in my case).
Updating the color of the bars works as intended, but the legend doesn't. Here is an example of what I do right now :
chart.getLegendStore().data.items.forEach(function(x){
x.data.mark = 'rgb(255,255,255)';
});
The colors are correctly set, but they only update when I click on the legend item. I guess it's because ExtJS has no way to know that the underlying store has been modified. I tried going up the callstack with the debugger but I didn't find anything useful.
Is there a better way to do what I want, or/and how to make the legend update instanly ?
EDIT: If it helps, here is how I update the bars :
serie.setConfig("colors", newColors);
EDIT2 : And here is the full chart code :
Ext.define('QuoteBarChart', {
extend: 'Ext.chart.CartesianChart',
alias: 'widget.quotebarchart',
xtype: 'quotebarchart',
requires: [
'Ext.chart.axis.Category',
'Ext.chart.axis.Numeric',
'Ext.chart.series.Bar',
'Ext.chart.series.Line',
'Ext.chart.theme.Muted',
'Ext.chart.interactions.ItemHighlight'
],
flex: 2,
height: 600,
theme: 'Muted',
itemId: 'chartId',
store: {
type: 'quote'
},
insetPadding: {
top: 40,
bottom: 40,
left: 20,
right: 40
},
axes: [{
type: 'numeric',
position: 'left',
fields: ['won', 'lost', 'open'],
minimum: 0,
grid: true,
titleMargin: 20,
title: 'Offres'
}, {
type: 'category',
position: 'bottom',
label: {
rotate: {
degrees: 45
}
},
fields: ['month']
}
],
series: [{
type: 'bar',
axis: 'left',
xField: 'month',
itemId: 'barId',
yField: ['open','lost','won'],
title: ['Ouvertes', 'Perdues','Gagnées'],
stacked: true,
fullStack: true,
colors: [
'rgb(64, 145, 186)', 'rgb(151, 65, 68)','rgb(140, 166, 64)'
],
highlight: {
strokeStyle: 'red',
fillStyle: 'black'
},
tooltip: {
trackMouse: true,
scope: this,
renderer: function (toolTip, storeItem, item) {
var name = "";
switch(item.field) {
case 'won': name = "Gagnées"; break;
case 'lost': name = "Perdues"; break;
case 'open': name = "Ouvertes"; break;
}
toolTip.setHtml("");
}
}
}],
legend: {
docked: 'bottom',
listeners: {
itemclick: 'onLegendItemClick',
itemmouseenter: 'onLegendItemHover'
}
}
)};
Ok, instead of modify colors of the series and colors of the legend, you can modify all of them in the same time doing this
chart.setColors(['red','blue','green']);
chart.redraw();
So you need to set colors on chart and not on series, and modify the array on button click.
This is something about the ExtJs5 charts.I have trouble changing the bar chart's labels.
Codes is as below:
Ext.create('Ext.chart.CartesianChart', {
store: {
fields: ['pet', 'households', 'total'],
data: [{
pet: {name:'Cats'},
households: 38,
total: 93
}]
},
axes: [{
type: 'numeric',
position: 'left'
}, {
type: 'category',
position: 'bottom'
}],
series: [{
type: 'bar',
xField: 'pet',
yField: 'households',
label:{
field:'pet',
renderer:function(pet){
return 'Dear '+pet.name;
}
}
}]
});
You must have noticed that the field 'pet' is an object instead of a string.
The renderer in the series label returns the value I want it to be,but the label is still [object Object]!
Labels under the category(x axis in your code) are rendered by 'category' not the series.Try code below:
{
type: 'category',
position: 'bottom',
renderer:function(label){
return label.name;//the var 'label' represents the pet object.
}
}
By the way,I found another problem. No matter how many models are there in the chart store,only the first bar is displayed!
If you try the live code example in the documentation at:
http://docs.sencha.com/ext-js/4-1/#!/api/Ext.chart.series.Bar
More than one label looks beautiful:
data: [
{ 'name': 'metric one', 'data':5 },
{ 'name': 'metric two', 'data':27 }
]
However as soon as you reduce the dataset down to one label, the output looks horrible(notice the label for the bar appears half outside the top of the chart area, instead of vertically aligned with the bar it is to label):
Is this a bug in ExtJS? How do I work around this? Exact ExtJS code that produces this output:
var store = Ext.create('Ext.data.JsonStore', {
fields: ['name', 'data'],
data: [
{ 'name': 'metric one', 'data':5 }
]
});
Ext.create('Ext.chart.Chart', {
renderTo: Ext.getBody(),
width: 500,
height: 300,
animate: true,
store: store,
axes: [{
type: 'Numeric',
position: 'bottom',
fields: ['data'],
label: {
renderer: Ext.util.Format.numberRenderer('0,0')
},
title: 'Sample Values',
grid: true,
minimum: 0
}, {
type: 'Category',
position: 'left',
fields: ['name'],
title: 'Sample Metrics'
}],
series: [{
type: 'bar',
axis: 'bottom',
highlight: true,
tips: {
trackMouse: true,
width: 140,
height: 28,
renderer: function(storeItem, item) {
this.setTitle(storeItem.get('name') + ': ' + storeItem.get('data') + ' views');
}
},
label: {
display: 'insideEnd',
field: 'data',
renderer: Ext.util.Format.numberRenderer('0'),
orientation: 'horizontal',
color: '#333',
'text-anchor': 'middle'
},
xField: 'name',
yField: 'data'
}]
});
One solution is to replace
axisRange = to - from,
on line 383 of Axis.js in ExtJS with
axisRange = to - from == 0 ? 1 : to - from,
to prevent a divide by zero being assigned to the y coordinate of the
axis label.
Yes, the default rendering does look weird when it is just one record.
It can be fixed or worked around though.
In concept, override the series renderer to fix the height and y point in case of single record -
renderer: function(sprite, record, attr, index, store) {
if (store.getCount() == 1) {
attr.height = 80;
attr.y = 75;
}
return attr;
}
You can make changes to the actual overridden values (attr.height and attr.y) to suit your visual needs.
Here is your example modified to look close to what you would expect.
var store = Ext.create('Ext.data.JsonStore', {
fields: ['name', 'data'],
data: [
{'name': 'metric one','data': 5}
//,{'name': 'metric two','data': 7}
]
});
Ext.create('Ext.chart.Chart', {
renderTo: Ext.getBody(),
width: 500,
height: 300,
animate: true,
store: store,
axes: [{
type: 'Numeric',
position: 'bottom',
fields: ['data'],
label: {
renderer: Ext.util.Format.numberRenderer('0,0')
},
title: 'Sample Values',
grid: true,
minimum: 0},
{
type: 'Category',
position: 'left',
fields: ['name'],
title: 'Sample Metrics'}],
series: [{
type: 'bar',
axis: 'bottom',
highlight: true,
tips: {
trackMouse: true,
width: 140,
height: 28,
renderer: function(storeItem, item) {
this.setTitle(storeItem.get('name') + ': ' + storeItem.get('data') + ' views');
}
},
label: {
display: 'insideEnd',
field: 'data',
renderer: Ext.util.Format.numberRenderer('0'),
orientation: 'horizontal',
color: '#333',
'text-anchor': 'middle'
},
xField: 'name',
yField: 'data',
renderer: function(sprite, record, attr, index, store) {
if (store.getCount() == 1) {
attr.height = 80;
attr.y = 75;
}
return attr;
}}]
});
If it seems right, just change the height to 150 from 300 :
Ext.create('Ext.chart.Chart', {
renderTo: Ext.getBody(),
width: 500,
height: 150,
Updating to ExtJS 4.2 should fixes this.
The problem is not in one bar, it is because of the range so if you have a wide range and one bar the labels will not repeat, it is great to hear that it is fixed in version 4.2 please confirm this if you try it.