flot-rails 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/README.md +2 -2
  2. data/lib/flot/rails/version.rb +2 -2
  3. data/vendor/assets/javascripts/excanvas.js +1428 -1427
  4. data/vendor/assets/javascripts/excanvas.min.js +1 -1
  5. data/vendor/assets/javascripts/jquery.colorhelpers.js +179 -179
  6. data/vendor/assets/javascripts/jquery.colorhelpers.min.js +21 -1
  7. data/vendor/assets/javascripts/jquery.flot.canvas.js +317 -0
  8. data/vendor/assets/javascripts/jquery.flot.canvas.min.js +28 -0
  9. data/vendor/assets/javascripts/jquery.flot.categories.js +190 -0
  10. data/vendor/assets/javascripts/jquery.flot.categories.min.js +44 -0
  11. data/vendor/assets/javascripts/jquery.flot.crosshair.js +176 -167
  12. data/vendor/assets/javascripts/jquery.flot.crosshair.min.js +59 -1
  13. data/vendor/assets/javascripts/jquery.flot.errorbars.js +353 -0
  14. data/vendor/assets/javascripts/jquery.flot.errorbars.min.js +63 -0
  15. data/vendor/assets/javascripts/jquery.flot.fillbetween.js +226 -183
  16. data/vendor/assets/javascripts/jquery.flot.fillbetween.min.js +30 -1
  17. data/vendor/assets/javascripts/jquery.flot.image.js +241 -238
  18. data/vendor/assets/javascripts/jquery.flot.image.min.js +53 -1
  19. data/vendor/assets/javascripts/jquery.flot.js +2980 -2599
  20. data/vendor/assets/javascripts/jquery.flot.min.js +26 -4
  21. data/vendor/assets/javascripts/jquery.flot.navigate.js +345 -336
  22. data/vendor/assets/javascripts/jquery.flot.navigate.min.js +96 -1
  23. data/vendor/assets/javascripts/jquery.flot.pie.js +561 -499
  24. data/vendor/assets/javascripts/jquery.flot.pie.min.js +56 -1
  25. data/vendor/assets/javascripts/jquery.flot.resize.js +60 -60
  26. data/vendor/assets/javascripts/jquery.flot.resize.min.js +21 -1
  27. data/vendor/assets/javascripts/jquery.flot.selection.js +360 -344
  28. data/vendor/assets/javascripts/jquery.flot.selection.min.js +79 -1
  29. data/vendor/assets/javascripts/jquery.flot.stack.js +188 -184
  30. data/vendor/assets/javascripts/jquery.flot.stack.min.js +36 -1
  31. data/vendor/assets/javascripts/jquery.flot.symbol.js +71 -70
  32. data/vendor/assets/javascripts/jquery.flot.symbol.min.js +14 -1
  33. data/vendor/assets/javascripts/jquery.flot.threshold.js +142 -103
  34. data/vendor/assets/javascripts/jquery.flot.threshold.min.js +43 -1
  35. data/vendor/assets/javascripts/jquery.flot.time.js +424 -0
  36. data/vendor/assets/javascripts/jquery.flot.time.min.js +9 -0
  37. metadata +25 -7
@@ -1,183 +1,226 @@
1
- /*
2
- Flot plugin for computing bottoms for filled line and bar charts.
3
-
4
- The case: you've got two series that you want to fill the area
5
- between. In Flot terms, you need to use one as the fill bottom of the
6
- other. You can specify the bottom of each data point as the third
7
- coordinate manually, or you can use this plugin to compute it for you.
8
-
9
- In order to name the other series, you need to give it an id, like this
10
-
11
- var dataset = [
12
- { data: [ ... ], id: "foo" } , // use default bottom
13
- { data: [ ... ], fillBetween: "foo" }, // use first dataset as bottom
14
- ];
15
-
16
- $.plot($("#placeholder"), dataset, { line: { show: true, fill: true }});
17
-
18
- As a convenience, if the id given is a number that doesn't appear as
19
- an id in the series, it is interpreted as the index in the array
20
- instead (so fillBetween: 0 can also mean the first series).
21
-
22
- Internally, the plugin modifies the datapoints in each series. For
23
- line series, extra data points might be inserted through
24
- interpolation. Note that at points where the bottom line is not
25
- defined (due to a null point or start/end of line), the current line
26
- will show a gap too. The algorithm comes from the jquery.flot.stack.js
27
- plugin, possibly some code could be shared.
28
- */
29
-
30
- (function ($) {
31
- var options = {
32
- series: { fillBetween: null } // or number
33
- };
34
-
35
- function init(plot) {
36
- function findBottomSeries(s, allseries) {
37
- var i;
38
- for (i = 0; i < allseries.length; ++i) {
39
- if (allseries[i].id == s.fillBetween)
40
- return allseries[i];
41
- }
42
-
43
- if (typeof s.fillBetween == "number") {
44
- i = s.fillBetween;
45
-
46
- if (i < 0 || i >= allseries.length)
47
- return null;
48
-
49
- return allseries[i];
50
- }
51
-
52
- return null;
53
- }
54
-
55
- function computeFillBottoms(plot, s, datapoints) {
56
- if (s.fillBetween == null)
57
- return;
58
-
59
- var other = findBottomSeries(s, plot.getData());
60
- if (!other)
61
- return;
62
-
63
- var ps = datapoints.pointsize,
64
- points = datapoints.points,
65
- otherps = other.datapoints.pointsize,
66
- otherpoints = other.datapoints.points,
67
- newpoints = [],
68
- px, py, intery, qx, qy, bottom,
69
- withlines = s.lines.show,
70
- withbottom = ps > 2 && datapoints.format[2].y,
71
- withsteps = withlines && s.lines.steps,
72
- fromgap = true,
73
- i = 0, j = 0, l;
74
-
75
- while (true) {
76
- if (i >= points.length)
77
- break;
78
-
79
- l = newpoints.length;
80
-
81
- if (points[i] == null) {
82
- // copy gaps
83
- for (m = 0; m < ps; ++m)
84
- newpoints.push(points[i + m]);
85
- i += ps;
86
- }
87
- else if (j >= otherpoints.length) {
88
- // for lines, we can't use the rest of the points
89
- if (!withlines) {
90
- for (m = 0; m < ps; ++m)
91
- newpoints.push(points[i + m]);
92
- }
93
- i += ps;
94
- }
95
- else if (otherpoints[j] == null) {
96
- // oops, got a gap
97
- for (m = 0; m < ps; ++m)
98
- newpoints.push(null);
99
- fromgap = true;
100
- j += otherps;
101
- }
102
- else {
103
- // cases where we actually got two points
104
- px = points[i];
105
- py = points[i + 1];
106
- qx = otherpoints[j];
107
- qy = otherpoints[j + 1];
108
- bottom = 0;
109
-
110
- if (px == qx) {
111
- for (m = 0; m < ps; ++m)
112
- newpoints.push(points[i + m]);
113
-
114
- //newpoints[l + 1] += qy;
115
- bottom = qy;
116
-
117
- i += ps;
118
- j += otherps;
119
- }
120
- else if (px > qx) {
121
- // we got past point below, might need to
122
- // insert interpolated extra point
123
- if (withlines && i > 0 && points[i - ps] != null) {
124
- intery = py + (points[i - ps + 1] - py) * (qx - px) / (points[i - ps] - px);
125
- newpoints.push(qx);
126
- newpoints.push(intery)
127
- for (m = 2; m < ps; ++m)
128
- newpoints.push(points[i + m]);
129
- bottom = qy;
130
- }
131
-
132
- j += otherps;
133
- }
134
- else { // px < qx
135
- if (fromgap && withlines) {
136
- // if we come from a gap, we just skip this point
137
- i += ps;
138
- continue;
139
- }
140
-
141
- for (m = 0; m < ps; ++m)
142
- newpoints.push(points[i + m]);
143
-
144
- // we might be able to interpolate a point below,
145
- // this can give us a better y
146
- if (withlines && j > 0 && otherpoints[j - otherps] != null)
147
- bottom = qy + (otherpoints[j - otherps + 1] - qy) * (px - qx) / (otherpoints[j - otherps] - qx);
148
-
149
- //newpoints[l + 1] += bottom;
150
-
151
- i += ps;
152
- }
153
-
154
- fromgap = false;
155
-
156
- if (l != newpoints.length && withbottom)
157
- newpoints[l + 2] = bottom;
158
- }
159
-
160
- // maintain the line steps invariant
161
- if (withsteps && l != newpoints.length && l > 0
162
- && newpoints[l] != null
163
- && newpoints[l] != newpoints[l - ps]
164
- && newpoints[l + 1] != newpoints[l - ps + 1]) {
165
- for (m = 0; m < ps; ++m)
166
- newpoints[l + ps + m] = newpoints[l + m];
167
- newpoints[l + 1] = newpoints[l - ps + 1];
168
- }
169
- }
170
-
171
- datapoints.points = newpoints;
172
- }
173
-
174
- plot.hooks.processDatapoints.push(computeFillBottoms);
175
- }
176
-
177
- $.plot.plugins.push({
178
- init: init,
179
- options: options,
180
- name: 'fillbetween',
181
- version: '1.0'
182
- });
183
- })(jQuery);
1
+ /* Flot plugin for computing bottoms for filled line and bar charts.
2
+
3
+ Copyright (c) 2007-2013 IOLA and Ole Laursen.
4
+ Licensed under the MIT license.
5
+
6
+ The case: you've got two series that you want to fill the area between. In Flot
7
+ terms, you need to use one as the fill bottom of the other. You can specify the
8
+ bottom of each data point as the third coordinate manually, or you can use this
9
+ plugin to compute it for you.
10
+
11
+ In order to name the other series, you need to give it an id, like this:
12
+
13
+ var dataset = [
14
+ { data: [ ... ], id: "foo" } , // use default bottom
15
+ { data: [ ... ], fillBetween: "foo" }, // use first dataset as bottom
16
+ ];
17
+
18
+ $.plot($("#placeholder"), dataset, { lines: { show: true, fill: true }});
19
+
20
+ As a convenience, if the id given is a number that doesn't appear as an id in
21
+ the series, it is interpreted as the index in the array instead (so fillBetween:
22
+ 0 can also mean the first series).
23
+
24
+ Internally, the plugin modifies the datapoints in each series. For line series,
25
+ extra data points might be inserted through interpolation. Note that at points
26
+ where the bottom line is not defined (due to a null point or start/end of line),
27
+ the current line will show a gap too. The algorithm comes from the
28
+ jquery.flot.stack.js plugin, possibly some code could be shared.
29
+
30
+ */
31
+
32
+ (function ( $ ) {
33
+
34
+ var options = {
35
+ series: {
36
+ fillBetween: null // or number
37
+ }
38
+ };
39
+
40
+ function init( plot ) {
41
+
42
+ function findBottomSeries( s, allseries ) {
43
+
44
+ var i;
45
+
46
+ for ( i = 0; i < allseries.length; ++i ) {
47
+ if ( allseries[ i ].id === s.fillBetween ) {
48
+ return allseries[ i ];
49
+ }
50
+ }
51
+
52
+ if ( typeof s.fillBetween === "number" ) {
53
+ if ( s.fillBetween < 0 || s.fillBetween >= allseries.length ) {
54
+ return null;
55
+ }
56
+ return allseries[ s.fillBetween ];
57
+ }
58
+
59
+ return null;
60
+ }
61
+
62
+ function computeFillBottoms( plot, s, datapoints ) {
63
+
64
+ if ( s.fillBetween == null ) {
65
+ return;
66
+ }
67
+
68
+ var other = findBottomSeries( s, plot.getData() );
69
+
70
+ if ( !other ) {
71
+ return;
72
+ }
73
+
74
+ var ps = datapoints.pointsize,
75
+ points = datapoints.points,
76
+ otherps = other.datapoints.pointsize,
77
+ otherpoints = other.datapoints.points,
78
+ newpoints = [],
79
+ px, py, intery, qx, qy, bottom,
80
+ withlines = s.lines.show,
81
+ withbottom = ps > 2 && datapoints.format[2].y,
82
+ withsteps = withlines && s.lines.steps,
83
+ fromgap = true,
84
+ i = 0,
85
+ j = 0,
86
+ l, m;
87
+
88
+ while ( true ) {
89
+
90
+ if ( i >= points.length ) {
91
+ break;
92
+ }
93
+
94
+ l = newpoints.length;
95
+
96
+ if ( points[ i ] == null ) {
97
+
98
+ // copy gaps
99
+
100
+ for ( m = 0; m < ps; ++m ) {
101
+ newpoints.push( points[ i + m ] );
102
+ }
103
+
104
+ i += ps;
105
+
106
+ } else if ( j >= otherpoints.length ) {
107
+
108
+ // for lines, we can't use the rest of the points
109
+
110
+ if ( !withlines ) {
111
+ for ( m = 0; m < ps; ++m ) {
112
+ newpoints.push( points[ i + m ] );
113
+ }
114
+ }
115
+
116
+ i += ps;
117
+
118
+ } else if ( otherpoints[ j ] == null ) {
119
+
120
+ // oops, got a gap
121
+
122
+ for ( m = 0; m < ps; ++m ) {
123
+ newpoints.push( null );
124
+ }
125
+
126
+ fromgap = true;
127
+ j += otherps;
128
+
129
+ } else {
130
+
131
+ // cases where we actually got two points
132
+
133
+ px = points[ i ];
134
+ py = points[ i + 1 ];
135
+ qx = otherpoints[ j ];
136
+ qy = otherpoints[ j + 1 ];
137
+ bottom = 0;
138
+
139
+ if ( px === qx ) {
140
+
141
+ for ( m = 0; m < ps; ++m ) {
142
+ newpoints.push( points[ i + m ] );
143
+ }
144
+
145
+ //newpoints[ l + 1 ] += qy;
146
+ bottom = qy;
147
+
148
+ i += ps;
149
+ j += otherps;
150
+
151
+ } else if ( px > qx ) {
152
+
153
+ // we got past point below, might need to
154
+ // insert interpolated extra point
155
+
156
+ if ( withlines && i > 0 && points[ i - ps ] != null ) {
157
+ intery = py + ( points[ i - ps + 1 ] - py ) * ( qx - px ) / ( points[ i - ps ] - px );
158
+ newpoints.push( qx );
159
+ newpoints.push( intery );
160
+ for ( m = 2; m < ps; ++m ) {
161
+ newpoints.push( points[ i + m ] );
162
+ }
163
+ bottom = qy;
164
+ }
165
+
166
+ j += otherps;
167
+
168
+ } else { // px < qx
169
+
170
+ // if we come from a gap, we just skip this point
171
+
172
+ if ( fromgap && withlines ) {
173
+ i += ps;
174
+ continue;
175
+ }
176
+
177
+ for ( m = 0; m < ps; ++m ) {
178
+ newpoints.push( points[ i + m ] );
179
+ }
180
+
181
+ // we might be able to interpolate a point below,
182
+ // this can give us a better y
183
+
184
+ if ( withlines && j > 0 && otherpoints[ j - otherps ] != null ) {
185
+ bottom = qy + ( otherpoints[ j - otherps + 1 ] - qy ) * ( px - qx ) / ( otherpoints[ j - otherps ] - qx );
186
+ }
187
+
188
+ //newpoints[l + 1] += bottom;
189
+
190
+ i += ps;
191
+ }
192
+
193
+ fromgap = false;
194
+
195
+ if ( l !== newpoints.length && withbottom ) {
196
+ newpoints[ l + 2 ] = bottom;
197
+ }
198
+ }
199
+
200
+ // maintain the line steps invariant
201
+
202
+ if ( withsteps && l !== newpoints.length && l > 0 &&
203
+ newpoints[ l ] !== null &&
204
+ newpoints[ l ] !== newpoints[ l - ps ] &&
205
+ newpoints[ l + 1 ] !== newpoints[ l - ps + 1 ] ) {
206
+ for (m = 0; m < ps; ++m) {
207
+ newpoints[ l + ps + m ] = newpoints[ l + m ];
208
+ }
209
+ newpoints[ l + 1 ] = newpoints[ l - ps + 1 ];
210
+ }
211
+ }
212
+
213
+ datapoints.points = newpoints;
214
+ }
215
+
216
+ plot.hooks.processDatapoints.push( computeFillBottoms );
217
+ }
218
+
219
+ $.plot.plugins.push({
220
+ init: init,
221
+ options: options,
222
+ name: "fillbetween",
223
+ version: "1.0"
224
+ });
225
+
226
+ })(jQuery);
@@ -1 +1,30 @@
1
- (function(b){var a={series:{fillBetween:null}};function c(f){function d(j,h){var g;for(g=0;g<h.length;++g){if(h[g].id==j.fillBetween){return h[g]}}if(typeof j.fillBetween=="number"){g=j.fillBetween;if(g<0||g>=h.length){return null}return h[g]}return null}function e(B,u,g){if(u.fillBetween==null){return}var p=d(u,B.getData());if(!p){return}var y=g.pointsize,E=g.points,h=p.datapoints.pointsize,x=p.datapoints.points,r=[],w,v,k,G,F,q,t=u.lines.show,o=y>2&&g.format[2].y,n=t&&u.lines.steps,D=true,C=0,A=0,z;while(true){if(C>=E.length){break}z=r.length;if(E[C]==null){for(m=0;m<y;++m){r.push(E[C+m])}C+=y}else{if(A>=x.length){if(!t){for(m=0;m<y;++m){r.push(E[C+m])}}C+=y}else{if(x[A]==null){for(m=0;m<y;++m){r.push(null)}D=true;A+=h}else{w=E[C];v=E[C+1];G=x[A];F=x[A+1];q=0;if(w==G){for(m=0;m<y;++m){r.push(E[C+m])}q=F;C+=y;A+=h}else{if(w>G){if(t&&C>0&&E[C-y]!=null){k=v+(E[C-y+1]-v)*(G-w)/(E[C-y]-w);r.push(G);r.push(k);for(m=2;m<y;++m){r.push(E[C+m])}q=F}A+=h}else{if(D&&t){C+=y;continue}for(m=0;m<y;++m){r.push(E[C+m])}if(t&&A>0&&x[A-h]!=null){q=F+(x[A-h+1]-F)*(w-G)/(x[A-h]-G)}C+=y}}D=false;if(z!=r.length&&o){r[z+2]=q}}}}if(n&&z!=r.length&&z>0&&r[z]!=null&&r[z]!=r[z-y]&&r[z+1]!=r[z-y+1]){for(m=0;m<y;++m){r[z+y+m]=r[z+m]}r[z+1]=r[z-y+1]}}g.points=r}f.hooks.processDatapoints.push(e)}b.plot.plugins.push({init:c,options:a,name:"fillbetween",version:"1.0"})})(jQuery);
1
+ /* Flot plugin for computing bottoms for filled line and bar charts.
2
+
3
+ Copyright (c) 2007-2013 IOLA and Ole Laursen.
4
+ Licensed under the MIT license.
5
+
6
+ The case: you've got two series that you want to fill the area between. In Flot
7
+ terms, you need to use one as the fill bottom of the other. You can specify the
8
+ bottom of each data point as the third coordinate manually, or you can use this
9
+ plugin to compute it for you.
10
+
11
+ In order to name the other series, you need to give it an id, like this:
12
+
13
+ var dataset = [
14
+ { data: [ ... ], id: "foo" } , // use default bottom
15
+ { data: [ ... ], fillBetween: "foo" }, // use first dataset as bottom
16
+ ];
17
+
18
+ $.plot($("#placeholder"), dataset, { lines: { show: true, fill: true }});
19
+
20
+ As a convenience, if the id given is a number that doesn't appear as an id in
21
+ the series, it is interpreted as the index in the array instead (so fillBetween:
22
+ 0 can also mean the first series).
23
+
24
+ Internally, the plugin modifies the datapoints in each series. For line series,
25
+ extra data points might be inserted through interpolation. Note that at points
26
+ where the bottom line is not defined (due to a null point or start/end of line),
27
+ the current line will show a gap too. The algorithm comes from the
28
+ jquery.flot.stack.js plugin, possibly some code could be shared.
29
+
30
+ */(function(e){function n(e){function t(e,t){var n;for(n=0;n<t.length;++n)if(t[n].id===e.fillBetween)return t[n];return typeof e.fillBetween=="number"?e.fillBetween<0||e.fillBetween>=t.length?null:t[e.fillBetween]:null}function n(e,n,r){if(n.fillBetween==null)return;var i=t(n,e.getData());if(!i)return;var s=r.pointsize,o=r.points,u=i.datapoints.pointsize,a=i.datapoints.points,f=[],l,c,h,p,d,v,m=n.lines.show,g=s>2&&r.format[2].y,y=m&&n.lines.steps,b=!0,w=0,E=0,S,x;for(;;){if(w>=o.length)break;S=f.length;if(o[w]==null){for(x=0;x<s;++x)f.push(o[w+x]);w+=s}else if(E>=a.length){if(!m)for(x=0;x<s;++x)f.push(o[w+x]);w+=s}else if(a[E]==null){for(x=0;x<s;++x)f.push(null);b=!0,E+=u}else{l=o[w],c=o[w+1],p=a[E],d=a[E+1],v=0;if(l===p){for(x=0;x<s;++x)f.push(o[w+x]);v=d,w+=s,E+=u}else if(l>p){if(m&&w>0&&o[w-s]!=null){h=c+(o[w-s+1]-c)*(p-l)/(o[w-s]-l),f.push(p),f.push(h);for(x=2;x<s;++x)f.push(o[w+x]);v=d}E+=u}else{if(b&&m){w+=s;continue}for(x=0;x<s;++x)f.push(o[w+x]);m&&E>0&&a[E-u]!=null&&(v=d+(a[E-u+1]-d)*(l-p)/(a[E-u]-p)),w+=s}b=!1,S!==f.length&&g&&(f[S+2]=v)}if(y&&S!==f.length&&S>0&&f[S]!==null&&f[S]!==f[S-s]&&f[S+1]!==f[S-s+1]){for(x=0;x<s;++x)f[S+s+x]=f[S+x];f[S+1]=f[S-s+1]}}r.points=f}e.hooks.processDatapoints.push(n)}var t={series:{fillBetween:null}};e.plot.plugins.push({init:n,options:t,name:"fillbetween",version:"1.0"})})(jQuery);
@@ -1,238 +1,241 @@
1
- /*
2
- Flot plugin for plotting images, e.g. useful for putting ticks on a
3
- prerendered complex visualization.
4
-
5
- The data syntax is [[image, x1, y1, x2, y2], ...] where (x1, y1) and
6
- (x2, y2) are where you intend the two opposite corners of the image to
7
- end up in the plot. Image must be a fully loaded Javascript image (you
8
- can make one with new Image()). If the image is not complete, it's
9
- skipped when plotting.
10
-
11
- There are two helpers included for retrieving images. The easiest work
12
- the way that you put in URLs instead of images in the data (like
13
- ["myimage.png", 0, 0, 10, 10]), then call $.plot.image.loadData(data,
14
- options, callback) where data and options are the same as you pass in
15
- to $.plot. This loads the images, replaces the URLs in the data with
16
- the corresponding images and calls "callback" when all images are
17
- loaded (or failed loading). In the callback, you can then call $.plot
18
- with the data set. See the included example.
19
-
20
- A more low-level helper, $.plot.image.load(urls, callback) is also
21
- included. Given a list of URLs, it calls callback with an object
22
- mapping from URL to Image object when all images are loaded or have
23
- failed loading.
24
-
25
- Options for the plugin are
26
-
27
- series: {
28
- images: {
29
- show: boolean
30
- anchor: "corner" or "center"
31
- alpha: [0,1]
32
- }
33
- }
34
-
35
- which can be specified for a specific series
36
-
37
- $.plot($("#placeholder"), [{ data: [ ... ], images: { ... } ])
38
-
39
- Note that because the data format is different from usual data points,
40
- you can't use images with anything else in a specific data series.
41
-
42
- Setting "anchor" to "center" causes the pixels in the image to be
43
- anchored at the corner pixel centers inside of at the pixel corners,
44
- effectively letting half a pixel stick out to each side in the plot.
45
-
46
-
47
- A possible future direction could be support for tiling for large
48
- images (like Google Maps).
49
-
50
- */
51
-
52
- (function ($) {
53
- var options = {
54
- series: {
55
- images: {
56
- show: false,
57
- alpha: 1,
58
- anchor: "corner" // or "center"
59
- }
60
- }
61
- };
62
-
63
- $.plot.image = {};
64
-
65
- $.plot.image.loadDataImages = function (series, options, callback) {
66
- var urls = [], points = [];
67
-
68
- var defaultShow = options.series.images.show;
69
-
70
- $.each(series, function (i, s) {
71
- if (!(defaultShow || s.images.show))
72
- return;
73
-
74
- if (s.data)
75
- s = s.data;
76
-
77
- $.each(s, function (i, p) {
78
- if (typeof p[0] == "string") {
79
- urls.push(p[0]);
80
- points.push(p);
81
- }
82
- });
83
- });
84
-
85
- $.plot.image.load(urls, function (loadedImages) {
86
- $.each(points, function (i, p) {
87
- var url = p[0];
88
- if (loadedImages[url])
89
- p[0] = loadedImages[url];
90
- });
91
-
92
- callback();
93
- });
94
- }
95
-
96
- $.plot.image.load = function (urls, callback) {
97
- var missing = urls.length, loaded = {};
98
- if (missing == 0)
99
- callback({});
100
-
101
- $.each(urls, function (i, url) {
102
- var handler = function () {
103
- --missing;
104
-
105
- loaded[url] = this;
106
-
107
- if (missing == 0)
108
- callback(loaded);
109
- };
110
-
111
- $('<img />').load(handler).error(handler).attr('src', url);
112
- });
113
- }
114
-
115
- function drawSeries(plot, ctx, series) {
116
- var plotOffset = plot.getPlotOffset();
117
-
118
- if (!series.images || !series.images.show)
119
- return;
120
-
121
- var points = series.datapoints.points,
122
- ps = series.datapoints.pointsize;
123
-
124
- for (var i = 0; i < points.length; i += ps) {
125
- var img = points[i],
126
- x1 = points[i + 1], y1 = points[i + 2],
127
- x2 = points[i + 3], y2 = points[i + 4],
128
- xaxis = series.xaxis, yaxis = series.yaxis,
129
- tmp;
130
-
131
- // actually we should check img.complete, but it
132
- // appears to be a somewhat unreliable indicator in
133
- // IE6 (false even after load event)
134
- if (!img || img.width <= 0 || img.height <= 0)
135
- continue;
136
-
137
- if (x1 > x2) {
138
- tmp = x2;
139
- x2 = x1;
140
- x1 = tmp;
141
- }
142
- if (y1 > y2) {
143
- tmp = y2;
144
- y2 = y1;
145
- y1 = tmp;
146
- }
147
-
148
- // if the anchor is at the center of the pixel, expand the
149
- // image by 1/2 pixel in each direction
150
- if (series.images.anchor == "center") {
151
- tmp = 0.5 * (x2-x1) / (img.width - 1);
152
- x1 -= tmp;
153
- x2 += tmp;
154
- tmp = 0.5 * (y2-y1) / (img.height - 1);
155
- y1 -= tmp;
156
- y2 += tmp;
157
- }
158
-
159
- // clip
160
- if (x1 == x2 || y1 == y2 ||
161
- x1 >= xaxis.max || x2 <= xaxis.min ||
162
- y1 >= yaxis.max || y2 <= yaxis.min)
163
- continue;
164
-
165
- var sx1 = 0, sy1 = 0, sx2 = img.width, sy2 = img.height;
166
- if (x1 < xaxis.min) {
167
- sx1 += (sx2 - sx1) * (xaxis.min - x1) / (x2 - x1);
168
- x1 = xaxis.min;
169
- }
170
-
171
- if (x2 > xaxis.max) {
172
- sx2 += (sx2 - sx1) * (xaxis.max - x2) / (x2 - x1);
173
- x2 = xaxis.max;
174
- }
175
-
176
- if (y1 < yaxis.min) {
177
- sy2 += (sy1 - sy2) * (yaxis.min - y1) / (y2 - y1);
178
- y1 = yaxis.min;
179
- }
180
-
181
- if (y2 > yaxis.max) {
182
- sy1 += (sy1 - sy2) * (yaxis.max - y2) / (y2 - y1);
183
- y2 = yaxis.max;
184
- }
185
-
186
- x1 = xaxis.p2c(x1);
187
- x2 = xaxis.p2c(x2);
188
- y1 = yaxis.p2c(y1);
189
- y2 = yaxis.p2c(y2);
190
-
191
- // the transformation may have swapped us
192
- if (x1 > x2) {
193
- tmp = x2;
194
- x2 = x1;
195
- x1 = tmp;
196
- }
197
- if (y1 > y2) {
198
- tmp = y2;
199
- y2 = y1;
200
- y1 = tmp;
201
- }
202
-
203
- tmp = ctx.globalAlpha;
204
- ctx.globalAlpha *= series.images.alpha;
205
- ctx.drawImage(img,
206
- sx1, sy1, sx2 - sx1, sy2 - sy1,
207
- x1 + plotOffset.left, y1 + plotOffset.top,
208
- x2 - x1, y2 - y1);
209
- ctx.globalAlpha = tmp;
210
- }
211
- }
212
-
213
- function processRawData(plot, series, data, datapoints) {
214
- if (!series.images.show)
215
- return;
216
-
217
- // format is Image, x1, y1, x2, y2 (opposite corners)
218
- datapoints.format = [
219
- { required: true },
220
- { x: true, number: true, required: true },
221
- { y: true, number: true, required: true },
222
- { x: true, number: true, required: true },
223
- { y: true, number: true, required: true }
224
- ];
225
- }
226
-
227
- function init(plot) {
228
- plot.hooks.processRawData.push(processRawData);
229
- plot.hooks.drawSeries.push(drawSeries);
230
- }
231
-
232
- $.plot.plugins.push({
233
- init: init,
234
- options: options,
235
- name: 'image',
236
- version: '1.1'
237
- });
238
- })(jQuery);
1
+ /* Flot plugin for plotting images.
2
+
3
+ Copyright (c) 2007-2013 IOLA and Ole Laursen.
4
+ Licensed under the MIT license.
5
+
6
+ The data syntax is [ [ image, x1, y1, x2, y2 ], ... ] where (x1, y1) and
7
+ (x2, y2) are where you intend the two opposite corners of the image to end up
8
+ in the plot. Image must be a fully loaded Javascript image (you can make one
9
+ with new Image()). If the image is not complete, it's skipped when plotting.
10
+
11
+ There are two helpers included for retrieving images. The easiest work the way
12
+ that you put in URLs instead of images in the data, like this:
13
+
14
+ [ "myimage.png", 0, 0, 10, 10 ]
15
+
16
+ Then call $.plot.image.loadData( data, options, callback ) where data and
17
+ options are the same as you pass in to $.plot. This loads the images, replaces
18
+ the URLs in the data with the corresponding images and calls "callback" when
19
+ all images are loaded (or failed loading). In the callback, you can then call
20
+ $.plot with the data set. See the included example.
21
+
22
+ A more low-level helper, $.plot.image.load(urls, callback) is also included.
23
+ Given a list of URLs, it calls callback with an object mapping from URL to
24
+ Image object when all images are loaded or have failed loading.
25
+
26
+ The plugin supports these options:
27
+
28
+ series: {
29
+ images: {
30
+ show: boolean
31
+ anchor: "corner" or "center"
32
+ alpha: [ 0, 1 ]
33
+ }
34
+ }
35
+
36
+ They can be specified for a specific series:
37
+
38
+ $.plot( $("#placeholder"), [{
39
+ data: [ ... ],
40
+ images: { ... }
41
+ ])
42
+
43
+ Note that because the data format is different from usual data points, you
44
+ can't use images with anything else in a specific data series.
45
+
46
+ Setting "anchor" to "center" causes the pixels in the image to be anchored at
47
+ the corner pixel centers inside of at the pixel corners, effectively letting
48
+ half a pixel stick out to each side in the plot.
49
+
50
+ A possible future direction could be support for tiling for large images (like
51
+ Google Maps).
52
+
53
+ */
54
+
55
+ (function ($) {
56
+ var options = {
57
+ series: {
58
+ images: {
59
+ show: false,
60
+ alpha: 1,
61
+ anchor: "corner" // or "center"
62
+ }
63
+ }
64
+ };
65
+
66
+ $.plot.image = {};
67
+
68
+ $.plot.image.loadDataImages = function (series, options, callback) {
69
+ var urls = [], points = [];
70
+
71
+ var defaultShow = options.series.images.show;
72
+
73
+ $.each(series, function (i, s) {
74
+ if (!(defaultShow || s.images.show))
75
+ return;
76
+
77
+ if (s.data)
78
+ s = s.data;
79
+
80
+ $.each(s, function (i, p) {
81
+ if (typeof p[0] == "string") {
82
+ urls.push(p[0]);
83
+ points.push(p);
84
+ }
85
+ });
86
+ });
87
+
88
+ $.plot.image.load(urls, function (loadedImages) {
89
+ $.each(points, function (i, p) {
90
+ var url = p[0];
91
+ if (loadedImages[url])
92
+ p[0] = loadedImages[url];
93
+ });
94
+
95
+ callback();
96
+ });
97
+ }
98
+
99
+ $.plot.image.load = function (urls, callback) {
100
+ var missing = urls.length, loaded = {};
101
+ if (missing == 0)
102
+ callback({});
103
+
104
+ $.each(urls, function (i, url) {
105
+ var handler = function () {
106
+ --missing;
107
+
108
+ loaded[url] = this;
109
+
110
+ if (missing == 0)
111
+ callback(loaded);
112
+ };
113
+
114
+ $('<img />').load(handler).error(handler).attr('src', url);
115
+ });
116
+ };
117
+
118
+ function drawSeries(plot, ctx, series) {
119
+ var plotOffset = plot.getPlotOffset();
120
+
121
+ if (!series.images || !series.images.show)
122
+ return;
123
+
124
+ var points = series.datapoints.points,
125
+ ps = series.datapoints.pointsize;
126
+
127
+ for (var i = 0; i < points.length; i += ps) {
128
+ var img = points[i],
129
+ x1 = points[i + 1], y1 = points[i + 2],
130
+ x2 = points[i + 3], y2 = points[i + 4],
131
+ xaxis = series.xaxis, yaxis = series.yaxis,
132
+ tmp;
133
+
134
+ // actually we should check img.complete, but it
135
+ // appears to be a somewhat unreliable indicator in
136
+ // IE6 (false even after load event)
137
+ if (!img || img.width <= 0 || img.height <= 0)
138
+ continue;
139
+
140
+ if (x1 > x2) {
141
+ tmp = x2;
142
+ x2 = x1;
143
+ x1 = tmp;
144
+ }
145
+ if (y1 > y2) {
146
+ tmp = y2;
147
+ y2 = y1;
148
+ y1 = tmp;
149
+ }
150
+
151
+ // if the anchor is at the center of the pixel, expand the
152
+ // image by 1/2 pixel in each direction
153
+ if (series.images.anchor == "center") {
154
+ tmp = 0.5 * (x2-x1) / (img.width - 1);
155
+ x1 -= tmp;
156
+ x2 += tmp;
157
+ tmp = 0.5 * (y2-y1) / (img.height - 1);
158
+ y1 -= tmp;
159
+ y2 += tmp;
160
+ }
161
+
162
+ // clip
163
+ if (x1 == x2 || y1 == y2 ||
164
+ x1 >= xaxis.max || x2 <= xaxis.min ||
165
+ y1 >= yaxis.max || y2 <= yaxis.min)
166
+ continue;
167
+
168
+ var sx1 = 0, sy1 = 0, sx2 = img.width, sy2 = img.height;
169
+ if (x1 < xaxis.min) {
170
+ sx1 += (sx2 - sx1) * (xaxis.min - x1) / (x2 - x1);
171
+ x1 = xaxis.min;
172
+ }
173
+
174
+ if (x2 > xaxis.max) {
175
+ sx2 += (sx2 - sx1) * (xaxis.max - x2) / (x2 - x1);
176
+ x2 = xaxis.max;
177
+ }
178
+
179
+ if (y1 < yaxis.min) {
180
+ sy2 += (sy1 - sy2) * (yaxis.min - y1) / (y2 - y1);
181
+ y1 = yaxis.min;
182
+ }
183
+
184
+ if (y2 > yaxis.max) {
185
+ sy1 += (sy1 - sy2) * (yaxis.max - y2) / (y2 - y1);
186
+ y2 = yaxis.max;
187
+ }
188
+
189
+ x1 = xaxis.p2c(x1);
190
+ x2 = xaxis.p2c(x2);
191
+ y1 = yaxis.p2c(y1);
192
+ y2 = yaxis.p2c(y2);
193
+
194
+ // the transformation may have swapped us
195
+ if (x1 > x2) {
196
+ tmp = x2;
197
+ x2 = x1;
198
+ x1 = tmp;
199
+ }
200
+ if (y1 > y2) {
201
+ tmp = y2;
202
+ y2 = y1;
203
+ y1 = tmp;
204
+ }
205
+
206
+ tmp = ctx.globalAlpha;
207
+ ctx.globalAlpha *= series.images.alpha;
208
+ ctx.drawImage(img,
209
+ sx1, sy1, sx2 - sx1, sy2 - sy1,
210
+ x1 + plotOffset.left, y1 + plotOffset.top,
211
+ x2 - x1, y2 - y1);
212
+ ctx.globalAlpha = tmp;
213
+ }
214
+ }
215
+
216
+ function processRawData(plot, series, data, datapoints) {
217
+ if (!series.images.show)
218
+ return;
219
+
220
+ // format is Image, x1, y1, x2, y2 (opposite corners)
221
+ datapoints.format = [
222
+ { required: true },
223
+ { x: true, number: true, required: true },
224
+ { y: true, number: true, required: true },
225
+ { x: true, number: true, required: true },
226
+ { y: true, number: true, required: true }
227
+ ];
228
+ }
229
+
230
+ function init(plot) {
231
+ plot.hooks.processRawData.push(processRawData);
232
+ plot.hooks.drawSeries.push(drawSeries);
233
+ }
234
+
235
+ $.plot.plugins.push({
236
+ init: init,
237
+ options: options,
238
+ name: 'image',
239
+ version: '1.1'
240
+ });
241
+ })(jQuery);