I've implemented the technique described in this question to render vertical lines on my chart to show key dates when something important happened.
However, the text describing these events can be quite long, so just drawing text on the canvas isn't a good solution.
Is there some way to use the chart.js API to draw an invisible point on the chart (at the top of the line) which will become interactive and show a tooltip when the mouse hovers over it?
As far as I can see, only data points will show tooltips. I attempted to add another series to contain the lines data, but without much success - it also created a legend for this series, which I don't want. I set the values to 9999 to try to get them to appear at the top of the canvas, but this did not work and seems like a hack.
You could add a second dataset that contains a single value at the x-position where the vertical line should be drawn, its value should correspond to the highest value of the first dataset. To make the point invisible, define transparent background and border colors using 'rgba(0,0,0,0)'.
{
data: [null, null, 12],
pointRadius: 10,
backgroundColor: 'rgba(0,0,0,0)',
borderColor: 'rgba(0,0,0,0)'
}
To only display the legend label of the relevant dataset, you need to define a legend.labels.filter function.
legend: {
labels: {
filter: legendItem => legendItem.datasetIndex == 0
}
},
Further we need to define some tooltip.callback functions to show desired data in the tooltips.
Please take a look at below runnable code snippet and see how it works. This code uses the latest stable version of Chart.js (currently 2.9.3).
new Chart('canvas', {
type: 'line',
plugins: [{
beforeDraw: chart => {
var ctx = chart.chart.ctx;
var xAxis = chart.scales['x-axis-0'];
var yAxis = chart.scales['y-axis-0'];
ctx.save();
var lineAtIndex = chart.data.datasets[0].lineAtIndex;
var x = xAxis.getPixelForTick(lineAtIndex);
ctx.strokeStyle = '#ff0000';
ctx.beginPath();
ctx.moveTo(x, yAxis.bottom);
ctx.lineTo(x, yAxis.top);
ctx.stroke();
ctx.restore();
}
}],
data: {
labels: ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"],
datasets: [{
label: 'My Dataset',
data: [12, 3, 2, 1, 8, 8, 2, 2, 3, 5, 7, 1],
lineAtIndex: 2,
lineTooltip: ['This is', 'a multi-line', 'tooltip']
},
{
data: [null, null, 12],
pointRadius: 10,
backgroundColor: 'rgba(0,0,0,0)',
borderColor: 'rgba(0,0,0,0)'
}
]
},
options: {
legend: {
labels: {
filter: legendItem => legendItem.datasetIndex == 0
}
},
tooltips: {
callbacks: {
title: (tooltipItems, data) => {
if (tooltipItems[0].datasetIndex == 0) {
return data.labels[tooltipItems[0].index];
}
return data.datasets[0].lineTooltip;
},
label: (tooltipItems, data) => {
if (tooltipItems.datasetIndex == 0) {
return data.datasets[0].label + ': ' + data.datasets[0].data[tooltipItems.index];
}
return null;
}
}
},
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="canvas" height="90"></canvas>
Related
Hello,
I've followed this post (Moving vertical line when hovering over the chart using chart.js) to draw a vertical line on my chart.
With a single dataset, it's working just fine.
But for a multiple datasets display (with stacked options on the y-axis), the vertical line is drawn over the chart's tooltip.
Neither setting the z-index of the chart's tooltip nor the vertical line could solve my problem. Since I can't find any property to do that.
Do you have any idea/suggestion to solve this issue?
I'm using react-chart-js 2 with chart-js ^2.9.4 as a peer dependency.
You can use a custom plugin that draws after all the datasets have drawn but before the tooltip is drawn:
var options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderWidth: 1
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderWidth: 1
}
]
},
options: {
scales: {
yAxes: [{
stacked: true
}]
},
plugins: {
customLine: {
width: 5,
color: 'pink'
}
}
},
plugins: [{
id: 'customLine',
afterDatasetsDraw: (chart, x, opts) => {
const width = opts.width || 1;
const color = opts.color || 'black'
if (!chart.active || chart.active.length === 0) {
return;
}
const {
chartArea: {
top,
bottom
}
} = chart;
const xValue = chart.active[0]._model.x
ctx.lineWidth = width;
ctx.strokeStyle = color;
ctx.beginPath();
ctx.moveTo(xValue, top);
ctx.lineTo(xValue, bottom);
ctx.stroke();
}
}]
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
</body>
I have difficulty in changing the color of the bars in the bar chart to suit the theme of my website. I have gone to youtube and watched the following video https://www.youtube.com/watch?v=Cw87VN7K1Ek
and tried their solution to change color but was not successful. I would like to seek your help to know where I may have gone wrong or changes that have to be made to my code to successfully display the new color.
The following is the code snippet to configure the bar chart:
constructor() {
this.chartOptions = {
series: [
{
name: "My-series",
data: [10, 41, 35, 51, 49, 62, 69, 91, 148]
}
],
chart: {
height: 350,
type: "bar"
},
title: {
text: "My First Angular Chart"
},
xaxis: {
categories: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep"]
},
fill: {
colors: ['#f00']
}
};
}
The following is the result, the colors of the chart is still the default color from ApexCharts
I also would like to change the color of a specific bar (data point) within the bar chart when selected. I have looked through the following link: https://apexcharts.com/docs/options/states/, but this only changes the shade but I like to change the color but have not seem to find any resource to go about do it. I would sincerely appreciate if you have experienced the following before and has managed to change it successfully.
You can try this configuration:
var options = {
chart: {
type: 'bar',
height: 'auto'
},
series: [{
name: "My-series",
data: [10, 41, 35, 51, 49, 62, 69, 91, 148]
}],
dataLabels: {
enabled: false
},
xaxis: {
categories: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep"]
},
colors: [
function ({ value, seriesIndex, dataPointIndex, w }) {
if (dataPointIndex == 8) {
return "#7E36AF";
} else {
return "#D9534F";
}
}
]
}
var chart = new ApexCharts(document.querySelector("#chart"), options);
chart.render();
I hope it was helpful!
Below is the pen for different color options. It shows single color and changes to multi color after a delay just to showcase available options. Pick the one you like.
https://codepen.io/raevilman/full/dyXNgNo
Chart options used in above link.
var options = {
chart: {
type: "bar"
},
series: [
{
data: [10, 40, 20, 44, 22, 12]
}
],
xaxis: {
categories: [1, 2, 3, 4, 5, 6]
},
colors: ["#00FF00"]
};
PS: I couldn't get the way to change selection color for bar chart.
I've created a simple line chart with a straight line, but if the line runs along the top and bottom horizontal grid line it is displayed thinner than defined. Even if the grid lines are hidden.
https://i.stack.imgur.com/rD58f.png
My code:
window.onload = function() {
var config = {
type: "line",
data: {
labels: ["Jan", "Feb", "Mar","Jun","Jul","Aug","Sep", "Oct", "Nov"],
datasets: [ {
backgroundColor: "#ff0000",
borderColor: "#ff0000",
fill: false,
borderWidth: 2,
lineTension: 0,
data: [0, 0, 0, 1, 6, 8, 8, 8, 8]
}]
},
options: {
responsive: true,
scales: {
xAxes: [{
gridLines: { display: false }
}],
yAxes: [{
gridLines: { display: false }
}]
},
legend: {
display: false
}
}
};
var ctx = document.getElementById("canvas").getContext("2d");
var chart = new Chart(ctx, config);
}
How can I solve this?
I tried a litte bit. But the only solution i found which actually worked, was to add the space with the canvas helpers of chartjs. You can achieve this by adding the following code to your application:
var WIDE_CLIP = {top: 2, bottom: 4};
Chart.canvasHelpers.clipArea = function(ctx, clipArea) {
ctx.save();
ctx.beginPath();
ctx.rect(
clipArea.left,
clipArea.top - WIDE_CLIP.top,
clipArea.right - clipArea.left,
clipArea.bottom - clipArea.top + WIDE_CLIP.bottom
);
ctx.clip();
}
Take a look at this: https://stackoverflow.com/a/46303679/4032712
I tried to use the padding and position options but none of the seems to work for your problem. Hope I could help you with this!
I am using Chart.js grouped bar chart. I want to show my bars with gradient colors. Currently it show as shown in below image. Any help will be greatly appreciated.
var rateOfReturn= document.getElementById("rateofreturn-chart-canvas").getContext('2d');
var rateOfReturnData = {
labels: ["Monthly", "Quarterly", "Semiannually", "Annually"],
datasets: [
{
label: "label1",
backgroundColor: [
'#26343b',
'#26343b',
'#26343b',
'#26343b'
],
data: [4, 6, 8, -3],
},
{
label: "",
backgroundColor: [
'#be1a33',
'#be1a33',
'#be1a33',
'#be1a33'
],
data: [6, 10, 11, 7],
},
{
label: "",
backgroundColor: [
'#00b786',
'#00b786',
'#00b786',
'#00b786'
],
data: [13, 10, 9, 4],
},
{
label: "",
backgroundColor: [
'#f86929',
'#f86929',
'#f86929',
'#f86929'
],
data: [6, 8, 2, 11],
},
{
label: "",
backgroundColor: [
'#046cd0',
'#046cd0',
'#046cd0',
'#046cd0'
],
data: [4, 8, 7, 13],
}
]
};
rateOfReturn.canvas.height = 80;
var myBarChart = new Chart(rateOfReturn, {
type: 'bar',
data: rateOfReturnData,
options: {
legend:
{
display: false
},
scales:
{
xAxes: [{
title: "Test title",
ticks: {
beginAtZero: true,
titleFontWeight: "bold"
},
}],
yAxes: [{
scaleLabel: {
display: true,
labelString: 'Rate Of Return (ROR) % '
},
ticks: {
beginAtZero:true,
mirror:false,
suggestedMin: 0
},
}]
}
}
});
You want to use Chart.js plugins. They let you handle some events triggered through the chart creation such as the initialization, the resize, etc.
Chart.pluginService.register({
beforeUpdate: function(chart) {
// All the code added here will be executed before a chart update
}
});
You also want to use createLinearGradient to create a gradient color usable in a canvas :
var gradient = ctx.createLinearGradient(0,0,200,0); // Dimensions of the color rectangle
gradient.addColorStop(0,"green"); // First color
gradient.addColorStop(1,"white"); // Second color
Now you want to use both into one. Let's first see how it works.
You first have to add the two colors of the gradient you want to see in your chart data :
datasets: [{
label: "label1",
backgroundColor: [
['#26343b', 'white'], // `white` and `#FFFFFF` both stand for a white color
['#26343b', 'white'],
['#26343b', 'white'],
['#26343b', 'white']
],
data: [4, 6, 8, -3],
}, {
// ...
}]
Then you need to add the following plugin before you create the chart (using new Chart()), or else it won't be added into the chart's plugin service :
Chart.pluginService.register({
beforeUpdate: function(chart) {
// For every dataset ...
for (var i = 0; i < chart.config.data.datasets.length; i++) {
// We store it
var dataset = chart.config.data.datasets[i];
// For every data in this dataset
for (var j = 0; j < dataset.data.length; j++) {
// We store the data model (graph information)
var model = dataset._meta[0].data[j]._model;
// We use the model to get the left & right borders X position
// and to create the gradient
var start = model.x,
end = model.x + model.width,
gradient = rateOfReturn.createLinearGradient(start, 0, end - 5, 0);
// The colors of the gradient that were defined in the data
gradient.addColorStop(0, dataset.backgroundColor[j][0]);
gradient.addColorStop(1, dataset.backgroundColor[j][1]);
// We set this new color to the data background
dataset.backgroundColor[j] = gradient;
}
}
}
});
Follows the result of the plugin with your example, which you can find on this jsFiddle :
I am using flot jquery library to draw charts.
when my chart has a specific number of columns, I can set the x values for my points.
but now I have a dynmic data. so how can I know the points of the x axis please?
for example,
the x axis of the first point is 1325876000000
the x axis of the second point is 1328194400000
the third is 1330360000000
the fourth is 1332838400000
but lets say that I will have 9 columns. how can I know the x axis for them please?
I am printing the chart in this way
var holder = $('#vertical-chart');
if (holder.length) {
$.plot(holder, data, chartOptions);
}
the input data is like this
label: "label1"
data: [[1325876000000,0],[1325876000000,0],[1325876000000,0],[1325876000000,30]]
but now I don't know how many points in that array. it could be 11 or it could be 2
edit
this the chartoption
chartOptions = {
xaxis: {
min: (new Date(2011, 11, 15)).getTime(),
max: (new Date(2012, 04, 18)).getTime(),
mode: "time",
tickSize: [2, "month"],
monthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
tickLength: 0
},
grid: {
hoverable: true,
clickable: false,
borderWidth: 0
},
bars: {
show: true,
barWidth: 12 * 24 * 60 * 60 * 300,
fill: true,
lineWidth: 1,
order: true,
lineWidth: 0,
fillColor: { colors: [{ opacity: 1 }, { opacity: 1 }] }
},
tooltip: true,
tooltipOpts: {
content: '%s: %y'
},
colors: App.chartColors
}
When using $.plot(holder, data, chartOptions);, save the plot with a variable.
Declare var plot; globally,
and then call like this: plot = $.plot(holder, data, chartOptions);.
You can grab the data from the plot like this:
var datasets = [];
var xData = [];
datasets = plot.getData(); //this returns an array of all datasets
//goes through each series of data
for (var i = 0; i < datasets.length; i++){
//picks the series with label of "label 1"
if (datasets[i].label == "label 1"){
//copies x coordinates from the series into xData
for (var j = 0; j < datasets[i].data[j].length; j++){
xData.push(datasets[i].data[j][0]); //if you want y coords, use datasets[i].data[j][1]
}
}
}