Chart.js 4基于最低值的线性梯度

piah890a  于 2023-10-18  发布在  Chart.js
关注(0)|答案(1)|浏览(138)

下面是Chart.js中的标准示例:linear gradient。当我设置beginAtZero: false选项时,渐变效果良好。然而,当我设置选项beginAtZero: true时,梯度不会考虑最低值。它从图表底部开始,那里没有数据。
如何改变函数,使梯度考虑最低值的位置?
我试着计算了一下位置:

gradient = ctx.createLinearGradient(0, 
Math.max(...chart.getDatasetMeta(0).data.map(item => item.y)), 0, 
Math.min(...chart.getDatasetMeta(0).data.map(item => item.y)));

然而,当调用函数getDradient()时,数据点位置不可用。
请看代码笔:https://codepen.io/miloslav/pen/YzdwLOe

bmvo0sr5

bmvo0sr51#

使用可脚本化的borderColor: function(context, opts),您将chart、图表示例、chartArea和canvas 2d上下文提取为:

const chart = context.chart;
const {ctx, chartArea} = chart;

您还可以找到以下内容:

  • 此数据集使用的y轴的ID:
const yScaleId = opts._proxy.scales.y.id;

这是严格的方法,适用于具有多个y轴的图表;在实践中,您可能知道ID,在这种情况下,在那里;这只是默认轴,ID为y

  • 实际y缩放对象
chart.scales[yScaleId]

及其minmax值,scaleMinscaleMax

  • 这个数据集的数据数组:
context.dataset.data

,并从中得到数据的最小值和最大值dataMindataMax

  • 对于轴和数据的极值,这是一个简单的线性关系,该关系给予:
const fracStart = (dataMin - scaleMin)/(scaleMax - scaleMin),
       fracEnd = (dataMax - scaleMin)/(scaleMax - scaleMin);

这些数字应该在线性垂直梯度的定义中取代01,因此第一种颜色对应于最小值,最后一种颜色对应于最大值。

完整代码来自您的codepen:

const ctx = document.getElementById('myChart');

let width, height, gradient;
function getGradient(ctx, chartArea, fracStart = 0, fracEnd = 1) {
  const chartWidth = chartArea.right - chartArea.left;
  const chartHeight = chartArea.bottom - chartArea.top;
  if (!gradient || width !== chartWidth || height !== chartHeight) {
    // Create the gradient because this is either the first render
    // or the size of the chart has changed
    width = chartWidth;
    height = chartHeight;
    gradient = ctx.createLinearGradient(0, chartArea.bottom, 0, chartArea.top);
    const fracMid = (fracStart + fracEnd) / 2;
    gradient.addColorStop(fracStart, 'green');
    gradient.addColorStop(fracMid, 'yellow');
    gradient.addColorStop(fracEnd, 'red');
  }

  return gradient;
}

new Chart(ctx, {
  type: 'line',
  data: {
    labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
    datasets: [{
      label: '# of Votes',
      data: [31, 27, 30, 51, 28, 32],
      stepped: true,
      borderWidth: 4,
      borderColor: function(context, opts) {
        const chart = context.chart;
        const {ctx, chartArea} = chart;
        
         // the id of the y scale of this dataset:
        const yScaleId = opts._proxy.scales.y.id; 
        const scaleMin = chart.scales[yScaleId].min,
              scaleMax = chart.scales[yScaleId].max;
        const dataMin = Math.min(...context.dataset?.data ?? [scaleMin]),
              dataMax = Math.max(...context.dataset?.data ?? [scaleMax]);
        const fracStart = (dataMin - scaleMin)/(scaleMax - scaleMin),
              fracEnd = (dataMax - scaleMin)/(scaleMax - scaleMin);

        if (!chartArea) {
          // This case happens on initial chart load
          return;
        }
        return getGradient(ctx, chartArea, fracStart, fracEnd);
      },
    }]
  },
  options: {
    scales: {
      y: {
        beginAtZero: true
      }
    }
  }
});
<div>
  <canvas id="myChart"></canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

codepen fork

相关问题