aboutsummaryrefslogtreecommitdiffstats
path: root/public/javascripts/jquery.flot.tickrotor.js
diff options
context:
space:
mode:
Diffstat (limited to 'public/javascripts/jquery.flot.tickrotor.js')
-rw-r--r--public/javascripts/jquery.flot.tickrotor.js205
1 files changed, 205 insertions, 0 deletions
diff --git a/public/javascripts/jquery.flot.tickrotor.js b/public/javascripts/jquery.flot.tickrotor.js
new file mode 100644
index 000000000..404b2b0a7
--- /dev/null
+++ b/public/javascripts/jquery.flot.tickrotor.js
@@ -0,0 +1,205 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is flot-tickrotor.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mark Cote <mcote@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * flot-tickrotor: flot plugin to display angled X-axis tick labels.
+ *
+ * Requires flot 0.7 or higher and a browser supporting <canvas>.
+ *
+ * To activate, just set xaxis.rotateTicks to an angle in degrees. Labels
+ * are rotated clockwise, so if you want the labels to angle up and to the right (/)
+ * you need to provide an angle > 90. The text will be flipped so that it is still
+ * right-side-up.
+ * Angles greater than or equal to 180 are ignored.
+ */
+(function ($) {
+ var options = { };
+
+ function init(plot) {
+ // Taken from flot-axislabels.
+ // This is kind of a hack. There are no hooks in Flot between
+ // the creation and measuring of the ticks (setTicks, measureTickLabels
+ // in setupGrid() ) and the drawing of the ticks and plot box
+ // (insertAxisLabels in setupGrid() ).
+ //
+ // Therefore, we use a trick where we run the draw routine twice:
+ // the first time to get the tick measurements, so that we can change
+ // them, and then have it draw it again.
+ var ticks = [];
+ var font;
+ var secondPass = false;
+ var rotateTicks, rotateTicksRads, radsAboveHoriz;
+ plot.hooks.draw.push(function (plot, ctx) {
+ if (!secondPass) {
+ var opts = plot.getAxes().xaxis.options;
+ if (opts.rotateTicks === undefined) {
+ return;
+ }
+
+ rotateTicks = parseInt(opts.rotateTicks, 10);
+ if (rotateTicks.toString() != opts.rotateTicks || rotateTicks == 0 || rotateTicks >= 180) {
+ return;
+ }
+
+ rotateTicksRads = rotateTicks * Math.PI/180;
+ if (rotateTicks > 90) {
+ radsAboveHoriz = Math.PI - rotateTicksRads;
+ } else {
+ radsAboveHoriz = Math.PI/2 - rotateTicksRads;
+ }
+
+ font = opts.rotateTicksFont;
+ if (!font) {
+ font = $('.tickLabel').css('font');
+ }
+ if (!font) {
+ font = 'smaller sans-serif';
+ }
+
+ var elem, maxLabelWidth = 0, maxLabelHeight = 0, minX = 0, maxX = 0;
+
+ var xaxis = plot.getAxes().xaxis;
+ ticks = plot.getAxes().xaxis.ticks;
+ opts.ticks = []; // we'll make our own
+
+ var x;
+ for (var i = 0; i < ticks.length; i++) {
+ elem = $('<span style="font:' + font + '">' + ticks[i].label + '</span>');
+ plot.getPlaceholder().append(elem);
+ ticks[i].height = elem.outerHeight(true);
+ ticks[i].width = elem.outerWidth(true);
+ elem.remove();
+ if (ticks[i].height > maxLabelHeight) {
+ maxLabelHeight = ticks[i].height;
+ }
+ if (ticks[i].width > maxLabelWidth) {
+ maxLabelWidth = ticks[i].width;
+ }
+ var tick = ticks[i];
+ // See second-draw code below for explanation of offsets.
+ if (rotateTicks > 90) {
+ // See if any labels are too long and require increased left
+ // padding.
+ x = Math.round(plot.getPlotOffset().left + xaxis.p2c(tick.v))
+ - Math.ceil(Math.cos(radsAboveHoriz) * tick.height)
+ - Math.ceil(Math.cos(radsAboveHoriz) * tick.width);
+ if (x < minX) {
+ minX = x;
+ }
+ } else {
+ // See if any labels are too long and require increased right
+ // padding.
+ x = Math.round(plot.getPlotOffset().left + xaxis.p2c(tick.v))
+ + Math.ceil(Math.cos(radsAboveHoriz) * tick.height)
+ + Math.ceil(Math.cos(radsAboveHoriz) * tick.width);
+ if (x > maxX) {
+ maxX = x;
+ }
+ }
+ }
+
+ // Calculate maximum label height after rotating.
+ if (rotateTicks > 90) {
+ var acuteRads = rotateTicksRads - Math.PI/2;
+ opts.labelHeight = Math.ceil(Math.sin(acuteRads) * maxLabelWidth)
+ + Math.ceil(Math.sin(acuteRads) * maxLabelHeight);
+ } else {
+ var acuteRads = Math.PI/2 - rotateTicksRads;
+ // Center such that the top of the label is at the center of the tick.
+ opts.labelHeight = Math.ceil(Math.sin(rotateTicksRads) * maxLabelWidth)
+ + Math.ceil(Math.sin(acuteRads) * maxLabelHeight);
+ }
+
+ if (minX < 0) {
+ plot.getAxes().yaxis.options.labelWidth = -1 * minX;
+ }
+
+ // Doesn't seem to work if there are no values using the second y axis.
+ //if (maxX > xaxis.box.left + xaxis.box.width) {
+ // plot.getAxes().y2axis.options.labelWidth = maxX - xaxis.box.left - xaxis.box.width;
+ //}
+
+ // re-draw with new label widths and heights
+ secondPass = true;
+ plot.setupGrid();
+ plot.draw();
+ } else {
+ if (ticks.length == 0) {
+ return;
+ }
+ var xaxis = plot.getAxes().xaxis;
+ var box = xaxis.box;
+ var tick, label, xoffset, yoffset;
+ for (var i = 0; i < ticks.length; i++) {
+ tick = ticks[i];
+ if (!tick.label) {
+ continue;
+ }
+ ctx.save();
+ ctx.font = font;
+ if (rotateTicks <= 90) {
+ // Center such that the top of the label is at the center of the tick.
+ xoffset = -Math.ceil(Math.cos(radsAboveHoriz) * tick.height);
+ yoffset = Math.ceil(Math.sin(radsAboveHoriz) * tick.height);
+ ctx.translate(Math.round(plot.getPlotOffset().left + xaxis.p2c(tick.v)) + xoffset,
+ box.top + box.padding + plot.getOptions().grid.labelMargin + yoffset);
+ ctx.rotate(rotateTicksRads);
+ } else {
+ // We want the text to facing up, so we have to rotate counterclockwise,
+ // which means the label has to *end* at the center of the tick.
+ xoffset = Math.ceil(Math.cos(radsAboveHoriz) * tick.height)
+ - Math.ceil(Math.cos(radsAboveHoriz) * tick.width);
+ yoffset = Math.ceil(Math.sin(radsAboveHoriz) * tick.width)
+ + Math.ceil(Math.sin(radsAboveHoriz) * tick.height);
+ ctx.translate(Math.round(plot.getPlotOffset().left + xaxis.p2c(tick.v) + xoffset),
+ box.top + box.padding + plot.getOptions().grid.labelMargin + yoffset);
+ ctx.rotate(-radsAboveHoriz);
+ }
+ ctx.fillText(tick.label, 0, 0);
+ ctx.restore();
+ }
+ }
+ });
+ }
+
+ $.plot.plugins.push({
+ init: init,
+ options: options,
+ name: 'tickRotor',
+ version: '1.0'
+ });
+})(jQuery);