diff --git a/README.fastline.md b/README.fastline.md
new file mode 100644
index 0000000..32ec876
--- /dev/null
+++ b/README.fastline.md
@@ -0,0 +1,27 @@
+## Fast line plot plugin for Flot ##
+This plugin makes a very basic line plot. It is intended to efficiently render large and fast-updating data sets. I created this plugin when I needed to display lines of some thousands of points updating several times a second. While the original Flot implementation worked fine with Webkit (Safari and Chrome), the result on Firefox was catastrophic. This plugin gives the same performance on all three browsers.
+
+## Basic usage ##
+When creating a Flot chart, simply add the *fastline* tag to the series definition, like this:
+```
+var my_plot = $.plot($("#plot_container"), [data], series:{fastline:{ active:true, show:true }});
+```
+
+## Data format ##
+The pcolor plugin expects that the data is composed of 2 arrays, one for the horizontal coordinates and one for the vertical coordinates:
+```
+data = [x coordinates <1D array>, y coordinates <1D array>]
+```
+It is sorted differently than normal Flot lines to allow this sort of operations: ```Math.min.apply(null,vector)```.
+
+## Data range ##
+The displayed range can be adjusted in this way:
+```
+my_plot.getAxes().xaxis.options.min = new_x_min;
+my_plot.getAxes().xaxis.options.max = new_x_max;
+my_plot.getAxes().yaxis.options.min = new_y_min;
+my_plot.getAxes().yaxis.options.max = new_y_max;
+```
+
+## Example ##
+See included file example.fastline.html
diff --git a/README.pcolor.md b/README.pcolor.md
new file mode 100644
index 0000000..b538c69
--- /dev/null
+++ b/README.pcolor.md
@@ -0,0 +1,72 @@
+## 2D pseudo-color plot plugin for Flot ##
+This plugin takes a 2D array and maps the values to a defined color map.
+## Basic usage ##
+When creating a Flot chart, simply add the *pcolor* tag to the series definition, like this:
+```
+var my_plot = $.plot($("#plot_container"), [data], series:{pcolor:{ active:true, show:true, colormap: my_colormap, scalebar: scalebar_options }});
+```
+
+## Data format ##
+The pcolor plugin expects that the data is composed of 3 arrays, one for the horizontal coordinates, one for the vertical coordinates, and one for the values:
+```
+data = [x coordinates <1D or 2D array>, y coordinates <1D or 2D array>, values <2D array>]
+```
+The coordinate arrays can be either 1D or 2D.
+
+## Data range ##
+The minima and maxima in x and y directions are accessible in this way:
+```
+var x_min = my_plot.getAxes().xaxis.datamin
+var x_max = my_plot.getAxes().xaxis.datamax
+var y_min = my_plot.getAxes().yaxis.datamin
+var y_max = my_plot.getAxes().yaxis.datamax
+```
+The displayed range can be adjusted in this way:
+```
+my_plot.getAxes().xaxis.options.min = new_x_min;
+my_plot.getAxes().xaxis.options.max = new_x_max;
+my_plot.getAxes().yaxis.options.min = new_y_min;
+my_plot.getAxes().yaxis.options.max = new_y_max;
+```
+
+## Color map ##
+The colormap is an array defining a linear gradient. Each element of the array must be [color position, color code].
+For example, a blue/white/red gradient would be defined as:
+```
+var colormap_bwr = [[0,"#0000ff"],[0.5,"#ffffff"],[1,"#ff0000"]];
+```
+Another popular color map is the *jet* color map:
+```
+var colormap_jet = [ [0,"#00007f"], [0.125,"#0000ff"], [0.25,"#007fff"], [0.375,"#00ffff"],
+[0.5,"#7fff7f"], [0.625,"#ffff00"], [0.75,"#ff7f00"], [0.875,"#ff0000"], [1.0,"#7f0000"] ];
+```
+
+## Scale bar ##
+By default, a scale bar showing the extent of the represented colours appears in the top right corner of the plot. The scale bar options are:
+```
+scalebar_options = {
+ location:"top right" // combination of top, left, right and bottom
+ orientation:"vertical" // horizontal or vertical
+ width:100,
+ height:15,
+ fontsize:"9px",
+ fontfamily:"times",
+ labels:3, // number of labels, >1 to display any
+ labelformat:"1f",
+ labelformatter: function(value,precision){ return "text"; },
+ textalign:"right"
+}
+```
+The label format number represents the truncation precision and the letter the JavaScript function used to format the numbers: *f* = toFixed, *p* = toPrecision, *e* = toExponential, *c* = custom function provided in the *labelformatter* option.
+The label alignment, set by the ```textalign``` property, can be *left*, *center*, *right*, or *spread*. The last option, when the bar is horizontally oriented, spreads the labels across the whole scale bar width.
+The scale bar is deactivated by settings ```scalebar_options = null```.
+
+## Grid ##
+The grid can be displayed by setting ```grid: {aboveData:true}``` in Flot options. Note that it will display above the color bar.
+Another option exists, which requires to expose the *drawGrid* function of Flot. If you did so, you can add ```grid:true``` to *pcolor* options. The grid will be drawn above the plot but below the scale bar.
+
+## Performances and compatibility ##
+The pcolor plugin has been tested to work on Safari, Chrome and Firefox under Mac OS X. The behaviour in terms of performance was similar.
+
+## Example ##
+See included file example.pcolor.html
diff --git a/example.fastline.html b/example.fastline.html
new file mode 100644
index 0000000..d5819bb
--- /dev/null
+++ b/example.fastline.html
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example.pcolor.html b/example.pcolor.html
new file mode 100644
index 0000000..a182e6f
--- /dev/null
+++ b/example.pcolor.html
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/jquery.flot.fastline.js b/plugins/jquery.flot.fastline.js
new file mode 100644
index 0000000..79a25be
--- /dev/null
+++ b/plugins/jquery.flot.fastline.js
@@ -0,0 +1,83 @@
+(function ($) {
+ "use strict";
+ var pluginName = "fastline", pluginVersion = "0.1";
+ var options = {
+ series: {
+ fastline: {
+ active: false,
+ show: false,
+ }
+ }
+ };
+ var defaultOptions = {
+ };
+ function init(plot) {
+ plot.hooks.processOptions.push(processOptions);
+ function processOptions(plot,options){
+ if(options.series.fastline.active){
+ plot.hooks.drawSeries.push(drawSeries);
+ }
+ }
+ function drawSeries(plot, ctx, serie){
+ if (serie.fastline.show) {
+ var offset = plot.getPlotOffset();
+ if (serie.xaxis.min!=undefined) {var x_min = serie.xaxis.min;}
+ else {var x_min = Math.min.apply(null, serie.data[0]);}
+
+ if (serie.xaxis.max!=undefined) {var x_max = serie.xaxis.max;}
+ else {var x_max = Math.max.apply(null, serie.data[0]);}
+
+ if (serie.yaxis.min!=undefined) {var y_min = serie.yaxis.min;}
+ else {var y_min = Math.min.apply(null, serie.data[1]);}
+
+ if (serie.yaxis.max!=undefined) {var y_max = serie.yaxis.max;}
+ else {var y_max = Math.max.apply(null, serie.data[1]);}
+
+ var dx = x_max - x_min;
+ var dy = y_max - y_min;
+ var np = serie.data[0].length;
+ var w = plot.width();
+ var h = plot.height();
+
+ // builds line
+ ctx.save();
+ ctx.beginPath();
+ ctx.lineWidth=1;
+ ctx.strokeStyle=serie.color;
+ var ox = offset.left;
+ var oh = h+offset.top;
+ var oy = offset.top;
+ var ow = w+offset.left;
+ var px = ox, py=oy;
+ var xscale = w/dx;
+ var yscale = h/dy;
+ var first = true;
+ var pnx = ox, pny = oh;
+ for (var i = 0; i < np; i++) {
+ px = ox + parseInt((serie.data[0][i]-x_min)*xscale);
+ py = oh - parseInt((serie.data[1][i]-y_min)*yscale);
+ if (pnx!=px || pny!=py) {
+ if (px>=ox && py>=oy && px<=ow && py<=oh) {
+ if (first) {
+ ctx.moveTo(px,py);
+ first = false;
+ } else {
+ ctx.lineTo(px,py);
+ }
+ pnx = px;
+ pny = py;
+ }
+ }
+ }
+ ctx.stroke();
+ ctx.restore();
+ }
+ }
+ }
+ $.plot.plugins.push({
+ init: init,
+ options: options,
+ name: pluginName,
+ version: pluginVersion
+ });
+})(jQuery);
\ No newline at end of file
diff --git a/plugins/jquery.flot.pcolor.js b/plugins/jquery.flot.pcolor.js
new file mode 100644
index 0000000..b49d535
--- /dev/null
+++ b/plugins/jquery.flot.pcolor.js
@@ -0,0 +1,412 @@
+(function ($) {
+ "use strict";
+ var pluginName = "pcolor", pluginVersion = "0.2.1";
+ var options = {
+ series: {
+ pcolor: {
+ active: false,
+ show: false,
+ scalebar:
+ {
+ location: "top right", // can be a combination of top, right, left, bottom
+ orientation: "vertical", // horizontal or vertical
+ width:15, // pixel width
+ height:100, // pixel height
+ fontsize:"10px", // font size
+ fontfamily:"times", // font family
+ labels:3, // number of labels (>1 or not displayed)
+ labelformat:"1f", // label format: number = truncation accuracy
+ // letter = "f":toFixed, "p":toPrecision, "e":toExponential, "c":custom
+ labelformatter: function(value,precision){return ""},
+ textalign:"right" // alignment of labels: left (default), center, right or spread
+ }
+ }
+ }
+ };
+ function init(plot) {
+ var offset = null,opt = null,series = null;
+ plot.hooks.processOptions.push(processOptions);
+ function processOptions(plot,options){
+ // parses options for pcolor plot
+ if(options.series.pcolor.active){
+ // hook for pcolor rendering
+ plot.hooks.drawSeries.push(drawSeries);
+
+ // creates pcolor objects
+ plot.pcolor = {scalebar:{}}
+ if (options.series.pcolor.scalebar) {
+ // parses position string
+ var tags = options.series.pcolor.scalebar.location.split(" ");
+ var left = (tags.indexOf("left")>-1);
+ var right = (tags.indexOf("right")>-1);
+ var top = (tags.indexOf("top")>-1);
+ var bottom = (tags.indexOf("bottom")>-1);
+ plot.pcolor.scalebar.position = [top && left,
+ top && right,
+ bottom && right,
+ bottom && left].indexOf(true);
+ // determines if the scale bar is rendered
+ plot.pcolor.scalebar.show = (tags.length>0) && (tags.indexOf("none")==-1);
+ // orientation: horizontal=true, vertical=false (default)
+ plot.pcolor.scalebar.orientation = (options.series.pcolor.scalebar.orientation.indexOf("horizontal")>-1);
+ // alignment of labels
+ var align_left = (options.series.pcolor.scalebar.textalign=="left");
+ var align_center = (options.series.pcolor.scalebar.textalign=="center");
+ var align_right = (options.series.pcolor.scalebar.textalign=="right");
+ var align_spread = (options.series.pcolor.scalebar.textalign=="spread");
+ plot.pcolor.scalebar.textalign = [align_left,align_center,align_right,align_spread].indexOf(true);
+ plot.pcolor.scalebar.textalign = (plot.pcolor.scalebar.textalign>-1)*plot.pcolor.scalebar.textalign;
+ // spread not allowed for vertical configuration
+ if (!plot.pcolor.scalebar.orientation && plot.pcolor.scalebar.textalign==3) {
+ plot.pcolor.scalebar.textalign = 0;
+ }
+ // creates canvas with scale bar gradient
+ plot.pcolor.scalebar.grdcnv = document.createElement("canvas");
+ var sctx = plot.pcolor.scalebar.grdcnv.getContext("2d");
+ plot.pcolor.scalebar.grdcnv.width = options.series.pcolor.scalebar.width;
+ plot.pcolor.scalebar.grdcnv.height = options.series.pcolor.scalebar.height;
+ if (plot.pcolor.scalebar.orientation) {
+ var cgrd = sctx.createLinearGradient(0,0,plot.pcolor.scalebar.grdcnv.width,0);
+ } else {
+ var cgrd = sctx.createLinearGradient(0,plot.pcolor.scalebar.grdcnv.height,0,0);
+ }
+ } else {
+ plot.pcolor.scalebar.show = false;
+ }
+ // creates color map
+ // most convenient way found so far: draw a gradient on an off-screen canvas
+ // and store it as a bitmap
+ var ocnv = document.createElement("canvas");
+ ocnv.width = 16385;
+ ocnv.height = 1;
+ var octx = ocnv.getContext("2d");
+ var grd = octx.createLinearGradient(0,0,16385,0);
+ if (options.series.pcolor.colormap==undefined) {
+ var colormap = [[0,"#0000ff"],[0.5,"#ffffff"],[1,"#ff0000"]];
+ } else {
+ var colormap = options.series.pcolor.colormap;
+ }
+ for (var n=0; n0) {
+ offset = plot.getPlotOffset();
+ var w = serie.data[2][0].length, h = serie.data[2].length;
+ var pw = plot.width()+offset.left+offset.right, ph = plot.height()+offset.top+offset.bottom;
+ var cw = ctx.canvas.width, ch = ctx.canvas.height;
+ var ocnv = plot.pcolor.ocnv;
+ var octx = plot.pcolor.octx;
+ ocnv.width = w;
+ ocnv.height = h;
+ var img = octx.createImageData(w, h);
+
+ if (typeof serie.data[0][0] == "number") { // 1D map for x coordinates => makes 2D map
+ var new_map_x = new Array(h);
+ var x_min = Math.min.apply(null, serie.data[0]);
+ var x_max = Math.max.apply(null, serie.data[0]);
+ for (var i=0; i=x_min && serie.data[0][i][j]<=x_max &&
+ serie.data[1][i][j]>=y_min && serie.data[1][i][j]<=y_max) {
+ var px = (w-1)*(serie.data[0][i][j]-x_min)/dx;
+ var py = (h-1)*(serie.data[1][i][j]-y_min)/dy;
+ var pxm = Math.floor(px);
+ var pym = Math.floor(py);
+ var pxp = Math.ceil(px);
+ var pyp = Math.ceil(py);
+ var idxmm = (pym*w+pxm)*4;
+ var idxpm = (pyp*w+pxm)*4;
+ var idxmp = (pym*w+pxp)*4;
+ var idxpp = (pyp*w+pxp)*4;
+ var v = 4*parseInt(((serie.data[2][i][j]-c_min)/dc)*16384);
+ var r = plot.pcolor.colormap.data[v];
+ var g = plot.pcolor.colormap.data[v+1];
+ var b = plot.pcolor.colormap.data[v+2];
+ img.data[idxmm] = r;
+ img.data[idxmm+1] = g;
+ img.data[idxmm+2] = b;
+ img.data[idxmm+3] = 255;
+ if (idxmp!=idxmm) {
+ img.data[idxmp] = r;
+ img.data[idxmp+1] = g;
+ img.data[idxmp+2] = b;
+ img.data[idxmp+3] = 255;
+ }
+ if (idxpm!=idxmm) {
+ img.data[idxpm] = r;
+ img.data[idxpm+1] = g;
+ img.data[idxpm+2] = b;
+ img.data[idxpm+3] = 255;
+ }
+ if (idxpp!=idxmm) {
+ img.data[idxpp] = r;
+ img.data[idxpp+1] = g;
+ img.data[idxpp+2] = b;
+ img.data[idxpp+3] = 255;
+ }
+ }
+ }
+ }
+ octx.putImageData(img,0,0);
+ ctx.save();
+ ctx.beginPath();
+ ctx.rect(offset.left,offset.top,pw-offset.left-offset.right,ph-offset.top-offset.bottom);
+ ctx.clip();
+ ctx.setTransform(sw,0,0,sh,0,0);
+ ctx.drawImage(ocnv,offset.left/sw*cw/pw,offset.top/sh*ch/ph);
+ ctx.restore();
+ // adds scalebar if necessary
+ if (plot.pcolor.scalebar.show) {
+ ctx.save();
+ // prepares labels
+ if (serie.pcolor.scalebar.labels>1) {
+ ctx.font = serie.pcolor.scalebar.fontsize + " " + serie.pcolor.scalebar.fontfamily;
+ // formats labels and computes their width
+ var labels = new Array(serie.pcolor.scalebar.labels);
+ var lwidths = new Array(serie.pcolor.scalebar.labels);
+ var dt = dc/(serie.pcolor.scalebar.labels-1);
+ // couldn't find a standard way to obtain the font height
+ // using the full block character trick instead.
+ var tmh = ctx.measureText('\u2588').width;
+ for (var t=0; t1, as otherwise it makes no sense
+ if (serie.pcolor.scalebar.labels>1) {
+ // positions the background for the labels and the labels inside
+ ctx.fillStyle="rgba(255,255,255,0.66)";
+ if (plot.pcolor.scalebar.orientation) {
+ // for horizontal orientation
+ ctx.fillRect(cpx+ocpx, cpy+ocpy, plot.pcolor.scalebar.grdcnv.width, tmh+4);
+ ctx.fillStyle="#000000";
+ var cdw = (plot.pcolor.scalebar.grdcnv.width-tmw-4)/(serie.pcolor.scalebar.labels-1);
+ var labx = cpx+ocpx+otx+2; // horizontal offset
+ var laby = cpy+ocpy+oty; // vertical position
+ for (t=0; t