Chart.js 更改图例切换行为

Chart.js change legend toggle behaviour(Chart.js 更改图例切换行为)

本文介绍了Chart.js 更改图例切换行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

I have a radar chart from chart.js. Currently it loads in all the data which works great and the supporting legend behaves by clicking on the legend label which toggles off the data associated to the legend able. I want to be able to click on the legend label, it then toggles all the other off and maybe introduce an 'all' option? Is this doable with chart.js?

Here is how my chart looks now:

var chartata = { 
labels: [ 
"Strategic Development and Ownership", 
"Driving change through others", 
"Exec Disposition", 
"Commercial Acumen", 
"Develops High Performance Teams", 
"Innovation and risk taking", 
"Global Leadership", 
"Industry Leader" 
]}; 

var ctx = $("#allRadarData"); 

var config = { 
    type: 'radar', 
    data: chartata,     
    animationEasing: 'linear',
        options: {           
         legend: {
            fontSize: 10,
            display: true,
            itemWidth: 150,
            position: 'bottom',
            fullWidth: true,
            labels: {
                fontColor: 'rgb(0,0,0)',
                boxWidth: 10,
                padding: 20
            },
        },
         tooltips: {
            enabled: true
        },
        scale: {
            ticks: {
                fontSize: 15,
                beginAtZero: true,
                stepSize: 1,
                max: 5
            }
        } 

    },
}, 

LineGraph = new Chart(ctx, config); 

var colorArray = [

    ["#f44336", false],
    ["#E91E63", false],
    ["#9C27B0", false],
    ["#673AB7", false],
    ['#3F51B5', false],
    ["#607D8B", false]
];


for (var i in data) { 
    tmpscore=[]; 
    tmpscore.push(data[i].score1); 
    tmpscore.push(data[i].score2); 
    tmpscore.push(data[i].score3); 
    tmpscore.push(data[i].score4); 
    tmpscore.push(data[i].score5); 
    tmpscore.push(data[i].score6); 
    tmpscore.push(data[i].score7); 
    tmpscore.push(data[i].score8); 

    var color, done = false;
    while (!done) {
        var test = colorArray[parseInt(Math.random() * 10)];
        if (!test[1]) {
            color = test[0];
            colorArray[colorArray.indexOf(test)][1] = true;
            done = !done;
        }
    }


newDataset = { 
    label: data[i].firstName+' '+data[i].lastName, 
     borderColor: color,
    backgroundColor: "rgba(0,0,0,0)", 
    data: tmpscore, 
}; 

config.data.datasets.push(newDataset); 

} 

LineGraph.update(); 
},  
}); 

});

解决方案

To reverse how legend label clicking behaves, you can use the legend onClick option to implement the new click logic. Here is an example below that will give you the desired behavior. Note, in this implementation if you click an already hidden label, it will unhide it, and hide all the others.

function(e, legendItem) {
  var index = legendItem.datasetIndex;
  var ci = this.chart;
  var alreadyHidden = (ci.getDatasetMeta(index).hidden === null) ? false : ci.getDatasetMeta(index).hidden;

  ci.data.datasets.forEach(function(e, i) {
    var meta = ci.getDatasetMeta(i);

    if (i !== index) {
      if (!alreadyHidden) {
        meta.hidden = meta.hidden === null ? !meta.hidden : null;
      } else if (meta.hidden === null) {
        meta.hidden = true;
      }
    } else if (i === index) {
      meta.hidden = null;
    }
  });

  ci.update();
};

Here is a working example as well.

If however, you want a more complex logic that will unhide a label that is currently hidden when at least one other label is currently visible, then you can use the below implementation.

function(e, legendItem) {
  var index = legendItem.datasetIndex;
  var ci = this.chart;
  var alreadyHidden = (ci.getDatasetMeta(index).hidden === null) ? false : ci.getDatasetMeta(index).hidden;       
  var anyOthersAlreadyHidden = false;
  var allOthersHidden = true;

  // figure out the current state of the labels
  ci.data.datasets.forEach(function(e, i) {
    var meta = ci.getDatasetMeta(i);

    if (i !== index) {
      if (meta.hidden) {
        anyOthersAlreadyHidden = true;
      } else {
        allOthersHidden = false;
      }
    }
  });

  // if the label we clicked is already hidden 
  // then we now want to unhide (with any others already unhidden)
  if (alreadyHidden) {
    ci.getDatasetMeta(index).hidden = null;
  } else { 
    // otherwise, lets figure out how to toggle visibility based upon the current state
    ci.data.datasets.forEach(function(e, i) {
      var meta = ci.getDatasetMeta(i);

      if (i !== index) {
        // handles logic when we click on visible hidden label and there is currently at least
        // one other label that is visible and at least one other label already hidden
        // (we want to keep those already hidden still hidden)
        if (anyOthersAlreadyHidden && !allOthersHidden) {
          meta.hidden = true;
        } else {
          // toggle visibility
          meta.hidden = meta.hidden === null ? !meta.hidden : null;
        }
      } else {
        meta.hidden = null;
      }
    });
  }

  ci.update();
}

Here is a working example for this alternate implementation as well.

To use this in your specific code, just place it in your chart's legend config using the onClick property.

var config = { 
  type: 'radar', 
  data: chartata,   
  animationEasing: 'linear',
    options: {       
     legend: {
      fontSize: 10,
      display: true,
      itemWidth: 150,
      position: 'bottom',
      fullWidth: true,
      labels: {
        fontColor: 'rgb(0,0,0)',
        boxWidth: 10,
        padding: 20
      },
      onClick: function(e, legendItem) {
        var index = legendItem.datasetIndex;
        var ci = this.chart;
        var alreadyHidden = (ci.getDatasetMeta(index).hidden === null) ? false : ci.getDatasetMeta(index).hidden;

        ci.data.datasets.forEach(function(e, i) {
          var meta = ci.getDatasetMeta(i);

          if (i !== index) {
            if (!alreadyHidden) {
              meta.hidden = meta.hidden === null ? !meta.hidden : null;
            } else if (meta.hidden === null) {
              meta.hidden = true;
            }
          } else if (i === index) {
            meta.hidden = null;
          }
        });

        ci.update();
      },
    },
     tooltips: {
      enabled: true
    },
    scale: {
      ticks: {
        fontSize: 15,
        beginAtZero: true,
        stepSize: 1,
        max: 5
      }
    }
  },
}, 

It was not clear what behavior you wanted the 'all' option to have, but you might be able to use the legend.labels.generateLabels option to trick Chart.js to add an 'all' label (you will have to modify the above onClick logic to deal with that thought.

However, I think a better solution would be to implement your own link or button outside of the chart.js canvas that would show/hide all datasets. Check out the Chart.js radar sample page to see how they bind buttons with chart actions.

这篇关于Chart.js 更改图例切换行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:Chart.js 更改图例切换行为