Reputation: 555
I have a multiple Y axis on my chart Codepen Example. I am wondering if user can choose which dataset he/she want on which y-axis? Is there a way to show which data is currently using which Y-axis, and users haveoption to change the data to different axis (left or right) if they like on the legend?
Chart.defaults.global.elements.line.fill = false;
var barChartData = {
labels: [1510332261000, 1510332473000, 1510332489000, 1510332726000, 1510332777000, 1510332778000, 1510332958000, 1510333050000, 1510333131000, 1510333389000, 1510333476000, 1510333493000, 1510333588000, 1510333604000, 1510333664000, 1510333668000, 1510333758000, 1510333801000, 1510333820000, 1510333821000, 1510333878000, 1510333928000],
datasets: [{
type: 'line',
label: 'a (F)',
id: "y-axis-0",
backgroundColor: "rgba(217,83,79,0.75)",
data: [70, 72, 73, 73, 75, 50, 50, 40, 40, 45, 70, 73, 70, 73, 73, 73, 74, 73, 73, 73]
}, {
type: 'line',
label: 'b (V)',
id: "y-axis-0",
backgroundColor: "rgba(92,184,92,0.75)",
data: [12.9, 17.9, 15.9, 17.9, 17.9, 17.9, 15.9, 17.9, 15.8, 17.8, 16.8, 17.8, 17.9, 17.9, 17.8, 17.8, 19.8, 17.9, 17.8, 20.8]
}, {
type: 'line',
label: 'c (%)',
id: "y-axis-0",
backgroundColor: "rgba(51,51,51,0.5)",
data: [30, 30, 50, 30, 20, 10, 30, 40, 30, 50, 30, 70, 30, 50, 30, 80, 90, 30, 30, 30]
}, {
type: 'line',
label: 'd (AH)',
id: "y-axis-1",
backgroundColor: "rgba(151,187,205,0.5)",
data: [10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6]
}]
};
var ctx = document.getElementById("myChart");
// allocate and initialize a chart
var ch = new Chart(ctx, {
type: 'bar',
data: barChartData,
options: {
title: {
display: true,
text: "Chart.js"
},
tooltips: {
mode: 'label'
},
responsive: true,
scales: {
xAxes: [{
stacked: true
}],
yAxes: [{
position: "left",
id: "y-axis-0",
}, {
position: "right",
id: "y-axis-1",
}]
}
}
});
.myChartDiv {
max-width: 600px;
max-height: 400px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.min.js"></script>
<html>
<body>
<div class="myChartDiv">
<canvas id="myChart" width="600" height="400"></canvas>
</div>
</body>
</html>
Update
I customized the legend as this, and use Ahmed 's suggestion code to fix Y-axis scale. I also added Ahmed's y axis code to the update, but somehow, it still doesn't work as I expect. Here is the new codepen that I just updated
Upvotes: 4
Views: 4155
Reputation: 9753
Fist of all in your barChartData.datasets[]
you are using id
but you should use yAxisID
instead. giving id
there has no impact on the chart. here is the doc for that: http://www.chartjs.org/docs/latest/charts/line.html#dataset-properties
Now onto what you're asking, you can add a click handler to the legend to toggle between axes on click, here is an example of that:
a fork codepen off of yours with new code: https://codepen.io/anon/pen/ooZMwG?editors=0010
set options.legend.onClick
to this function:
function(e, legendItem) {
var index = legendItem.datasetIndex;
var ci = this.chart;
var axisIds = []
var yAxes = ci.options.scales.yAxes;
for (var i = 0; i < yAxes.length; i++) { // loop over the registered yAxes
yAxes[i].gridLines.color = "rgba(0,0,0,0.1)"; // reset all scale gridlines to default
axisIds.push(yAxes[i].id) // get all yAxes ids
}
var meta = ci.getDatasetMeta(index);
var currentAxisId = meta.yAxisID
var currentAxisIdIndex = axisIds.indexOf(currentAxisId);
var newAxisIdIndex;
// basically get the next axis id in the array, if the last one, get the first (circular)
if (currentAxisIdIndex == axisIds.length - 1) newAxisIdIndex = 0;
else newAxisIdIndex = currentAxisIdIndex + 1;
var newAxisId = axisIds[newAxisIdIndex];
meta.yAxisID = newAxisId // set the new axis id to the next one in the array
axis = ci.scales[newAxisId];
axis.options.gridLines.color = "rgba(0,0,0,1)"; // change lines color of the new axes
ci.update(); // update chart
}
**UPDATE: **
based on your new codepen, here are a few things to help:
I have added a new update to my answer to add offfset to all Y Axes in the chart. Use that instead of what you have in the pen.
then update your changeLeftRightY
to the following and make sure your legend HTML container has the id: legend
changeLeftRightY = function(e, index) {
//console.log("-- " + data.datasets[index].yAxisID)
var ci = e.view.ch;
var axisIds = []
var yAxes = ci.options.scales.yAxes;
for (var i = 0; i < yAxes.length; i++) { // loop over the registered yAxes
yAxes[i].gridLines.color = "rgba(0,0,0,0.1)"; // reset all scale gridlines to default
axisIds.push(yAxes[i].id) // get all yAxes ids
}
var meta = ci.getDatasetMeta(index);
var currentAxisId = meta.yAxisID
var currentAxisIdIndex = axisIds.indexOf(currentAxisId);
var newAxisIdIndex;
// basically get the next axis id in the array, if the last one, get the first (circular)
if (currentAxisIdIndex == axisIds.length - 1) newAxisIdIndex = 0;
else newAxisIdIndex = currentAxisIdIndex + 1;
var newAxisId = axisIds[newAxisIdIndex];
meta.yAxisID = newAxisId // set the new axis id to the next one in the array
axis = ci.scales[newAxisId];
axis.options.gridLines.color = "rgba(0,0,0,1)"; // change lines color of the new axes
document.getElementById('legend').innerHTML = ci.generateLegend();
ci.update()
}
Here is a codepen with the code result *I have made some changes to some of your code to make it easier to read.
If that codepen is changed or deleted, here is the full code
// set default no fill beneath the line
Chart.defaults.global.elements.line.fill = false;
// Define a plugin to provide data labels
Chart.pluginService.register({
beforeUpdate: function(chart){
console.log("beforeUpdate");
// get custom defined offset
var offset = chart.options.customOffset;
// exisit gracefully if offset not defined or less than 0
if(!offset || offset < 0) return;
var yAxes = chart.options.scales.yAxes;
for(var i=0; i<yAxes.length; i++){
var axis = yAxes[i];
var datasets = chart.data.datasets;
var max = Number.MIN_VALUE;
var min = Number.MAX_VALUE;
var datasetsOnAxis = [];
for(var j=0; j<datasets.length; j++){ // add datasets for this axes to datasetsOnAxis
var dataset = datasets[j];
var meta = chart.getDatasetMeta(j);
if (meta.yAxisID === axis.id) datasetsOnAxis.push(dataset);
}
for(var k=0; k<datasetsOnAxis.length; k++){
var dataset = datasetsOnAxis[k]
var newMax = Math.max.apply(null, dataset.data);
var newMin = Math.min.apply(null, dataset.data);
max = newMax > max ? newMax : max;
min = newMin > min ? min : newMin;
}
axis.ticks.max = max + offset;
axis.ticks.min = min - offset;
}
}
});
var barChartData = {
labels: [1510332261000, 1510332473000, 1510332489000, 1510332726000, 1510332777000, 1510332778000, 1510332958000, 1510333050000, 1510333131000, 1510333389000, 1510333476000, 1510333493000, 1510333588000, 1510333604000, 1510333664000, 1510333668000, 1510333758000, 1510333801000, 1510333820000, 1510333821000, 1510333878000, 1510333928000],
datasets: [{
type: 'line',
label: 'a (F)',
yAxisID: "y-axis-0",
backgroundColor: "rgba(217,83,79,0.75)",
data: [70, 72, 73, 73, 75, 50, 50, 40, 40, 45, 70, 73, 70, 73, 73, 73, 74, 73, 73, 73]
}, {
type: 'line',
label: 'b (V)',
yAxisID: "y-axis-0",
backgroundColor: "rgba(92,184,92,0.75)",
data: [12.9, 17.9, 15.9, 17.9, 17.9, 17.9, 15.9, 17.9, 15.8, 17.8, 16.8, 17.8, 17.9, 17.9, 17.8, 17.8, 19.8, 17.9, 17.8, 20.8]
}, {
type: 'line',
label: 'c (%)',
yAxisID: "y-axis-0",
backgroundColor: "rgba(51,51,51,0.5)",
data: [30, 30, 50, 30, 20, 10, 30, 40, 30, 50, 30, 70, 30, 50, 30, 80, 90, 30, 30, 30]
}, {
type: 'line',
label: 'd (AH)',
yAxisID: "y-axis-1",
backgroundColor: "rgba(151,187,205,0.5)",
data: [10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6, 10.6]
}]
};
var options = {
title: {
display: true,
text: "Chart.js"
},
legendCallback: function (chart) {
console.log('legendCallback');
var legendHtml = [];
legendHtml.push('<div id="legend">');
for (var i = 0; i < chart.data.datasets.length; i++) {
var meta = ch.getDatasetMeta(i);
var yAxis = meta.yAxisID =='y-axis-0' ? "Left Axis" : "Right Axis"
if (chart.data.datasets[i].label) {
var datasetIndex = chart.legend.legendItems[i].datasetIndex
var color = chart.data.datasets[i].backgroundColor;
var label = chart.data.datasets[i].label;
legendHtml.push(
'<div class="lgnd-item-container">'+
'<input class="lgnd-ckeckbox" type="checkbox" checked '+
'onclick="updateDataset(event, '+datasetIndex+')"/>'+
'<div class="lgnd-square" style="background-color:'+color+'"></div>'+
'<div class="lgnd-label">'+label+' '+yAxis+'</div>'+
'<input class="lgnd-btn" type="button" value="Change" onclick="changeLeftRightY(event,'+datasetIndex +')"></input>'+
'</div>');
}
}
legendHtml.push('</div>');
return legendHtml.join("");
},
legend:{
display:false
},
customOffset: 2,
responsive: true,
tooltips: {
mode: 'label',
position: 'nearest'
},
scales: {
xAxes: [{
stacked: true
}],
yAxes: [{
position: "left",
id: "y-axis-0",
}, {
position: "right",
id: "y-axis-1",
}]
}
}
// Show/hide chart by click legend
updateDataset = function (e, datasetIndex) {
var index = datasetIndex;
var ci = e.view.ch;
var meta = ci.getDatasetMeta(index);
// See controller.isDatasetVisible comment
meta.hidden = meta.hidden === null ? !ci.data.datasets[index].hidden : null;
// We hid a dataset ... rerender the chart
ci.update();
};
var ctx = document.getElementById("myChart");
// allocate and initialize a chart
window.ch = new Chart(ctx, {
type: 'line',
data: barChartData,
options: options
});
document.getElementById("chartLegend").innerHTML = ch.generateLegend();
changeLeftRightY = function(e, index) {
//console.log("-- " + data.datasets[index].yAxisID)
var ci = e.view.ch;
var axisIds = []
var yAxes = ci.options.scales.yAxes;
for (var i = 0; i < yAxes.length; i++) { // loop over the registered yAxes
yAxes[i].gridLines.color = "rgba(0,0,0,0.1)"; // reset all scale gridlines to default
axisIds.push(yAxes[i].id) // get all yAxes ids
}
var meta = ci.getDatasetMeta(index);
var currentAxisId = meta.yAxisID
var currentAxisIdIndex = axisIds.indexOf(currentAxisId);
var newAxisIdIndex;
// basically get the next axis id in the array, if the last one, get the first (circular)
if (currentAxisIdIndex == axisIds.length - 1) newAxisIdIndex = 0;
else newAxisIdIndex = currentAxisIdIndex + 1;
var newAxisId = axisIds[newAxisIdIndex];
meta.yAxisID = newAxisId // set the new axis id to the next one in the array
axis = ci.scales[newAxisId];
axis.options.gridLines.color = "rgba(0,0,0,1)"; // change lines color of the new axes
document.getElementById('legend').innerHTML = ci.generateLegend();
ci.update()
}
CSS:
.myChartDiv {
max-width: 600px;
max-height: 400px;
}
.lgnd-square {
float: left;
height: 20px;
width:20px;
overflow:hidden;
margin: 5px;
}
.lgnd-ckeckbox{
float:left;
margin: 10px;
}
.lgnd-btn{
float: left;
margin: 5px;
}
.lgnd-item-container{
width: 300px;
height: 40px;
}
.lgnd-label{
float:left;
margin: 5px;
}
HTML:
<html>
<body>
<div class="myChartDiv">
<canvas id="myChart" width="600" height="400"></canvas>
</div>
<div id="chartLegend"></div>
</body>
</html>
Upvotes: 2