Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overlay Line on chart.js Graph

I was wondering if it was possible to overlay a line ontop of a chart.js graph, such as a line graph ? For example, on the x axis a horizontal line would be drawn at value 20 across the graph

like image 973
LaurenceHerbert Avatar asked Jan 21 '15 20:01

LaurenceHerbert


3 Answers

I've created something called an overlay chart that i have added to my fork of chart.js (https://github.com/leighquince/Chart.js) that could be used in this situation. it works in the same was as a line or bar chart, only difference is you declare an extra property called type that can either be 'line' or 'bar'. Then just call new Chart(ctx).Overlay(data).

So for your example you could just have your bar chart and then provided another data set (with some better colors than i have used) to show the line.

var data = {
  labels: ["January", "February", "March", "April", "May", "June", "July"],
  datasets: [{
    label: "My First dataset",
    //new option, barline will default to bar as that what is used to create the scale
    type: "line",
    fillColor: "rgba(220,220,220,0.2)",
    strokeColor: "rgba(0,0,0,0.6)",
    pointColor: "rgba(0,0,0,0.6)",
    pointStrokeColor: "#fff",
    pointHighlightFill: "#fff",
    pointHighlightStroke: "rgba(220,220,220,1)",
    datasetFill:false,
    data: [20, 20, 20, 20, 20, 20, 20]
  }, {
    label: "My First dataset",
    //new option, barline will default to bar as that what is used to create the scale
    type: "bar",
    fillColor: "rgba(220,20,220,0.2)",
    strokeColor: "rgba(220,20,220,1)",
    pointColor: "rgba(220,20,220,1)",
    pointStrokeColor: "#fff",
    pointHighlightFill: "#fff",
    pointHighlightStroke: "rgba(220,220,220,1)",
    data: [32, 25, 33, 88, 12, 92, 33]
  }]
};
var ctx = document.getElementById("canvas").getContext("2d");
var chart = new Chart(ctx).Overlay(data, {
  responsive: false
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://raw.githack.com/leighquince/Chart.js/master/Chart.js"></script>

<canvas id="canvas" width="400"></canvas>
like image 96
Quince Avatar answered Oct 23 '22 09:10

Quince


I needed something similar, but instead of a line graph I needed like a real overlay line that was flat.

Just extended the chart like so:

    Chart.types.Bar.extend({
        name: 'BarOverlay',
        draw: function (ease) {
            Chart.types.Bar.prototype.draw.apply(this);
            ctx.beginPath();
            ctx.lineWidth = 2;
            ctx.strokeStyle = 'rgba(255, 0, 0, 1.0)';
            ctx.moveTo(35, this.scale.calculateY(100));
            ctx.lineTo(this.scale.calculateX(this.datasets[0].bars.length), this.scale.calculateY(100));
            ctx.stroke();
        }
    });

Mine is hard-coded to draw a line at the "100" mark (in this case, where we were looking at having a target of 100%).

And call it like so:

new Chart(ctx).BarOverlay(data, options);

I also found Quince's code out of date and not compatible with the 1.0.2 Chart.js code somehow (rendering went all sideways).

like image 33
StrangeWill Avatar answered Oct 23 '22 10:10

StrangeWill


StrangeWill's answer was excellent as a foundation but I needed data-driven vertical lines on a bar graph so modified it as follows:

First I added a property to the options array (adding another dataset is perhaps cleaner but I would have had to tell ChartJS to ignore it), where each option is a data value index that I want to highlight, roughly as follows:

ChartDefaults.verticalOverlayAtBar = [itemOne, itemTwo]
...
var HistoryChart = new Chart(ctx).BarOverlay(ChartData, ChartDefaults);

I then modified StrangeWill's code, extending it to iterate the array of items from above and draw vertical lines on the indicated bar.

Chart.types.Bar.extend({
    name: 'BarOverlay',
    draw: function (ease) {

        // First draw the main chart
        Chart.types.Bar.prototype.draw.apply(this);

        var ctx = this.chart.ctx;
        var barWidth = this.scale.calculateBarWidth(this.datasets.length);

        for (var i = 0; i < this.options.verticalOverlayAtBar.length; ++i) {

            var overlayBar = this.options.verticalOverlayAtBar[i];

            // I'm hard-coding this to only work with the first dataset, and using a Y value that I know is maximum
            var x = this.scale.calculateBarX(this.datasets.length, 0, overlayBar);
            var y = this.scale.calculateY(2000);

            var bar_base = this.scale.endPoint

            ctx.beginPath();
            ctx.lineWidth = 2;
            ctx.strokeStyle = 'rgba(255, 0, 0, 1.0)';
            ctx.moveTo(x, bar_base);
            ctx.lineTo(x, y);
            ctx.stroke();
        }
        ctx.closePath();
    }
});

It's not perfect as I'm not familiar with the internals ChartJs code, in particular my lines were 2 bars off although my suspicion is that that's a fencepost error in the data array rather than the chart calculations. However, hopefully it's a useful step forwards for someone else.

like image 2
christutty Avatar answered Oct 23 '22 09:10

christutty