McAsh
McAsh

Reputation: 215

Style specific bar column with Flot

I'm working with Flot to create a bar chart. However, I need to add special styling to certain columns. Is this possible at all?

My HTML looks like this:

<div id="monthly-usage" style="width: 100%; height: 400px;"></div>

And my JS like this:

somePlot = null;

$(function() {
//Data from this year and last year
  var thisYear = [
    [3, 231.01],
    [4, 219.65],
    [5, 222.47],
    [6, 223.09],
    [7, 248.43],
    [8, 246.22]
  ];

  var lastYear = [
    [3, 171.7],
    [4, 130.62],
    [5, 163.03],
    [6, 166.46],
    [7, 176.16],
    [8, 169.04]
  ];

  var usageData = [{
    //Usage this year
    label: "2014",
    data: thisYear,
    bars: {
      show: true,
      barWidth: .3,
      fill: true,
      lineWidth: 0,
      order: 1,
      fillColor: 'rgba(194, 46, 52, .85)'
    },
    color: '#c22e34'
  }, {
    //Usage last year to compare with current usage
    label: "2013",
    data: lastYear,
    bars: {
      show: true,
      barWidth: .3,
      fill: true,
      lineWidth: 0,
      order: 2,
      fillColor: 'rgba(73, 80, 94, .85)'
    },
    color: '#49505e'
  }];

  //X-axis labels
  var months = [
    [0, "Jan"],
    [1, "Feb"],
    [2, "Mar"],
    [3, "Apr"],
    [4, "Maj"],
    [5, "Jun"],
    [6, "Jul"],
    [7, "Aug"],
    [8, "Sep"],
    [9, "Okt"],
    [10, "Nov"],
    [11, "Dec"]
  ];

  //Draw the graph
  somePlot = $.plot(('#monthly-usage'), usageData, {
    grid: {
    color: '#646464',
    borderColor: 'transparent',
    hoverable: true
  },
  xaxis: {
    ticks: months,
    color: '#d4d4d4'
  },
  yaxis: {
    tickSize: 50,
    tickFormatter: function(y, axis) {
      return y + " kWh";
    }
  },
  legend: {
    show: false
  }
  });

  var ctx = somePlot.getCanvas().getContext("2d"); // get the context from plot
  var data = somePlot.getData()[0].data; // get your series data
  var xaxis = somePlot.getXAxes()[0]; // xAxis
  var yaxis = somePlot.getYAxes()[0]; // yAxis
  var offset = somePlot.getPlotOffset(); // plots offset
  var imageObj = new Image(); // create image
  imageObj.onload = function() { // when finish loading image add to canvas
    xPos = xaxis.p2c(data[4][0]) + offset.left;
    yPos = yaxis.p2c(data[4][1]) + offset.top; 
    ctx.drawImage(this, xPos, yPos);
    xPos = xaxis.p2c(data[5][0]) + offset.left;
    yPos = yaxis.p2c(data[5][1]) + offset.top; 
    ctx.drawImage(this, xPos, yPos);
  };
    imageObj.src = 'path/to/file.png'; // set it's source to kick off load
  });
});

Optimally, I would like to insert an icon in bar 5 and 6 that warns the user. Alternatively, I'd like to change the color of bars 5 and 6. Any ideas on how to fix this?

EDIT: I've updated my JS according to Mark's answer which works.

@Mark, how can I position the images correctly. They are a bit off. I need the image inside the red bar and not besides the bar. I'm trying to finetune this but it doesn't seem as if I can use for instance "0.5". I use side by side bars which is different from your version.

xPos = xaxis.p2c(data[4][0]) + offset.left;
yPos = yaxis.p2c(data[4][1]) + offset.top; 

This is how the images are placed right now

Upvotes: 2

Views: 541

Answers (2)

Mark
Mark

Reputation: 108567

flot gives you access to the HTML5 Canvas it's drawing on; so you just add your icon on there yourself. Borrowing from my own answer here.

  var ctx = somePlot.getCanvas().getContext("2d"); // get the context from plot
  var data = somePlot.getData()[0].data; // get your series data
  var xaxis = somePlot.getXAxes()[0]; // xAxis
  var yaxis = somePlot.getYAxes()[0]; // yAxis
  var offset = somePlot.getPlotOffset(); // plots offset
  $.get("someImage.txt", function(img) { // grad some image, I'm loading it from a base64 resource
    var imageObj = new Image(); // create image
    imageObj.onload = function() { // when finish loading image add to canvas
      var xPos = xaxis.p2c(data[4][0]) + offset.left;
      var yPos = yaxis.p2c(data[4][2]) + offset.top; 
      ctx.drawImage(this, xPos, yPos);
      xPos = xaxis.p2c(data[5][0]) + offset.left;
      yPos = yaxis.p2c(data[5][3]) + offset.top; 
      ctx.drawImage(this, xPos, yPos);
    };
    imageObj.src = img; // set it's source to kick off load
  });

Example here.

Looks like:

enter image description here

Upvotes: 0

Stephen Thomas
Stephen Thomas

Reputation: 14053

You can't do exactly what you ask with standard options, but there are a couple of possible approaches:

  1. Write your own draw method and use the hooks to install it in place of the standard flot drawing code. This obviously entails a lot of work, but you'll have complete control over how to render your data. (That said, I wouldn't recommend it.)

  2. Break your data into two different data sets. One data set would have dummy values (e.g. 0, or whatever your minimum is) for bars 5 and 6. The second data set would have dummy values for all bars except 5 and 6. You could then style the "two" data sets independently, giving each, for example a different color. Graph the two sets as a stacked bar chart with whatever additional styling tweaks are appropriate for your chart.

(As a FYI, there's a fair bit of information and examples at jsDataV.is. Look at the "Book" section; chapter 2 is dedicated to flot.)

Upvotes: 1

Related Questions