Related
Is it possible to select a column in a stack bar chart with a colored border? Like this
I started from here:
https://jsfiddle.net/sdfx/hwx9awgn/
// Return with commas in between
var numberWithCommas = function(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
};
var dataPack1 = [40, 47, 44, 38, 27, 31, 25];
var dataPack2 = [10, 12, 7, 5, 4, 6, 8];
var dataPack3 = [17, 11, 22, 18, 12, 7, 5];
var dates = ["SN 1.0.1", "SN 1.0.2", "SN 1.0.3", "SN 1.0.4", "SN 1.0.5", "SN 2.0.0", "SN 2.0.1"];
// Chart.defaults.global.elements.rectangle.backgroundColor = '#FF0000';
var bar_ctx = document.getElementById('bar-chart');
var bar_chart = new Chart(bar_ctx, {
type: 'bar',
data: {
labels: dates,
datasets: [{
label: 'Bad Style',
data: dataPack1,
backgroundColor: "#512DA8",
hoverBackgroundColor: "#7E57C2",
hoverBorderWidth: 0
}, {
label: 'Warning',
data: dataPack2,
backgroundColor: "#FFA000",
hoverBackgroundColor: "#FFCA28",
hoverBorderWidth: 0
}, {
label: 'Error',
data: dataPack3,
backgroundColor: "#D32F2F",
hoverBackgroundColor: "#EF5350",
hoverBorderWidth: 0
}, ]
},
options: {
animation: {
duration: 10,
},
tooltips: {
mode: 'label',
callbacks: {
label: function(tooltipItem, data) {
return data.datasets[tooltipItem.datasetIndex].label + ": " + numberWithCommas(tooltipItem.yLabel);
}
}
},
scales: {
xAxes: [{
stacked: true,
gridLines: {
display: false
},
}],
yAxes: [{
stacked: true,
ticks: {
callback: function(value) {
return numberWithCommas(value);
},
},
}],
}, // scales legend: {display: true} } // options } );
Yes what you can do is in the onClick as second argument you get an array with all the active elements. So what you can do is loop over each dataset in your chart and see if the index matches one of the list with active elements.
If this is the case you give it a borderWidth of 1, else you put it to 0. After you did this you call chart variable.update();
To make this work you need to remove the hoverBorderWidth of all datasets and give all datasets a borderColor of yellow
Use attribute borderColor with an array and borderWith with and object.
datasets: [
{
label: 'Bad Style',
data: dataPack1,
backgroundColor: "#512DA8",
borderColor: [
'rgb(243, 255, 51)',
'rgb(81,45,168)',
'rgb(243, 255, 51)',
'rgb(81,45,168)',
'rgb(81,45,168)',
'rgb(81,45,168)',
'rgb(81,45,168)',
],
borderWidth: {
top: 0,
right: 4,
bottom: 0,
left: 4
},
},
rgb(243, 255, 51) is yellow color.
To change the color, try this:
var borderColor = [
'rgb(81,45,168)',
'rgb(81,45,168)',
'rgb(81,45,168)',
'rgb(81,45,168)',
'rgb(81,45,168)',
'rgb(81,45,168)',
'rgb(81,45,168)',
];
var bar_ctx = document.getElementById('bar-chart');
var bar_chart = new Chart(bar_ctx, {
type: 'bar',
data: {
labels: dates,
datasets: [
{
label: 'Bad Style',
data: dataPack1,
backgroundColor: "#512DA8",
hoverBackgroundColor: "#7E57C2",
hoverBorderWidth: 0,
borderColor: borderColor,
borderWidth: '4',
},
{
label: 'Warning',
data: dataPack2,
backgroundColor: "#FFA000",
hoverBackgroundColor: "#FFCA28",
hoverBorderWidth: 0,
borderColor: borderColor,
borderWidth: '4',
},
{
label: 'Error',
data: dataPack3,
backgroundColor: "#D32F2F",
hoverBackgroundColor: "#EF5350",
hoverBorderWidth: 0,
borderColor: borderColor,
borderWidth: '4',
},
]
},
options: {
onClick: function(e){
var element = this.getElementAtEvent(e);
borderColor[element[0]._index] = 'rgb(244,140,4)';
this.update();
},
animation: {
duration: 10,
},
tooltips: {
mode: 'label',
callbacks: {
label: function(tooltipItem, data) {
return data.datasets[tooltipItem.datasetIndex].label + ": " + numberWithCommas(tooltipItem.yLabel);
}
}
},
scales: {
xAxes: [{
stacked: true,
gridLines: { display: false },
}],
yAxes: [{
stacked: true,
ticks: {
callback: function(value) { return numberWithCommas(value); },
},
}],
}, // scales
legend: {display: true}
} // options
}
);
I use chart.js with React. My question is how to show the month label (MMM) only once per month?
The chart currently has labels: [May 15, May 18, May 21, May 24, ...]
As result I want to get: [May 15, 18, 21, 24, 27, 30, Jun 2, 5, ...]
CodeSandbox
Line Chart:
import React from 'react'
import { Line } from 'react-chartjs-2'
import date from 'date-and-time'
const startDate = new Date(2020, 4, 15)
//===fake data===
const json = '{"responses":[{"rows":[{"values":["1"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["1"]},{"values":["6"]},{"values":["7"]},{"values":["5"]},{"values":["8"]},{"values":["9"]},{"values":["2"]},{"values":["1"]},{"values":["1"]},{"values":["1"]},{"values":["6"]},{"values":["3"]},{"values":["0"]},{"values":["20"]},{"values":["9"]},{"values":["3"]},{"values":["2"]},{"values":["1"]},{"values":["13"]},{"values":["3"]},{"values":["13"]},{"values":["13"]},{"values":["7"]},{"values":["12"]},{"values":["0"]}]}]}'
const values = JSON.parse(json).responses[0].rows.map((row, index) => {
let date = new Date(2020, 4, 20)
date.setDate(startDate.getDate() + index)
return {
y: row.values[0],
x: date,
}
})
//===============
const options = {
legend: {
display: false,
},
hover: {
mode: 'index',
intersect: false,
animationDuration: 0,
},
scales: {
yAxes: [{ position: 'right' }],
xAxes: [{
gridLines: { display: false },
distribution: 'linear',
type: 'time',
time: {
parser: 'MMM D',
tooltipFormat: 'MMM D',
unit: 'day',
unitStepSize: 3,
displayFormats: {
day: 'MMM D',
},
},
ticks: {
min: startDate,
max: date.format(date.addDays(new Date(), 1), 'MMM D'),
autoSkip: true
},
}],
},
tooltips: {
mode: 'x-axis',
},
}
const data = {
datasets: [
{
label: 'test',
fill: false,
data: values,
backgroundColor: '#fff',
borderWidth: 2,
lineTension: 0,
borderColor: 'forestgreen',
hoverBorderWidth: 2,
pointBorderColor: 'rgba(0, 0, 0, 0)',
pointBackgroundColor: 'rgba(0, 0, 0, 0)',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'forestgreen',
showLine: true,
}
],
}
const LineChart = () => <Line data={data} options={options}/>
export default LineChart
Solution 1 label filter:
According to the filtering labels sample you can set a function to define what should be displayed:
options: {
scales: {
x: {
display: true,
ticks: {
callback: function(dataLabel, index) {
// Apply logic to remove name of the month
return dataLabel
}
}
},
y: {
display: true,
beginAtZero: false
}
}
}
Github source of the example
Solution 2:
You could prepare your labels array beforehand. Filter the occurence of all the upcoming mentions and feed this array to chart.js.
Define different displayFormats for day and month.
Enable ticks.major.
Mark the desired ticks as major through the afterBuildTicks callback.
time: {
...
displayFormats: {
day: 'D',
month: 'MMM D',
},
},
ticks: {
major: {
enabled: true
}
},
afterBuildTicks: (scale, ticks) => {
ticks.forEach((t, i) => t.major = i == 0 || new Date(t.value).getMonth() != new Date(ticks[i - 1].value).getMonth());
return ticks;
}
Please take a look at your amended code and see how it works.
const startDate = new Date(2020, 4, 15)
//===fake data===
const json = '{"responses":[{"rows":[{"values":["1"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["0"]},{"values":["1"]},{"values":["6"]},{"values":["7"]},{"values":["5"]},{"values":["8"]},{"values":["9"]},{"values":["2"]},{"values":["1"]},{"values":["1"]},{"values":["1"]},{"values":["6"]},{"values":["3"]},{"values":["0"]},{"values":["20"]},{"values":["9"]},{"values":["3"]},{"values":["2"]},{"values":["1"]},{"values":["13"]},{"values":["3"]},{"values":["13"]},{"values":["13"]},{"values":["7"]},{"values":["12"]},{"values":["0"]}]}]}'
const values = JSON.parse(json).responses[0].rows.map((row, index) => {
let date = new Date(2020, 4, 20);
date.setDate(startDate.getDate() + index)
return {
y: row.values[0],
x: date
}
})
//===============
const options = {
legend: {
display: false
},
hover: {
mode: 'index',
intersect: false,
animationDuration: 0
},
scales: {
yAxes: [{
position: 'right'
}],
xAxes: [{
gridLines: {
display: false
},
distribution: 'linear',
type: 'time',
time: {
tooltipFormat: 'MMM D',
unit: 'day',
unitStepSize: 3,
displayFormats: {
day: 'D',
month: 'MMM D',
},
},
ticks: {
major: {
enabled: true
}
},
afterBuildTicks: (scale, ticks) => {
ticks.forEach((t, i) => t.major = i == 0 || new Date(t.value).getMonth() != new Date(ticks[i - 1].value).getMonth());
return ticks;
}
}]
},
tooltips: {
mode: 'x-axis',
}
};
const data = {
datasets: [{
label: 'test',
fill: false,
data: values,
backgroundColor: '#fff',
borderWidth: 2,
lineTension: 0,
borderColor: 'forestgreen',
hoverBorderWidth: 2,
pointBorderColor: 'rgba(0, 0, 0, 0)',
pointBackgroundColor: 'rgba(0, 0, 0, 0)',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'forestgreen',
showLine: true,
}],
};
new Chart('myChart', {
type: 'line',
data: data,
options: options
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>
<canvas id="myChart" height="90"></canvas>
I'm trying to make a Chart.js with a dynamic x-axis that will always use the next 7 months as the ticks for the x-axis.
But I'm having two problems:
The lines are not showing on my graph
The x-axis is only showing the first and last month, none of the months in-between.
Here is an example I made in paint to show what I'm trying to achieve:
And here is the code I have so far:
/* Build the charts */
var ctx = document.getElementById('ROIchart').getContext('2d');
var chart = new Chart(ctx, {
// The type of chart we want to create
type: 'line',
// The data for our dataset
data: {
datasets: [{
label: 'Paid Search and Leads',
backgroundColor: 'red',
borderColor: 'red',
data: [10, 10, 10, 10, 10, 10, 10],
}, {
label: 'SEO and Content',
backgroundColor: 'green',
borderColor: 'green',
data: [0, 2, 8, 21, 57, 77, 100],
fill: true,
}]
},
// Configuration options go here
options: {
responsive: true,
scales: {
xAxes: [{
type: 'time',
time: {
unit: 'month'
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>
<canvas id="ROIchart"></canvas>
With the moment.js library, you can look at the length of your array, and from a starting month generate the months, and then put them as labels
/* Build the charts */
var ctx = document.getElementById('ROIchart').getContext('2d');
var array1 = [10, 10, 10, 10, 10, 10, 10];
var months = []
for (let i = 0; i < array1.length; i++) {
months.push(moment().year(2020).month(i+1).date(0).startOf('month'))
}
var chart = new Chart(ctx, {
type: 'line',
data: {
labels: months,
datasets: [{
label: 'Paid Search and Leads',
backgroundColor: 'red',
borderColor: 'red',
data: array1,
}, {
label: 'SEO and Content',
backgroundColor: 'green',
borderColor: 'green',
data: [0, 2, 8, 21, 57, 77, 100],
fill: true,
}]
},
options: {
responsive: true,
scales: {
xAxes: [{
type: 'time',
time: {
unit: 'month'
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.js"></script>
<canvas id="ROIchart"></canvas>
I am using Chart.js (http://www.chartjs.org/docs/) for charting.
My type Chart is Bar.
Label of X axis have 4 lines.
I Change color of X axis values. color of values is one color.
But I want one line per color and color same like the bar color.
var barChartData = {
labels: [["Injection", 10, 20], // here I want to change the color
["Electronics", 5, 15],
["TOTAL", 15, 35]
],
datasets: [{
label: "2018",
backgroundColor: window.chartColors.orange,
yAxisID: 'A',
data: [10, 5, 15]
}, {
label: "2017",
backgroundColor: window.chartColors.green,
yAxisID: 'A',
data: [20, 15, 35]
}]
};
var canvas = document.getElementById('canvas').getContext('2d');
new Chart(canvas, {
type: 'bar',
data: barChartData,
options: {
scales: {
yAxes: [{
id: 'A',
type: 'linear',
position: 'left',
}, {
id: 'B',
type: 'linear',
position: 'right',
ticks: {
max: 100,
min: 0
}
}],
xAxes: [{
ticks: {
fontColor: "#222", // This here that I changed.
},
}]
}
}
})
I want to change color of labels are 10, 5, 15 is orange and 20, 15, 35 is green and Injection, Electronics, TOTAL is black
Can I do that? How?
var myData = [
["id1","test 11111","AA",1.95],
["id2","test 2","BB",1.94],
["id3","test 3","CC",1.93],
["id4","test 4","DD",1.93],
["id5","test 5","EE",1.91],
["id6","test 6","FF",1.90],
["id7","test 7","GG",1.82],
["id8","test 8","HH",1.85],
["id9","test 9","II",1.83],
["id10","test 10","JJ",1.79]
];
var ctx = $("#c");
var myChart = new Chart(ctx, {
type: 'bar',
data: {
datasets: [{
label: '# of Votes',
xAxisID:'modelAxis',
data: myData.map((entry)=>entry[3])
}]
},
options:{
scales:{
xAxes:[
{
id:'modelAxis',
type:"category",
ticks:{
//maxRotation:0,
autoSkip: false,
callback:function(label, x2, x3, x4){
return label;
}
},
labels:myData.map((entry=>entry[1]))
},
{
id:'groupAxis',
type:"category",
gridLines: {
display: false,
drawBorder: false,
drawOnChartArea: false,
offsetGridLines: false
},
ticks:{
padding:0,
maxRotation:0,
fontSize: 10,
fontColor: '#FF9090',
autoSkip: false,
callback:function(label){
return label;
}
},
offset: true,
labels:myData.map((entry=>entry[1]))
},{
id:'groupAxis2',
type:"category",
gridLines: {
display: false,
drawBorder: false,
drawOnChartArea: false,
offsetGridLines: false
},
scaleLabel:{
padding: 10,
},
ticks:{
padding:0,
fontSize: 10,
fontColor: '#AB64F4',
maxRotation:0,
autoSkip: false,
callback:function(label){
return label;
}
},
offset: true,
labels:myData.map((entry=>entry[1]))
}
],
yAxes:[{
ticks:{
beginAtZero:true
}
}]
}
}
});
I want to show a stacked area chart in a new window. The enviroment is the ExtJs Webdesktop.
When I create the window through:
Ext.create('Desktop.displayPresences.view.displayPresencesChart').show()
I always get these error messages:
mypath/desktop/widget/cartesian.js?_dc=1423082524533 404 (Not Found)
Error: [Ext.create] Unrecognized class name / alias: widget.cartesian
I researched a lot but couldn't solve the problem yet.
What I've done:
Added this to app.json
"requires": [
"ext-charts"
],
Through sencha cmd I tried these commands
sencha app build
sencha app refresh
sencha app watch
In the google develeopers tools in the sources tab I can see that the necessary file 'Ext.chart.series.Cartesian' is loaded. It is in the packages/ext-charts/src/chart/series folder.
This is my code
Ext.define('Desktop.displayPresences.view.displayPresencesChart', {
extend: 'Ext.Window',
requires: [
'Ext.chart.*',
'Ext.data.JsonStore'
],
xtype: 'area-stacked',
width: 650,
initComponent: function() {
var me = this;
this.myDataStore = Ext.create('Ext.data.JsonStore', {
fields: ['month', 'data1', 'data2', 'data3', 'data4' ],
data: [
{ month: 'Jan', data1: 20, data2: 37, data3: 35, data4: 4 },
{ month: 'Feb', data1: 20, data2: 37, data3: 36, data4: 5 },
{ month: 'Mar', data1: 19, data2: 36, data3: 37, data4: 4 },
{ month: 'Apr', data1: 18, data2: 36, data3: 38, data4: 5 },
{ month: 'May', data1: 18, data2: 35, data3: 39, data4: 4 },
{ month: 'Jun', data1: 17, data2: 34, data3: 42, data4: 4 },
{ month: 'Jul', data1: 16, data2: 34, data3: 43, data4: 4 },
{ month: 'Aug', data1: 16, data2: 33, data3: 44, data4: 4 },
{ month: 'Sep', data1: 16, data2: 32, data3: 44, data4: 4 },
{ month: 'Oct', data1: 16, data2: 32, data3: 45, data4: 4 },
{ month: 'Nov', data1: 15, data2: 31, data3: 46, data4: 4 },
{ month: 'Dec', data1: 15, data2: 31, data3: 47, data4: 4 }
]
});
me.items = [{
xtype: 'cartesian',
width: '100%',
height: 500,
legend: {
docked: 'bottom'
},
store: this.myDataStore,
insetPadding: 40,
sprites: [{
type: 'text',
text: 'Area Charts - Stacked Area',
font: '22px Helvetica',
width: 100,
height: 30,
x: 40, // the sprite x position
y: 20 // the sprite y position
}, {
type: 'text',
text: 'Data: Browser Stats 2012',
font: '10px Helvetica',
x: 12,
y: 430
}, {
type: 'text',
text: 'Source: http://www.w3schools.com/',
font: '10px Helvetica',
x: 12,
y: 440
}],
axes: [{
type: 'numeric',
fields: 'data1',
position: 'left',
grid: true,
minimum: 0,
renderer: function (v) { return v.toFixed(v < 10 ? 1: 0) + '%'; }
}, {
type: 'category',
fields: 'month',
position: 'bottom',
grid: true,
label: {
rotate: {
degrees: -45
}
}
}],
series: [{
type: 'area',
axis: 'left',
title: [ 'IE', 'Firefox', 'Chrome', 'Safari' ],
xField: 'month',
yField: [ 'data1', 'data2', 'data3', 'data4' ],
style: {
opacity: 0.80
},
highlight: {
fillStyle: '#000',
lineWidth: 2,
strokeStyle: '#fff'
},
tooltip: {
trackMouse: true,
style: 'background: #fff',
renderer: function(storeItem, item) {
var browser = item.series.getTitle()[Ext.Array.indexOf(item.series.getYField(), item.field)];
this.setHtml(browser + ' for ' + storeItem.get('month') + ': ' + storeItem.get(item.field) + '%');
}
}
}]
}];
this.callParent();
}
});
I don't know why the xtype: 'cartesian' is searching at this location (mypath/desktop/widget/cartesian.js)?
Normally you need for an xtype an alias, but when I check Ext.chart.series.Cartesian there is no alias definied?
So I tried to define one by myself. But then I just got the message: Uncaught TypeError: undefined is not a function.
Any ideas how to fix this?
This is my file structure in the developer tools:
Best regards
I could solve it, my entry in app.json was wrong.
If you want to use the cartesian as a xtype you have to use the new 'sencha-charts', 'ext-charts' was from the old ExtJs Version.
Additionally I set 'Ext.chart.Cartesian' as a direct require.
If you look more at the Ext.chart.series.Cartesian and its parent Ext.chart.series.Series, you'll see that they are not widgets - that is, they re not descendants of Ext.component.Component. This explains the lack of an xtype.
The widget that has the xtype of 'cartesian' is Ext.chart.Cartesian.
The next part of the answer is why you can't see that. You've got the package loaded via app.json correctly, and I would assume that the Ext.chart.Cartesian is being loaded correctly by your wildcard requires (I don't use those, personally). So on that part, I'm stumped - the only thing I can suggest is checking in the dev tools to make sure the Cartesian chart is loaded, and possibly dropping the wildcard requires for an explicit list of the desired classes.