0

I've looked at the docs/examples for chartjs, but does anyone know a way to do the following?

  • Create bars where the width (x-axis) is variable but the height is always full (aka the entire y-axis)?
  • There can be x number of those bars in a chart
  • Create a line that spans all the way across the x axis but can change it's y-axis (aka not a straight line, but a curvy one).

I have a crude drawing here where the yellow is the bars and the black is the line

I kinda got the first part down using stacked bars and swapping the axis, but the y-axis (the bars height) is only set to 1. That's a problem when trying to draw a curved line in mixed mode since there is only one y-axis point (instead of many y-axis points):

Here's another attempt that has multiple y-axis points, but I cannot control the bar widths:

If anyone can help (or at least tell me if I'm going in the right direction), it would be greatly appreciated!

Please see code in the jsfiddle link
ekjcfn3902039
  • 1,673
  • 3
  • 29
  • 54

2 Answers2

1

Hmh, that's difficult... The only solution I would have is to create a bar chart with very many very small bars.

I made a JSBin with my solution but it's far from perfect, but the only way to achieve it in chart.js. I didn't test the performance as I don't know your data, but this will be very important and the biggest problem.

Right now only one rectangle is possible, but it's not difficult to improve it to multiple rectangles.

Here's all my code, same as JSBin:

var chartData = {
  datasets: [{
    type: 'line',
    label: 'Dataset 1',
    borderColor: 'blue',
    borderWidth: 2,
    fill: false,
    data: []
  }, {
    type: 'bar',
    label: 'Dataset 2',
    backgroundColor: 'red',
    data: [],
  }]
};

var newData0 = []
var newData1 = []
var labels = []
var counter = 50

// Rectangle between two random Integers
var rectangleBetween = [Math.round(Math.random()*counter), Math.round(Math.random()*counter)]
rectangleBetween.sort(function(a, b){return a - b})

for (var i = 0; i < counter; i++) {
  labels.push(i)

  // Data for Dataset 1 (line):
  var newObj0 = {}
  newObj0.x = i
  // 50/50 chance of data
  if (Math.random()<0.5) {
    newObj0.y = Math.round(Math.random()*100)
  } else {
    newObj0.y = null
  }
  newData0.push(newObj0)

  // Data for Dataset 2 (bar):
  var newObj1 = {}
  if (i >= rectangleBetween[0] && i <= rectangleBetween[1]) {
    newObj1.x = i
    newObj1.y = 100
  } else {
    newObj1.x = i
    newObj1.y = 0
  }  
  newData1.push(newObj1)
}

chartData.datasets[0].data = newData0
chartData.datasets[1].data = newData1
chartData.labels = labels


var ctx = document.getElementById('chart').getContext('2d');
myMixedChart = new Chart(ctx, {
  type: 'bar',
  data: chartData,
  options: {
    responsive: true,
    spanGaps: true,
    title: {
      display: true,
      text: 'Chart.js Combo Bar Line Chart'
    },
    tooltips: {
      mode: 'index',
      intersect: true
    },
    scales: {
      xAxes: [{
        //barThickness: 80, // number (pixels) or 'flex'
        //maxBarThickness: 100, // number (pixels)
        barPercentage: 1.0,
        categoryPercentage: 1.0,
        gridLines: {
          display: false
        }
      }]
    }
  }
});
HeadhunterKev
  • 1,728
  • 5
  • 13
  • FWIW my line is really a scatter plot (with showLines=true) with about 2000 points and I can have anywhere between 0 - 50 bars on average. – ekjcfn3902039 Nov 12 '19 at 16:21
  • I took your example and made a small static sample. It seems there are gaps between the bars. I am not sure how to close those gaps. I would also like to place a border around the overall bar shape (instead of a border on each individual slice of the bar). I would also like to have some opacity for the overall bar shape (instead of on each individual slice of the bar). Here's my edits: https://jsbin.com/dubofajefo/1/edit?js,output Is this possible given your example? – ekjcfn3902039 Nov 12 '19 at 19:00
  • OK, I think I give up. I can't find a way to display the bars behind each other when on the same index, it always displays them next to each other. [Here are information about that, but only for category and time scale, not for a linear scale](https://github.com/chartjs/Chart.js/pull/4545). So only one rectangle is possible. That's the reason for the gaps between the bars as well. I don't think borders are possible for each data, [only for the complete dataset](https://github.com/chartjs/Chart.js/issues/5071#issuecomment-353720717). I'm sorry I can't help you, I don't know another solution. – HeadhunterKev Nov 13 '19 at 16:00
  • Me either, but thanks for looking into it! I'' post a feature request for it if it can't be done – ekjcfn3902039 Nov 13 '19 at 16:23
1

It looks like this is the best solution:

https://codepen.io/kurkle/pen/ExxdyXQ

var ctx = document.getElementById("chart").getContext("2d");
var chart = new Chart(ctx, {
  type: "horizontalBar",
  data: {
    labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
    datasets: [
      {
        label: "Bar1",
        data: [[2.5, 5.7]],
      },
      {
        label: "Bar2",
        data: [[6, 8]],
      },
      {
        label: "Bar3",
        data: [[9,10]],
      },
      {
        label: "Line",
        type: "line",
        backgroundColor: "rgb(75, 192, 192, 0.5)",
        borderColor: "rgb(75, 192, 192)",
        fill: false,
        tension: 0,
        data: [11, 10, 9, 8, 7, 6, 5, 4, 3, 2],
        yAxisID: "line"
      }
    ]
  },
  options: {
    datasets: {
      horizontalBar: {
        backgroundColor: "rgb(255, 99, 132, 0.5)",
        borderColor: "rgb(255, 99, 132)",
        borderWidth: 1,
        barPercentage: 1,
        categoryPercentage: 1,
        yAxisID: "bar"
      }
    },
    scales: {
      yAxes: [
        {
          id: "bar",
          type: 'category',
          stacked: true,
          labels: ['bar'],
          offset: true
        },
        {
          id: "line",
          position: 'right',
          ticks: {
            min: 0,
            stepSize: 1
          }
        }
      ]
    }
  }
});

Credit to the original author of this code (Jukka Kurkela aka kurkle). He answered this on the chart.js GitHub issues page.

HeadhunterKev
  • 1,728
  • 5
  • 13
ekjcfn3902039
  • 1,673
  • 3
  • 29
  • 54