From e7a909a6f8b1b76939b071611629cf3c3d9ec80c Mon Sep 17 00:00:00 2001 From: "olau@iola.dk" Date: Tue, 8 Sep 2009 20:30:14 +0000 Subject: [PATCH] Added axis transformation support git-svn-id: https://flot.googlecode.com/svn/trunk@202 1e0a6537-2640-0410-bfb7-f154510ff394 --- API.txt | 29 +++++++++++++++++++++++++++-- NEWS.txt | 2 ++ jquery.flot.js | 43 ++++++++++++++++++++++++++++++------------- 3 files changed, 59 insertions(+), 15 deletions(-) diff --git a/API.txt b/API.txt index 22787dc..e43d92a 100644 --- a/API.txt +++ b/API.txt @@ -166,8 +166,6 @@ If you want the legend to appear somewhere else in the DOM, you can specify "container" as a jQuery object/expression to put the legend table into. The "position" and "margin" etc. options will then be ignored. Note that Flot will overwrite the contents of the container. -Most of the above settings do not apply - Customizing the axes @@ -178,9 +176,13 @@ Customizing the axes min: null or number max: null or number autoscaleMargin: null or number + labelWidth: null or number labelHeight: null or number + transform: null or fn: number -> number + inverseTransform: null or fn: number -> number + ticks: null or number or ticks array or (fn: range -> ticks array) tickSize: number or array minTickSize: number or array @@ -208,6 +210,29 @@ nearest whole tick. The default value is "null" for the x axis and labels in pixels. They're useful in case you need to align several plots. +"transform" and "inverseTransform" are callbacks you can put in to +change the way the data is drawn. You can design a function to +compress or expand certain parts of the axis non-linearly, e.g. +suppress weekends or compress far away points with a logarithm or some +other means. When Flot draws the plot, each value is first put through +the transform function. Here's an example, the x axis can be turned +into a natural logarithm axis with the following code: + + xaxis: { + transform: function (v) { return Math.log(v); }, + inverseTransform: function (v) { return Math.exp(v); } + } + +Note that for finding extrema, Flot assumes that the transform +function does not reorder values (monotonicity is assumed). + +The inverseTransform is simply the inverse of the transform function +(so v == inverseTransform(transform(v)) for all relevant v). It is +required for converting from canvas coordinates to data coordinates, +e.g. for a mouse interaction where a certain pixel is clicked. If you +don't use any interactive features of Flot, you may not need it. + + The rest of the options deal with the ticks. If you don't specify any ticks, a tick generator algorithm will make diff --git a/NEWS.txt b/NEWS.txt index 9f8173f..f7cdee7 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -111,6 +111,8 @@ Changes: - More configurable grid. +- Axis transformation support, useful for non-linear plots, e.g. log + axes and compressed time axes (like omitting weekends). Bug fixes: diff --git a/jquery.flot.js b/jquery.flot.js index aa96388..be0c15b 100644 --- a/jquery.flot.js +++ b/jquery.flot.js @@ -28,6 +28,8 @@ }, xaxis: { mode: null, // null or "time" + transform: null, // null or f: number -> number to transform axis + inverseTransform: null, // if transform is set, this should be the inverse function min: null, // min. value to show, null means set automatically max: null, // max. value to show, null means set automatically autoscaleMargin: null, // margin in % to add if auto-setting min/max @@ -561,27 +563,42 @@ } function setupGrid() { - function setTransformationHelpers(axis) { - var s, m; + function setTransformationHelpers(axis, o) { + function identity(x) { return x; } + + var s, m, t = o.transform || identity, + it = o.inverseTransform; // add transformation helpers if (axis == axes.xaxis || axis == axes.x2axis) { // precompute how much the axis is scaling a point // in canvas space - s = axis.scale = plotWidth / (axis.max - axis.min); - m = axis.min; - + s = axis.scale = plotWidth / (t(axis.max) - t(axis.min)); + m = t(axis.min); + // data point to canvas coordinate - axis.p2c = function (p) { return (p - m) * s; }; - // canvas coordinate to data point - axis.c2p = function (c) { return m + c / s; }; + if (t === identity) // slight optimization + axis.p2c = function (p) { return (p - m) * s; }; + else + axis.p2c = function (p) { return (t(p) - m) * s; }; + // canvas coordinate to data point + if (!it) + axis.c2p = function (c) { return m + c / s; }; + else + axis.c2p = function (c) { return it(m + c / s); }; } else { - s = axis.scale = plotHeight / (axis.max - axis.min) - m = axis.max; + s = axis.scale = plotHeight / (t(axis.max) - t(axis.min)); + m = t(axis.max); - axis.p2c = function (p) { return (m - p) * s; }; - axis.c2p = function (p) { return m - p / s; }; + if (t === identity) + axis.p2c = function (p) { return (m - p) * s; }; + else + axis.p2c = function (p) { return (m - t(p)) * s; }; + if (!it) + axis.c2p = function (c) { return m - c / s; }; + else + axis.c2p = function (c) { return it(m - c / s); }; } } @@ -686,7 +703,7 @@ } for (axis in axes) - setTransformationHelpers(axes[axis]); + setTransformationHelpers(axes[axis], options[axis]); if (options.grid.show) insertLabels();