Chartjs-Chart.js only last point

1👍

Update

I just saw Edi’s answer as I submitted mine and he mentioned the pointRadius. I noticed this too messing around and as he stated, you can pass in an array to simplify this.

I wrote a method below to “grow” the array (scaling with the data) in order to ensure that the last data point has a radius > 0.

The custom Line chart appears to render much smoother because the native draw function has been modified.


Chart.js 2.0 introduces the concept of controllers for each dataset. Like scales, new controllers can be written as needed.

I copied the source for controller.line.js and modified the loop for the draw() method to only draw the last point. This is the easiest solution without having to figure out how to set an array of radius values.

/** Initialize array with radius of n and queue values ahead of it */
function pointRadiusLast(radius, length, initialArray) {
  var result = initialArray || [ radius ];
  while (result.length < length) result.unshift(0); // Place zeros in front
  return result;
}
// https://www.chartjs.org/docs/latest/developers/charts.html
var valueOrDefault = Chart.helpers.valueOrDefault;
const lineEnabled = (dataset, options) => valueOrDefault(dataset.showLine, options.showLines)
Chart.defaults.derivedLine = Chart.defaults.line;
var customController = Chart.controllers.line.extend({
  /** If you want to EXTEND the draw function.
  draw: function(ease) {
    Chart.controllers.line.prototype.draw.call(this, ease); // Override the super method
    var meta = this.getMeta();
    var pt0 = meta.data[0];
    var radius = pt0._view.radius;
    var ctx = this.chart.chart.ctx;
    ctx.save();
    // Custom drawing...
    ctx.restore();
  }
  
  If you want to OVERRIDE the draw function...
  */
  draw: function(ease) {
    var me = this;
    var chart = me.chart;
    var meta = me.getMeta();
    var points = meta.data || [];
    var area = chart.chartArea;
    var ilen = points.length;
    var halfBorderWidth;
    var i = 0;
    if (lineEnabled(me.getDataset(), chart.options)) {
      halfBorderWidth = (meta.dataset._model.borderWidth || 0) / 2;
      Chart.helpers.canvas.clipArea(chart.ctx, {
        left: area.left,
        right: area.right,
        top: area.top - halfBorderWidth,
        bottom: area.bottom + halfBorderWidth
      });
      meta.dataset.draw();
      Chart.helpers.canvas.unclipArea(chart.ctx);
    }
    // Draw the points
    for (; i < ilen; ++i) {
      if (i === ilen - 1) { // Only the last or simply... points[ilen - 1].draw(area)
        points[i].draw(area);
      }
    }
  }
});
Chart.controllers.derivedLine = customController; // Specify type on chart below

var data = [
  { month : 'January'  , low : 25, high : 43 },
  { month : 'February' , low : 27, high : 47 },
  { month : 'March'    , low : 35, high : 56 },
  { month : 'April'    , low : 44, high : 67 },
  { month : 'May'      , low : 54, high : 76 },
  { month : 'June'     , low : 63, high : 85 }
];

var additionalData = [
  { month : 'July'      , low : 68, high : 89 },
  { month : 'August'    , low : 66, high : 87 },
  { month : 'September' , low : 59, high : 81 },
  { month : 'October'   , low : 46, high : 69 },
  { month : 'November'  , low : 37, high : 59 },
  { month : 'December'  , low : 30, high : 48 }
];

var defaults = {
  fill: false,
  lineTension: 0.1,
  borderCapStyle: 'butt',
  borderDash: [],
  borderDashOffset: 0.0,
  borderJoinStyle: 'miter',
  pointBackgroundColor: "#fff",
  pointBorderWidth: 1,
  pointHoverRadius: 5,
  pointHoverBorderWidth: 2,
  //pointRadius: 0, <-- Do not specify this, we will supply it below
  pointHitRadius: 10
};

/** Initialize array with radius of n and queue values ahead of it */
function pointRadiusLast(radius, length, initialArray) {
  var result = initialArray || [ radius ];
  while (result.length < length) result.unshift(0);
  return result;
}

var dataSets = [
  Object.assign({
    label: "Low",
    backgroundColor: "rgba(75,192,192,0.4)",
    borderColor: "rgba(75,192,192,1)",
    pointBorderColor: "rgba(75,192,192,1)",
    pointHoverBackgroundColor: "rgba(75,192,192,1)",
    pointHoverBorderColor: "rgba(220,220,220,1)",
    data: data.map(item => item.low)
  }, defaults),
  Object.assign({
    label: "High",
    backgroundColor: "rgba(192,75,75,0.4)",
    borderColor: "rgba(192,75,75,1)",
    pointBorderColor: "rgba(192,75,75,1)",
    pointHoverBackgroundColor: "rgba(192,75,75,1)",
    pointHoverBorderColor: "rgba(192,75,75,1)",
    data: data.map(item => item.high)
  }, defaults)
];

var chartOptions = {
  title : {
    text : 'Weather Averages for Washington, DC',
    display : true
  },
  showLines: true
};

var defaultChart = Chart.Line(document.getElementById('default-line-chart'), {
  data: {
    labels: data.map(item => item.month),
    datasets: dataSets.map(dataset => $.extend(true, {}, dataset, {
      pointRadius : pointRadiusLast(5, data.length)
    }))
  },
  options : $.extend(true, {}, chartOptions, {
    title : {
      text : chartOptions.title.text + ' (Default)'
    }
  })
});

var customChart = new Chart(document.getElementById('custom-line-chart'), {
  type: 'derivedLine',
  data: {
    labels: data.map(item => item.month),
    datasets: dataSets.map(dataset => $.extend(true, {}, dataset, {
      pointRadius : 5
    }))
  },
  options : $.extend(true, {}, chartOptions, {
    title : {
      text : chartOptions.title.text + ' (Custom)'
    }
  })
});

setTimeout(function() {
  var category = 'month', fields = [ 'low', 'high' ];
  var counter = additionalData.length;
  var intervalId = setInterval(function() {
    if (counter --> 0) {
      var record = additionalData[additionalData.length - counter - 1];
      addData(defaultChart, record, category, fields);
      addData(customChart, record, category, fields);
    } else {
      clearInterval(intervalId);
    }
  }, 1000); // Update every second
}, 1000); // 1 second delay

function addData(chart, data, xField, yFields) {
  chart.data.labels.push(data[xField]);
  chart.data.datasets.forEach((dataset, i) => {
    dataset.data.push(data[yFields[i]]);
    if (chart.config.type === 'line') { // Only the normal Line chart
      dataset.pointRadius = pointRadiusLast(5, dataset.data.length);
    }
  });
  chart.update();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.min.js"></script>
<canvas id="default-line-chart" width="400" height="120"></canvas>
<canvas id="custom-line-chart" width="400" height="120"></canvas>

6👍

You can set the pointRadius to zero, eg:

var myChart = new Chart(
    ctx, {
        type: 'line',
        data: {
            labels: [...]
            datasets: [
              {
                data: [...],
                pointRadius: 0,  # <<< Here.
              }
            ]
        },
        options: {}
    })

For many points (like your question) change pointRadius to array:

pointRadius: [0, 0, 0, 0, 0, 0, 5] 

Follow my full example in Fiddle

Leave a comment