2017-03-06 66 views
0

我有一個頁面上的條形圖,顯示的數據是動態更新的。我遇到的問題是,我需要根據顯示的數據更改y軸的類型。當數據的範圍小於100(例如0-99)時,我需要它是線性標度,如果它的值更大(例如0-1000),則需要對數。動態更新chartjs圖的刻度類型

我可以計算出我是否需要對數刻度或者不好,但是當涉及到改變刻度類型時我很茫然。我試圖改變圖表的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'; 
           } 
          } 

所有這些approac的他改變圖表對象,但顯示不受影響。

有沒有辦法在不破壞和重新創建整個圖表的情況下動態更改chartjs條形圖的比例類型?

回答

0

我終於找到了解決方案,但它並不簡單。

感謝@jordanwillis在使用`scaleMerge'輔助函數方面指向正確方向的指針。

我創建了一個plugin做所有的工作:

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, 

註釋掉回調的蜱是針對情況(像我)你不想刻度值以對數表示的科學記數法顯示。

這讓看起來輸出,如:

logarithmic

設置爲1

linear

將其設置爲3

最高等級屬性

或與該回調組:

logarithmic with natural ticks

0

您在正確的軌道上,但問題在於每種比例類型,底層比例服務都使用相應的一組屬性來呈現比例。

因此,當您將比例配置爲「線性」時,會觸發一組隱藏軸屬性以設置產生渲染線性比例的隱藏軸屬性。但是,當您將比例配置爲'對數'時,需要對隱藏軸屬性進行不同設置以生成呈現的對數比例。長話短說,您必須使用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(); 
}); 
+0

這並不出現在刻度實際上改變爲對數之一,蜱之間的差在yscale當「變化」被製成設置比例爲對數是所有蜱的空間分隔都是相同的,根據定義,它是一個線性尺度。我終於找到了一個解決方案(我必須感謝你指向'scaleMerge'的指針),看看我的答案 – MikeW