Search code examples
reactjschart.jsbar-chartreact-chartjs-2

How to set X coordinate for each bar with react chart js 2?


I want to make a chart with min and max vertical lines and bars between them. I can't find information how to set bars' X coordinate or make custom line plot with vertical 'bars' instead of points. And also I don't understand how to scale X axis, why MAX is left-side MIN? Min=22.5, Max=24.5 plot

let plot_options = {
    showScale: true,
    pointDot: true,
    showLines: true,
    maintainAspectRatio: false,
    annotation: {
        annotations: [
            {
                type: 'line',
                mode: 'vertical',
                scaleID: 'y-axis-0',
                value: min,
                borderColor: 'red',
                borderWidth: 2,
                label: {
                    backgroundColor: 'red',
                    content: 'Min',
                    enabled: true,
                },
            },
            {
                type: 'line',
                mode: 'vertical',
                scaleID: 'y-axis-0',
                value: max,
                borderColor: 'red',
                borderWidth: 2,
                label: {
                    backgroundColor: 'red',
                    content: 'MAX',
                    enabled: true,
                },
            },
        ]
    },
    title: {
        display: true,
        text: plotHeader,
    },
    responsive: true,
    legend: {
        display: false,
    },
    scales: {
        xAxes: [{
            scaleLabel: {
                display: true,
                labelString: labelx
            },
            ticks: {
                min: min,
                max: max
            }
        }],
        yAxes: [{
            scaleLabel: {
                display: true,
                labelString: labely
            },
            ticks: {
                beginAtZero: true,
            },
        }]
    },
}

data = {
        barPercentage: 0.5,
        barThickness: 6,
        maxBarThickness: 8,
        minBarLength: 2,
        labels: labels,
        datasets: [{
                    data: values,
                    borderColor: BLUE,
                    backgroundColor: BLUE
                }]
      }
<Bar options={plot_options}  data={data} plugins={ChartAnnotation}  />

That's what I expect: plot2


Solution

  • This solution is based on this answer for the positioning of the bars on a linear x-axis.

    You can further use the Plugin Core API to draw the vertical min and max lines with their labels directly on the canvas. The API offers a number of hooks that can be used to perform custom code. In your case, you could use the afterDraw hook together with CanvasRenderingContext2D.

    Please take a look at the runnable code below and see how it works. It should not be too hard to make similar code work with react-chartjs-2.

    new Chart("chart", {
      type: 'bar',
      plugins: [{
        afterDraw: chart => {
          let ctx = chart.chart.ctx;
          ctx.save();
          let xAxis = chart.scales['x-axis-0'];      
          let yAxis = chart.scales['y-axis-0'];      
          let dataset = chart.data.datasets[0];
          [dataset.min, dataset.max].forEach((v, i) => {      
            var x = xAxis.getPixelForValue(+v * 1000);
            ctx.fillStyle = 'red';
            ctx.font = '14px Arial';
            ctx.textAlign = 'center';        
            ctx.fillText(i == 0 ? 'Min' : 'Max', x, yAxis.top + 14);
            ctx.fillStyle = 'gray';
            ctx.font = '12px Arial';
            ctx.fillText(v, x, yAxis.bottom + 20);
            ctx.beginPath();
            ctx.moveTo(x, yAxis.top + 20);
            ctx.strokeStyle = 'red';
            ctx.lineTo(x, yAxis.bottom + 3);
            ctx.stroke();
          });
          ctx.restore();
        }
      }],  
      data: {
        datasets: [{
          min: 22.5,
          max: 24.5,
          data: [
            { x: '22.83', y: 18 },
            { x: '23.17', y: 15 },
            { x: '23.44', y: 13 },
            { x: '24.32', y: 20 }
          ],
          borderColor: 'blue',
          backgroundColor: 'blue',
          barThickness: 20
        }]
      },
      options: {
        legend: {
          display: false,
        },
        scales: {
          xAxes: [{
            offset: true,
            type: 'time',
            time: {
              parser: 'X',
              unit: 'millisecond',
              displayFormats: {
                millisecond: 'X'
              }
            },
            ticks: {
              source: 'data',
              min: '22.5',
              callback: (v, i, values) => values[i].value / 1000
            },
            gridLines: {
              display: false
            },
          }],
          yAxes: [{
            ticks: {
              beginAtZero: true,
              max: 22,
              stepSize: 2
            }
          }]
        }
      }
    });
    canvas {
      max-width: 500px;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.bundle.min.js"></script>
    <canvas id="chart" height="200"></canvas>