2

I'm creating a line chart using chartjs (v3) (and react-chartjs to integrate) and I'm having some bad times to customize the line to start at the middle of the first column (and also finishes at the middle of the last column) because the first column will always be in a zero Y position so that makes the line start at the very left. So I need to figure out how to make the lines to mark in the middle of the column instead of the border.

This is the result I have:

what I have

And I need something like this:

what I need

My config:

<Line
  data={data}
  height={440}
  width={480}
  options={{
    ...options,
    scales: {
      x: {
        grid: {
          color(context) {
            if (context.tick.value === 0) return '#B3B3B3';

            return '#E6E6E6';
          },
          tickWidth: 0,
          lineWidth: 1,
        },
        border: {
          dash(context) {
            if (context.tick.value === 0) return [0];

            return [5, 5];
          },
          width: 0,
        },
        ticks: {
          display: false,
        },
      },
      y: {
        grid: {
          color(context) {
            if ([0, 30, 70].includes(context.tick.value)) {
              return '#B3B3B3';
            }

            return '#E6E6E6';
          },
          lineWidth(context) {
            if ([30, 70].includes(context.tick.value)) {
              return 2;
            }

            return 1;
          },
          tickWidth: 0,
        },
        border: {
          dash(context) {
            if (context.tick.value === 0) return [0];

            return [5, 5];
          },
          width: 1,
        },
        min: 0,
        max: 100,
        ticks: {
          font: {
            weight: 'bold',
            size: 10,
            family: 'Open Sans',
          },
          color: '#000000',
        },
      },
    },
    animation: false,
    plugins: {
      legend: {
        display: false,
      },
      tooltip: {
        enabled: false,
      },
    },
  }}
/>
3
  • I obviously can't test your configuration, but you may try to set scales.x.offset: true option, see the docs
    – kikon
    Commented May 22 at 20:12
  • @kikon I tried to set the offset to true and the padding is good. But the "pointers" are still on the column border instead of being on the middle of the column.
    – PedroB
    Commented May 22 at 20:30
  • 1
    I'm not sure how are you defining "columns"; if they are based on the grid lines, you can set offset: true for the x.grid configuration too, see the docs. It would be useful to simplify your code and extract something easily runnable that we can work with. Your issue doesn't seem to have anything to do with react, nor with multiple datasets, so you can make something on the lines of this fiddle.
    – kikon
    Commented May 22 at 21:18

1 Answer 1

1
...      

      options: {
            scales: {
                x: {
                    type: 'linear', // Use linear scale for x-axis
                    ticks: {
                        stepSize: 0, // Set step size to 0
                        precision: 0
                        // No decimal places
                    }
                },
                y: {
                    ticks: {
                        stepSize: 1, // Set step size to 1
                        precision: 0 // No decimal places
                    }
                }
            },
...

or

...

options: {
    scales: {
        x: {
            type: 'category', // Use category scale for x-axis
            labels: ['1', '1.5', '2', '2.5', '3', '3.5', '4', '4.5', '5'], // Custom labels
            ticks: {
                precision: 1, // No decimal places
                maxRotation: 0, // Disable label rotation
                autoSkip: false, // Do not skip any labels
                padding: 10 // Padding between ticks and chart area
            }
        },
        y: {
            ticks: {
                stepSize: 1, // Set step size to 1
                precision: 0 // No decimal places
            }
        }
    }
}

...
  • We set the type of the x-axis scale to 'category'.
  • Custom labels are provided for each point,
  • We disable label rotation (maxRotation: 0),
  • We prevent skipping of labels (autoSkip: false),
  • A padding of 10px is added between the ticks and the chart area to make room for the labels.

Here is a fully static page that I used for proof of concept for the quick solution I came up with:

<html lang="en"><head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Random Line Chart</title>
    <!-- Include Chart.js -->
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <style>
        #myChart
        {
            aspect-ratio: 1/1;
            display: block;
            height: 718px;
            width: 756px;
        }
    </style>
</head>
<body>
    <canvas id="myChart" width="1502" height="1378" style="display: block; box-sizing: border-box; height: 689px; width: 751px;"></canvas>
    <script>
        document.addEventListener('DOMContentLoaded', function () {
            var ctx = document.getElementById('myChart').getContext('2d');

            function generateRandomData(numLines, numPoints, maxY) {
                var data = [];
                var labels = Array.from({ length: numPoints }, (_, i) => (i + 1).toString());
                var colors = ['red', 'blue', 'green', 'orange', 'purple']; // Line colors

                // Generate random data for each line
                for (var i = 0; i < numLines; i++) {
                    var lineData = [];
                    for (var j = 0; j < numPoints; j++) {
                        // Generate random y values within the specified range
                        var randomY = Math.floor(Math.random() * (maxY)) + 1;
                        lineData.push({ x: (j + randomY - 0.5).toString(), y: randomY });
                    }
                    data.push({
                        label: 'Line ' + String.fromCharCode(65 + i), // A, B, C, D, E
                        data: lineData,
                        borderColor: colors[i % colors.length], // Cycle through colors
                        borderWidth: 2,
                        fill: false
                    });
                }

                return { labels: labels, datasets: data };
            }

            // Create the chart with random data
            var myChart = new Chart(ctx, {
                type: 'line',
                data: generateRandomData(5, 5, 10), // 5 lines, 5 points per line, maxY = 10
                options: {
                    scales: {
                        x: {
                            type: 'linear', // Use linear scale for x-axis
                            ticks: {
                                stepSize: 1, // Set step size to 1
                                precision: 0 // No decimal places
                            }
                        },
                        y: {
                            ticks: {
                                stepSize: 1, // Set step size to 1
                                precision: 0 // No decimal places
                            }
                        }
                    },
                    plugins: {
                        legend: {
                            display: true
                        }
                    }
                }
            });
        });
    </script>


</body></html>

Not the answer you're looking for? Browse other questions tagged or ask your own question.