Chart.js 2.0 - How to change default appearance of canvas/chart elements

12,197

1.Remove the grid line up the y-axis

Just set display to false for options.scales.yAxes. This will remove all the labels too - we'll call the library method to draw the labels (without drawing the y-axis) in the plugin (see Step 4)


2.Remove the points on the first and last items of the dataset that meet the left/right edge of the chart

Just pass in an array to pointRadius and pointHoverRadius instead of a number. The following arrays will hide the first and last points (with your data)

...
pointRadius: [0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0],
pointHoverRadius: [0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0],
...

You might have to generate this using a script if your data length is dynamic.


3.Inset the y-axis scale labels

Set ticks.mirror for options.scales.yAxes to true. The plugin (from Step 4) will then just call the library draw method for the scale.


4.Make x-axis grid lines overlay on top of the line data fill

To make the gridLines appear (like it is) over the fill but under the points, the easiest way would be to draw it under the fill and set the fill to a slightly transparent value.

backgroundColor: "rgba(247,155,45,0.4)",

We have to draw the gridLines on our own since we don't want them to start from the edge. So set gridLines.display to false for options.scales.yAxes and register the following plugin

Chart.pluginService.register({
    afterDraw: function (chart, easingDecimal) {
        var yScale = chart.scales['y-axis-0'];
        var helpers = Chart.helpers;
        var chartArea = chart.chartArea;

        // draw labels - all we do is turn on display and call scale.draw
        yScale.options.display = true;
        yScale.draw.apply(yScale, [chartArea]);
        yScale.options.display = false;

        yScale.ctx.save();
            // draw under the fill
        yScale.ctx.globalCompositeOperation = 'destination-over';
        // draw the grid lines - simplified version of library code
        helpers.each(yScale.ticks, function (label, index) {
            if (label === undefined || label === null) {
                return;
            }

            var yLineValue = this.getPixelForTick(index);
            yLineValue += helpers.aliasPixel(this.ctx.lineWidth);

            this.ctx.lineWidth = this.options.gridLines.lineWidth;
            this.ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)';

            this.ctx.beginPath();
            this.ctx.moveTo(chartArea.left + 40, yLineValue);
            this.ctx.lineTo(chartArea.right, yLineValue);
            this.ctx.stroke();

        }, yScale);
        yScale.ctx.restore();
    },
})

Plugins will be called for all charts. If you want to skip the above logic for some charts, all you have to is set some property on the options object and check for it before you run your logic (e.g. yAxis.options.custom at the same level as yAxis.options.display


If you want to hide the 0 and 500 labels, you can set ticks.callback for options.scales.yAxes, like so

callback: function(value) {
  if (value !== 0 && value !== 500)
    return '' + value;
},

Note that it works as long as your scale is within the suggestedMin and suggestedMax. If your data goes outside these bounds, you'll have to use the scale properties.


To make the x-axis label background white, just add the below bit to the end of the plugin's afterDraw method

yScale.ctx.save();
yScale.ctx.fillStyle = 'white';
yScale.ctx.globalCompositeOperation = 'destination-over';
yScale.ctx.fillRect(0, yScale.bottom, chartArea.right, chartArea.bottom);
yScale.ctx.restore();

It just draws a white rectangle under the canvas content. Because your background color is set via the CSS, the rectangle is on top of the background color and everything is shiny.

You also have to move your background-color from your .chartjs-wrap to your canvas (otherwise you get a orange border at the bottom)

canvas {
    background-color: rgba(250, 210, 162, 1.0);
    ...

Updated version of your JSBin will all the above applied - http://jsbin.com/parucayara/1/edit?output

Share:
12,197
elzi
Author by

elzi

Contact email: [email protected]

Updated on June 05, 2022

Comments

  • elzi
    elzi almost 2 years

    I'm using the new Chart.js and trying to accomplish several customizations. Versed in JS but new to canvas, I'm struggling a bit. I'll try to provide as much information as possible.

     

    Related Links

     

    Code - JSBin

    JavaScript

    /**
     * Chart.js Global Config
     */
    Chart.defaults.global.pointHitDetectionRadius = 5;
    window.count = 0;
    
    
    
    
    /**
     * Chart Data
     * @type {Object}
     */
    var lineChartData = {
      labels: ["", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC", ""],
      datasets: [{
        label: "Students",
        data: [ 200, 250,220,180,290,300,370,350,200,280,260,190,210, 200 ],
        backgroundColor: "rgba(247,155,45,1.0)",
        borderColor: "rgba(247,155,45,1.0)",
        borderCapStyle: 'butt',
        borderDash: [],
        borderDashOffset: 0.0,
        pointBorderColor: "rgba(245,245,245,1)",
        pointBackgroundColor: "rgba(80,81,81,1)",
        pointHoverBorderWidth: 5,
        pointBorderWidth: 5,
        pointRadius: 8,
        pointHoverRadius: 9,
        pointHitRadius: 8,
      }]
    };
    
    
    
    /**
     * Init
     */
    window.onload = function() {
    
      var $chart = $('#chart');
    
      window.lineChart = new Chart($chart[0], {
        type: 'line',
    
        data: lineChartData,
    
        options: {
          showLines: true,
    
          // Legend
          legend : {
            display: false
          },
    
          // title
          title:{
            display:false,
            text:'Student Hours'
          },
    
          // Tooltips
          tooltips: {
            enabled: false,
          },
    
          // Scales
          scales: {
            yAxes: [{
              id: 'y-axis-0',
              gridLines: {
                display: true,
                lineWidth: 1,
                color: "rgba(255,255,255,0.85)"
              },
              ticks: {
                beginAtZero:true,
                mirror:false,
                suggestedMin: 0,
                suggestedMax: 500,
              },
              afterBuildTicks: function(chart) {
    
              }
            }],
            xAxes: [{
              id: 'x-axis-0',
              gridLines: {
                display: false
              },
              ticks: {
                beginAtZero: true
              }
            }]
          },
        }
      });
    
    };
    

    HTML

    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width">
      <title>JS Bin</title>
    
      <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.3/Chart.bundle.min.js"></script>
      <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
    
    </head>
    <body>
      <div id="chartjs-container" class="chartjs-wrap">
        <canvas id="chart"></canvas>
      </div>
    </body>
    </html>
    

    CSS

    #chartjs-container {
      width:80%;
      margin:20px auto;
      position: relative;
    }
    
    .chartjs-wrap {
      background-color: rgba(250, 210, 162, 1.0);
    }
    
      canvas {
        -moz-user-select: none;
        -webkit-user-select: none;
        -ms-user-select: none;
    
        height:100%;
      }
    

     

    What I'm trying to do

    1. Remove the grid line up the y-axis
    2. Remove the points on the first and last items of the dataset that meet the left/right edge of the chart
    3. Inset the y-axis scale labels
    4. Make x-axis grid lines overlay on top of the line data fill

     

    Screenshots

    Current State current-state-ss

    Desired State (Approximate) desired-state-ss

     

    Any help pointing me in the right direction would be great. Is there an equivalent on "Inspect Element" for canvas? These fixes would be trivial in CSS but I'm unsure on how to debug.

    Cheers

  • markE
    markE almost 8 years
    Nice methodology! Turn off the offending pieces and plugin the desired pieces using .pluginService.
  • elzi
    elzi almost 8 years
    Hi there. First off - thank you, amazing work. Few things: 1) There is a slight display bug on the top and bottom (500/0) values on the y axis. Would I be able to fix that within the afterDraw hook or in chartjs options itself. 2) Will this method with pluginServe.register work if there is possibly more than one chart on the same page? Accepting the answer anyway - thanks a ton.
  • elzi
    elzi almost 8 years
    Noticed a few other odds and ends. The newline drawn gridlines having a higher z-index than the points, so the lines go right through them. Also - would you know how to accomplish the white background for the x-axis labels on the bottom?
  • potatopeelings
    potatopeelings almost 8 years
    @elzi - the white background should be fairly simple with ctx.globalCompositeOperation = 'destination-over'. Having the gridLines over the chartfill and under the points is, I reckon, a bit messy (both of them get drawn in the same method - better to have the gridLines under the fill and make the fill slightly transparent so that it shows through. I'll give it a shot in a few hours. jsbin.com/vahonumosu/1/edit for the white fill (there's a bit of CSS change as well. I'll update the answer when I do the other one) Cheers!
  • elzi
    elzi almost 8 years
    @potatopeelings Thanks for the help. I'm not sure if this is the place for it or if SO allows it (if not, any moderator feel free to delete this comment), but our agency is looking to contract someone to finish these customizations for the chart. If you'd be willing to do such a thing, reach out! Cheers.
  • potatopeelings
    potatopeelings almost 8 years
    @elzi - I'm not sure about the if SO allows it part (from meta, I get the general idea that it's ok to contact someone if they have their contact info on their about About page). I don't freelance, but if it's just a few days of work and your agency is willing to try someone else out, my SO is looking to do contracting work and is on the AU version of freelancer. I can email you the freelancer link if you have a contact email. Cheers!
  • elzi
    elzi almost 8 years
    @potatopeelings Thanks! I updated my profile with a contact email as well.