flot-rails 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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);