BioInfoBrett
BioInfoBrett

Reputation: 305

How to fill background colors on line-charts?

I'm migrating some plots from Plot.ly to Chart.js v2.9, and I'm trying to add background colors to my new Chart.js plots to match their predecessor: enter image description here

But when I add the appropriate plugin to my Chart.js config, instead I get this:

enter image description here

Here is my plugin code:

 [{
  beforeDraw: function (chart, easing) {
    let config: DragenChartConfiguration = chart.config;
    if (chart.ctx) {
      if (config.dragen?.hBars) {
        var ctx = chart.ctx;
        var chartArea = chart.chartArea;

        for (const hBar of config.dragen.hBars) {
          ctx.save();
          ctx.fillStyle = hBar.color;
          ctx.fillRect(chartArea.left, hBar.from, chartArea.right - chartArea.left, hBar.to - hBar.from);
          ctx.restore();
        }
      }
    }
  }
}] 

Where each "Hbar" object simply defines a color and a Y-axis range I want to color:

hBars: Array(3)
0: {from: 28, to: 100, color: "rgb(195, 230, 195)"}
1: {from: 20, to: 28, color: "rgb(230, 220, 195)"}
2: {from: 0, to: 20, color: "rgb(230, 195, 195)"}
length: 3

What am I missing here?

Upvotes: 0

Views: 243

Answers (1)

LeeLenalee
LeeLenalee

Reputation: 31439

You are taking raw values instead of getting the pixels for those values, if you do that it will work:

Plugin V3:

{
  id: 'backgrounds',
  beforeDraw: (chart, args, options) => {
    const { ctx, chartArea, scales: {y} } = chart;
    
    options.hbars.forEach((hBar) => {
      ctx.save();
      ctx.fillStyle = hBar.color;
      ctx.fillRect(chartArea.left, y.getPixelForValue(hBar.from), chartArea.right - chartArea.left, y.getPixelForValue(hBar.to) - y.getPixelForValue(hBar.from));
      ctx.restore();
    })
  }
}

Plugin V2:

{
  id: 'backgrounds',
  beforeDraw: (chart, x, options) => {
    const { ctx, chartArea, scales } = chart;
    const y = scales['y-axis-0']
    
    options.hbars.forEach((hBar) => {
      ctx.save();
      ctx.fillStyle = hBar.color;
      ctx.fillRect(chartArea.left, y.getPixelForValue(hBar.from), chartArea.right - chartArea.left, y.getPixelForValue(hBar.to) - y.getPixelForValue(hBar.from));
      ctx.restore();
    }) 
  }

Working example V3:

var options = {
  type: 'line',
  data: {
    labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
    datasets: [{
        label: '# of Votes',
        data: [100, 19, 3, 5, 2, 3],
        borderWidth: 1
      },
      {
        label: '# of Points',
        data: [7, 11, 5, 8, 3, 7],
        borderWidth: 1
      }
    ]
  },
  options: {
    plugins: {
      backgrounds: {
        hbars: [{
            from: 28,
            to: 100,
            color: "rgb(195, 230, 195)"
          },
          {
            from: 20,
            to: 28,
            color: "rgb(230, 220, 195)"
          },
          {
            from: 0,
            to: 20,
            color: "rgb(230, 195, 195)"
          }
        ]
      }
    }
  },
  plugins: [{
    id: 'backgrounds',
    beforeDraw: (chart, args, options) => {
      const {
        ctx,
        chartArea,
        scales: {
          y
        }
      } = chart;

      options.hbars.forEach((hBar) => {
        ctx.save();
        ctx.fillStyle = hBar.color;
        ctx.fillRect(chartArea.left, y.getPixelForValue(hBar.from), chartArea.right - chartArea.left, y.getPixelForValue(hBar.to) - y.getPixelForValue(hBar.from));
        ctx.restore();
      })
    }
  }]
}

var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
  <canvas id="chartJSContainer" width="600" height="400"></canvas>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.2.0/chart.js"></script>
</body>

Working example V2:

var options = {
  type: 'line',
  data: {
    labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
    datasets: [{
        label: '# of Votes',
        data: [100, 19, 3, 5, 2, 3],
        borderWidth: 1
      },
      {
        label: '# of Points',
        data: [7, 11, 5, 8, 3, 7],
        borderWidth: 1
      }
    ]
  },
  options: {
    plugins: {
      backgrounds: {
        hbars: [{
            from: 28,
            to: 100,
            color: "rgb(195, 230, 195)"
          },
          {
            from: 20,
            to: 28,
            color: "rgb(230, 220, 195)"
          },
          {
            from: 0,
            to: 20,
            color: "rgb(230, 195, 195)"
          }
        ]
      }
    }
  },
  plugins: [{
    id: 'backgrounds',
    beforeDraw: (chart, x, options) => {
      const {
        ctx,
        chartArea,
        scales
      } = chart;
      const y = scales['y-axis-0']

      options.hbars.forEach((hBar) => {
        ctx.save();
        ctx.fillStyle = hBar.color;
        ctx.fillRect(chartArea.left, y.getPixelForValue(hBar.from), chartArea.right - chartArea.left, y.getPixelForValue(hBar.to) - y.getPixelForValue(hBar.from));
        ctx.restore();
      })
    }
  }]
}

var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
  <canvas id="chartJSContainer" width="600" height="400"></canvas>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
</body>

Fiddle V3: https://jsfiddle.net/Leelenaleee/6s8upz10/15/

Fiddle V2: https://jsfiddle.net/Leelenaleee/tj71gLa2/10/

Upvotes: 1

Related Questions