]> git.proxmox.com Git - ceph.git/blob - ceph/qa/workunits/erasure-code/jquery.flot.categories.js
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / qa / workunits / erasure-code / jquery.flot.categories.js
1 /* Flot plugin for plotting textual data or categories.
2
3 Copyright (c) 2007-2014 IOLA and Ole Laursen.
4 Licensed under the MIT license.
5
6 Consider a dataset like [["February", 34], ["March", 20], ...]. This plugin
7 allows you to plot such a dataset directly.
8
9 To enable it, you must specify mode: "categories" on the axis with the textual
10 labels, e.g.
11
12 $.plot("#placeholder", data, { xaxis: { mode: "categories" } });
13
14 By default, the labels are ordered as they are met in the data series. If you
15 need a different ordering, you can specify "categories" on the axis options
16 and list the categories there:
17
18 xaxis: {
19 mode: "categories",
20 categories: ["February", "March", "April"]
21 }
22
23 If you need to customize the distances between the categories, you can specify
24 "categories" as an object mapping labels to values
25
26 xaxis: {
27 mode: "categories",
28 categories: { "February": 1, "March": 3, "April": 4 }
29 }
30
31 If you don't specify all categories, the remaining categories will be numbered
32 from the max value plus 1 (with a spacing of 1 between each).
33
34 Internally, the plugin works by transforming the input data through an auto-
35 generated mapping where the first category becomes 0, the second 1, etc.
36 Hence, a point like ["February", 34] becomes [0, 34] internally in Flot (this
37 is visible in hover and click events that return numbers rather than the
38 category labels). The plugin also overrides the tick generator to spit out the
39 categories as ticks instead of the values.
40
41 If you need to map a value back to its label, the mapping is always accessible
42 as "categories" on the axis object, e.g. plot.getAxes().xaxis.categories.
43
44 */
45
46 (function ($) {
47 var options = {
48 xaxis: {
49 categories: null
50 },
51 yaxis: {
52 categories: null
53 }
54 };
55
56 function processRawData(plot, series, data, datapoints) {
57 // if categories are enabled, we need to disable
58 // auto-transformation to numbers so the strings are intact
59 // for later processing
60
61 var xCategories = series.xaxis.options.mode == "categories",
62 yCategories = series.yaxis.options.mode == "categories";
63
64 if (!(xCategories || yCategories))
65 return;
66
67 var format = datapoints.format;
68
69 if (!format) {
70 // FIXME: auto-detection should really not be defined here
71 var s = series;
72 format = [];
73 format.push({ x: true, number: true, required: true });
74 format.push({ y: true, number: true, required: true });
75
76 if (s.bars.show || (s.lines.show && s.lines.fill)) {
77 var autoscale = !!((s.bars.show && s.bars.zero) || (s.lines.show && s.lines.zero));
78 format.push({ y: true, number: true, required: false, defaultValue: 0, autoscale: autoscale });
79 if (s.bars.horizontal) {
80 delete format[format.length - 1].y;
81 format[format.length - 1].x = true;
82 }
83 }
84
85 datapoints.format = format;
86 }
87
88 for (var m = 0; m < format.length; ++m) {
89 if (format[m].x && xCategories)
90 format[m].number = false;
91
92 if (format[m].y && yCategories)
93 format[m].number = false;
94 }
95 }
96
97 function getNextIndex(categories) {
98 var index = -1;
99
100 for (var v in categories)
101 if (categories[v] > index)
102 index = categories[v];
103
104 return index + 1;
105 }
106
107 function categoriesTickGenerator(axis) {
108 var res = [];
109 for (var label in axis.categories) {
110 var v = axis.categories[label];
111 if (v >= axis.min && v <= axis.max)
112 res.push([v, label]);
113 }
114
115 res.sort(function (a, b) { return a[0] - b[0]; });
116
117 return res;
118 }
119
120 function setupCategoriesForAxis(series, axis, datapoints) {
121 if (series[axis].options.mode != "categories")
122 return;
123
124 if (!series[axis].categories) {
125 // parse options
126 var c = {}, o = series[axis].options.categories || {};
127 if ($.isArray(o)) {
128 for (var i = 0; i < o.length; ++i)
129 c[o[i]] = i;
130 }
131 else {
132 for (var v in o)
133 c[v] = o[v];
134 }
135
136 series[axis].categories = c;
137 }
138
139 // fix ticks
140 if (!series[axis].options.ticks)
141 series[axis].options.ticks = categoriesTickGenerator;
142
143 transformPointsOnAxis(datapoints, axis, series[axis].categories);
144 }
145
146 function transformPointsOnAxis(datapoints, axis, categories) {
147 // go through the points, transforming them
148 var points = datapoints.points,
149 ps = datapoints.pointsize,
150 format = datapoints.format,
151 formatColumn = axis.charAt(0),
152 index = getNextIndex(categories);
153
154 for (var i = 0; i < points.length; i += ps) {
155 if (points[i] == null)
156 continue;
157
158 for (var m = 0; m < ps; ++m) {
159 var val = points[i + m];
160
161 if (val == null || !format[m][formatColumn])
162 continue;
163
164 if (!(val in categories)) {
165 categories[val] = index;
166 ++index;
167 }
168
169 points[i + m] = categories[val];
170 }
171 }
172 }
173
174 function processDatapoints(plot, series, datapoints) {
175 setupCategoriesForAxis(series, "xaxis", datapoints);
176 setupCategoriesForAxis(series, "yaxis", datapoints);
177 }
178
179 function init(plot) {
180 plot.hooks.processRawData.push(processRawData);
181 plot.hooks.processDatapoints.push(processDatapoints);
182 }
183
184 $.plot.plugins.push({
185 init: init,
186 options: options,
187 name: 'categories',
188 version: '1.0'
189 });
190 })(jQuery);