I have a simple Chart.js line chart, which shows the costs of two decisions. I now want to show the break even of one over the other, which is basically the intersection.
I made an example of what I have so far here
var ctx = document.getElementById("chart");
var options = {
type: 'line',
data: {
labels: ["1", "2", "4", "6", "7", "10"],
datasets: [
{
backgroundColor: "rgba(151,187,205,0.2)",
borderColor: "rgba(151,187,205,1)",
data: [80, 80, 80, 80, 80, 80]
},
{
backgroundColor: "rgba(220,220,220,0.2)",
borderColor: "rgba(220,220,220,1)",
data: [8.84, 17.68, 35.36, 53.04, 70.72, 88.4]
}
]
},
options: {
tooltips: {
enabled: false
},
legend: {
position: 'top'
}
}
};
var myChart = new Chart(ctx, options);
How can I
Show a tooltip at the interception of the two lines
Show the values for the interception (inside a tooltip or at the axis)
Move the legend inside the chart
Any help would be appreciated. Thank you.
This is very specific to the problem
Chart.plugins.register({
afterInit: function(chart) {
var intersect = getIntersection();
var datasets = chart.data.datasets;
var labels = chart.data.labels;
labels.push(intersect.x)
labels.sort(function(a,b){return a - b});
y = labels.indexOf(intersect.x);
chart.data.datasets.forEach(function(ds,i){ds.data.splice(y, 0, intersect.y)});
}
})
function getIntersection(){
var y2=17.68, y1=8.84,x2=2,x1=1,x3 = x1, x4 = x2,
y4=80,y3=80;
var x=((x1*y2-y1*x2)*(x3-x4)-(x1-x2)*(x3*y4-y3*x4))/((x1-x2)*(y3-y4)-(y1-y2)*(x3-x4));
var y=((x1*y2-y1*x2)*(y3-y4)-(y1-y2)*(x3*y4-y3*x4))/((x1-x2)*(y3-y4)-(y1-y2)*(x3-x4));
x = Math.round(x*100)/100;
y = Math.round(y*100)/100;
return {x:x,y:y} ;
http://jsfiddle.net/o3cyhxrn/4/
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>
My problem is similar to How to show bar labels in legend in Chart.js 2.1.6?
I want to have to same output a pie chart give, but I do not want to create multiple datasets. I managed to do this, but now I can't find how.
Here is my code sample :
var myChart = new Chart(ctx, {
type: type_p,
data: {
labels: ['Lundi','Mardi'],
datasets: [{
data: [50,20],
backgroundColor: color,
borderColor: color,
borderWidth: 1
}]
}
I want the same legend as a pie chart, but with a bar chart:
Is this a way to do this?
To accomplish this, you would have to generate custom labels (using generateLabels() function) based on the labels array of your dataset.
legend: {
labels: {
generateLabels: function(chart) {
var labels = chart.data.labels;
var dataset = chart.data.datasets[0];
var legend = labels.map(function(label, index) {
return {
datasetIndex: 0,
fillStyle: dataset.backgroundColor && dataset.backgroundColor[index],
strokeStyle: dataset.borderColor && dataset.borderColor[index],
lineWidth: dataset.borderWidth,
text: label
}
});
return legend;
}
}
}
add this in your chart options
ᴡᴏʀᴋɪɴɢ ᴇxᴀᴍᴘʟᴇ ⧩
var ctx = canvas.getContext('2d');
var chart = new Chart(ctx, {
type: 'bar',
data: {
labels: ['Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi'],
datasets: [{
data: [1, 2, 3, 4, 5],
backgroundColor: ['#ff6384', '#36a2eb', '#ffce56', '#4bc0c0', '#9966ff'],
borderColor: ['#ff6384', '#36a2eb', '#ffce56', '#4bc0c0', '#9966ff'],
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
},
legend: {
labels: {
generateLabels: function(chart) {
var labels = chart.data.labels;
var dataset = chart.data.datasets[0];
var legend = labels.map(function(label, index) {
return {
datasetIndex: 0,
fillStyle: dataset.backgroundColor && dataset.backgroundColor[index],
strokeStyle: dataset.borderColor && dataset.borderColor[index],
lineWidth: dataset.borderWidth,
text: label
}
});
return legend;
}
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script>
<canvas id="canvas"></canvas>
I'm actualy using Chart JS 2.0.1 to draw charts on a page.
My customers asked me to add a line in a bar chart so that they can see the limit they can't go over. Like that: Bar chart with line on y axes
So, I'm trying to extend the Bar Chart into a new one which takes a parameter called lineAtValue which provides the y value for the line.
I succeeded in extending the bar chart but it overrides the others bar charts displayed in the page and I don't need that in the other Bar Charts.
Here is what I did : http://jsfiddle.net/d5ye1xpe/
And I'd like to be able to have something like this one : jsfiddle.net/L3uhpvd5/ (sorry I can't upload more than two links) with the
Chart.barWithLine(ctx,config);
But with the version 2.0.1 of Chart JS
Thanks,
Ptournem
If this helps, I rewrite #Ptournem answer to be a valid 2.3.0 plugin with some sort of configutation
Chart.plugins.register({
config: {
/** #type {rbg|rgba|hex} Stroke color */
strokeColor: "rgb(255, 0, 0)",
/** #type {int} Column width */
lineWidth: 1,
},
afterDatasetsDraw: function(chartInstance, easing) {
var value = chartInstance.config.lineAtValue;
if (typeof value === 'undefined') return;
var ctx = chartInstance.chart.ctx,
xaxis = chartInstance.scales['x-axis-0'],
yaxis = chartInstance.scales['y-axis-0'];
ctx.save();
ctx.beginPath();
ctx.moveTo(xaxis.left, yaxis.getPixelForValue(value));
ctx.lineWidth = this.config.lineWidth;
ctx.strokeStyle = this.config.strokeColor;
ctx.lineTo(xaxis.right, yaxis.getPixelForValue(value));
ctx.stroke();
ctx.restore();
},
// IPlugin interface
afterDatasetsUpdate: function(chartInstance) {},
afterDraw: function(chartInstance, easing) {},
afterEvent: function(chartInstance, event) {},
afterInit: function(chartInstance) {},
afterScaleUpdate: function(chartInstance) {},
afterUpdate: function(chartInstance) {},
beforeRender: function(chartInstance) {},
beforeDatasetsDraw: function(chartInstance, easing) {},
beforeDatasetsUpdate: function(chartInstance) {},
beforeDraw: function(chartInstance, easing) {},
beforeEvent: function(chartInstance, event) {},
beforeInit: function(chartInstance) {},
beforeUpdate: function(chartInstance) {},
destroy: function(chartInstance) {},
resize: function(chartInstance, newChartSize) {},
});
Mixed type charts are supported by Chart 2.x versions.
You can create config like following :-
var config = {
type: 'bar',
data: {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [{
type: 'bar',
label: "My First dataset",
data: [65, 0, 80, 81, 56, 85, 40],
fill: false
},{
type: 'line',
label: "My Second dataset",
data: [80, 80, 80, 80, 80, 80, 80],
fill: false,
borderColor: 'red',
pointStyle: 'line',
pointBorderWidth: 3
}]
}
};
Created Js Fiddle here: https://jsfiddle.net/nehadeshpande/eu70wzo4/
Please let me know if this is helpful.
Thanks,
Neha
This is helpful but I found it not that optimized to add new Dataset just for a line that is actually not a data.
I finally suceeded in creating the new type that extend the bar type and add a line if the value is provided.
// Store the original Draw function
var originalLineDraw = Chart.controllers.bar.prototype.draw;
// extend the new type
Chart.helpers.extend(Chart.controllers.bar.prototype, {
draw: function () {
// use the base draw function
originalLineDraw.apply(this, arguments);
// get chart and context
var chart = this.chart;
var ctx = chart.chart.ctx;
// get lineAtValue value
var value = chart.config.lineAtValue;
// stop if it doesn't exist
if (typeof value === "undefined") {
return;
}
// draw the line
var xaxis = chart.scales['x-axis-0'];
var yaxis = chart.scales['y-axis-0'];
ctx.save();
ctx.beginPath();
ctx.moveTo(xaxis.left, yaxis.getPixelForValue(value));
ctx.strokeStyle = '#ff0000';
ctx.lineTo(xaxis.right, yaxis.getPixelForValue(value));
ctx.stroke();
ctx.restore();
}
});
But thank you for your help =)
the jsfiddle below shows the problem.
The first data inserts are fine, but when the length of the data set is capped at 10 you see the undesired behaviour where data points are animated top-down instead of moving left. It's extremely distracting.
http://jsfiddle.net/kLg5ntou/32/
setInterval(function () {
data.labels.push(Math.floor(Date.now() / 1000));
data.datasets[0].data.push(Math.floor(10 + Math.random() * 80));
// limit to 10
data.labels = data.labels.splice(-10);
data.datasets[0].data = data.datasets[0].data.splice(-10);
chart.update(); // addData/removeData replaced with update in v2
}, 1000);
Is there a way to have the line chart move left having the newly inserted data point appear on the right? As opposed to the wavy distracting animation?
thanks
This code uses streaming plugin and works as expected.
http://jsfiddle.net/nagix/kvu0r6j2/
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-streaming#1.5.0/dist/chartjs-plugin-streaming.min.js"></script>
var ctx = document.getElementById("chart").getContext("2d");
var chart = new Chart(ctx, {
type: 'line',
data: {
labels: [],
datasets: [{
label: "My First dataset",
backgroundColor: "rgba(95,186,88,0.7)",
borderColor: "rgba(95,186,88,1)",
pointBackgroundColor: "rgba(0,0,0,0)",
pointBorderColor: "rgba(0,0,0,0)",
pointHoverBackgroundColor: "rgba(95,186,88,1)",
pointHoverBorderColor: "rgba(95,186,88,1)",
data: []
}]
},
options: {
scales: {
xAxes: [{
type: 'realtime'
}]
},
plugins: {
streaming: {
onRefresh: function(chart) {
chart.data.labels.push(Date.now());
chart.data.datasets[0].data.push(
Math.floor(10 + Math.random() * 80)
);
},
delay: 2000
}
}
}
});
You should use 2.5.0 chartsjs
here it works :
http://jsfiddle.net/kLg5ntou/93
var data = {
labels: ["0", "1", "2", "3", "4", "5", "6"],
datasets: [
{
label: "My First dataset",
fillColor: "rgba(95,186,88,0.7)",
strokeColor: "rgba(95,186,88,1)",
pointColor: "rgba(0,0,0,0)",
pointStrokeColor: "rgba(0,0,0,0)",
pointHighlightFill: "rgba(95,186,88,1)",
pointHighlightStroke: "rgba(95,186,88,1)",
data: [65, 59, 80, 81, 56, 55, 40]
}
]
};
var ctx = document.getElementById("chart").getContext("2d");
var chart = new Chart(ctx, {type: 'line', data: data});
setInterval(function () {
chart.config.data.labels.push(Math.floor(Date.now() / 1000));
chart.config.data.datasets[0].data.push(Math.floor(10 + Math.random() * 80));
// limit to 10
chart.config.data.labels.shift();
chart.config.data.datasets[0].data.shift();
I want to draw the X-axis, i.e. a horizontal line at Y = 0, to better see where the positive and negative values of Y are.
I want something like this:
Is this possible in Chart.js
EDIT 1
I want to draw the line in the Chart object, so being able to interact with it. For example: points over the X-axis could be drawn green and points under it could be red.
You can Use :
scales: {
xAxes: [{
gridLines: {
zeroLineWidth: 3,
zeroLineColor: "#2C292E",
},
}]
}
Blockquote
You can extend the chart to do both - draw the line and color the points
Chart.types.Line.extend({
name: "LineAlt",
initialize: function (data) {
Chart.types.Line.prototype.initialize.apply(this, arguments);
this.datasets.forEach(function (dataset, i) {
dataset.points.forEach(function (point) {
// color points depending on value
if (point.value < 0) {
// we set the colors from the data argument
point.fillColor = data.datasets[i].pointColor[0];
} else {
point.fillColor = data.datasets[i].pointColor[1];
}
// we need this so that the points internal color is also updated - otherwise our set colors will disappear after a tooltip hover
point.save();
})
})
},
draw: function () {
Chart.types.Line.prototype.draw.apply(this, arguments);
// draw y = 0 line
var ctx = this.chart.ctx;
var scale = this.scale;
ctx.save();
ctx.strokeStyle = '#ff0000';
ctx.beginPath();
ctx.moveTo(Math.round(scale.xScalePaddingLeft), scale.calculateY(0));
ctx.lineTo(scale.width, scale.calculateY(0));
ctx.stroke();
ctx.restore();
}
});
var data = {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [
{
label: "My First dataset",
fillColor: "rgba(220,220,220,0.2)",
strokeColor: "rgba(220,220,220,1)",
// point color is a an array instead of a string
pointColor: ["rgba(220,0,0,1)", "rgba(0,220,0,1)"],
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(220,220,220,1)",
data: [65, 59, 80, 81, -56, -55, 40]
}
]
};
var ctx = document.getElementById("myChart").getContext("2d");
// use our new chart type LineAlt
var myNewChart = new Chart(ctx).LineAlt(data);
Fiddle - http://jsfiddle.net/mbddzwxL/