【问题标题】:dynamically update the scale type of chartjs graph动态更新chartjs图表的比例类型
【发布时间】:2017-07-26 07:41:01
【问题描述】:

我在页面上有一个条形图,其中显示了动态更新的数据。我遇到的问题是我需要根据显示的数据更改 y 轴的类型。当数据的范围小于 100(例如 0-99)时,我需要它是一个线性比例,如果它更大(例如 0-1000),我需要它是对数。

我可以计算出是否需要对数刻度,但是在更改刻度类型时我不知所措。我尝试更改图表的options 对象并调用update()

myChart.options/scales.yAxes.map(function (axis) { axis.type = 'logarithmic' });
myChart.update();

还尝试直接更改比例本身:

Object.keys(mychart.scales).forEach((function (axisName) {
            var axis = myChart.scales[axisName];
            if (axis && axis.id.startsWith('y')) {
                axis.options.type = 'logarithmic'
            }
        }));
myChart.update();

然后我尝试使用beforeBuildTicks 回调,认为在更新数据和重绘图表时更改类型可能为时已晚或时间错误:

beforeBuildTicks: function (scale) {
                                if (scale.chart) {
                                    console.log('logarithmic');
                                    scale.options.type = 'logarithmic';
                                 }
                            }

所有这些方法都会更改图表对象,但不影响显示。

有没有办法在不破坏和重新创建整个图表的情况下动态更改 chartjs 条形图的比例类型?

【问题讨论】:

    标签: javascript charts chart.js


    【解决方案1】:

    我终于找到了解决方案,但这并不简单。

    感谢@jordanwillis 为使用scaleMerge() 辅助函数提供了正确的方向。

    我创建了一个完成所有工作的插件

    var changeScaleTypePlugin = {
        beforeUpdate: function(chartInstance) {
            var self = this;
            chartInstance.beforeInit = null;
            if (chartInstance.options.changeScale) {
                self.changeScales(chartInstance);
                if (chartInstance.options.scaleTypeChanged) {
                    chartInstance.options.scaleTypeChanged = false;
                    Object.keys(chartInstance.scales).forEach(function(axisName) {
                        var scale = chartInstance.scales[axisName];
                        Chart.layoutService.removeBox(chartInstance, scale);
                    });
                    chartInstance.initialize();
                }
            }
        },
        changeScales: function(chartInstance) {
            var maxValue = Math.max.apply(null, chartInstance.data.datasets.map(function(dataset) {
                return Math.max.apply(null, dataset.data);
            }));
            var minValue = Math.min.apply(null, chartInstance.data.datasets.map(function(dataset) {
                return Math.min.apply(null, dataset.data);
            }));
            var logMax = Math.floor(Math.log(maxValue) / Math.LN10);
            var logMin = Math.floor(Math.log(minValue) / Math.LN10);
            if (logMax - logMin > chartInstance.options.maxRankDifference) {
                if (!chartInstance.options.scaleTypeChanged && chartInstance.options.scales.yAxes.filter(function(axis) {
                        return axis.type !== 'logarithmic';
                    }).length) {
                    console.log('logarithmic');
                    chartInstance.options.scaleTypeChanged = true;
                    chartInstance.options.scales.yAxes = Chart.helpers.scaleMerge(Chart.defaults.scale, {
                        yAxes: chartInstance.options.logarithmicScaleOptions
                    }).yAxes;
                }
            } else {
                if (!chartInstance.options.scaleTypeChanged && chartInstance.options.scales.yAxes.filter(function(axis) {
                        return axis.type !== 'linear';
                    }).length) {
                    console.log('linear');
                    chartInstance.options.scaleTypeChanged = true;
                    chartInstance.options.scales.yAxes = Chart.helpers.scaleMerge(Chart.defaults.scale, {
                        yAxes: chartInstance.options.linearScaleOptions
                    }).yAxes;
                }
            }
        }
    };
    
    Chart.pluginService.register(changeScaleTypePlugin);
    

    要应用它,只需在图表的选项中添加一些属性:

    options: {
        linearScaleOptions: [{
            id: 'y-axis-0',
            type: 'linear',
            tick: {
                // callback: Chart.Ticks.formatters.linear,
                min: 0
            }
        }],
        logarithmicScaleOptions: [{
            id: 'y-axis-0',
            type: 'logarithmic',
            ticks: {
                // callback: function (tickValue, index, ticks)  {
                //        var remain = tickValue / (Math.pow(10, Math.floor(Math.log(tickValue) / Math.LN10)));
    
                //        if (tickValue === 0) {
                //            return '0';
                //        } else if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === ticks.length - 1) {
                //            return tickValue;
                //        }
                //        return '';
                //},
                min: 0
            }
        }],
        changeScale: true,
        maxRankDifference: 1,
    }
    

    刻度上注释掉的回调适用于(像我一样)您不希望刻度值在对数刻度上以科学计数法显示的情况。

    这给出了如下所示的输出:

    将最大排名属性设置为 1

    设置为 3

    或使用回调集:

    【讨论】:

      【解决方案2】:

      您在正确的轨道上,但问题是对于每种比例类型,基础比例服务使用一组相应的属性来呈现比例。

      因此,当您将比例配置为“线性”时,会触发设置一组隐藏轴属性,以生成渲染的线性比例。但是,当您将比例配置为“对数”时,隐藏轴属性需要进行不同的设置以生成渲染的对数比例。

      长话短说,您必须使用Chart.helpers.scaleMerge() 函数为您处理所有这些(您不能只是简单地更改图表选项中的比例类型并重新渲染)。

      我创建了一个working example 来演示如何实现您的目标。其工作原理如下所示。

      document.getElementById('changeScaleAndData').addEventListener('click', function() {
        if (isLinear) {
          myBar.options.scales.yAxes = Chart.helpers.scaleMerge(Chart.defaults.scale, {yAxes: logarithmicScaleOptions}).yAxes;
          isLinear = false;
        } else {
          myBar.options.scales.yAxes = Chart.helpers.scaleMerge(Chart.defaults.scale, {yAxes: linearScaleOptions}).yAxes;
          isLinear = true;
        }
      
        myBar.data.datasets[0].data = [
          randomScalingFactor(), 
          randomScalingFactor(), 
          randomScalingFactor(), 
        ];
      
        myBar.update();
      });
      

      【讨论】:

      • 这似乎并没有实际将刻度更改为对数刻度,当进行“更改”以将刻度设置为对数时,yscale 上的刻度之间的差异在所有刻度之间都是相同的是空间分离,根据定义,它是一个线性比例。我终于找到了一个解决方案(我必须感谢你指向scaleMerge 的指针)看看我的答案
      【解决方案3】:

      我发现更改轴类型后删除和重新创建图表更容易。 IE 如果我有一个带有 id logScale 的复选框来设置我的轴​​是否是日志,我可以说:

      $("#logScale").change(function () {
          $('#chart').remove();
          createChart();
      })
      

      其中 createChart 是创建图表的代码。注意我参考#logScale来设置Y轴类型:

      $('#chartContainer').append('<canvas id="chart" style="max-height:300px;max-width:95%"></canvas>');
          var axisType = $("#logScale").prop("checked") ? 'logarithmic' : 'linear';
              ctx = document.getElementById('chart').getContext('2d');
              chartObject = new Chart(ctx, {
                  options: {
                      scales: {
                          xAxes: [{
                          yAxes: [{
                              type: axisType
                          }]
                      } //and whatever other chart data you have
      

      【讨论】:

        猜你喜欢
        • 2013-06-25
        • 2021-03-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多