Dynamic point size, labels, & more with Chart.js scriptable options

I’ve gotten a couple questions recently about how to dynamically set the size of points for on Chart.js line chart. This is a good opportunity to describe two powerful features of Chart.js: indexable options and scriptable options.

Indexable options

Using the example of point size, pointRadius can be an array. Each element in the array corresponds to a data point. This type of option is known as an “indexable” option.

For example, this configuration will make the first and third points have a 10-pixel radius:

{
  type: 'line',
  data: {
    labels: ['Q1', 'Q2', 'Q3', 'Q4'],
    datasets: [{
      label: 'Users',
      data: [50, 60, 70, 180],
      pointRadius: [10, 0, 10, 0]
    }]
  }
}


(sandbox link)

Scriptable options

In addition to Indexable options, you can achieve a lot more by using the powerful concept of Scriptable Options.

Here’s an example of using a scriptable option to make any datapoint greater than 65 show with a large point:

{
  type: 'line',
  data: {
    labels: ['Q1', 'Q2', 'Q3', 'Q4'],
    datasets: [{
      label: 'Users',
      data: [50, 60, 70, 180],
      borderColor: '#ff0000',
      backgroundColor: '#ff000033',
    }]
  },
  options: {
    elements: {
      point: {
        radius: (context) => {
          const index = context.dataIndex;
          const value = context.dataset.data[index];
          return value > 65 ? 10 : 0;
        }
      }
    }
  }
}

(sandbox link)

Scriptable options are not just for point radii – with Chart.js v3, most options are scriptable! In the example below, we compute a random borderColor on a bar chart and dynamically title the chart based on the sum of its data.

{
  type: 'bar',
  data: {
    labels: ['Q1', 'Q2', 'Q3', 'Q4'],
    datasets: [{
      label: 'Users',
      data: [50, 60, 70, 180],
      borderColor: (context) => `#${Math.floor(Math.random()*16777215).toString(16)}`,
      borderWidth: 4,
      backgroundColor: '#eee',
    }]
  },
  options: {
    plugins: {
      title: {
        display: true,
        text: (context) => {
          const dataset = context.chart.data.datasets[0];
          let sum = 0;
          for (let i=0; i < dataset.data.length; i++) {
            sum += dataset.data[i]; 
          }
          return `Total sum: ${sum}`;
        }
      }
    }
  }
}


(sandbox link)

Scriptable options with Chart.js open up a wide range of possibilities and special customized logic :grin:

Hope this helps a few people. Let me know if you have any questions!

2 Likes

Hello! I don’t know whether it is because I’ve missed something ,but I just can’t reappearance your chart, the radius was not return as we expect, I’d really appreciate it if you can share me some advice!

Hey @Noah, can you provide your config or a link to the chart sandbox? I can help troubleshoot.

Sorry to reply you so late, guess there may be a large time difference…
I install the expansion of chart.js through composer like this.

3fa5e7b9d17f7b19f5495bd1f02aa08a

This is the code and the display of it.

All the radius of the points in the chart seem to have been set to NULL or maybe zero? which I guess it’s because the function itself doesn’t work as we expect and return NULL .

Hi @Noah, there must be something wrong with your setup that is not included in your post. The raw Javascript works fine: Edit fiddle - JSFiddle - Code Playground. It also works fine on QuickChart.

You may want to compare your implementation with this reference implementation, double check your version of Chart.js, etc. Maybe logging the index and value variables will help shed some light on the problem?