Search code examples
chart.jsradar-chart

How to center the ticks between grid lines in Radar chart?


The problem is that I don't know how to position the ticks (numbers from 1 to 5) between the grid lines. Currently it is showing above the grid lines:

current layout with the ticks above grid lines

Here is the javascript code:

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

new Chart(ctx, {
  type: "radar",
  data: {
    labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange", "Turquesa"],
    datasets: [
      {
        data: [4, 3.5, 2, 5, 4.5, 4, 2],
        borderWidth: 1,
        backgroundColor: "#ECAE4880",
        borderColor: "#FBDDAD",
        color: "#f00"
      }
    ]
  },
  options: {
    elements: {
      point: {
        pointStyle: false
      }
    },
    scales: {
      r: {
        min: 0,
        max: 5,
        backgroundColor: "#FDF7EC",
        ticks: {
          backdropPadding: {
            x: 16,
            y: 16
          },
          z: 10,
          backdropColor: "transparent",
          color: "red",
          backgroundColor: "black",
          stepSize: 1
        },
        grid: {
          color: "#EA910B",
          backgroundColor: "red"
        },
        angleLines: {
          color: "transparent",
          // borderDash: 0
        }
        // angleLines: {
        //   display: false
        // },
        // suggestedMin: 50,
        // suggestedMax: 100
      }
    },
    plugins: {
      legend: {
        display: false
      },
      title: {
        display: false
      },
      subtitle: {
        display: false
      }
    }
  }
  // plugins: [
  //   {
  //     id: "centerTick",
  //     afterDraw: (chart, args, opts) => {
  //       const { ctx } = chart;
  //       ctx.fillStyle = opts.color || Chart.defaults.color;
  //       ctx.fillText(
  //         chart.scales.r.min,
  //         chart.scales.r.xCenter -
  //           ctx.measureText(chart.scales.r.min).width / 2,
  //         chart.scales.r.yCenter
  //       );
  //     }
  //   }
  // ]
});

Here is the link to code: https://codepen.io/luaneaquino/pen/qBzaEOL

I tried setting plugin (commented code), but it does not work:

// plugins: [
  //   {
  //     id: "centerTick",
  //     afterDraw: (chart, args, opts) => {
  //       const { ctx } = chart;
  //       ctx.fillStyle = opts.color || Chart.defaults.color;
  //       ctx.fillText(
  //         chart.scales.r.min,
  //         chart.scales.r.xCenter -
  //           ctx.measureText(chart.scales.r.min).width / 2,
  //         chart.scales.r.yCenter
  //       );
  //     }
  //   }
  // ]

I expect the ticks be like this image below: expected layout with the ticks between the grid lines


Solution

  • I also tried using the plugin to redraw the label in the new position, but the label would have a weird tiny offset, so I simply added a tiny offset to the result to correct this error.

     const ctx = document.getElementById('radarChart').getContext('2d');
    
            const data = {
                labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
                datasets: [{
                    label: 'My First Dataset',
                    data: [5, 4, 3, 2, 1, 2],
                    fill: true,
                    backgroundColor: 'rgba(255, 159, 64, 0.2)',
                    borderColor: 'rgb(255, 159, 64)',
                    pointBackgroundColor: 'rgb(255, 159, 64)',
                    pointBorderColor: '#fff',
                    pointHoverBackgroundColor: '#fff',
                    pointHoverBorderColor: 'rgb(255, 159, 64)'
                }]
            };
    
            const options = {
                scales: {
                    r: {
                        angleLines: {
                            display: true
                        },
                        suggestedMin: 0,
                        suggestedMax: 5,
                        ticks: {
                            stepSize: 1,
                            showLabelBackdrop: false,
                            display: false
                        },
                        grid: {
                            circular: true
                        }
                    }
                }
            };
    
            const radarChart = new Chart(ctx, {
                type: 'radar',
                data: data,
                options: options,
                plugins: [{
                    id: 'customTicks',
                    afterDraw(chart) {
                        const ctx = chart.ctx;
                        const scale = chart.scales.r;
                        ctx.save();
                        ctx.translate(chart.width / 2, chart.height / 2);
                        ctx.font = Chart.helpers.fontString(Chart.defaults.font.size, Chart.defaults.font.style, Chart.defaults.font.family);
                        ctx.fillStyle = Chart.defaults.color;
    
                        const tickValues = scale.ticks.map(t => t.value);
                        const tickSpacing = scale.drawingArea / (tickValues.length-1);
    
                        tickValues.forEach((value, index) => {
                            if (value % 1 === 0 && value !== 0) {
                                const radius = tickSpacing * index;
                                const angleRadians = (Math.PI / 2);
                                const x = radius * Math.cos(angleRadians);
                                const y = tickSpacing - radius * Math.sin(angleRadians);
                                ctx.fillText(value, x-4, y-13);
                            }
                        });
    
                        ctx.restore();
                    }
                }]
            });
    *{margin:0}
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <canvas id="radarChart" width="400" height="400"></canvas>