Chart.js: A changing borderDash in a single dataset

Created on 18 Jun 2020  ·  1Comment  ·  Source: chartjs/Chart.js

Feature Proposal

Different borderDash from datapoint to datapoint.

A function is needed that calculates the length of the line between 2 data points, so it can calculate de borderDash between points by using a single line.

Feature Use Case

https://codepen.io/hedva/pen/BajQEwm

This is usefull for charts with a forecast and charts with gaps in the data (to be filled in).
You don't want a second dataset to 'hack' dashed lines into the chart. It gives awefull bar charts with 2 datasets when you change chart type.

forecastchart

Possible Implementation

If you can somehow calculate the length of a line between 2 points, you can calculate how many dash/dots/solid etc you need.

borderDash: [170, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 130, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5]

This should be calculated somehow by someone with big brain

https://codepen.io/hedva/pen/BajQEwm

This is probably easier for line charts with straight lines then with curves.

enhancement

Most helpful comment

Update: I'm very close with the help of this comment:
https://github.com/chartjs/Chart.js/issues/2430#issuecomment-425617777

The only thing missing right now is the fill color.
Maybe someone can figure that out?

Here is a fiddle:
https://jsfiddle.net/haeydc7m/4/

chartjs

var ctx = document.getElementById('myChart').getContext('2d');
Chart.defaults.superLine = Chart.defaults.line;
Chart.controllers.superLine = Chart.controllers.line.extend({
  draw: function(ease) {
    var
      startIndex = 0,
      meta = this.getMeta(),
      points = meta.data || [],
      colors = this.getDataset().colors,
      borderDash = this.getDataset().dash,
      area = this.chart.chartArea,
      originalDatasets = meta.dataset._children
        .filter(function(data) {
          return !isNaN(data._view.y);
        });

    function _setLine(newColor, borderDash, meta) {
      meta.dataset._view.borderColor = newColor;
      meta.dataset._view.borderDash = [borderDash, borderDash];
      meta.dataset._view.backgroundColor = newColor;
    }


    if (!colors) {
      Chart.controllers.line.prototype.draw.call(this, ease);
      return;
    }

    for (var i = 2; i <= colors.length; i++) {
      if (borderDash[i-1] !== borderDash[i]) {
        _setLine(colors[i-1], borderDash[i-1], meta);
        meta.dataset._children = originalDatasets.slice(startIndex, i);
        meta.dataset.draw();
        startIndex = i - 1;
      }
    }

    meta.dataset._children = originalDatasets.slice(startIndex);
    meta.dataset.draw();
    meta.dataset._children = originalDatasets;

    points.forEach(function(point) {
      point.draw(area);
    });
  }
});

var chart = new Chart(ctx, {
    type: 'superLine',
    data: {
        labels: ["January", "February", "March", "April", "May", "June", "July"],
        datasets: [{
            label: "Test Graph",
            borderColor: 'rgba(244, 0, 0, 1)',
            backgroundColor: 'rgb(255, 99, 132, 0.5)',
            dash: [0, 0, 2, 10, 0, 2, 5],
            data: [0, 10, 5, 2, 20, 30, 45],
            colors: ['', 'red', 'grey', 'red', 'blue', 'green', 'black'],
            fill: true,
            pointRadius: 0
        }]
    },
    options: {}
});

>All comments

Update: I'm very close with the help of this comment:
https://github.com/chartjs/Chart.js/issues/2430#issuecomment-425617777

The only thing missing right now is the fill color.
Maybe someone can figure that out?

Here is a fiddle:
https://jsfiddle.net/haeydc7m/4/

chartjs

var ctx = document.getElementById('myChart').getContext('2d');
Chart.defaults.superLine = Chart.defaults.line;
Chart.controllers.superLine = Chart.controllers.line.extend({
  draw: function(ease) {
    var
      startIndex = 0,
      meta = this.getMeta(),
      points = meta.data || [],
      colors = this.getDataset().colors,
      borderDash = this.getDataset().dash,
      area = this.chart.chartArea,
      originalDatasets = meta.dataset._children
        .filter(function(data) {
          return !isNaN(data._view.y);
        });

    function _setLine(newColor, borderDash, meta) {
      meta.dataset._view.borderColor = newColor;
      meta.dataset._view.borderDash = [borderDash, borderDash];
      meta.dataset._view.backgroundColor = newColor;
    }


    if (!colors) {
      Chart.controllers.line.prototype.draw.call(this, ease);
      return;
    }

    for (var i = 2; i <= colors.length; i++) {
      if (borderDash[i-1] !== borderDash[i]) {
        _setLine(colors[i-1], borderDash[i-1], meta);
        meta.dataset._children = originalDatasets.slice(startIndex, i);
        meta.dataset.draw();
        startIndex = i - 1;
      }
    }

    meta.dataset._children = originalDatasets.slice(startIndex);
    meta.dataset.draw();
    meta.dataset._children = originalDatasets;

    points.forEach(function(point) {
      point.draw(area);
    });
  }
});

var chart = new Chart(ctx, {
    type: 'superLine',
    data: {
        labels: ["January", "February", "March", "April", "May", "June", "July"],
        datasets: [{
            label: "Test Graph",
            borderColor: 'rgba(244, 0, 0, 1)',
            backgroundColor: 'rgb(255, 99, 132, 0.5)',
            dash: [0, 0, 2, 10, 0, 2, 5],
            data: [0, 10, 5, 2, 20, 30, 45],
            colors: ['', 'red', 'grey', 'red', 'blue', 'green', 'black'],
            fill: true,
            pointRadius: 0
        }]
    },
    options: {}
});
Was this page helpful?
0 / 5 - 0 ratings