blacklight_range_limit 7.2.0 → 7.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/app/assets/javascripts/blacklight_range_limit.js +7 -0
  4. data/app/assets/javascripts/blacklight_range_limit/range_limit_distro_facets.js +23 -11
  5. data/app/assets/javascripts/blacklight_range_limit/range_limit_slider.js +83 -76
  6. data/app/assets/stylesheets/blacklight_range_limit/blacklight_range_limit.css +26 -1
  7. data/app/helpers/range_limit_helper.rb +3 -3
  8. data/app/views/blacklight_range_limit/_range_limit_panel.html.erb +30 -27
  9. data/app/views/blacklight_range_limit/_range_segments.html.erb +6 -6
  10. data/app/views/blacklight_range_limit/range_limit_panel.html.erb +10 -0
  11. data/config/locales/blacklight_range_limit.en.yml +7 -0
  12. data/lib/blacklight_range_limit.rb +2 -4
  13. data/lib/blacklight_range_limit/controller_override.rb +28 -0
  14. data/lib/blacklight_range_limit/routes.rb +1 -1
  15. data/lib/blacklight_range_limit/routes/range_searchable.rb +1 -0
  16. data/lib/blacklight_range_limit/view_helper_override.rb +0 -13
  17. data/spec/features/a_javascript_spec.rb +11 -4
  18. data/spec/spec_helper.rb +12 -1
  19. data/vendor/assets/javascripts/flot/jquery.canvaswrapper.js +550 -0
  20. data/vendor/assets/javascripts/flot/jquery.colorhelpers.js +199 -0
  21. data/vendor/assets/javascripts/flot/jquery.flot.browser.js +98 -0
  22. data/vendor/assets/javascripts/flot/jquery.flot.drawSeries.js +663 -0
  23. data/vendor/assets/javascripts/flot/jquery.flot.hover.js +360 -0
  24. data/vendor/assets/javascripts/flot/jquery.flot.js +1610 -1928
  25. data/vendor/assets/javascripts/flot/jquery.flot.saturated.js +43 -0
  26. data/vendor/assets/javascripts/flot/jquery.flot.selection.js +237 -68
  27. data/vendor/assets/javascripts/flot/jquery.flot.uiConstants.js +10 -0
  28. metadata +10 -3
  29. data/vendor/assets/javascripts/flot/excanvas.min.js +0 -1
@@ -0,0 +1,199 @@
1
+ /* Plugin for jQuery for working with colors.
2
+ *
3
+ * Version 1.1.
4
+ *
5
+ * Inspiration from jQuery color animation plugin by John Resig.
6
+ *
7
+ * Released under the MIT license by Ole Laursen, October 2009.
8
+ *
9
+ * Examples:
10
+ *
11
+ * $.color.parse("#fff").scale('rgb', 0.25).add('a', -0.5).toString()
12
+ * var c = $.color.extract($("#mydiv"), 'background-color');
13
+ * console.log(c.r, c.g, c.b, c.a);
14
+ * $.color.make(100, 50, 25, 0.4).toString() // returns "rgba(100,50,25,0.4)"
15
+ *
16
+ * Note that .scale() and .add() return the same modified object
17
+ * instead of making a new one.
18
+ *
19
+ * V. 1.1: Fix error handling so e.g. parsing an empty string does
20
+ * produce a color rather than just crashing.
21
+ */
22
+
23
+ (function($) {
24
+ $.color = {};
25
+
26
+ // construct color object with some convenient chainable helpers
27
+ $.color.make = function (r, g, b, a) {
28
+ var o = {};
29
+ o.r = r || 0;
30
+ o.g = g || 0;
31
+ o.b = b || 0;
32
+ o.a = a != null ? a : 1;
33
+
34
+ o.add = function (c, d) {
35
+ for (var i = 0; i < c.length; ++i) {
36
+ o[c.charAt(i)] += d;
37
+ }
38
+
39
+ return o.normalize();
40
+ };
41
+
42
+ o.scale = function (c, f) {
43
+ for (var i = 0; i < c.length; ++i) {
44
+ o[c.charAt(i)] *= f;
45
+ }
46
+
47
+ return o.normalize();
48
+ };
49
+
50
+ o.toString = function () {
51
+ if (o.a >= 1.0) {
52
+ return "rgb(" + [o.r, o.g, o.b].join(",") + ")";
53
+ } else {
54
+ return "rgba(" + [o.r, o.g, o.b, o.a].join(",") + ")";
55
+ }
56
+ };
57
+
58
+ o.normalize = function () {
59
+ function clamp(min, value, max) {
60
+ return value < min ? min : (value > max ? max : value);
61
+ }
62
+
63
+ o.r = clamp(0, parseInt(o.r), 255);
64
+ o.g = clamp(0, parseInt(o.g), 255);
65
+ o.b = clamp(0, parseInt(o.b), 255);
66
+ o.a = clamp(0, o.a, 1);
67
+ return o;
68
+ };
69
+
70
+ o.clone = function () {
71
+ return $.color.make(o.r, o.b, o.g, o.a);
72
+ };
73
+
74
+ return o.normalize();
75
+ }
76
+
77
+ // extract CSS color property from element, going up in the DOM
78
+ // if it's "transparent"
79
+ $.color.extract = function (elem, css) {
80
+ var c;
81
+
82
+ do {
83
+ c = elem.css(css).toLowerCase();
84
+ // keep going until we find an element that has color, or
85
+ // we hit the body or root (have no parent)
86
+ if (c !== '' && c !== 'transparent') {
87
+ break;
88
+ }
89
+
90
+ elem = elem.parent();
91
+ } while (elem.length && !$.nodeName(elem.get(0), "body"));
92
+
93
+ // catch Safari's way of signalling transparent
94
+ if (c === "rgba(0, 0, 0, 0)") {
95
+ c = "transparent";
96
+ }
97
+
98
+ return $.color.parse(c);
99
+ }
100
+
101
+ // parse CSS color string (like "rgb(10, 32, 43)" or "#fff"),
102
+ // returns color object, if parsing failed, you get black (0, 0,
103
+ // 0) out
104
+ $.color.parse = function (str) {
105
+ var res, m = $.color.make;
106
+
107
+ // Look for rgb(num,num,num)
108
+ res = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str);
109
+ if (res) {
110
+ return m(parseInt(res[1], 10), parseInt(res[2], 10), parseInt(res[3], 10));
111
+ }
112
+
113
+ // Look for rgba(num,num,num,num)
114
+ res = /rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str)
115
+ if (res) {
116
+ return m(parseInt(res[1], 10), parseInt(res[2], 10), parseInt(res[3], 10), parseFloat(res[4]));
117
+ }
118
+
119
+ // Look for rgb(num%,num%,num%)
120
+ res = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)%\s*,\s*([0-9]+(?:\.[0-9]+)?)%\s*,\s*([0-9]+(?:\.[0-9]+)?)%\s*\)/.exec(str);
121
+ if (res) {
122
+ return m(parseFloat(res[1]) * 2.55, parseFloat(res[2]) * 2.55, parseFloat(res[3]) * 2.55);
123
+ }
124
+
125
+ // Look for rgba(num%,num%,num%,num)
126
+ res = /rgba\(\s*([0-9]+(?:\.[0-9]+)?)%\s*,\s*([0-9]+(?:\.[0-9]+)?)%\s*,\s*([0-9]+(?:\.[0-9]+)?)%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str);
127
+ if (res) {
128
+ return m(parseFloat(res[1]) * 2.55, parseFloat(res[2]) * 2.55, parseFloat(res[3]) * 2.55, parseFloat(res[4]));
129
+ }
130
+
131
+ // Look for #a0b1c2
132
+ res = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str);
133
+ if (res) {
134
+ return m(parseInt(res[1], 16), parseInt(res[2], 16), parseInt(res[3], 16));
135
+ }
136
+
137
+ // Look for #fff
138
+ res = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str);
139
+ if (res) {
140
+ return m(parseInt(res[1] + res[1], 16), parseInt(res[2] + res[2], 16), parseInt(res[3] + res[3], 16));
141
+ }
142
+
143
+ // Otherwise, we're most likely dealing with a named color
144
+ var name = $.trim(str).toLowerCase();
145
+ if (name === "transparent") {
146
+ return m(255, 255, 255, 0);
147
+ } else {
148
+ // default to black
149
+ res = lookupColors[name] || [0, 0, 0];
150
+ return m(res[0], res[1], res[2]);
151
+ }
152
+ }
153
+
154
+ var lookupColors = {
155
+ aqua: [0, 255, 255],
156
+ azure: [240, 255, 255],
157
+ beige: [245, 245, 220],
158
+ black: [0, 0, 0],
159
+ blue: [0, 0, 255],
160
+ brown: [165, 42, 42],
161
+ cyan: [0, 255, 255],
162
+ darkblue: [0, 0, 139],
163
+ darkcyan: [0, 139, 139],
164
+ darkgrey: [169, 169, 169],
165
+ darkgreen: [0, 100, 0],
166
+ darkkhaki: [189, 183, 107],
167
+ darkmagenta: [139, 0, 139],
168
+ darkolivegreen: [85, 107, 47],
169
+ darkorange: [255, 140, 0],
170
+ darkorchid: [153, 50, 204],
171
+ darkred: [139, 0, 0],
172
+ darksalmon: [233, 150, 122],
173
+ darkviolet: [148, 0, 211],
174
+ fuchsia: [255, 0, 255],
175
+ gold: [255, 215, 0],
176
+ green: [0, 128, 0],
177
+ indigo: [75, 0, 130],
178
+ khaki: [240, 230, 140],
179
+ lightblue: [173, 216, 230],
180
+ lightcyan: [224, 255, 255],
181
+ lightgreen: [144, 238, 144],
182
+ lightgrey: [211, 211, 211],
183
+ lightpink: [255, 182, 193],
184
+ lightyellow: [255, 255, 224],
185
+ lime: [0, 255, 0],
186
+ magenta: [255, 0, 255],
187
+ maroon: [128, 0, 0],
188
+ navy: [0, 0, 128],
189
+ olive: [128, 128, 0],
190
+ orange: [255, 165, 0],
191
+ pink: [255, 192, 203],
192
+ purple: [128, 0, 128],
193
+ violet: [128, 0, 128],
194
+ red: [255, 0, 0],
195
+ silver: [192, 192, 192],
196
+ white: [255, 255, 255],
197
+ yellow: [255, 255, 0]
198
+ };
199
+ })(jQuery);
@@ -0,0 +1,98 @@
1
+ /** ## jquery.flot.browser.js
2
+
3
+ This plugin is used to make available some browser-related utility functions.
4
+
5
+ ### Methods
6
+ */
7
+
8
+ (function ($) {
9
+ 'use strict';
10
+
11
+ var browser = {
12
+ /**
13
+ - getPageXY(e)
14
+
15
+ Calculates the pageX and pageY using the screenX, screenY properties of the event
16
+ and the scrolling of the page. This is needed because the pageX and pageY
17
+ properties of the event are not correct while running tests in Edge. */
18
+ getPageXY: function (e) {
19
+ // This code is inspired from https://stackoverflow.com/a/3464890
20
+ var doc = document.documentElement,
21
+ pageX = e.clientX + (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0),
22
+ pageY = e.clientY + (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0);
23
+ return { X: pageX, Y: pageY };
24
+ },
25
+
26
+ /**
27
+ - getPixelRatio(context)
28
+
29
+ This function returns the current pixel ratio defined by the product of desktop
30
+ zoom and page zoom.
31
+ Additional info: https://www.html5rocks.com/en/tutorials/canvas/hidpi/
32
+ */
33
+ getPixelRatio: function(context) {
34
+ var devicePixelRatio = window.devicePixelRatio || 1,
35
+ backingStoreRatio =
36
+ context.webkitBackingStorePixelRatio ||
37
+ context.mozBackingStorePixelRatio ||
38
+ context.msBackingStorePixelRatio ||
39
+ context.oBackingStorePixelRatio ||
40
+ context.backingStorePixelRatio || 1;
41
+ return devicePixelRatio / backingStoreRatio;
42
+ },
43
+
44
+ /**
45
+ - isSafari, isMobileSafari, isOpera, isFirefox, isIE, isEdge, isChrome, isBlink
46
+
47
+ This is a collection of functions, used to check if the code is running in a
48
+ particular browser or Javascript engine.
49
+ */
50
+ isSafari: function() {
51
+ // *** https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser
52
+ // Safari 3.0+ "[object HTMLElementConstructor]"
53
+ return /constructor/i.test(window.top.HTMLElement) || (function (p) { return p.toString() === "[object SafariRemoteNotification]"; })(!window.top['safari'] || (typeof window.top.safari !== 'undefined' && window.top.safari.pushNotification));
54
+ },
55
+
56
+ isMobileSafari: function() {
57
+ //isMobileSafari adapted from https://stackoverflow.com/questions/3007480/determine-if-user-navigated-from-mobile-safari
58
+ return navigator.userAgent.match(/(iPod|iPhone|iPad)/) && navigator.userAgent.match(/AppleWebKit/);
59
+ },
60
+
61
+ isOpera: function() {
62
+ // *** https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser
63
+ //Opera 8.0+
64
+ return (!!window.opr && !!opr.addons) || !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0;
65
+ },
66
+
67
+ isFirefox: function() {
68
+ // *** https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser
69
+ // Firefox 1.0+
70
+ return typeof InstallTrigger !== 'undefined';
71
+ },
72
+
73
+ isIE: function() {
74
+ // *** https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser
75
+ // Internet Explorer 6-11
76
+ return /*@cc_on!@*/false || !!document.documentMode;
77
+ },
78
+
79
+ isEdge: function() {
80
+ // *** https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser
81
+ // Edge 20+
82
+ return !browser.isIE() && !!window.StyleMedia;
83
+ },
84
+
85
+ isChrome: function() {
86
+ // *** https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser
87
+ // Chrome 1+
88
+ return !!window.chrome && !!window.chrome.webstore;
89
+ },
90
+
91
+ isBlink: function() {
92
+ // *** https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser
93
+ return (browser.isChrome() || browser.isOpera()) && !!window.CSS;
94
+ }
95
+ };
96
+
97
+ $.plot.browser = browser;
98
+ })(jQuery);
@@ -0,0 +1,663 @@
1
+ /**
2
+ ## jquery.flot.drawSeries.js
3
+
4
+ This plugin is used by flot for drawing lines, plots, bars or area.
5
+
6
+ ### Public methods
7
+ */
8
+
9
+ (function($) {
10
+ "use strict";
11
+
12
+ function DrawSeries() {
13
+ function plotLine(datapoints, xoffset, yoffset, axisx, axisy, ctx, steps) {
14
+ var points = datapoints.points,
15
+ ps = datapoints.pointsize,
16
+ prevx = null,
17
+ prevy = null;
18
+ var x1 = 0.0,
19
+ y1 = 0.0,
20
+ x2 = 0.0,
21
+ y2 = 0.0,
22
+ mx = null,
23
+ my = null,
24
+ i = 0;
25
+
26
+ ctx.beginPath();
27
+ for (i = ps; i < points.length; i += ps) {
28
+ x1 = points[i - ps];
29
+ y1 = points[i - ps + 1];
30
+ x2 = points[i];
31
+ y2 = points[i + 1];
32
+
33
+ if (x1 === null || x2 === null) {
34
+ mx = null;
35
+ my = null;
36
+ continue;
37
+ }
38
+
39
+ if (isNaN(x1) || isNaN(x2) || isNaN(y1) || isNaN(y2)) {
40
+ prevx = null;
41
+ prevy = null;
42
+ continue;
43
+ }
44
+
45
+ if(steps){
46
+ if (mx !== null && my !== null) {
47
+ // if middle point exists, transfer p2 -> p1 and p1 -> mp
48
+ x2 = x1;
49
+ y2 = y1;
50
+ x1 = mx;
51
+ y1 = my;
52
+
53
+ // 'remove' middle point
54
+ mx = null;
55
+ my = null;
56
+
57
+ // subtract pointsize from i to have current point p1 handled again
58
+ i -= ps;
59
+ } else if (y1 !== y2 && x1 !== x2) {
60
+ // create a middle point
61
+ y2 = y1;
62
+ mx = x2;
63
+ my = y1;
64
+ }
65
+ }
66
+
67
+ // clip with ymin
68
+ if (y1 <= y2 && y1 < axisy.min) {
69
+ if (y2 < axisy.min) {
70
+ // line segment is outside
71
+ continue;
72
+ }
73
+ // compute new intersection point
74
+ x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
75
+ y1 = axisy.min;
76
+ } else if (y2 <= y1 && y2 < axisy.min) {
77
+ if (y1 < axisy.min) {
78
+ continue;
79
+ }
80
+
81
+ x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
82
+ y2 = axisy.min;
83
+ }
84
+
85
+ // clip with ymax
86
+ if (y1 >= y2 && y1 > axisy.max) {
87
+ if (y2 > axisy.max) {
88
+ continue;
89
+ }
90
+
91
+ x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
92
+ y1 = axisy.max;
93
+ } else if (y2 >= y1 && y2 > axisy.max) {
94
+ if (y1 > axisy.max) {
95
+ continue;
96
+ }
97
+
98
+ x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
99
+ y2 = axisy.max;
100
+ }
101
+
102
+ // clip with xmin
103
+ if (x1 <= x2 && x1 < axisx.min) {
104
+ if (x2 < axisx.min) {
105
+ continue;
106
+ }
107
+
108
+ y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
109
+ x1 = axisx.min;
110
+ } else if (x2 <= x1 && x2 < axisx.min) {
111
+ if (x1 < axisx.min) {
112
+ continue;
113
+ }
114
+
115
+ y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
116
+ x2 = axisx.min;
117
+ }
118
+
119
+ // clip with xmax
120
+ if (x1 >= x2 && x1 > axisx.max) {
121
+ if (x2 > axisx.max) {
122
+ continue;
123
+ }
124
+
125
+ y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
126
+ x1 = axisx.max;
127
+ } else if (x2 >= x1 && x2 > axisx.max) {
128
+ if (x1 > axisx.max) {
129
+ continue;
130
+ }
131
+
132
+ y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
133
+ x2 = axisx.max;
134
+ }
135
+
136
+ if (x1 !== prevx || y1 !== prevy) {
137
+ ctx.moveTo(axisx.p2c(x1) + xoffset, axisy.p2c(y1) + yoffset);
138
+ }
139
+
140
+ prevx = x2;
141
+ prevy = y2;
142
+ ctx.lineTo(axisx.p2c(x2) + xoffset, axisy.p2c(y2) + yoffset);
143
+ }
144
+ ctx.stroke();
145
+ }
146
+
147
+ function plotLineArea(datapoints, axisx, axisy, fillTowards, ctx, steps) {
148
+ var points = datapoints.points,
149
+ ps = datapoints.pointsize,
150
+ bottom = fillTowards > axisy.min ? Math.min(axisy.max, fillTowards) : axisy.min,
151
+ i = 0,
152
+ ypos = 1,
153
+ areaOpen = false,
154
+ segmentStart = 0,
155
+ segmentEnd = 0,
156
+ mx = null,
157
+ my = null;
158
+
159
+ // we process each segment in two turns, first forward
160
+ // direction to sketch out top, then once we hit the
161
+ // end we go backwards to sketch the bottom
162
+ while (true) {
163
+ if (ps > 0 && i > points.length + ps) {
164
+ break;
165
+ }
166
+
167
+ i += ps; // ps is negative if going backwards
168
+
169
+ var x1 = points[i - ps],
170
+ y1 = points[i - ps + ypos],
171
+ x2 = points[i],
172
+ y2 = points[i + ypos];
173
+
174
+ if (ps === -2) {
175
+ /* going backwards and no value for the bottom provided in the series*/
176
+ y1 = y2 = bottom;
177
+ }
178
+
179
+ if (areaOpen) {
180
+ if (ps > 0 && x1 != null && x2 == null) {
181
+ // at turning point
182
+ segmentEnd = i;
183
+ ps = -ps;
184
+ ypos = 2;
185
+ continue;
186
+ }
187
+
188
+ if (ps < 0 && i === segmentStart + ps) {
189
+ // done with the reverse sweep
190
+ ctx.fill();
191
+ areaOpen = false;
192
+ ps = -ps;
193
+ ypos = 1;
194
+ i = segmentStart = segmentEnd + ps;
195
+ continue;
196
+ }
197
+ }
198
+
199
+ if (x1 == null || x2 == null) {
200
+ mx = null;
201
+ my = null;
202
+ continue;
203
+ }
204
+
205
+ if(steps){
206
+ if (mx !== null && my !== null) {
207
+ // if middle point exists, transfer p2 -> p1 and p1 -> mp
208
+ x2 = x1;
209
+ y2 = y1;
210
+ x1 = mx;
211
+ y1 = my;
212
+
213
+ // 'remove' middle point
214
+ mx = null;
215
+ my = null;
216
+
217
+ // subtract pointsize from i to have current point p1 handled again
218
+ i -= ps;
219
+ } else if (y1 !== y2 && x1 !== x2) {
220
+ // create a middle point
221
+ y2 = y1;
222
+ mx = x2;
223
+ my = y1;
224
+ }
225
+ }
226
+
227
+ // clip x values
228
+
229
+ // clip with xmin
230
+ if (x1 <= x2 && x1 < axisx.min) {
231
+ if (x2 < axisx.min) {
232
+ continue;
233
+ }
234
+
235
+ y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
236
+ x1 = axisx.min;
237
+ } else if (x2 <= x1 && x2 < axisx.min) {
238
+ if (x1 < axisx.min) {
239
+ continue;
240
+ }
241
+
242
+ y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
243
+ x2 = axisx.min;
244
+ }
245
+
246
+ // clip with xmax
247
+ if (x1 >= x2 && x1 > axisx.max) {
248
+ if (x2 > axisx.max) {
249
+ continue;
250
+ }
251
+
252
+ y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
253
+ x1 = axisx.max;
254
+ } else if (x2 >= x1 && x2 > axisx.max) {
255
+ if (x1 > axisx.max) {
256
+ continue;
257
+ }
258
+
259
+ y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
260
+ x2 = axisx.max;
261
+ }
262
+
263
+ if (!areaOpen) {
264
+ // open area
265
+ ctx.beginPath();
266
+ ctx.moveTo(axisx.p2c(x1), axisy.p2c(bottom));
267
+ areaOpen = true;
268
+ }
269
+
270
+ // now first check the case where both is outside
271
+ if (y1 >= axisy.max && y2 >= axisy.max) {
272
+ ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.max));
273
+ ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.max));
274
+ continue;
275
+ } else if (y1 <= axisy.min && y2 <= axisy.min) {
276
+ ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.min));
277
+ ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.min));
278
+ continue;
279
+ }
280
+
281
+ // else it's a bit more complicated, there might
282
+ // be a flat maxed out rectangle first, then a
283
+ // triangular cutout or reverse; to find these
284
+ // keep track of the current x values
285
+ var x1old = x1,
286
+ x2old = x2;
287
+
288
+ // clip the y values, without shortcutting, we
289
+ // go through all cases in turn
290
+
291
+ // clip with ymin
292
+ if (y1 <= y2 && y1 < axisy.min && y2 >= axisy.min) {
293
+ x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
294
+ y1 = axisy.min;
295
+ } else if (y2 <= y1 && y2 < axisy.min && y1 >= axisy.min) {
296
+ x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
297
+ y2 = axisy.min;
298
+ }
299
+
300
+ // clip with ymax
301
+ if (y1 >= y2 && y1 > axisy.max && y2 <= axisy.max) {
302
+ x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
303
+ y1 = axisy.max;
304
+ } else if (y2 >= y1 && y2 > axisy.max && y1 <= axisy.max) {
305
+ x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
306
+ y2 = axisy.max;
307
+ }
308
+
309
+ // if the x value was changed we got a rectangle
310
+ // to fill
311
+ if (x1 !== x1old) {
312
+ ctx.lineTo(axisx.p2c(x1old), axisy.p2c(y1));
313
+ // it goes to (x1, y1), but we fill that below
314
+ }
315
+
316
+ // fill triangular section, this sometimes result
317
+ // in redundant points if (x1, y1) hasn't changed
318
+ // from previous line to, but we just ignore that
319
+ ctx.lineTo(axisx.p2c(x1), axisy.p2c(y1));
320
+ ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2));
321
+
322
+ // fill the other rectangle if it's there
323
+ if (x2 !== x2old) {
324
+ ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2));
325
+ ctx.lineTo(axisx.p2c(x2old), axisy.p2c(y2));
326
+ }
327
+ }
328
+ }
329
+
330
+ /**
331
+ - drawSeriesLines(series, ctx, plotOffset, plotWidth, plotHeight, drawSymbol, getColorOrGradient)
332
+
333
+ This function is used for drawing lines or area fill. In case the series has line decimation function
334
+ attached, before starting to draw, as an optimization the points will first be decimated.
335
+
336
+ The series parameter contains the series to be drawn on ctx context. The plotOffset, plotWidth and
337
+ plotHeight are the corresponding parameters of flot used to determine the drawing surface.
338
+ The function getColorOrGradient is used to compute the fill style of lines and area.
339
+ */
340
+ function drawSeriesLines(series, ctx, plotOffset, plotWidth, plotHeight, drawSymbol, getColorOrGradient) {
341
+ ctx.save();
342
+ ctx.translate(plotOffset.left, plotOffset.top);
343
+ ctx.lineJoin = "round";
344
+
345
+ if (series.lines.dashes && ctx.setLineDash) {
346
+ ctx.setLineDash(series.lines.dashes);
347
+ }
348
+
349
+ var datapoints = {
350
+ format: series.datapoints.format,
351
+ points: series.datapoints.points,
352
+ pointsize: series.datapoints.pointsize
353
+ };
354
+
355
+ if (series.decimate) {
356
+ datapoints.points = series.decimate(series, series.xaxis.min, series.xaxis.max, plotWidth, series.yaxis.min, series.yaxis.max, plotHeight);
357
+ }
358
+
359
+ var lw = series.lines.lineWidth;
360
+
361
+ ctx.lineWidth = lw;
362
+ ctx.strokeStyle = series.color;
363
+ var fillStyle = getFillStyle(series.lines, series.color, 0, plotHeight, getColorOrGradient);
364
+ if (fillStyle) {
365
+ ctx.fillStyle = fillStyle;
366
+ plotLineArea(datapoints, series.xaxis, series.yaxis, series.lines.fillTowards || 0, ctx, series.lines.steps);
367
+ }
368
+
369
+ if (lw > 0) {
370
+ plotLine(datapoints, 0, 0, series.xaxis, series.yaxis, ctx, series.lines.steps);
371
+ }
372
+
373
+ ctx.restore();
374
+ }
375
+
376
+ /**
377
+ - drawSeriesPoints(series, ctx, plotOffset, plotWidth, plotHeight, drawSymbol, getColorOrGradient)
378
+
379
+ This function is used for drawing points using a given symbol. In case the series has points decimation
380
+ function attached, before starting to draw, as an optimization the points will first be decimated.
381
+
382
+ The series parameter contains the series to be drawn on ctx context. The plotOffset, plotWidth and
383
+ plotHeight are the corresponding parameters of flot used to determine the drawing surface.
384
+ The function drawSymbol is used to compute and draw the symbol chosen for the points.
385
+ */
386
+ function drawSeriesPoints(series, ctx, plotOffset, plotWidth, plotHeight, drawSymbol, getColorOrGradient) {
387
+ function drawCircle(ctx, x, y, radius, shadow, fill) {
388
+ ctx.moveTo(x + radius, y);
389
+ ctx.arc(x, y, radius, 0, shadow ? Math.PI : Math.PI * 2, false);
390
+ }
391
+ drawCircle.fill = true;
392
+ function plotPoints(datapoints, radius, fill, offset, shadow, axisx, axisy, drawSymbolFn) {
393
+ var points = datapoints.points,
394
+ ps = datapoints.pointsize;
395
+
396
+ ctx.beginPath();
397
+ for (var i = 0; i < points.length; i += ps) {
398
+ var x = points[i],
399
+ y = points[i + 1];
400
+ if (x == null || x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) {
401
+ continue;
402
+ }
403
+
404
+ x = axisx.p2c(x);
405
+ y = axisy.p2c(y) + offset;
406
+
407
+ drawSymbolFn(ctx, x, y, radius, shadow, fill);
408
+ }
409
+ if (drawSymbolFn.fill && !shadow) {
410
+ ctx.fill();
411
+ }
412
+ ctx.stroke();
413
+ }
414
+
415
+ ctx.save();
416
+ ctx.translate(plotOffset.left, plotOffset.top);
417
+
418
+ var datapoints = {
419
+ format: series.datapoints.format,
420
+ points: series.datapoints.points,
421
+ pointsize: series.datapoints.pointsize
422
+ };
423
+
424
+ if (series.decimatePoints) {
425
+ datapoints.points = series.decimatePoints(series, series.xaxis.min, series.xaxis.max, plotWidth, series.yaxis.min, series.yaxis.max, plotHeight);
426
+ }
427
+
428
+ var lw = series.points.lineWidth,
429
+ radius = series.points.radius,
430
+ symbol = series.points.symbol,
431
+ drawSymbolFn;
432
+
433
+ if (symbol === 'circle') {
434
+ drawSymbolFn = drawCircle;
435
+ } else if (typeof symbol === 'string' && drawSymbol && drawSymbol[symbol]) {
436
+ drawSymbolFn = drawSymbol[symbol];
437
+ } else if (typeof drawSymbol === 'function') {
438
+ drawSymbolFn = drawSymbol;
439
+ }
440
+
441
+ // If the user sets the line width to 0, we change it to a very
442
+ // small value. A line width of 0 seems to force the default of 1.
443
+
444
+ if (lw === 0) {
445
+ lw = 0.0001;
446
+ }
447
+
448
+ ctx.lineWidth = lw;
449
+ ctx.fillStyle = getFillStyle(series.points, series.color, null, null, getColorOrGradient);
450
+ ctx.strokeStyle = series.color;
451
+ plotPoints(datapoints, radius,
452
+ true, 0, false,
453
+ series.xaxis, series.yaxis, drawSymbolFn);
454
+ ctx.restore();
455
+ }
456
+
457
+ function drawBar(x, y, b, barLeft, barRight, fillStyleCallback, axisx, axisy, c, horizontal, lineWidth) {
458
+ var left = x + barLeft,
459
+ right = x + barRight,
460
+ bottom = b, top = y,
461
+ drawLeft, drawRight, drawTop, drawBottom = false,
462
+ tmp;
463
+
464
+ drawLeft = drawRight = drawTop = true;
465
+
466
+ // in horizontal mode, we start the bar from the left
467
+ // instead of from the bottom so it appears to be
468
+ // horizontal rather than vertical
469
+ if (horizontal) {
470
+ drawBottom = drawRight = drawTop = true;
471
+ drawLeft = false;
472
+ left = b;
473
+ right = x;
474
+ top = y + barLeft;
475
+ bottom = y + barRight;
476
+
477
+ // account for negative bars
478
+ if (right < left) {
479
+ tmp = right;
480
+ right = left;
481
+ left = tmp;
482
+ drawLeft = true;
483
+ drawRight = false;
484
+ }
485
+ }
486
+ else {
487
+ drawLeft = drawRight = drawTop = true;
488
+ drawBottom = false;
489
+ left = x + barLeft;
490
+ right = x + barRight;
491
+ bottom = b;
492
+ top = y;
493
+
494
+ // account for negative bars
495
+ if (top < bottom) {
496
+ tmp = top;
497
+ top = bottom;
498
+ bottom = tmp;
499
+ drawBottom = true;
500
+ drawTop = false;
501
+ }
502
+ }
503
+
504
+ // clip
505
+ if (right < axisx.min || left > axisx.max ||
506
+ top < axisy.min || bottom > axisy.max) {
507
+ return;
508
+ }
509
+
510
+ if (left < axisx.min) {
511
+ left = axisx.min;
512
+ drawLeft = false;
513
+ }
514
+
515
+ if (right > axisx.max) {
516
+ right = axisx.max;
517
+ drawRight = false;
518
+ }
519
+
520
+ if (bottom < axisy.min) {
521
+ bottom = axisy.min;
522
+ drawBottom = false;
523
+ }
524
+
525
+ if (top > axisy.max) {
526
+ top = axisy.max;
527
+ drawTop = false;
528
+ }
529
+
530
+ left = axisx.p2c(left);
531
+ bottom = axisy.p2c(bottom);
532
+ right = axisx.p2c(right);
533
+ top = axisy.p2c(top);
534
+
535
+ // fill the bar
536
+ if (fillStyleCallback) {
537
+ c.fillStyle = fillStyleCallback(bottom, top);
538
+ c.fillRect(left, top, right - left, bottom - top)
539
+ }
540
+
541
+ // draw outline
542
+ if (lineWidth > 0 && (drawLeft || drawRight || drawTop || drawBottom)) {
543
+ c.beginPath();
544
+
545
+ // FIXME: inline moveTo is buggy with excanvas
546
+ c.moveTo(left, bottom);
547
+ if (drawLeft) {
548
+ c.lineTo(left, top);
549
+ } else {
550
+ c.moveTo(left, top);
551
+ }
552
+
553
+ if (drawTop) {
554
+ c.lineTo(right, top);
555
+ } else {
556
+ c.moveTo(right, top);
557
+ }
558
+
559
+ if (drawRight) {
560
+ c.lineTo(right, bottom);
561
+ } else {
562
+ c.moveTo(right, bottom);
563
+ }
564
+
565
+ if (drawBottom) {
566
+ c.lineTo(left, bottom);
567
+ } else {
568
+ c.moveTo(left, bottom);
569
+ }
570
+
571
+ c.stroke();
572
+ }
573
+ }
574
+
575
+ /**
576
+ - drawSeriesBars(series, ctx, plotOffset, plotWidth, plotHeight, drawSymbol, getColorOrGradient)
577
+
578
+ This function is used for drawing series represented as bars. In case the series has decimation
579
+ function attached, before starting to draw, as an optimization the points will first be decimated.
580
+
581
+ The series parameter contains the series to be drawn on ctx context. The plotOffset, plotWidth and
582
+ plotHeight are the corresponding parameters of flot used to determine the drawing surface.
583
+ The function getColorOrGradient is used to compute the fill style of bars.
584
+ */
585
+ function drawSeriesBars(series, ctx, plotOffset, plotWidth, plotHeight, drawSymbol, getColorOrGradient) {
586
+ function plotBars(datapoints, barLeft, barRight, fillStyleCallback, axisx, axisy) {
587
+ var points = datapoints.points,
588
+ ps = datapoints.pointsize,
589
+ fillTowards = series.bars.fillTowards || 0,
590
+ defaultBottom = fillTowards > axisy.min ? Math.min(axisy.max, fillTowards) : axisy.min;
591
+
592
+ for (var i = 0; i < points.length; i += ps) {
593
+ if (points[i] == null) {
594
+ continue;
595
+ }
596
+
597
+ // Use third point as bottom if pointsize is 3
598
+ var bottom = ps === 3 ? points[i + 2] : defaultBottom;
599
+ drawBar(points[i], points[i + 1], bottom, barLeft, barRight, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal, series.bars.lineWidth);
600
+ }
601
+ }
602
+
603
+ ctx.save();
604
+ ctx.translate(plotOffset.left, plotOffset.top);
605
+
606
+ var datapoints = {
607
+ format: series.datapoints.format,
608
+ points: series.datapoints.points,
609
+ pointsize: series.datapoints.pointsize
610
+ };
611
+
612
+ if (series.decimate) {
613
+ datapoints.points = series.decimate(series, series.xaxis.min, series.xaxis.max, plotWidth);
614
+ }
615
+
616
+ ctx.lineWidth = series.bars.lineWidth;
617
+ ctx.strokeStyle = series.color;
618
+
619
+ var barLeft;
620
+ var barWidth = series.bars.barWidth[0] || series.bars.barWidth;
621
+ switch (series.bars.align) {
622
+ case "left":
623
+ barLeft = 0;
624
+ break;
625
+ case "right":
626
+ barLeft = -barWidth;
627
+ break;
628
+ default:
629
+ barLeft = -barWidth / 2;
630
+ }
631
+
632
+ var fillStyleCallback = series.bars.fill ? function(bottom, top) {
633
+ return getFillStyle(series.bars, series.color, bottom, top, getColorOrGradient);
634
+ } : null;
635
+
636
+ plotBars(datapoints, barLeft, barLeft + barWidth, fillStyleCallback, series.xaxis, series.yaxis);
637
+ ctx.restore();
638
+ }
639
+
640
+ function getFillStyle(filloptions, seriesColor, bottom, top, getColorOrGradient) {
641
+ var fill = filloptions.fill;
642
+ if (!fill) {
643
+ return null;
644
+ }
645
+
646
+ if (filloptions.fillColor) {
647
+ return getColorOrGradient(filloptions.fillColor, bottom, top, seriesColor);
648
+ }
649
+
650
+ var c = $.color.parse(seriesColor);
651
+ c.a = typeof fill === "number" ? fill : 0.4;
652
+ c.normalize();
653
+ return c.toString();
654
+ }
655
+
656
+ this.drawSeriesLines = drawSeriesLines;
657
+ this.drawSeriesPoints = drawSeriesPoints;
658
+ this.drawSeriesBars = drawSeriesBars;
659
+ this.drawBar = drawBar;
660
+ };
661
+
662
+ $.plot.drawSeries = new DrawSeries();
663
+ })(jQuery);