瀏覽代碼

Initial import

pull/1/head
Chris Smith 13 年之前
當前提交
b3e1c9d1d5
共有 63 個文件被更改,包括 13551 次插入0 次删除
  1. 1
    0
      .gitignore
  2. 207
    0
      data.php
  3. 1024
    0
      flot/API.txt
  4. 71
    0
      flot/FAQ.txt
  5. 22
    0
      flot/LICENSE.txt
  6. 15
    0
      flot/Makefile
  7. 340
    0
      flot/NEWS.txt
  8. 105
    0
      flot/PLUGINS.txt
  9. 81
    0
      flot/README.txt
  10. 143
    0
      flot/examples/ajax.html
  11. 75
    0
      flot/examples/annotating.html
  12. 二進制
      flot/examples/arrow-down.gif
  13. 二進制
      flot/examples/arrow-left.gif
  14. 二進制
      flot/examples/arrow-right.gif
  15. 二進制
      flot/examples/arrow-up.gif
  16. 38
    0
      flot/examples/basic.html
  17. 4
    0
      flot/examples/data-eu-gdp-growth-1.json
  18. 4
    0
      flot/examples/data-eu-gdp-growth-2.json
  19. 4
    0
      flot/examples/data-eu-gdp-growth-3.json
  20. 4
    0
      flot/examples/data-eu-gdp-growth-4.json
  21. 4
    0
      flot/examples/data-eu-gdp-growth-5.json
  22. 4
    0
      flot/examples/data-eu-gdp-growth.json
  23. 4
    0
      flot/examples/data-japan-gdp-growth.json
  24. 4
    0
      flot/examples/data-usa-gdp-growth.json
  25. 39
    0
      flot/examples/dual-axis.html
  26. 75
    0
      flot/examples/graph-types.html
  27. 二進制
      flot/examples/hs-2004-27-a-large_web.jpg
  28. 45
    0
      flot/examples/image.html
  29. 43
    0
      flot/examples/index.html
  30. 93
    0
      flot/examples/interacting.html
  31. 6
    0
      flot/examples/layout.css
  32. 118
    0
      flot/examples/navigate.html
  33. 114
    0
      flot/examples/selection.html
  34. 65
    0
      flot/examples/setting-options.html
  35. 77
    0
      flot/examples/stacking.html
  36. 54
    0
      flot/examples/thresholding.html
  37. 71
    0
      flot/examples/time.html
  38. 95
    0
      flot/examples/tracking.html
  39. 98
    0
      flot/examples/turning-series.html
  40. 90
    0
      flot/examples/visitors.html
  41. 98
    0
      flot/examples/zooming.html
  42. 1427
    0
      flot/excanvas.js
  43. 1
    0
      flot/excanvas.min.js
  44. 174
    0
      flot/jquery.colorhelpers.js
  45. 1
    0
      flot/jquery.colorhelpers.min.js
  46. 156
    0
      flot/jquery.flot.crosshair.js
  47. 1
    0
      flot/jquery.flot.crosshair.min.js
  48. 237
    0
      flot/jquery.flot.image.js
  49. 1
    0
      flot/jquery.flot.image.min.js
  50. 2119
    0
      flot/jquery.flot.js
  51. 1
    0
      flot/jquery.flot.min.js
  52. 272
    0
      flot/jquery.flot.navigate.js
  53. 1
    0
      flot/jquery.flot.navigate.min.js
  54. 750
    0
      flot/jquery.flot.pie.js
  55. 299
    0
      flot/jquery.flot.selection.js
  56. 1
    0
      flot/jquery.flot.selection.min.js
  57. 152
    0
      flot/jquery.flot.stack.js
  58. 1
    0
      flot/jquery.flot.stack.min.js
  59. 103
    0
      flot/jquery.flot.threshold.js
  60. 1
    0
      flot/jquery.flot.threshold.min.js
  61. 4376
    0
      flot/jquery.js
  62. 19
    0
      flot/jquery.min.js
  63. 123
    0
      index.html

+ 1
- 0
.gitignore 查看文件

@@ -0,0 +1 @@
1
+/Statements

+ 207
- 0
data.php 查看文件

@@ -0,0 +1,207 @@
1
+<?PHP
2
+
3
+ // Description prefixes used to indicate types
4
+ $types = array(
5
+  'SO - ' => 'Standing Order',
6
+  'DD - Hbos Card Services' => 'Internal Transfer',
7
+  'DD - ' => 'Direct Debit',
8
+  'CHQ - ' => 'Cheque',
9
+  'Bank Credit - ' => 'Bank Credit',
10
+  'Bill Payment - Hfx Credit Card' => 'Internal Transfer',
11
+  'Bill Payment - ' => 'Bill Payment',
12
+  'DC - ' => 'Debit Card',
13
+  'DC Cashback - ' => 'Debit Card Cashback',
14
+  'DC Refund - ' => 'Debit Card Refund',
15
+  'Link ATM - ' => 'Cash Withdrawal',
16
+  'ATM - ' => 'Cash Withdrawal',
17
+  'Faster Payment - ' => 'Transfer',
18
+  'PAYMENT REC\'D - THANK YOU' => 'Internal Transfer',
19
+  'DIRECT DEBIT THANK YOU' => 'Internal Transfer',
20
+ );
21
+
22
+ // Types where the real description should be discarded in favour
23
+ // of the type name
24
+ $genericTypes = array(
25
+  'Internal Transfer',
26
+  'Cash Withdrawal',
27
+  'Cheque',
28
+ );
29
+
30
+ // Custom user rules for grouping different descriptions
31
+ $rules = array(
32
+  '^(?i)tesco' => 'Tesco',
33
+  '^(?i)(sacat )?sainsbury\'?s' => 'Sainsbury\'s',
34
+  '^(?i)marks & spencer' => 'M&S',
35
+  '^(?i)argos' => 'Argos',
36
+  '^(?i)subway' => 'Subway',
37
+  '^(?i)specsavers' => 'Specsavers',
38
+  '^(?i)adsl24' => 'ADSL 24',
39
+  '^(?i)foxtons' => 'Foxtons',
40
+  '^(?i)(eve online|ccp games)' => 'CCP Games',
41
+  '^(?i)nandos' => 'Nandos',
42
+  '^(?i)pizza express' => 'Pizza Express',
43
+  '^(?i)steam(games|powered)\.com' => 'Steam',
44
+  '^(?i)spotify(\.com|subs|\s)' => 'Spotify',
45
+  '^(?i)t-\s?mobile' => 'T-Mobile',
46
+  '^(?i)TGI Friday\'s' => 'TGI Friday\'s',
47
+  '^(?i)wh smith' => 'WH Smiths',
48
+  '^(?i)Codeweavers' => 'Codeweavers',
49
+  '^(?i)Cineworld' => 'Cineworld',
50
+  '^(?i)123-reg\.co\.uk' => '123-reg.co.uk',
51
+  '866-321-8851' => 'Amazon Kindle',
52
+  '(?i)Amazon Digital Dwnlds\s*amazon.co.uk' => 'Amazon MP3',
53
+  '^(?i)Ocado' => 'Ocado',
54
+ );
55
+
56
+ // Categories
57
+ $categories = array(
58
+  'Groceries' => array('Tesco', 'Ocado', 'M&S'),
59
+  'Home expenses' => array('T-Mobile', 'Bt Group Plc', 'Edf Energy', 'Foxtons', 'ADSL 24', 'Lb Southwark', '(?i)0800 Repair'),
60
+  'Entertainment' => array('Amazon', 'Spotify', 'Cineworld', '(?i)sky payments', 'Steam', '(?i)play.com'),
61
+  'Online' => array('(?i)giganews', 'Shane', '(?i)^github'),
62
+  'Cash' => array('Cash Withdrawal'),
63
+  'Going out' => array('(?i)tayyab', '(?i)founders arms', 'Nandos', '(?i)all bar one', 'TGI Friday\'s', '(?i)^piccolino', 'EAT & DRINK', '(?i)www.urbanbite.com'),
64
+  'Transport' => array('(?i)ec mainline'),
65
+  'Health/Medical' => array('Specsavers'),
66
+  '(Ignored)' => array('Internal Transfer'),
67
+ );
68
+
69
+ // Formats part (one field) of a transaction
70
+ function parseStatementPart($key, $value) {
71
+  if ($key == 'Date') {
72
+   $format = 'd/m/' . (strlen($value) == 8 ? 'y' : 'Y');
73
+   return DateTime::createFromFormat($format, $value)->setTime(0, 0, 0);
74
+  } else if ($key == 'Amount') {
75
+   return (double) $value;
76
+  }
77
+
78
+  return $value;
79
+ }
80
+
81
+ // Formats an entire transaction from a statement
82
+ function parseStatementLine($line) {
83
+  global $categories, $genericTypes, $types, $rules;
84
+
85
+  if (preg_match('/^(.*?)\s*\((.*? @ RATE .*?)\)$/', $line['Description'], $m)) {
86
+   $line['Description'] = $m[1];
87
+   $line['Exchange'] = $m[2];
88
+  }
89
+
90
+  foreach ($types as $prefix => $type) {
91
+   if (strpos($line['Description'], $prefix) === 0) {
92
+    $line['Type'] = $type;
93
+
94
+    if (array_search($type, $genericTypes) === false) {
95
+     $line['Description'] = substr($line['Description'], strlen($prefix));
96
+    } else {
97
+     $line['RawDescription'] = $line['Description'];
98
+     $line['Description'] = $type;
99
+    }
100
+
101
+    break;
102
+   }
103
+  }
104
+
105
+  foreach ($rules as $regex => $replacement) {
106
+   if (preg_match('(' . $regex . ')', $line['Description'])) {
107
+    $line['RawDescription'] = $line['Description'];
108
+    $line['Description'] = $replacement;
109
+   }
110
+  }
111
+
112
+  foreach ($categories as $cat => $entries) {
113
+   foreach ($entries as $regex) {
114
+    if (preg_match('(' . $regex . ')', $line['Description'])) {
115
+     $line['Category'] = $cat;
116
+     break;
117
+    }
118
+   }
119
+  }
120
+
121
+  return $line;
122
+ }
123
+
124
+ // Loads statements from the specified directory
125
+ function loadStatements($dir = 'Statements') {
126
+  $results = array();
127
+
128
+  foreach (glob($dir . '/*.csv') as $statement) {
129
+   $fh = fopen($statement, 'r');
130
+   $data = array();
131
+
132
+   $headers = array_map('trim', fgetcsv($fh));
133
+
134
+   while (!feof($fh)) {
135
+    $line = parseStatementLine(array_combine($headers, array_map('parseStatementPart', $headers, array_map('trim', fgetcsv($fh)))));
136
+    $data[] = $line;
137
+   }
138
+   fclose($fh);
139
+
140
+   $results[basename($statement)] = $data;
141
+  }
142
+
143
+  return $results;
144
+ }
145
+
146
+ $entries = array_reduce(loadStatements(), 'array_merge', array());
147
+
148
+ usort($entries, function($a, $b) { return $a['Date']->getTimestamp() - $b['Date']->getTimestamp(); });
149
+
150
+ $descs = array_unique(array_map(function($t) { return $t['Description']; }, $entries));
151
+ sort($descs);
152
+
153
+ $amounts = array();
154
+ $rawmonths = array();
155
+ $months = array();
156
+ $bydesc = array();
157
+ array_walk($entries, function($entry) use(&$months, &$bydesc, &$amounts, &$rawmonths) {
158
+  $rawmonths[$entry['Date']->format('Y-m')][] = $entry;
159
+
160
+  if (!isset($entry['Category']) || $entry['Category'] != '(Ignored)') {
161
+   $amounts[$entry['Date']->format('Y-m')][$entry['Amount'] < 0 ? 'out' : 'in'] += $entry['Amount'];
162
+   $months[$entry['Date']->format('Y-m')][$entry['Description']]['Count']++; 
163
+   $months[$entry['Date']->format('Y-m')][$entry['Description']]['Amount'] += $entry['Amount'];
164
+   $bydesc[$entry['Description']]['Count']++;
165
+   $bydesc[$entry['Description']]['Amount'] += $entry['Amount'];
166
+  }
167
+ });
168
+
169
+ ksort($months);
170
+ ksort($amounts);
171
+
172
+ $monthsbydesc = array();
173
+
174
+ array_walk(array_slice(array_reverse($months), 0, 6, true), function($monthentries, $month) use(&$monthsbydesc) {
175
+  array_walk($monthentries, function($entry, $desc) use(&$monthsbydesc, $month) {
176
+   $monthsbydesc[$desc][$month]['Count'] += $entry['Count'];
177
+   $monthsbydesc[$desc][$month]['Amount'] += $entry['Amount'];
178
+  });
179
+ });
180
+
181
+ $total = 0;
182
+ array_walk($monthsbydesc, function($data, $desc) use(&$total) {
183
+  $prob = count($data) / 6;
184
+  $count = array_sum(array_map(function($x) { return $x['Count']; }, $data));
185
+  $amount = array_sum(array_map(function($x) { return $x['Amount']; }, $data)); 
186
+  $avgcount = $count / count($data);
187
+  $avgamount = $amount / $count;
188
+  $total += $prob * $avgcount * $avgamount;
189
+  //echo "P($desc) = $prob, with avg of $avgcount trans/month, averaging $avgamount\n";
190
+ });
191
+
192
+ $transData = array(array(), array());
193
+ array_walk($months, function($entries, $month) use(&$transData) {
194
+  $ins = array_filter($entries, function($x) { return $x['Amount'] > 0; });
195
+  $outs = array_filter($entries, function($x) { return $x['Amount'] < 0; });
196
+
197
+  $totalin = array_sum(array_map(function($x) { return $x['Amount']; }, $ins));
198
+  $totalout = array_sum(array_map(function($x) { return -1 * $x['Amount']; }, $outs));
199
+  $time = strtotime($month . '-01') * 1000;
200
+
201
+  $transData[0][] = array($time, $totalin);
202
+  $transData[1][] = array($time, $totalout);
203
+ });
204
+
205
+?>
206
+var transData = <?PHP echo json_encode($transData); ?>;
207
+var monthData = <?PHP echo json_encode($rawmonths); ?>;

+ 1024
- 0
flot/API.txt
文件差異過大導致無法顯示
查看文件


+ 71
- 0
flot/FAQ.txt 查看文件

@@ -0,0 +1,71 @@
1
+Frequently asked questions
2
+--------------------------
3
+
4
+Q: How much data can Flot cope with?
5
+
6
+A: Flot will happily draw everything you send to it so the answer
7
+depends on the browser. The excanvas emulation used for IE (built with
8
+VML) makes IE by far the slowest browser so be sure to test with that
9
+if IE users are in your target group.
10
+
11
+1000 points is not a problem, but as soon as you start having more
12
+points than the pixel width, you should probably start thinking about
13
+downsampling/aggregation as this is near the resolution limit of the
14
+chart anyway. If you downsample server-side, you also save bandwidth.
15
+
16
+
17
+Q: Flot isn't working when I'm using JSON data as source!
18
+
19
+A: Actually, Flot loves JSON data, you just got the format wrong.
20
+Double check that you're not inputting strings instead of numbers,
21
+like [["0", "-2.13"], ["5", "4.3"]]. This is most common mistake, and
22
+the error might not show up immediately because Javascript can do some
23
+conversion automatically.
24
+
25
+
26
+Q: Can I export the graph?
27
+
28
+A: This is a limitation of the canvas technology. There's a hook in
29
+the canvas object for getting an image out, but you won't get the tick
30
+labels. And it's not likely to be supported by IE. At this point, your
31
+best bet is probably taking a screenshot, e.g. with PrtScn.
32
+
33
+
34
+Q: The bars are all tiny in time mode?
35
+
36
+A: It's not really possible to determine the bar width automatically.
37
+So you have to set the width with the barWidth option which is NOT in
38
+pixels, but in the units of the x axis (or the y axis for horizontal
39
+bars). For time mode that's milliseconds so the default value of 1
40
+makes the bars 1 millisecond wide.
41
+
42
+
43
+Q: Can I use Flot with libraries like Mootools or Prototype?
44
+
45
+A: Yes, Flot supports it out of the box and it's easy! Just use jQuery
46
+instead of $, e.g. call jQuery.plot instead of $.plot and use
47
+jQuery(something) instead of $(something). As a convenience, you can
48
+put in a DOM element for the graph placeholder where the examples and
49
+the API documentation are using jQuery objects.
50
+
51
+Depending on how you include jQuery, you may have to add one line of
52
+code to prevent jQuery from overwriting functions from the other
53
+libraries, see the documentation in jQuery ("Using jQuery with other
54
+libraries") for details.
55
+
56
+
57
+Q: Flot doesn't work with [widget framework xyz]!
58
+
59
+A: The problem is most likely within the framework, or your use of the
60
+framework.
61
+
62
+The only non-standard thing used by Flot is the canvas tag; otherwise
63
+it is simply a series of absolute positioned divs within the
64
+placeholder tag you put in. If this is not working, it's probably
65
+because the framework you're using is doing something weird with the
66
+DOM. As a last resort, you might try replotting and see if it helps.
67
+
68
+If you find there's a specific thing we can do to Flot to help, feel
69
+free to submit a bug report. Otherwise, you're welcome to ask for help
70
+on the mailing list, but please don't submit a bug report to Flot -
71
+try the framework instead.

+ 22
- 0
flot/LICENSE.txt 查看文件

@@ -0,0 +1,22 @@
1
+Copyright (c) 2007-2009 IOLA and Ole Laursen
2
+
3
+Permission is hereby granted, free of charge, to any person
4
+obtaining a copy of this software and associated documentation
5
+files (the "Software"), to deal in the Software without
6
+restriction, including without limitation the rights to use,
7
+copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+copies of the Software, and to permit persons to whom the
9
+Software is furnished to do so, subject to the following
10
+conditions:
11
+
12
+The above copyright notice and this permission notice shall be
13
+included in all copies or substantial portions of the Software.
14
+
15
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+OTHER DEALINGS IN THE SOFTWARE.

+ 15
- 0
flot/Makefile 查看文件

@@ -0,0 +1,15 @@
1
+# Makefile for generating minified files
2
+
3
+YUICOMPRESSOR_PATH=../yuicompressor-2.3.5.jar
4
+
5
+# if you need another compressor path, just copy the above line to a
6
+# file called Makefile.local, customize it and you're good to go
7
+-include Makefile.local
8
+
9
+.PHONY: all
10
+
11
+# we cheat and process all .js files instead of listing them
12
+all: $(patsubst %.js,%.min.js,$(filter-out %.min.js,$(wildcard *.js)))
13
+
14
+%.min.js: %.js
15
+	java -jar $(YUICOMPRESSOR_PATH) $< -o $@

+ 340
- 0
flot/NEWS.txt 查看文件

@@ -0,0 +1,340 @@
1
+Flot 0.6
2
+--------
3
+
4
+API changes:
5
+
6
+1. Selection support has been moved to a plugin. Thus if you're
7
+passing selection: { mode: something }, you MUST include the file
8
+jquery.flot.selection.js after jquery.flot.js. This reduces the size
9
+of base Flot and makes it easier to customize the selection as well as
10
+improving code clarity. The change is based on patch from andershol.
11
+
12
+2. In the global options specified in the $.plot command,
13
+"lines", "points", "bars" and "shadowSize" have been moved to a
14
+sub-object called "series", i.e.
15
+
16
+  $.plot(placeholder, data, { lines: { show: true }})
17
+
18
+should be changed to
19
+
20
+  $.plot(placeholder, data, { series: { lines: { show: true }}})
21
+
22
+All future series-specific options will go into this sub-object to
23
+simplify plugin writing. Backward-compatibility code is in place, so
24
+old code should not break.
25
+
26
+3. "plothover" no longer provides the original data point, but instead
27
+a normalized one, since there may be no corresponding original point.
28
+
29
+4. Due to a bug in previous versions of jQuery, you now need at least
30
+jQuery 1.2.6. But if you can, try jQuery 1.3.2 as it got some
31
+improvements in event handling speed.
32
+
33
+
34
+Changes:
35
+
36
+- Added support for disabling interactivity for specific data series
37
+  (request from Ronald Schouten and Steve Upton).
38
+
39
+- Flot now calls $() on the placeholder and optional legend container
40
+  passed in so you can specify DOM elements or CSS expressions to make
41
+  it easier to use Flot with libraries like Prototype or Mootools or
42
+  through raw JSON from Ajax responses.
43
+
44
+- A new "plotselecting" event is now emitted while the user is making
45
+  a selection.
46
+
47
+- The "plothover" event is now emitted immediately instead of at most
48
+  10 times per second, you'll have to put in a setTimeout yourself if
49
+  you're doing something really expensive on this event.
50
+
51
+- The built-in date formatter can now be accessed as
52
+  $.plot.formatDate(...) (suggestion by Matt Manela) and even
53
+  replaced.
54
+
55
+- Added "borderColor" option to the grid (patch from Amaury Chamayou
56
+  and patch from Mike R. Williamson).
57
+
58
+- Added support for gradient backgrounds for the grid, take a look at
59
+  the "setting options" example (based on patch from Amaury Chamayou,
60
+  issue 90).
61
+
62
+- Gradient bars (suggestion by stefpet).
63
+  
64
+- Added a "plotunselected" event which is triggered when the selection
65
+  is removed, see "selection" example (suggestion by Meda Ugo);
66
+
67
+- The option legend.margin can now specify horizontal and vertical
68
+  margins independently (suggestion by someone who's annoyed).
69
+
70
+- Data passed into Flot is now copied to a new canonical format to
71
+  enable further processing before it hits the drawing routines. As a
72
+  side-effect, this should make Flot more robust in the face of bad
73
+  data (and fixes issue 112).
74
+
75
+- Step-wise charting: line charts have a new option "steps" that when
76
+  set to true connects the points with horizontal/vertical steps
77
+  instead of diagonal lines.
78
+
79
+- The legend labelFormatter now passes the series in addition to just
80
+  the label (suggestion by Vincent Lemeltier).
81
+
82
+- Horizontal bars (based on patch by Jason LeBrun).
83
+
84
+- Support for partial bars by specifying a third coordinate, i.e. they
85
+  don't have to start from the axis. This can be used to make stacked
86
+  bars.
87
+
88
+- New option to disable the (grid.show).
89
+
90
+- Added pointOffset method for converting a point in data space to an
91
+  offset within the placeholder.
92
+  
93
+- Plugin system: register an init method in the $.flot.plugins array
94
+  to get started, see PLUGINS.txt for details on how to write plugins
95
+  (it's easy). There are also some extra methods to enable access to
96
+  internal state.
97
+
98
+- Hooks: you can register functions that are called while Flot is
99
+  crunching the data and doing the plot. This can be used to modify
100
+  Flot without changing the source, useful for writing plugins. Some
101
+  hooks are defined, more are likely to come.
102
+  
103
+- Threshold plugin: you can set a threshold and a color, and the data
104
+  points below that threshold will then get the color. Useful for
105
+  marking data below 0, for instance.
106
+
107
+- Stack plugin: you can specify a stack key for each series to have
108
+  them summed. This is useful for drawing additive/cumulative graphs
109
+  with bars and (currently unfilled) lines.
110
+
111
+- Crosshairs plugin: trace the mouse position on the axes, enable with
112
+  crosshair: { mode: "x"} (see the new tracking example for a use).
113
+
114
+- Image plugin: plot prerendered images.
115
+
116
+- Navigation plugin for panning and zooming a plot.
117
+
118
+- More configurable grid.
119
+
120
+- Axis transformation support, useful for non-linear plots, e.g. log
121
+  axes and compressed time axes (like omitting weekends).
122
+
123
+- Support for twelve-hour date formatting (patch by Forrest Aldridge).
124
+
125
+- The color parsing code in Flot has been cleaned up and split out so
126
+  it's now available as a separate jQuery plugin. It's included inline
127
+  in the Flot source to make dependency managing easier. This also
128
+  makes it really easy to use the color helpers in Flot plugins.
129
+
130
+Bug fixes:
131
+
132
+- Fixed two corner-case bugs when drawing filled curves (report and
133
+  analysis by Joshua Varner).
134
+- Fix auto-adjustment code when setting min to 0 for an axis where the
135
+  dataset is completely flat on that axis (report by chovy).
136
+- Fixed a bug with passing in data from getData to setData when the
137
+  secondary axes are used (issue 65, reported by nperelman).
138
+- Fixed so that it is possible to turn lines off when no other chart
139
+  type is shown (based on problem reported by Glenn Vanderburg), and
140
+  fixed so that setting lineWidth to 0 also hides the shadow (based on
141
+  problem reported by Sergio Nunes).
142
+- Updated mousemove position expression to the latest from jQuery (bug
143
+  reported by meyuchas).
144
+- Use CSS borders instead of background in legend (fix printing issue 25
145
+  and 45).
146
+- Explicitly convert axis min/max to numbers.
147
+- Fixed a bug with drawing marking lines with different colors
148
+  (reported by Khurram).
149
+- Fixed a bug with returning y2 values in the selection event (fix
150
+  by exists, issue 75).
151
+- Only set position relative on placeholder if it hasn't already a
152
+  position different from static (reported by kyberneticist, issue 95).
153
+- Don't round markings to prevent sub-pixel problems (reported by Dan
154
+  Lipsitt).
155
+- Make the grid border act similarly to a regular CSS border, i.e.
156
+  prevent it from overlapping the plot itself. This also fixes a
157
+  problem with anti-aliasing when the width is 1 pixel (reported by
158
+  Anthony Ettinger).
159
+- Imported version 3 of excanvas and fixed two issues with the newer
160
+  version. Hopefully, this will make Flot work with IE8 (nudge by
161
+  Fabien Menager, further analysis by Booink, issue 133).
162
+- Changed the shadow code for lines to hopefully look a bit better
163
+  with vertical lines.
164
+- Round tick positions to avoid possible problems with fractions
165
+  (suggestion by Fred, issue 130).
166
+- Made the heuristic for determining how many ticks to aim for a bit
167
+  smarter.
168
+- Fix for uneven axis margins (report and patch by Paul Kienzle) and
169
+  snapping to ticks (concurrent report and patch by lifthrasiir).
170
+- Fixed bug with slicing in findNearbyItems (patch by zollman).
171
+- Make heuristic for x axis label widths more dynamic (patch by
172
+  rickinhethuis).
173
+- Make sure points on top take precedence when finding nearby points
174
+  when hovering (reported by didroe, issue 224).
175
+
176
+Flot 0.5
177
+--------
178
+
179
+Backwards API change summary: Timestamps are now in UTC. Also
180
+"selected" event -> becomes "plotselected" with new data, the
181
+parameters for setSelection are now different (but backwards
182
+compatibility hooks are in place), coloredAreas becomes markings with
183
+a new interface (but backwards compatibility hooks are in place).
184
+
185
+
186
+Interactivity: added a new "plothover" event and this and the
187
+"plotclick" event now returns the closest data item (based on patch by
188
+/david, patch by Mark Byers for bar support). See the revamped
189
+"interacting with the data" example for some hints on what you can do.
190
+
191
+Highlighting: you can now highlight points and datapoints are
192
+autohighlighted when you hover over them (if hovering is turned on).
193
+
194
+Support for dual axis has been added (based on patch by someone who's
195
+annoyed and /david). For each data series you can specify which axes
196
+it belongs to, and there are two more axes, x2axis and y2axis, to
197
+customize. This affects the "selected" event which has been renamed to
198
+"plotselected" and spews out { xaxis: { from: -10, to: 20 } ... },
199
+setSelection in which the parameters are on a new form (backwards
200
+compatible hooks are in place so old code shouldn't break) and
201
+markings (formerly coloredAreas).
202
+
203
+Timestamps in time mode are now displayed according to
204
+UTC instead of the time zone of the visitor. This affects the way the
205
+timestamps should be input; you'll probably have to offset the
206
+timestamps according to your local time zone. It also affects any
207
+custom date handling code (which basically now should use the
208
+equivalent UTC date mehods, e.g. .setUTCMonth() instead of
209
+.setMonth().
210
+
211
+Added support for specifying the size of tick labels (axis.labelWidth,
212
+axis.labelHeight). Useful for specifying a max label size to keep
213
+multiple plots aligned.
214
+
215
+Markings, previously coloredAreas, are now specified as ranges on the
216
+axes, like { xaxis: { from: 0, to: 10 }}. Furthermore with markings
217
+you can now draw horizontal/vertical lines by setting from and to to
218
+the same coordinate (idea from line support patch by by Ryan Funduk).
219
+
220
+The "fill" option can now be a number that specifies the opacity of
221
+the fill.
222
+
223
+You can now specify a coordinate as null (like [2, null]) and Flot
224
+will take the other coordinate into account when scaling the axes
225
+(based on patch by joebno).
226
+
227
+New option for bars "align". Set it to "center" to center the bars on
228
+the value they represent.
229
+
230
+setSelection now takes a second parameter which you can use to prevent
231
+the method from firing the "plotselected" handler. 
232
+
233
+Using the "container" option in legend now overwrites the container
234
+element instead of just appending to it (fixes infinite legend bug,
235
+reported by several people, fix by Brad Dewey).
236
+
237
+Fixed a bug in calculating spacing around the plot (reported by
238
+timothytoe). Fixed a bug in finding max values for all-negative data
239
+sets. Prevent the possibility of eternal looping in tick calculations.
240
+Fixed a bug when borderWidth is set to 0 (reported by
241
+Rob/sanchothefat). Fixed a bug with drawing bars extending below 0
242
+(reported by James Hewitt, patch by Ryan Funduk). Fixed a
243
+bug with line widths of bars (reported by MikeM). Fixed a bug with
244
+'nw' and 'sw' legend positions. Improved the handling of axis
245
+auto-scaling with bars. Fixed a bug with multi-line x-axis tick
246
+labels (reported by Luca Ciano). IE-fix help by Savage Zhang.
247
+
248
+
249
+Flot 0.4
250
+--------
251
+
252
+API changes: deprecated axis.noTicks in favor of just specifying the
253
+number as axis.ticks. So "xaxis: { noTicks: 10 }" becomes
254
+"xaxis: { ticks: 10 }"
255
+
256
+Time series support. Specify axis.mode: "time", put in Javascript
257
+timestamps as data, and Flot will automatically spit out sensible
258
+ticks. Take a look at the two new examples. The format can be
259
+customized with axis.timeformat and axis.monthNames, or if that fails
260
+with axis.tickFormatter.
261
+
262
+Support for colored background areas via grid.coloredAreas. Specify an
263
+array of { x1, y1, x2, y2 } objects or a function that returns these
264
+given { xmin, xmax, ymin, ymax }.
265
+
266
+More members on the plot object (report by Chris Davies and others).
267
+"getData" for inspecting the assigned settings on data series (e.g.
268
+color) and "setData", "setupGrid" and "draw" for updating the contents
269
+without a total replot.
270
+
271
+The default number of ticks to aim for is now dependent on the size of
272
+the plot in pixels. Support for customizing tick interval sizes
273
+directly with axis.minTickSize and axis.tickSize.
274
+
275
+Cleaned up the automatic axis scaling algorithm and fixed how it
276
+interacts with ticks. Also fixed a couple of tick-related corner case
277
+bugs (one reported by mainstreetmark, another reported by timothytoe).
278
+
279
+The option axis.tickFormatter now takes a function with two
280
+parameters, the second parameter is an optional object with
281
+information about the axis. It has min, max, tickDecimals, tickSize.
282
+
283
+Added support for segmented lines (based on patch from Michael
284
+MacDonald) and for ignoring null and bad values (suggestion from Nick
285
+Konidaris and joshwaihi). 
286
+
287
+Added support for changing the border width (joebno and safoo).
288
+Label colors can be changed via CSS by selecting the tickLabel class.
289
+
290
+Fixed a bug in handling single-item bar series (reported by Emil
291
+Filipov). Fixed erratic behaviour when interacting with the plot
292
+with IE 7 (reported by Lau Bech Lauritzen). Prevent IE/Safari text
293
+selection when selecting stuff on the canvas.
294
+
295
+
296
+
297
+Flot 0.3
298
+--------
299
+
300
+This is mostly a quick-fix release because jquery.js wasn't included
301
+in the previous zip/tarball.
302
+
303
+Support clicking on the plot. Turn it on with grid: { clickable: true },
304
+then you get a "plotclick" event on the graph placeholder with the
305
+position in units of the plot.
306
+
307
+Fixed a bug in dealing with data where min = max, thanks to Michael
308
+Messinides.
309
+
310
+Include jquery.js in the zip/tarball.
311
+
312
+
313
+Flot 0.2
314
+--------
315
+
316
+Added support for putting a background behind the default legend. The
317
+default is the partly transparent background color. Added
318
+backgroundColor and backgroundOpacity to the legend options to control
319
+this.
320
+
321
+The ticks options can now be a callback function that takes one
322
+parameter, an object with the attributes min and max. The function
323
+should return a ticks array.
324
+
325
+Added labelFormatter option in legend, useful for turning the legend
326
+labels into links.
327
+
328
+Fixed a couple of bugs.
329
+
330
+The API should now be fully documented.
331
+
332
+Patch from Guy Fraser to make parts of the code smaller.
333
+
334
+API changes: Moved labelMargin option to grid from x/yaxis.
335
+
336
+
337
+Flot 0.1
338
+--------
339
+
340
+First public release.

+ 105
- 0
flot/PLUGINS.txt 查看文件

@@ -0,0 +1,105 @@
1
+Writing plugins
2
+---------------
3
+
4
+To make a new plugin, create an init function and a set of options (if
5
+needed), stuff it into an object and put it in the $.plot.plugins
6
+array. For example:
7
+
8
+  function myCoolPluginInit(plot) { plot.coolstring = "Hello!" };
9
+  var myCoolOptions = { coolstuff: { show: true } }
10
+  $.plot.plugins.push({ init: myCoolPluginInit, options: myCoolOptions });
11
+
12
+  // now when $.plot is called, the returned object will have the
13
+  // attribute "coolstring"
14
+
15
+Now, given that the plugin might run in many different places, it's
16
+a good idea to avoid leaking names. We can avoid this by wrapping the
17
+above lines in an anonymous function which we call immediately, like
18
+this: (function () { inner code ... })(). To make it even more robust
19
+in case $ is not bound to jQuery but some other Javascript library, we
20
+can write it as
21
+
22
+  (function ($) {
23
+    // plugin definition
24
+    // ...
25
+  })(jQuery);
26
+
27
+Here is a simple debug plugin which alerts each of the series in the
28
+plot. It has a single option that control whether it is enabled and
29
+how much info to output:
30
+
31
+  (function ($) {
32
+    function init(plot) {
33
+      var debugLevel = 1;
34
+    
35
+      function checkDebugEnabled(plot, options) {
36
+        if (options.debug) {
37
+          debugLevel = options.debug;
38
+            
39
+          plot.hooks.processDatapoints.push(alertSeries);
40
+        }
41
+      }
42
+
43
+      function alertSeries(plot, series, datapoints) {
44
+        var msg = "series " + series.label;
45
+        if (debugLevel > 1)
46
+          msg += " with " + series.data.length + " points";
47
+        alert(msg);
48
+      }
49
+    
50
+      plot.hooks.processOptions.push(checkDebugEnabled);
51
+    }
52
+
53
+    var options = { debug: 0 };
54
+    
55
+    $.plot.plugins.push({
56
+        init: init,
57
+        options: options,
58
+        name: "simpledebug",
59
+        version: "0.1"
60
+    });
61
+  })(jQuery);
62
+
63
+We also define "name" and "version". It's not used by Flot, but might
64
+be helpful for other plugins in resolving dependencies.
65
+  
66
+Put the above in a file named "jquery.flot.debug.js", include it in an
67
+HTML page and then it can be used with:
68
+
69
+  $.plot($("#placeholder"), [...], { debug: 2 });
70
+
71
+This simple plugin illustrates a couple of points:
72
+
73
+ - It uses the anonymous function trick to avoid name pollution.
74
+ - It can be enabled/disabled through an option.
75
+ - Variables in the init function can be used to store plot-specific
76
+   state between the hooks.
77
+
78
+ 
79
+Options guidelines
80
+==================
81
+   
82
+Plugins should always support appropriate options to enable/disable
83
+them because the plugin user may have several plots on the same page
84
+where only one should use the plugin.
85
+
86
+If the plugin needs series-specific options, you can put them in
87
+"series" in the options object, e.g.
88
+
89
+  var options = {
90
+    series: {
91
+      downsample: {
92
+        algorithm: null,
93
+        maxpoints: 1000
94
+      }
95
+    }
96
+  }
97
+
98
+Then they will be copied by Flot into each series, providing the
99
+defaults in case the plugin user doesn't specify any. Again, in most
100
+cases it's probably a good idea if the plugin is turned off rather
101
+than on per default, just like most of the powerful features in Flot.
102
+
103
+Think hard and long about naming the options. These names are going to
104
+be public API, and code is going to depend on them if the plugin is
105
+successful.

+ 81
- 0
flot/README.txt 查看文件

@@ -0,0 +1,81 @@
1
+About
2
+-----
3
+
4
+Flot is a Javascript plotting library for jQuery. Read more at the
5
+website:
6
+
7
+  http://code.google.com/p/flot/
8
+
9
+Take a look at the examples linked from above, they should give a good
10
+impression of what Flot can do and the source code of the examples is
11
+probably the fastest way to learn how to use Flot.
12
+  
13
+
14
+Installation
15
+------------
16
+
17
+Just include the Javascript file after you've included jQuery.
18
+
19
+Note that you need to get a version of Excanvas (e.g. the one bundled
20
+with Flot) which is canvas emulation on Internet Explorer. You can
21
+include the excanvas script like this:
22
+
23
+  <!--[if IE]><script language="javascript" type="text/javascript" src="excanvas.pack.js"></script><![endif]-->
24
+
25
+If it's not working on your development IE 6.0, check that it has
26
+support for VML which excanvas is relying on. It appears that some
27
+stripped down versions used for test environments on virtual machines
28
+lack the VML support.
29
+  
30
+Also note that you need at least jQuery 1.2.6 (but at least jQuery
31
+1.3.2 is recommended for interactive charts because of performance
32
+improvements in event handling).
33
+
34
+
35
+Basic usage
36
+-----------
37
+
38
+Create a placeholder div to put the graph in:
39
+
40
+   <div id="placeholder"></div>
41
+
42
+You need to set the width and height of this div, otherwise the plot
43
+library doesn't know how to scale the graph. You can do it inline like
44
+this:
45
+
46
+   <div id="placeholder" style="width:600px;height:300px"></div>
47
+
48
+You can also do it with an external stylesheet. Make sure that the
49
+placeholder isn't within something with a display:none CSS property -
50
+in that case, Flot has trouble measuring label dimensions which
51
+results in garbled looks and might have trouble measuring the
52
+placeholder dimensions which is fatal (it'll throw an exception).
53
+
54
+Then when the div is ready in the DOM, which is usually on document
55
+ready, run the plot function:
56
+
57
+  $.plot($("#placeholder"), data, options);
58
+
59
+Here, data is an array of data series and options is an object with
60
+settings if you want to customize the plot. Take a look at the
61
+examples for some ideas of what to put in or look at the reference
62
+in the file "API.txt". Here's a quick example that'll draw a line from
63
+(0, 0) to (1, 1):
64
+
65
+  $.plot($("#placeholder"), [ [[0, 0], [1, 1]] ], { yaxis: { max: 1 } });
66
+
67
+The plot function immediately draws the chart and then returns a plot
68
+object with a couple of methods.
69
+
70
+
71
+What's with the name?
72
+---------------------
73
+
74
+First: it's pronounced with a short o, like "plot". Not like "flawed".
75
+
76
+So "Flot" rhymes with "plot".
77
+
78
+And if you look up "flot" in a Danish-to-English dictionary, some up
79
+the words that come up are "good-looking", "attractive", "stylish",
80
+"smart", "impressive", "extravagant". One of the main goals with Flot
81
+is pretty looks.

+ 143
- 0
flot/examples/ajax.html 查看文件

@@ -0,0 +1,143 @@
1
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2
+<html>
3
+ <head>
4
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+    <title>Flot Examples</title>
6
+    <link href="layout.css" rel="stylesheet" type="text/css"></link>
7
+    <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
8
+    <script language="javascript" type="text/javascript" src="../jquery.js"></script>
9
+    <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
10
+ </head>
11
+    <body>
12
+    <h1>Flot Examples</h1>
13
+
14
+    <div id="placeholder" style="width:600px;height:300px;"></div>
15
+
16
+    <p>Example of loading data dynamically with AJAX. Percentage change in GDP (source: <a href="http://epp.eurostat.ec.europa.eu/tgm/table.do?tab=table&init=1&plugin=1&language=en&pcode=tsieb020">Eurostat</a>). Click the buttons below.</p>
17
+
18
+    <p>The data is fetched over HTTP, in this case directly from text
19
+    files. Usually the URL would point to some web server handler
20
+    (e.g. a PHP page or Java/.NET/Python/Ruby on Rails handler) that
21
+    extracts it from a database and serializes it to JSON.</p>
22
+
23
+    <p>
24
+      <input class="fetchSeries" type="button" value="First dataset"> -
25
+      <a href="data-eu-gdp-growth.json">data</a> -
26
+      <span></span>
27
+    </p>
28
+
29
+    <p>
30
+      <input class="fetchSeries" type="button" value="Second dataset"> -
31
+      <a href="data-japan-gdp-growth.json">data</a> -
32
+      <span></span>
33
+    </p>
34
+
35
+    <p>
36
+      <input class="fetchSeries" type="button" value="Third dataset"> -
37
+      <a href="data-usa-gdp-growth.json">data</a> -
38
+      <span></span>
39
+    </p>
40
+
41
+    <p>If you combine AJAX with setTimeout, you can poll the server
42
+       for new data.</p>
43
+
44
+    <p>
45
+      <input class="dataUpdate" type="button" value="Poll for data">
46
+    </p>
47
+
48
+<script id="source" language="javascript" type="text/javascript">
49
+$(function () {
50
+    var options = {
51
+        lines: { show: true },
52
+        points: { show: true },
53
+        xaxis: { tickDecimals: 0, tickSize: 1 }
54
+    };
55
+    var data = [];
56
+    var placeholder = $("#placeholder");
57
+    
58
+    $.plot(placeholder, data, options);
59
+
60
+    
61
+    // fetch one series, adding to what we got
62
+    var alreadyFetched = {};
63
+    
64
+    $("input.fetchSeries").click(function () {
65
+        var button = $(this);
66
+        
67
+        // find the URL in the link right next to us 
68
+        var dataurl = button.siblings('a').attr('href');
69
+
70
+        // then fetch the data with jQuery
71
+        function onDataReceived(series) {
72
+            // extract the first coordinate pair so you can see that
73
+            // data is now an ordinary Javascript object
74
+            var firstcoordinate = '(' + series.data[0][0] + ', ' + series.data[0][1] + ')';
75
+
76
+            button.siblings('span').text('Fetched ' + series.label + ', first point: ' + firstcoordinate);
77
+
78
+            // let's add it to our current data
79
+            if (!alreadyFetched[series.label]) {
80
+                alreadyFetched[series.label] = true;
81
+                data.push(series);
82
+            }
83
+            
84
+            // and plot all we got
85
+            $.plot(placeholder, data, options);
86
+         }
87
+        
88
+        $.ajax({
89
+            url: dataurl,
90
+            method: 'GET',
91
+            dataType: 'json',
92
+            success: onDataReceived
93
+        });
94
+    });
95
+
96
+
97
+    // initiate a recurring data update
98
+    $("input.dataUpdate").click(function () {
99
+        // reset data
100
+        data = [];
101
+        alreadyFetched = {};
102
+        
103
+        $.plot(placeholder, data, options);
104
+
105
+        var iteration = 0;
106
+        
107
+        function fetchData() {
108
+            ++iteration;
109
+
110
+            function onDataReceived(series) {
111
+                // we get all the data in one go, if we only got partial
112
+                // data, we could merge it with what we already got
113
+                data = [ series ];
114
+                
115
+                $.plot($("#placeholder"), data, options);
116
+            }
117
+        
118
+            $.ajax({
119
+                // usually, we'll just call the same URL, a script
120
+                // connected to a database, but in this case we only
121
+                // have static example files so we need to modify the
122
+                // URL
123
+                url: "data-eu-gdp-growth-" + iteration + ".json",
124
+                method: 'GET',
125
+                dataType: 'json',
126
+                success: onDataReceived
127
+            });
128
+            
129
+            if (iteration < 5)
130
+                setTimeout(fetchData, 1000);
131
+            else {
132
+                data = [];
133
+                alreadyFetched = {};
134
+            }
135
+        }
136
+
137
+        setTimeout(fetchData, 1000);
138
+    });
139
+});
140
+</script>
141
+
142
+ </body>
143
+</html>

+ 75
- 0
flot/examples/annotating.html 查看文件

@@ -0,0 +1,75 @@
1
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2
+<html>
3
+ <head>
4
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+    <title>Flot Examples</title>
6
+    <link href="layout.css" rel="stylesheet" type="text/css"></link>
7
+    <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
8
+    <script language="javascript" type="text/javascript" src="../jquery.js"></script>
9
+    <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
10
+ </head>
11
+    <body>
12
+    <h1>Flot Examples</h1>
13
+
14
+    <div id="placeholder" style="width:600px;height:300px;"></div>
15
+
16
+    <p>Flot has support for simple background decorations such as
17
+    lines and rectangles. They can be useful for marking up certain
18
+    areas. You can easily add any HTML you need with standard DOM
19
+    manipulation, e.g. for labels. For drawing custom shapes there is
20
+    also direct access to the canvas.</p>
21
+
22
+<script id="source" language="javascript" type="text/javascript">
23
+$(function () {
24
+    // generate a dataset
25
+    var d1 = [];
26
+    for (var i = 0; i < 20; ++i)
27
+        d1.push([i, Math.sin(i)]);
28
+    
29
+    var data = [{ data: d1, label: "Pressure", color: "#333" }];
30
+
31
+    // setup background areas
32
+    var markings = [
33
+        { color: '#f6f6f6', yaxis: { from: 1 } },
34
+        { color: '#f6f6f6', yaxis: { to: -1 } },
35
+        { color: '#000', lineWidth: 1, xaxis: { from: 2, to: 2 } },
36
+        { color: '#000', lineWidth: 1, xaxis: { from: 8, to: 8 } }
37
+    ];
38
+    
39
+    var placeholder = $("#placeholder");
40
+    
41
+    // plot it
42
+    var plot = $.plot(placeholder, data, {
43
+        bars: { show: true, barWidth: 0.5, fill: 0.9 },
44
+        xaxis: { ticks: [], autoscaleMargin: 0.02 },
45
+        yaxis: { min: -2, max: 2 },
46
+        grid: { markings: markings }
47
+    });
48
+
49
+    // add labels
50
+    var o;
51
+
52
+    o = plot.pointOffset({ x: 2, y: -1.2});
53
+    // we just append it to the placeholder which Flot already uses
54
+    // for positioning
55
+    placeholder.append('<div style="position:absolute;left:' + (o.left + 4) + 'px;top:' + o.top + 'px;color:#666;font-size:smaller">Warming up</div>');
56
+
57
+    o = plot.pointOffset({ x: 8, y: -1.2});
58
+    placeholder.append('<div style="position:absolute;left:' + (o.left + 4) + 'px;top:' + o.top + 'px;color:#666;font-size:smaller">Actual measurements</div>');
59
+
60
+    // draw a little arrow on top of the last label to demonstrate
61
+    // canvas drawing
62
+    var ctx = plot.getCanvas().getContext("2d");
63
+    ctx.beginPath();
64
+    o.left += 4;
65
+    ctx.moveTo(o.left, o.top);
66
+    ctx.lineTo(o.left, o.top - 10);
67
+    ctx.lineTo(o.left + 10, o.top - 5);
68
+    ctx.lineTo(o.left, o.top);
69
+    ctx.fillStyle = "#000";
70
+    ctx.fill();
71
+});
72
+</script>
73
+
74
+ </body>
75
+</html>

二進制
flot/examples/arrow-down.gif 查看文件


二進制
flot/examples/arrow-left.gif 查看文件


二進制
flot/examples/arrow-right.gif 查看文件


二進制
flot/examples/arrow-up.gif 查看文件


+ 38
- 0
flot/examples/basic.html 查看文件

@@ -0,0 +1,38 @@
1
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2
+<html>
3
+ <head>
4
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+    <title>Flot Examples</title>
6
+    <link href="layout.css" rel="stylesheet" type="text/css"></link>
7
+    <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
8
+    <script language="javascript" type="text/javascript" src="../jquery.js"></script>
9
+    <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
10
+ </head>
11
+    <body>
12
+    <h1>Flot Examples</h1>
13
+
14
+    <div id="placeholder" style="width:600px;height:300px;"></div>
15
+
16
+    <p>Simple example. You don't need to specify much to get an
17
+       attractive look. Put in a placeholder, make sure you set its
18
+       dimensions (otherwise the plot library will barf) and call the
19
+       plot function with the data. The axes are automatically
20
+       scaled.</p>
21
+
22
+<script id="source" language="javascript" type="text/javascript">
23
+$(function () {
24
+    var d1 = [];
25
+    for (var i = 0; i < 14; i += 0.5)
26
+        d1.push([i, Math.sin(i)]);
27
+
28
+    var d2 = [[0, 3], [4, 8], [8, 5], [9, 13]];
29
+
30
+    // a null signifies separate line segments
31
+    var d3 = [[0, 12], [7, 12], null, [7, 2.5], [12, 2.5]];
32
+    
33
+    $.plot($("#placeholder"), [ d1, d2, d3 ]);
34
+});
35
+</script>
36
+
37
+ </body>
38
+</html>

+ 4
- 0
flot/examples/data-eu-gdp-growth-1.json 查看文件

@@ -0,0 +1,4 @@
1
+{
2
+    label: 'Europe (EU27)',
3
+    data: [[1999, 3.0], [2000, 3.9]]
4
+}

+ 4
- 0
flot/examples/data-eu-gdp-growth-2.json 查看文件

@@ -0,0 +1,4 @@
1
+{
2
+    label: 'Europe (EU27)',
3
+    data: [[1999, 3.0], [2000, 3.9], [2001, 2.0], [2002, 1.2]]
4
+}

+ 4
- 0
flot/examples/data-eu-gdp-growth-3.json 查看文件

@@ -0,0 +1,4 @@
1
+{
2
+    label: 'Europe (EU27)',
3
+    data: [[1999, 3.0], [2000, 3.9], [2001, 2.0], [2002, 1.2], [2003, 1.3], [2004, 2.5]]
4
+}

+ 4
- 0
flot/examples/data-eu-gdp-growth-4.json 查看文件

@@ -0,0 +1,4 @@
1
+{
2
+    label: 'Europe (EU27)',
3
+    data: [[1999, 3.0], [2000, 3.9], [2001, 2.0], [2002, 1.2], [2003, 1.3], [2004, 2.5], [2005, 2.0], [2006, 3.1]]
4
+}

+ 4
- 0
flot/examples/data-eu-gdp-growth-5.json 查看文件

@@ -0,0 +1,4 @@
1
+{
2
+    label: 'Europe (EU27)',
3
+    data: [[1999, 3.0], [2000, 3.9], [2001, 2.0], [2002, 1.2], [2003, 1.3], [2004, 2.5], [2005, 2.0], [2006, 3.1], [2007, 2.9], [2008, 0.9]]
4
+}

+ 4
- 0
flot/examples/data-eu-gdp-growth.json 查看文件

@@ -0,0 +1,4 @@
1
+{
2
+    label: 'Europe (EU27)',
3
+    data: [[1999, 3.0], [2000, 3.9], [2001, 2.0], [2002, 1.2], [2003, 1.3], [2004, 2.5], [2005, 2.0], [2006, 3.1], [2007, 2.9], [2008, 0.9]]
4
+}

+ 4
- 0
flot/examples/data-japan-gdp-growth.json 查看文件

@@ -0,0 +1,4 @@
1
+{
2
+    label: 'Japan',
3
+    data: [[1999, -0.1], [2000, 2.9], [2001, 0.2], [2002, 0.3], [2003, 1.4], [2004, 2.7], [2005, 1.9], [2006, 2.0], [2007, 2.3], [2008, -0.7]]
4
+}

+ 4
- 0
flot/examples/data-usa-gdp-growth.json 查看文件

@@ -0,0 +1,4 @@
1
+{
2
+    label: 'USA',
3
+    data: [[1999, 4.4], [2000, 3.7], [2001, 0.8], [2002, 1.6], [2003, 2.5], [2004, 3.6], [2005, 2.9], [2006, 2.8], [2007, 2.0], [2008, 1.1]]
4
+}

+ 39
- 0
flot/examples/dual-axis.html
文件差異過大導致無法顯示
查看文件


+ 75
- 0
flot/examples/graph-types.html 查看文件

@@ -0,0 +1,75 @@
1
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2
+<html>
3
+ <head>
4
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+    <title>Flot Examples</title>
6
+    <link href="layout.css" rel="stylesheet" type="text/css"></link>
7
+    <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
8
+    <script language="javascript" type="text/javascript" src="../jquery.js"></script>
9
+    <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
10
+ </head>
11
+    <body>
12
+    <h1>Flot Examples</h1>
13
+
14
+    <div id="placeholder" style="width:600px;height:300px"></div>
15
+
16
+    <p>Flot supports lines, points, filled areas, bars and any
17
+    combinations of these, in the same plot and even on the same data
18
+    series.</p>
19
+
20
+<script id="source" language="javascript" type="text/javascript">
21
+$(function () {
22
+    var d1 = [];
23
+    for (var i = 0; i < 14; i += 0.5)
24
+        d1.push([i, Math.sin(i)]);
25
+
26
+    var d2 = [[0, 3], [4, 8], [8, 5], [9, 13]];
27
+
28
+    var d3 = [];
29
+    for (var i = 0; i < 14; i += 0.5)
30
+        d3.push([i, Math.cos(i)]);
31
+
32
+    var d4 = [];
33
+    for (var i = 0; i < 14; i += 0.1)
34
+        d4.push([i, Math.sqrt(i * 10)]);
35
+    
36
+    var d5 = [];
37
+    for (var i = 0; i < 14; i += 0.5)
38
+        d5.push([i, Math.sqrt(i)]);
39
+
40
+    var d6 = [];
41
+    for (var i = 0; i < 14; i += 0.5 + Math.random())
42
+        d6.push([i, Math.sqrt(2*i + Math.sin(i) + 5)]);
43
+                        
44
+    $.plot($("#placeholder"), [
45
+        {
46
+            data: d1,
47
+            lines: { show: true, fill: true }
48
+        },
49
+        {
50
+            data: d2,
51
+            bars: { show: true }
52
+        },
53
+        {
54
+            data: d3,
55
+            points: { show: true }
56
+        },
57
+        {
58
+            data: d4,
59
+            lines: { show: true }
60
+        },
61
+        {
62
+            data: d5,
63
+            lines: { show: true },
64
+            points: { show: true }
65
+        },
66
+        {
67
+            data: d6,
68
+            lines: { show: true, steps: true }
69
+        }
70
+    ]);
71
+});
72
+</script>
73
+
74
+ </body>
75
+</html>

二進制
flot/examples/hs-2004-27-a-large_web.jpg 查看文件


+ 45
- 0
flot/examples/image.html 查看文件

@@ -0,0 +1,45 @@
1
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2
+<html>
3
+ <head>
4
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+    <title>Flot Examples</title>
6
+    <link href="layout.css" rel="stylesheet" type="text/css"></link>
7
+    <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
8
+    <script language="javascript" type="text/javascript" src="../jquery.js"></script>
9
+    <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
10
+    <script language="javascript" type="text/javascript" src="../jquery.flot.image.js"></script>
11
+ </head>
12
+ <body>
13
+    <h1>Flot Examples</h1>
14
+
15
+    <div id="placeholder" style="width:400px;height:400px;"></div>
16
+
17
+    <p>The Cat's Eye Nebula (<a href="http://hubblesite.org/gallery/album/nebula/pr2004027a/">picture from Hubble</a>).</p>
18
+    
19
+    <p>With the image plugin, you can plot images. This is for example
20
+    useful for getting ticks on complex prerendered visualizations.
21
+    Instead of inputting data points, you put in the images and where
22
+    their two opposite corners are supposed to be in plot space.</p>
23
+
24
+    <p>Images represent a little further complication because you need
25
+    to make sure they are loaded before you can use them (Flot skips
26
+    incomplete images). The plugin comes with a couple of helpers
27
+    for doing that.</p>
28
+
29
+<script id="source" language="javascript" type="text/javascript">
30
+$(function () {
31
+    var data = [ [ ["hs-2004-27-a-large_web.jpg", -10, -10, 10, 10] ] ];
32
+    var options = {
33
+            series: { images: { show: true } },
34
+            xaxis: { min: -8, max: 4 },
35
+            yaxis: { min: -8, max: 4 }
36
+    };
37
+
38
+    $.plot.image.loadDataImages(data, options, function () {
39
+        $.plot($("#placeholder"), data, options);
40
+    });
41
+});
42
+</script>
43
+
44
+ </body>
45
+</html>

+ 43
- 0
flot/examples/index.html 查看文件

@@ -0,0 +1,43 @@
1
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2
+<html>
3
+ <head>
4
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+    <title>Flot Examples</title>
6
+    <link href="layout.css" rel="stylesheet" type="text/css"></link>
7
+    <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
8
+    <script language="javascript" type="text/javascript" src="../jquery.js"></script>
9
+    <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
10
+ </head>
11
+ <body>
12
+    <h1>Flot Examples</h1>
13
+
14
+    <p>Here are some examples for <a href="http://code.google.com/p/flot/">Flot</a>, the Javascript charting library for jQuery:</p>
15
+
16
+    <ul>
17
+      <li><a href="basic.html">Basic example</a></li>
18
+      <li><a href="graph-types.html">Different graph types</a></li>
19
+      <li><a href="setting-options.html">Setting various options</a> and <a href="annotating.html">annotating a chart</a></li>
20
+      <li><a href="ajax.html">Updating graphs with AJAX</a></li>
21
+    </ul>
22
+
23
+    <p>Being interactive:</p>
24
+    
25
+    <ul>
26
+      <li><a href="turning-series.html">Turning series on/off</a></li>
27
+      <li><a href="selection.html">Rectangular selection support and zooming</a> and <a href="zooming.html">zooming with overview</a></li> (both with selection plugin)
28
+      <li><a href="interacting.html">Interacting with the data points</a></li>
29
+      <li><a href="navigate.html">Panning and zooming</a> (with navigation plugin)</li>
30
+    </ul>
31
+
32
+    <p>Some more esoteric features:</p>
33
+    
34
+    <ul>
35
+      <li><a href="time.html">Plotting time series</a> and <a href="visitors.html">visitors per day with zooming and weekends</a> (with selection plugin)</li>
36
+      <li><a href="dual-axis.html">Dual axis support</a></li>
37
+      <li><a href="thresholding.html">Thresholding the data</a> (with threshold plugin)</li>
38
+      <li><a href="stacking.html">Stacked charts</a> (with stacking plugin)</li>
39
+      <li><a href="tracking.html">Tracking curves with crosshair</a> (with crosshair plugin)</li>
40
+      <li><a href="image.html">Plotting prerendered images</a> (with image plugin)</li>
41
+    </ul>
42
+ </body>
43
+</html>

+ 93
- 0
flot/examples/interacting.html 查看文件

@@ -0,0 +1,93 @@
1
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2
+<html>
3
+ <head>
4
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+    <title>Flot Examples</title>
6
+    <link href="layout.css" rel="stylesheet" type="text/css"></link>
7
+    <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
8
+    <script language="javascript" type="text/javascript" src="../jquery.js"></script>
9
+    <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
10
+ </head>
11
+    <body>
12
+    <h1>Flot Examples</h1>
13
+
14
+    <div id="placeholder" style="width:600px;height:300px"></div>
15
+
16
+    <p>One of the goals of Flot is to support user interactions. Try
17
+    pointing and clicking on the points.</p>
18
+
19
+    <p id="hoverdata">Mouse hovers at
20
+    (<span id="x">0</span>, <span id="y">0</span>). <span id="clickdata"></span></p>
21
+
22
+    <p>A tooltip is easy to build with a bit of jQuery code and the
23
+    data returned from the plot.</p>
24
+
25
+    <p><input id="enableTooltip" type="checkbox">Enable tooltip</p>
26
+
27
+<script id="source" language="javascript" type="text/javascript">
28
+$(function () {
29
+    var sin = [], cos = [];
30
+    for (var i = 0; i < 14; i += 0.5) {
31
+        sin.push([i, Math.sin(i)]);
32
+        cos.push([i, Math.cos(i)]);
33
+    }
34
+
35
+    var plot = $.plot($("#placeholder"),
36
+           [ { data: sin, label: "sin(x)"}, { data: cos, label: "cos(x)" } ], {
37
+               series: {
38
+                   lines: { show: true },
39
+                   points: { show: true }
40
+               },
41
+               grid: { hoverable: true, clickable: true },
42
+               yaxis: { min: -1.2, max: 1.2 }
43
+             });
44
+
45
+    function showTooltip(x, y, contents) {
46
+        $('<div id="tooltip">' + contents + '</div>').css( {
47
+            position: 'absolute',
48
+            display: 'none',
49
+            top: y + 5,
50
+            left: x + 5,
51
+            border: '1px solid #fdd',
52
+            padding: '2px',
53
+            'background-color': '#fee',
54
+            opacity: 0.80
55
+        }).appendTo("body").fadeIn(200);
56
+    }
57
+
58
+    var previousPoint = null;
59
+    $("#placeholder").bind("plothover", function (event, pos, item) {
60
+        $("#x").text(pos.x.toFixed(2));
61
+        $("#y").text(pos.y.toFixed(2));
62
+
63
+        if ($("#enableTooltip:checked").length > 0) {
64
+            if (item) {
65
+                if (previousPoint != item.datapoint) {
66
+                    previousPoint = item.datapoint;
67
+                    
68
+                    $("#tooltip").remove();
69
+                    var x = item.datapoint[0].toFixed(2),
70
+                        y = item.datapoint[1].toFixed(2);
71
+                    
72
+                    showTooltip(item.pageX, item.pageY,
73
+                                item.series.label + " of " + x + " = " + y);
74
+                }
75
+            }
76
+            else {
77
+                $("#tooltip").remove();
78
+                previousPoint = null;            
79
+            }
80
+        }
81
+    });
82
+
83
+    $("#placeholder").bind("plotclick", function (event, pos, item) {
84
+        if (item) {
85
+            $("#clickdata").text("You clicked point " + item.dataIndex + " in " + item.series.label + ".");
86
+            plot.highlight(item.series, item.datapoint);
87
+        }
88
+    });
89
+});
90
+</script>
91
+
92
+ </body>
93
+</html>

+ 6
- 0
flot/examples/layout.css 查看文件

@@ -0,0 +1,6 @@
1
+body {
2
+  font-family: sans-serif;
3
+  font-size: 16px;
4
+  margin: 50px;
5
+  max-width: 800px;
6
+}

+ 118
- 0
flot/examples/navigate.html 查看文件

@@ -0,0 +1,118 @@
1
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2
+<html>
3
+ <head>
4
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+    <title>Flot Examples</title>
6
+    <link href="layout.css" rel="stylesheet" type="text/css"></link>
7
+    <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
8
+    <script language="javascript" type="text/javascript" src="../jquery.js"></script>
9
+    <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
10
+    <script language="javascript" type="text/javascript" src="../jquery.flot.navigate.js"></script>
11
+    <style>
12
+    #placeholder .button {
13
+        position: absolute;
14
+        cursor: pointer;
15
+    }
16
+    #placeholder div.button {
17
+        font-size: smaller;
18
+        color: #999;
19
+        background-color: #eee;
20
+        padding: 2px;
21
+    }
22
+    .message {
23
+        padding-left: 50px;
24
+        font-size: smaller;
25
+    }
26
+    </style>
27
+ </head>
28
+ <body>
29
+    <h1>Flot Examples</h1>
30
+
31
+    <div id="placeholder" style="width:600px;height:300px;"></div>
32
+
33
+    <p class="message"></p>
34
+
35
+    <p>With the navigate plugin it is easy to add panning and zooming.
36
+    Drag to pan, double click to zoom (or use the mouse scrollwheel).</p>
37
+
38
+    <p>The plugin fires events (useful for synchronizing several
39
+    plots) and adds a couple of public methods so you can easily build
40
+    a little user interface around it, like the little buttons at the
41
+    top right in the plot.</p>
42
+    
43
+
44
+<script id="source" language="javascript" type="text/javascript">
45
+$(function () {
46
+    // generate data set from a parametric function with a fractal
47
+    // look
48
+    function sumf(f, t, m) {
49
+        var res = 0;
50
+        for (var i = 1; i < m; ++i)
51
+            res += f(i * i * t) / (i * i);
52
+        return res;
53
+    }
54
+    
55
+    var d1 = [];
56
+    for (var t = 0; t <= 2 * Math.PI; t += 0.01)
57
+        d1.push([sumf(Math.cos, t, 10), sumf(Math.sin, t, 10)]);
58
+    var data = [ d1 ];
59
+
60
+    
61
+    var placeholder = $("#placeholder");
62
+    var options = {
63
+        series: { lines: { show: true }, shadowSize: 0 },
64
+        xaxis: { zoomRange: [0.1, 10], panRange: [-10, 10] },
65
+        yaxis: { zoomRange: [0.1, 10], panRange: [-10, 10] },
66
+        zoom: {
67
+            interactive: true
68
+        },
69
+        pan: {
70
+            interactive: true
71
+        }
72
+    };
73
+
74
+    var plot = $.plot(placeholder, data, options);
75
+
76
+    // show pan/zoom messages to illustrate events 
77
+    placeholder.bind('plotpan', function (event, plot) {
78
+        var axes = plot.getAxes();
79
+        $(".message").html("Panning to x: "  + axes.xaxis.min.toFixed(2)
80
+                           + " &ndash; " + axes.xaxis.max.toFixed(2)
81
+                           + " and y: " + axes.yaxis.min.toFixed(2)
82
+                           + " &ndash; " + axes.yaxis.max.toFixed(2));
83
+    });
84
+
85
+    placeholder.bind('plotzoom', function (event, plot) {
86
+        var axes = plot.getAxes();
87
+        $(".message").html("Zooming to x: "  + axes.xaxis.min.toFixed(2)
88
+                           + " &ndash; " + axes.xaxis.max.toFixed(2)
89
+                           + " and y: " + axes.yaxis.min.toFixed(2)
90
+                           + " &ndash; " + axes.yaxis.max.toFixed(2));
91
+    });
92
+
93
+    // add zoom out button 
94
+    $('<div class="button" style="right:20px;top:20px">zoom out</div>').appendTo(placeholder).click(function (e) {
95
+        e.preventDefault();
96
+        plot.zoomOut();
97
+    });
98
+
99
+    // and add panning buttons
100
+    
101
+    // little helper for taking the repetitive work out of placing
102
+    // panning arrows
103
+    function addArrow(dir, right, top, offset) {
104
+        $('<img class="button" src="arrow-' + dir + '.gif" style="right:' + right + 'px;top:' + top + 'px">').appendTo(placeholder).click(function (e) {
105
+            e.preventDefault();
106
+            plot.pan(offset);
107
+        });
108
+    }
109
+
110
+    addArrow('left', 55, 60, { left: -100 });
111
+    addArrow('right', 25, 60, { left: 100 });
112
+    addArrow('up', 40, 45, { top: -100 });
113
+    addArrow('down', 40, 75, { top: 100 });
114
+});
115
+</script>
116
+
117
+ </body>
118
+</html>

+ 114
- 0
flot/examples/selection.html 查看文件

@@ -0,0 +1,114 @@
1
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2
+<html>
3
+ <head>
4
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+    <title>Flot Examples</title>
6
+    <link href="layout.css" rel="stylesheet" type="text/css"></link>
7
+    <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
8
+    <script language="javascript" type="text/javascript" src="../jquery.js"></script>
9
+    <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
10
+    <script language="javascript" type="text/javascript" src="../jquery.flot.selection.js"></script>
11
+ </head>
12
+    <body>
13
+    <h1>Flot Examples</h1>
14
+
15
+    <div id="placeholder" style="width:600px;height:300px"></div>
16
+
17
+    <p>1000 kg. CO<sub>2</sub> emissions per year per capita for various countries (source: <a href="http://en.wikipedia.org/wiki/List_of_countries_by_carbon_dioxide_emissions_per_capita">Wikipedia</a>).</p>
18
+
19
+    <p>Flot supports selections through the selection plugin.
20
+       You can enable rectangular selection
21
+       or one-dimensional selection if the user should only be able to
22
+       select on one axis. Try left-click and drag on the plot above
23
+       where selection on the x axis is enabled.</p>
24
+
25
+    <p>You selected: <span id="selection"></span></p>
26
+
27
+    <p>The plot command returns a plot object you can use to control
28
+       the selection. Click the buttons below.</p>
29
+
30
+    <p><input id="clearSelection" type="button" value="Clear selection" />
31
+       <input id="setSelection" type="button" value="Select year 1994" /></p>
32
+
33
+    <p>Selections are really useful for zooming. Just replot the
34
+       chart with min and max values for the axes set to the values
35
+       in the "plotselected" event triggered. Enable the checkbox
36
+       below and select a region again.</p>
37
+
38
+    <p><input id="zoom" type="checkbox">Zoom to selection.</input></p>
39
+
40
+<script id="source" language="javascript" type="text/javascript">
41
+$(function () {
42
+    var data = [
43
+        {
44
+            label: "United States",
45
+            data: [[1990, 18.9], [1991, 18.7], [1992, 18.4], [1993, 19.3], [1994, 19.5], [1995, 19.3], [1996, 19.4], [1997, 20.2], [1998, 19.8], [1999, 19.9], [2000, 20.4], [2001, 20.1], [2002, 20.0], [2003, 19.8], [2004, 20.4]]
46
+        },
47
+        {
48
+            label: "Russia", 
49
+            data: [[1992, 13.4], [1993, 12.2], [1994, 10.6], [1995, 10.2], [1996, 10.1], [1997, 9.7], [1998, 9.5], [1999, 9.7], [2000, 9.9], [2001, 9.9], [2002, 9.9], [2003, 10.3], [2004, 10.5]]
50
+        },
51
+        {
52
+            label: "United Kingdom",
53
+            data: [[1990, 10.0], [1991, 11.3], [1992, 9.9], [1993, 9.6], [1994, 9.5], [1995, 9.5], [1996, 9.9], [1997, 9.3], [1998, 9.2], [1999, 9.2], [2000, 9.5], [2001, 9.6], [2002, 9.3], [2003, 9.4], [2004, 9.79]]
54
+        },
55
+        {
56
+            label: "Germany",
57
+            data: [[1990, 12.4], [1991, 11.2], [1992, 10.8], [1993, 10.5], [1994, 10.4], [1995, 10.2], [1996, 10.5], [1997, 10.2], [1998, 10.1], [1999, 9.6], [2000, 9.7], [2001, 10.0], [2002, 9.7], [2003, 9.8], [2004, 9.79]]
58
+        },
59
+        {
60
+            label: "Denmark",
61
+ 	    data: [[1990, 9.7], [1991, 12.1], [1992, 10.3], [1993, 11.3], [1994, 11.7], [1995, 10.6], [1996, 12.8], [1997, 10.8], [1998, 10.3], [1999, 9.4], [2000, 8.7], [2001, 9.0], [2002, 8.9], [2003, 10.1], [2004, 9.80]]
62
+        },
63
+        {
64
+            label: "Sweden",
65
+            data: [[1990, 5.8], [1991, 6.0], [1992, 5.9], [1993, 5.5], [1994, 5.7], [1995, 5.3], [1996, 6.1], [1997, 5.4], [1998, 5.4], [1999, 5.1], [2000, 5.2], [2001, 5.4], [2002, 6.2], [2003, 5.9], [2004, 5.89]]
66
+        },
67
+        {
68
+            label: "Norway",
69
+            data: [[1990, 8.3], [1991, 8.3], [1992, 7.8], [1993, 8.3], [1994, 8.4], [1995, 5.9], [1996, 6.4], [1997, 6.7], [1998, 6.9], [1999, 7.6], [2000, 7.4], [2001, 8.1], [2002, 12.5], [2003, 9.9], [2004, 19.0]]
70
+        }
71
+    ];
72
+
73
+    var options = {
74
+        series: {
75
+            lines: { show: true },
76
+            points: { show: true }
77
+        },
78
+        legend: { noColumns: 2 },
79
+        xaxis: { tickDecimals: 0 },
80
+        yaxis: { min: 0 },
81
+        selection: { mode: "x" }
82
+    };
83
+
84
+    var placeholder = $("#placeholder");
85
+
86
+    placeholder.bind("plotselected", function (event, ranges) {
87
+        $("#selection").text(ranges.xaxis.from.toFixed(1) + " to " + ranges.xaxis.to.toFixed(1));
88
+
89
+        var zoom = $("#zoom").attr("checked");
90
+        if (zoom)
91
+            plot = $.plot(placeholder, data,
92
+                          $.extend(true, {}, options, {
93
+                              xaxis: { min: ranges.xaxis.from, max: ranges.xaxis.to }
94
+                          }));
95
+    });
96
+
97
+    placeholder.bind("plotunselected", function (event) {
98
+        $("#selection").text("");
99
+    });
100
+    
101
+    var plot = $.plot(placeholder, data, options);
102
+
103
+    $("#clearSelection").click(function () {
104
+        plot.clearSelection();
105
+    });
106
+
107
+    $("#setSelection").click(function () {
108
+        plot.setSelection({ x1: 1994, x2: 1995 });
109
+    });
110
+});
111
+</script>
112
+
113
+ </body>
114
+</html>

+ 65
- 0
flot/examples/setting-options.html 查看文件

@@ -0,0 +1,65 @@
1
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2
+<html>
3
+ <head>
4
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+    <title>Flot Examples</title>
6
+    <link href="layout.css" rel="stylesheet" type="text/css"></link>
7
+    <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
8
+    <script language="javascript" type="text/javascript" src="../jquery.js"></script>
9
+    <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
10
+ </head>
11
+    <body>
12
+    <h1>Flot Examples</h1>
13
+
14
+    <div id="placeholder" style="width:600px;height:300px"></div>
15
+
16
+    <p>There are plenty of options you can set to control the precise
17
+    looks of your plot. You can control the axes, the legend, the
18
+    default graph type, the look of grid, etc.</p>
19
+
20
+    <p>The idea is that Flot goes to great lengths to provide <b>sensible
21
+    defaults</b> which you can then customize as needed for your
22
+    particular application. If you've found a use case where the
23
+    defaults can be improved, please don't hesitate to give your
24
+    feedback.</p>
25
+
26
+<script id="source" language="javascript" type="text/javascript">
27
+$(function () {
28
+    var d1 = [];
29
+    for (var i = 0; i < Math.PI * 2; i += 0.25)
30
+        d1.push([i, Math.sin(i)]);
31
+    
32
+    var d2 = [];
33
+    for (var i = 0; i < Math.PI * 2; i += 0.25)
34
+        d2.push([i, Math.cos(i)]);
35
+
36
+    var d3 = [];
37
+    for (var i = 0; i < Math.PI * 2; i += 0.1)
38
+        d3.push([i, Math.tan(i)]);
39
+    
40
+    $.plot($("#placeholder"), [
41
+        { label: "sin(x)",  data: d1},
42
+        { label: "cos(x)",  data: d2},
43
+        { label: "tan(x)",  data: d3}
44
+    ], {
45
+        series: {
46
+            lines: { show: true },
47
+            points: { show: true }
48
+        },
49
+        xaxis: {
50
+            ticks: [0, [Math.PI/2, "\u03c0/2"], [Math.PI, "\u03c0"], [Math.PI * 3/2, "3\u03c0/2"], [Math.PI * 2, "2\u03c0"]]
51
+        },
52
+        yaxis: {
53
+            ticks: 10,
54
+            min: -2,
55
+            max: 2
56
+        },
57
+        grid: {
58
+            backgroundColor: { colors: ["#fff", "#eee"] }
59
+        }
60
+    });
61
+});
62
+</script>
63
+
64
+ </body>
65
+</html>

+ 77
- 0
flot/examples/stacking.html 查看文件

@@ -0,0 +1,77 @@
1
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2
+<html>
3
+ <head>
4
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+    <title>Flot Examples</title>
6
+    <link href="layout.css" rel="stylesheet" type="text/css"></link>
7
+    <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
8
+    <script language="javascript" type="text/javascript" src="../jquery.js"></script>
9
+    <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
10
+    <script language="javascript" type="text/javascript" src="../jquery.flot.stack.js"></script>
11
+ </head>
12
+    <body>
13
+    <h1>Flot Examples</h1>
14
+
15
+    <div id="placeholder" style="width:600px;height:300px;"></div>
16
+
17
+    <p>With the stack plugin, you can have Flot stack the
18
+    series. This is useful if you wish to display both a total and the
19
+    constituents it is made of. The only requirement is that you provide
20
+    the input sorted on x.</p>
21
+
22
+    <p class="stackControls">
23
+    <input type="button" value="With stacking">
24
+    <input type="button" value="Without stacking">
25
+    </p>
26
+
27
+    <p class="graphControls">
28
+    <input type="button" value="Bars">
29
+    <input type="button" value="Lines">
30
+    <input type="button" value="Lines with steps">
31
+    </p>
32
+
33
+<script id="source">
34
+$(function () {
35
+    var d1 = [];
36
+    for (var i = 0; i <= 10; i += 1)
37
+        d1.push([i, parseInt(Math.random() * 30)]);
38
+
39
+    var d2 = [];
40
+    for (var i = 0; i <= 10; i += 1)
41
+        d2.push([i, parseInt(Math.random() * 30)]);
42
+
43
+    var d3 = [];
44
+    for (var i = 0; i <= 10; i += 1)
45
+        d3.push([i, parseInt(Math.random() * 30)]);
46
+
47
+    var stack = 0, bars = true, lines = false, steps = false;
48
+    
49
+    function plotWithOptions() {
50
+        $.plot($("#placeholder"), [ d1, d2, d3 ], {
51
+            series: {
52
+                stack: stack,
53
+                lines: { show: lines, steps: steps },
54
+                bars: { show: bars, barWidth: 0.6 }
55
+            }
56
+        });
57
+    }
58
+
59
+    plotWithOptions();
60
+    
61
+    $(".stackControls input").click(function (e) {
62
+        e.preventDefault();
63
+        stack = $(this).val() == "With stacking" ? true : null;
64
+        plotWithOptions();
65
+    });
66
+    $(".graphControls input").click(function (e) {
67
+        e.preventDefault();
68
+        bars = $(this).val().indexOf("Bars") != -1;
69
+        lines = $(this).val().indexOf("Lines") != -1;
70
+        steps = $(this).val().indexOf("steps") != -1;
71
+        plotWithOptions();
72
+    });
73
+});
74
+</script>
75
+
76
+ </body>
77
+</html>

+ 54
- 0
flot/examples/thresholding.html 查看文件

@@ -0,0 +1,54 @@
1
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2
+<html>
3
+ <head>
4
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+    <title>Flot Examples</title>
6
+    <link href="layout.css" rel="stylesheet" type="text/css"></link>
7
+    <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
8
+    <script language="javascript" type="text/javascript" src="../jquery.js"></script>
9
+    <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
10
+    <script language="javascript" type="text/javascript" src="../jquery.flot.threshold.js"></script>
11
+ </head>
12
+    <body>
13
+    <h1>Flot Examples</h1>
14
+
15
+    <div id="placeholder" style="width:600px;height:300px;"></div>
16
+
17
+    <p>With the threshold plugin, you can apply a specific color to
18
+    the part of a data series below a threshold. This is can be useful
19
+    for highlighting negative values, e.g. when displaying net results
20
+    or what's in stock.</p>
21
+
22
+    <p class="controls">
23
+    <input type="button" value="Threshold at 5">
24
+    <input type="button" value="Threshold at 0">
25
+    <input type="button" value="Threshold at -2.5">
26
+    </p>
27
+
28
+<script id="source" language="javascript" type="text/javascript">
29
+$(function () {
30
+    var d1 = [];
31
+    for (var i = 0; i <= 60; i += 1)
32
+        d1.push([i, parseInt(Math.random() * 30 - 10)]);
33
+
34
+    function plotWithOptions(t) {
35
+        $.plot($("#placeholder"), [ {
36
+            data: d1,
37
+            color: "rgb(30, 180, 20)",
38
+            threshold: { below: t, color: "rgb(200, 20, 30)" },
39
+            lines: { steps: true }
40
+        } ]);
41
+    }
42
+
43
+    plotWithOptions(0);
44
+    
45
+    $(".controls input").click(function (e) {
46
+        e.preventDefault();
47
+        var t = parseFloat($(this).val().replace('Threshold at ', ''));
48
+        plotWithOptions(t);
49
+    });
50
+});
51
+</script>
52
+
53
+ </body>
54
+</html>

+ 71
- 0
flot/examples/time.html
文件差異過大導致無法顯示
查看文件


+ 95
- 0
flot/examples/tracking.html 查看文件

@@ -0,0 +1,95 @@
1
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2
+<html>
3
+ <head>
4
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+    <title>Flot Examples</title>
6
+    <link href="layout.css" rel="stylesheet" type="text/css"></link>
7
+    <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
8
+    <script language="javascript" type="text/javascript" src="../jquery.js"></script>
9
+    <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
10
+    <script language="javascript" type="text/javascript" src="../jquery.flot.crosshair.js"></script>
11
+ </head>
12
+    <body>
13
+    <h1>Flot Examples</h1>
14
+
15
+    <div id="placeholder" style="width:600px;height:300px"></div>
16
+
17
+    <p>You can add crosshairs that'll track the mouse position, either
18
+    on both axes or as here on only one.</p>
19
+
20
+    <p>If you combine it with listening on hover events, you can use
21
+    it to track the intersection on the curves by interpolating
22
+    the data points (look at the legend).</p>
23
+
24
+    <p id="hoverdata"></p>
25
+
26
+<script id="source" language="javascript" type="text/javascript">
27
+var plot;
28
+$(function () {
29
+    var sin = [], cos = [];
30
+    for (var i = 0; i < 14; i += 0.1) {
31
+        sin.push([i, Math.sin(i)]);
32
+        cos.push([i, Math.cos(i)]);
33
+    }
34
+
35
+    plot = $.plot($("#placeholder"),
36
+                      [ { data: sin, label: "sin(x) = -0.00"},
37
+                        { data: cos, label: "cos(x) = -0.00" } ], {
38
+                            series: {
39
+                                lines: { show: true }
40
+                            },
41
+                            crosshair: { mode: "x" },
42
+                            grid: { hoverable: true, autoHighlight: false },
43
+                            yaxis: { min: -1.2, max: 1.2 }
44
+                        });
45
+    var legends = $("#placeholder .legendLabel");
46
+    legends.each(function () {
47
+        // fix the widths so they don't jump around
48
+        $(this).css('width', $(this).width());
49
+    });
50
+
51
+    var updateLegendTimeout = null;
52
+    var latestPosition = null;
53
+    
54
+    function updateLegend() {
55
+        updateLegendTimeout = null;
56
+        
57
+        var pos = latestPosition;
58
+        
59
+        var axes = plot.getAxes();
60
+        if (pos.x < axes.xaxis.min || pos.x > axes.xaxis.max ||
61
+            pos.y < axes.yaxis.min || pos.y > axes.yaxis.max)
62
+            return;
63
+
64
+        var i, j, dataset = plot.getData();
65
+        for (i = 0; i < dataset.length; ++i) {
66
+            var series = dataset[i];
67
+
68
+            // find the nearest points, x-wise
69
+            for (j = 0; j < series.data.length; ++j)
70
+                if (series.data[j][0] > pos.x)
71
+                    break;
72
+            
73
+            // now interpolate
74
+            var y, p1 = series.data[j - 1], p2 = series.data[j];
75
+            if (p1 == null)
76
+                y = p2[1];
77
+            else if (p2 == null)
78
+                y = p1[1];
79
+            else
80
+                y = p1[1] + (p2[1] - p1[1]) * (pos.x - p1[0]) / (p2[0] - p1[0]);
81
+
82
+            legends.eq(i).text(series.label.replace(/=.*/, "= " + y.toFixed(2)));
83
+        }
84
+    }
85
+    
86
+    $("#placeholder").bind("plothover",  function (event, pos, item) {
87
+        latestPosition = pos;
88
+        if (!updateLegendTimeout)
89
+            updateLegendTimeout = setTimeout(updateLegend, 50);
90
+    });
91
+});
92
+</script>
93
+
94
+ </body>
95
+</html>

+ 98
- 0
flot/examples/turning-series.html 查看文件

@@ -0,0 +1,98 @@
1
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2
+<html>
3
+ <head>
4
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+    <title>Flot Examples</title>
6
+    <link href="layout.css" rel="stylesheet" type="text/css"></link>
7
+    <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
8
+    <script language="javascript" type="text/javascript" src="../jquery.js"></script>
9
+    <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
10
+ </head>
11
+    <body>
12
+    <h1>Flot Examples</h1>
13
+
14
+    <div id="placeholder" style="width:600px;height:300px;"></div>
15
+
16
+    <p>Here is an example with real data: military budgets for
17
+        various countries in constant (2005) million US dollars (source: <a href="http://www.sipri.org/">SIPRI</a>).</p>
18
+
19
+    <p>Since all data is available client-side, it's pretty easy to
20
+       make the plot interactive. Try turning countries on/off with the
21
+       checkboxes below.</p>
22
+
23
+    <p id="choices">Show:</p>
24
+
25
+<script id="source" language="javascript" type="text/javascript">
26
+$(function () {
27
+    var datasets = {
28
+        "usa": {
29
+            label: "USA",
30
+            data: [[1988, 483994], [1989, 479060], [1990, 457648], [1991, 401949], [1992, 424705], [1993, 402375], [1994, 377867], [1995, 357382], [1996, 337946], [1997, 336185], [1998, 328611], [1999, 329421], [2000, 342172], [2001, 344932], [2002, 387303], [2003, 440813], [2004, 480451], [2005, 504638], [2006, 528692]]
31
+        },        
32
+        "russia": {
33
+            label: "Russia",
34
+            data: [[1988, 218000], [1989, 203000], [1990, 171000], [1992, 42500], [1993, 37600], [1994, 36600], [1995, 21700], [1996, 19200], [1997, 21300], [1998, 13600], [1999, 14000], [2000, 19100], [2001, 21300], [2002, 23600], [2003, 25100], [2004, 26100], [2005, 31100], [2006, 34700]]
35
+        },
36
+        "uk": {
37
+            label: "UK",
38
+            data: [[1988, 62982], [1989, 62027], [1990, 60696], [1991, 62348], [1992, 58560], [1993, 56393], [1994, 54579], [1995, 50818], [1996, 50554], [1997, 48276], [1998, 47691], [1999, 47529], [2000, 47778], [2001, 48760], [2002, 50949], [2003, 57452], [2004, 60234], [2005, 60076], [2006, 59213]]
39
+        },
40
+        "germany": {
41
+            label: "Germany",
42
+            data: [[1988, 55627], [1989, 55475], [1990, 58464], [1991, 55134], [1992, 52436], [1993, 47139], [1994, 43962], [1995, 43238], [1996, 42395], [1997, 40854], [1998, 40993], [1999, 41822], [2000, 41147], [2001, 40474], [2002, 40604], [2003, 40044], [2004, 38816], [2005, 38060], [2006, 36984]]
43
+        },
44
+        "denmark": {
45
+            label: "Denmark",
46
+            data: [[1988, 3813], [1989, 3719], [1990, 3722], [1991, 3789], [1992, 3720], [1993, 3730], [1994, 3636], [1995, 3598], [1996, 3610], [1997, 3655], [1998, 3695], [1999, 3673], [2000, 3553], [2001, 3774], [2002, 3728], [2003, 3618], [2004, 3638], [2005, 3467], [2006, 3770]]
47
+        },
48
+        "sweden": {
49
+            label: "Sweden",
50
+            data: [[1988, 6402], [1989, 6474], [1990, 6605], [1991, 6209], [1992, 6035], [1993, 6020], [1994, 6000], [1995, 6018], [1996, 3958], [1997, 5780], [1998, 5954], [1999, 6178], [2000, 6411], [2001, 5993], [2002, 5833], [2003, 5791], [2004, 5450], [2005, 5521], [2006, 5271]]
51
+        },
52
+        "norway": {
53
+            label: "Norway",
54
+            data: [[1988, 4382], [1989, 4498], [1990, 4535], [1991, 4398], [1992, 4766], [1993, 4441], [1994, 4670], [1995, 4217], [1996, 4275], [1997, 4203], [1998, 4482], [1999, 4506], [2000, 4358], [2001, 4385], [2002, 5269], [2003, 5066], [2004, 5194], [2005, 4887], [2006, 4891]]
55
+        }
56
+    };
57
+
58
+    // hard-code color indices to prevent them from shifting as
59
+    // countries are turned on/off
60
+    var i = 0;
61
+    $.each(datasets, function(key, val) {
62
+        val.color = i;
63
+        ++i;
64
+    });
65
+    
66
+    // insert checkboxes 
67
+    var choiceContainer = $("#choices");
68
+    $.each(datasets, function(key, val) {
69
+        choiceContainer.append('<br/><input type="checkbox" name="' + key +
70
+                               '" checked="checked" id="id' + key + '">' +
71
+                               '<label for="id' + key + '">'
72
+                                + val.label + '</label>');
73
+    });
74
+    choiceContainer.find("input").click(plotAccordingToChoices);
75
+
76
+    
77
+    function plotAccordingToChoices() {
78
+        var data = [];
79
+
80
+        choiceContainer.find("input:checked").each(function () {
81
+            var key = $(this).attr("name");
82
+            if (key && datasets[key])
83
+                data.push(datasets[key]);
84
+        });
85
+
86
+        if (data.length > 0)
87
+            $.plot($("#placeholder"), data, {
88
+                yaxis: { min: 0 },
89
+                xaxis: { tickDecimals: 0 }
90
+            });
91
+    }
92
+
93
+    plotAccordingToChoices();
94
+});
95
+</script>
96
+
97
+ </body>
98
+</html>

+ 90
- 0
flot/examples/visitors.html 查看文件

@@ -0,0 +1,90 @@
1
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2
+<html>
3
+ <head>
4
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+    <title>Flot Examples</title>
6
+    <link href="layout.css" rel="stylesheet" type="text/css"></link>
7
+    <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
8
+    <script language="javascript" type="text/javascript" src="../jquery.js"></script>
9
+    <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
10
+    <script language="javascript" type="text/javascript" src="../jquery.flot.selection.js"></script>
11
+ </head>
12
+    <body>
13
+    <h1>Flot Examples</h1>
14
+
15
+    <div id="placeholder" style="width:600px;height:300px;"></div>
16
+
17
+    <p>Visitors per day to the Flot homepage. Weekends are colored. Try zooming.
18
+      The plot below shows an overview.</p>
19
+
20
+    <div id="overview" style="margin-left:50px;margin-top:20px;width:400px;height:50px"></div>
21
+
22
+<script id="source">
23
+$(function () {
24
+    var d = [[1196463600000, 0], [1196550000000, 0], [1196636400000, 0], [1196722800000, 77], [1196809200000, 3636], [1196895600000, 3575], [1196982000000, 2736], [1197068400000, 1086], [1197154800000, 676], [1197241200000, 1205], [1197327600000, 906], [1197414000000, 710], [1197500400000, 639], [1197586800000, 540], [1197673200000, 435], [1197759600000, 301], [1197846000000, 575], [1197932400000, 481], [1198018800000, 591], [1198105200000, 608], [1198191600000, 459], [1198278000000, 234], [1198364400000, 1352], [1198450800000, 686], [1198537200000, 279], [1198623600000, 449], [1198710000000, 468], [1198796400000, 392], [1198882800000, 282], [1198969200000, 208], [1199055600000, 229], [1199142000000, 177], [1199228400000, 374], [1199314800000, 436], [1199401200000, 404], [1199487600000, 253], [1199574000000, 218], [1199660400000, 476], [1199746800000, 462], [1199833200000, 448], [1199919600000, 442], [1200006000000, 403], [1200092400000, 204], [1200178800000, 194], [1200265200000, 327], [1200351600000, 374], [1200438000000, 507], [1200524400000, 546], [1200610800000, 482], [1200697200000, 283], [1200783600000, 221], [1200870000000, 483], [1200956400000, 523], [1201042800000, 528], [1201129200000, 483], [1201215600000, 452], [1201302000000, 270], [1201388400000, 222], [1201474800000, 439], [1201561200000, 559], [1201647600000, 521], [1201734000000, 477], [1201820400000, 442], [1201906800000, 252], [1201993200000, 236], [1202079600000, 525], [1202166000000, 477], [1202252400000, 386], [1202338800000, 409], [1202425200000, 408], [1202511600000, 237], [1202598000000, 193], [1202684400000, 357], [1202770800000, 414], [1202857200000, 393], [1202943600000, 353], [1203030000000, 364], [1203116400000, 215], [1203202800000, 214], [1203289200000, 356], [1203375600000, 399], [1203462000000, 334], [1203548400000, 348], [1203634800000, 243], [1203721200000, 126], [1203807600000, 157], [1203894000000, 288]];
25
+
26
+    // first correct the timestamps - they are recorded as the daily
27
+    // midnights in UTC+0100, but Flot always displays dates in UTC
28
+    // so we have to add one hour to hit the midnights in the plot
29
+    for (var i = 0; i < d.length; ++i)
30
+      d[i][0] += 60 * 60 * 1000;
31
+
32
+    // helper for returning the weekends in a period
33
+    function weekendAreas(axes) {
34
+        var markings = [];
35
+        var d = new Date(axes.xaxis.min);
36
+        // go to the first Saturday
37
+        d.setUTCDate(d.getUTCDate() - ((d.getUTCDay() + 1) % 7))
38
+        d.setUTCSeconds(0);
39
+        d.setUTCMinutes(0);
40
+        d.setUTCHours(0);
41
+        var i = d.getTime();
42
+        do {
43
+            // when we don't set yaxis, the rectangle automatically
44
+            // extends to infinity upwards and downwards
45
+            markings.push({ xaxis: { from: i, to: i + 2 * 24 * 60 * 60 * 1000 } });
46
+            i += 7 * 24 * 60 * 60 * 1000;
47
+        } while (i < axes.xaxis.max);
48
+
49
+        return markings;
50
+    }
51
+    
52
+    var options = {
53
+        xaxis: { mode: "time" },
54
+        selection: { mode: "x" },
55
+        grid: { markings: weekendAreas }
56
+    };
57
+    
58
+    var plot = $.plot($("#placeholder"), [d], options);
59
+    
60
+    var overview = $.plot($("#overview"), [d], {
61
+        series: {
62
+            lines: { show: true, lineWidth: 1 },
63
+            shadowSize: 0
64
+        },
65
+        xaxis: { ticks: [], mode: "time" },
66
+        yaxis: { ticks: [], min: 0, autoscaleMargin: 0.1 },
67
+        selection: { mode: "x" }
68
+    });
69
+
70
+    // now connect the two
71
+    
72
+    $("#placeholder").bind("plotselected", function (event, ranges) {
73
+        // do the zooming
74
+        plot = $.plot($("#placeholder"), [d],
75
+                      $.extend(true, {}, options, {
76
+                          xaxis: { min: ranges.xaxis.from, max: ranges.xaxis.to }
77
+                      }));
78
+
79
+        // don't fire event on the overview to prevent eternal loop
80
+        overview.setSelection(ranges, true);
81
+    });
82
+    
83
+    $("#overview").bind("plotselected", function (event, ranges) {
84
+        plot.setSelection(ranges);
85
+    });
86
+});
87
+</script>
88
+
89
+ </body>
90
+</html>

+ 98
- 0
flot/examples/zooming.html 查看文件

@@ -0,0 +1,98 @@
1
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2
+<html>
3
+ <head>
4
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+    <title>Flot Examples</title>
6
+    <link href="layout.css" rel="stylesheet" type="text/css"></link>
7
+    <!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
8
+    <script language="javascript" type="text/javascript" src="../jquery.js"></script>
9
+    <script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
10
+    <script language="javascript" type="text/javascript" src="../jquery.flot.selection.js"></script>
11
+ </head>
12
+    <body>
13
+    <h1>Flot Examples</h1>
14
+
15
+    <div style="float:left">
16
+      <div id="placeholder" style="width:500px;height:300px"></div>
17
+    </div>
18
+    
19
+    <div id="miniature" style="float:left;margin-left:20px;margin-top:50px">
20
+      <div id="overview" style="width:166px;height:100px"></div>
21
+
22
+      <p id="overviewLegend" style="margin-left:10px"></p>
23
+    </div>
24
+
25
+    <p style="clear:left"> The selection support makes 
26
+      pretty advanced zooming schemes possible. With a few lines of code,
27
+      the small overview plot to the right has been connected to the large
28
+      plot. Try selecting a rectangle on either of them.</p>
29
+
30
+<script id="source">
31
+$(function () {
32
+    // setup plot
33
+    function getData(x1, x2) {
34
+        var d = [];
35
+        for (var i = 0; i <= 100; ++i) {
36
+            var x = x1 + i * (x2 - x1) / 100;
37
+            d.push([x, Math.sin(x * Math.sin(x))]);
38
+        }
39
+
40
+        return [
41
+            { label: "sin(x sin(x))", data: d }
42
+        ];
43
+    }
44
+
45
+    var options = {
46
+        legend: { show: false },
47
+        series: {
48
+            lines: { show: true },
49
+            points: { show: true }
50
+        },
51
+        yaxis: { ticks: 10 },
52
+        selection: { mode: "xy" }
53
+    };
54
+
55
+    var startData = getData(0, 3 * Math.PI);
56
+    
57
+    var plot = $.plot($("#placeholder"), startData, options);
58
+
59
+    // setup overview
60
+    var overview = $.plot($("#overview"), startData, {
61
+        legend: { show: true, container: $("#overviewLegend") },
62
+        series: {
63
+            lines: { show: true, lineWidth: 1 },
64
+            shadowSize: 0
65
+        },
66
+        xaxis: { ticks: 4 },
67
+        yaxis: { ticks: 3, min: -2, max: 2 },
68
+        grid: { color: "#999" },
69
+        selection: { mode: "xy" }
70
+    });
71
+
72
+    // now connect the two
73
+    
74
+    $("#placeholder").bind("plotselected", function (event, ranges) {
75
+        // clamp the zooming to prevent eternal zoom
76
+        if (ranges.xaxis.to - ranges.xaxis.from < 0.00001)
77
+            ranges.xaxis.to = ranges.xaxis.from + 0.00001;
78
+        if (ranges.yaxis.to - ranges.yaxis.from < 0.00001)
79
+            ranges.yaxis.to = ranges.yaxis.from + 0.00001;
80
+        
81
+        // do the zooming
82
+        plot = $.plot($("#placeholder"), getData(ranges.xaxis.from, ranges.xaxis.to),
83
+                      $.extend(true, {}, options, {
84
+                          xaxis: { min: ranges.xaxis.from, max: ranges.xaxis.to },
85
+                          yaxis: { min: ranges.yaxis.from, max: ranges.yaxis.to }
86
+                      }));
87
+        
88
+        // don't fire event on the overview to prevent eternal loop
89
+        overview.setSelection(ranges, true);
90
+    });
91
+    $("#overview").bind("plotselected", function (event, ranges) {
92
+        plot.setSelection(ranges);
93
+    });
94
+});
95
+</script>
96
+
97
+ </body>
98
+</html>

+ 1427
- 0
flot/excanvas.js
文件差異過大導致無法顯示
查看文件


+ 1
- 0
flot/excanvas.min.js
文件差異過大導致無法顯示
查看文件


+ 174
- 0
flot/jquery.colorhelpers.js 查看文件

@@ -0,0 +1,174 @@
1
+/* Plugin for jQuery for working with colors.
2
+ * 
3
+ * Version 1.0.
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() work in-place instead of returning
17
+ * new objects.
18
+ */ 
19
+
20
+(function() {
21
+    jQuery.color = {};
22
+
23
+    // construct color object with some convenient chainable helpers
24
+    jQuery.color.make = function (r, g, b, a) {
25
+        var o = {};
26
+        o.r = r || 0;
27
+        o.g = g || 0;
28
+        o.b = b || 0;
29
+        o.a = a != null ? a : 1;
30
+
31
+        o.add = function (c, d) {
32
+            for (var i = 0; i < c.length; ++i)
33
+                o[c.charAt(i)] += d;
34
+            return o.normalize();
35
+        };
36
+        
37
+        o.scale = function (c, f) {
38
+            for (var i = 0; i < c.length; ++i)
39
+                o[c.charAt(i)] *= f;
40
+            return o.normalize();
41
+        };
42
+        
43
+        o.toString = function () {
44
+            if (o.a >= 1.0) {
45
+                return "rgb("+[o.r, o.g, o.b].join(",")+")";
46
+            } else {
47
+                return "rgba("+[o.r, o.g, o.b, o.a].join(",")+")";
48
+            }
49
+        };
50
+
51
+        o.normalize = function () {
52
+            function clamp(min, value, max) {
53
+                return value < min ? min: (value > max ? max: value);
54
+            }
55
+            
56
+            o.r = clamp(0, parseInt(o.r), 255);
57
+            o.g = clamp(0, parseInt(o.g), 255);
58
+            o.b = clamp(0, parseInt(o.b), 255);
59
+            o.a = clamp(0, o.a, 1);
60
+            return o;
61
+        };
62
+
63
+        o.clone = function () {
64
+            return jQuery.color.make(o.r, o.b, o.g, o.a);
65
+        };
66
+
67
+        return o.normalize();
68
+    }
69
+
70
+    // extract CSS color property from element, going up in the DOM
71
+    // if it's "transparent"
72
+    jQuery.color.extract = function (elem, css) {
73
+        var c;
74
+        do {
75
+            c = elem.css(css).toLowerCase();
76
+            // keep going until we find an element that has color, or
77
+            // we hit the body
78
+            if (c != '' && c != 'transparent')
79
+                break;
80
+            elem = elem.parent();
81
+        } while (!jQuery.nodeName(elem.get(0), "body"));
82
+
83
+        // catch Safari's way of signalling transparent
84
+        if (c == "rgba(0, 0, 0, 0)")
85
+            c = "transparent";
86
+        
87
+        return jQuery.color.parse(c);
88
+    }
89
+    
90
+    // parse CSS color string (like "rgb(10, 32, 43)" or "#fff"),
91
+    // returns color object
92
+    jQuery.color.parse = function (str) {
93
+        var res, m = jQuery.color.make;
94
+
95
+        // Look for rgb(num,num,num)
96
+        if (res = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str))
97
+            return m(parseInt(res[1], 10), parseInt(res[2], 10), parseInt(res[3], 10));
98
+        
99
+        // Look for rgba(num,num,num,num)
100
+        if (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))
101
+            return m(parseInt(res[1], 10), parseInt(res[2], 10), parseInt(res[3], 10), parseFloat(res[4]));
102
+            
103
+        // Look for rgb(num%,num%,num%)
104
+        if (res = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str))
105
+            return m(parseFloat(res[1])*2.55, parseFloat(res[2])*2.55, parseFloat(res[3])*2.55);
106
+
107
+        // Look for rgba(num%,num%,num%,num)
108
+        if (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))
109
+            return m(parseFloat(res[1])*2.55, parseFloat(res[2])*2.55, parseFloat(res[3])*2.55, parseFloat(res[4]));
110
+        
111
+        // Look for #a0b1c2
112
+        if (res = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str))
113
+            return m(parseInt(res[1], 16), parseInt(res[2], 16), parseInt(res[3], 16));
114
+
115
+        // Look for #fff
116
+        if (res = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str))
117
+            return m(parseInt(res[1]+res[1], 16), parseInt(res[2]+res[2], 16), parseInt(res[3]+res[3], 16));
118
+
119
+        // Otherwise, we're most likely dealing with a named color
120
+        var name = jQuery.trim(str).toLowerCase();
121
+        if (name == "transparent")
122
+            return m(255, 255, 255, 0);
123
+        else {
124
+            res = lookupColors[name];
125
+            return m(res[0], res[1], res[2]);
126
+        }
127
+    }
128
+    
129
+    var lookupColors = {
130
+        aqua:[0,255,255],
131
+        azure:[240,255,255],
132
+        beige:[245,245,220],
133
+        black:[0,0,0],
134
+        blue:[0,0,255],
135
+        brown:[165,42,42],
136
+        cyan:[0,255,255],
137
+        darkblue:[0,0,139],
138
+        darkcyan:[0,139,139],
139
+        darkgrey:[169,169,169],
140
+        darkgreen:[0,100,0],
141
+        darkkhaki:[189,183,107],
142
+        darkmagenta:[139,0,139],
143
+        darkolivegreen:[85,107,47],
144
+        darkorange:[255,140,0],
145
+        darkorchid:[153,50,204],
146
+        darkred:[139,0,0],
147
+        darksalmon:[233,150,122],
148
+        darkviolet:[148,0,211],
149
+        fuchsia:[255,0,255],
150
+        gold:[255,215,0],
151
+        green:[0,128,0],
152
+        indigo:[75,0,130],
153
+        khaki:[240,230,140],
154
+        lightblue:[173,216,230],
155
+        lightcyan:[224,255,255],
156
+        lightgreen:[144,238,144],
157
+        lightgrey:[211,211,211],
158
+        lightpink:[255,182,193],
159
+        lightyellow:[255,255,224],
160
+        lime:[0,255,0],
161
+        magenta:[255,0,255],
162
+        maroon:[128,0,0],
163
+        navy:[0,0,128],
164
+        olive:[128,128,0],
165
+        orange:[255,165,0],
166
+        pink:[255,192,203],
167
+        purple:[128,0,128],
168
+        violet:[128,0,128],
169
+        red:[255,0,0],
170
+        silver:[192,192,192],
171
+        white:[255,255,255],
172
+        yellow:[255,255,0]
173
+    };    
174
+})();

+ 1
- 0
flot/jquery.colorhelpers.min.js 查看文件

@@ -0,0 +1 @@
1
+(function(){jQuery.color={};jQuery.color.make=function(E,D,B,C){var F={};F.r=E||0;F.g=D||0;F.b=B||0;F.a=C!=null?C:1;F.add=function(I,H){for(var G=0;G<I.length;++G){F[I.charAt(G)]+=H}return F.normalize()};F.scale=function(I,H){for(var G=0;G<I.length;++G){F[I.charAt(G)]*=H}return F.normalize()};F.toString=function(){if(F.a>=1){return"rgb("+[F.r,F.g,F.b].join(",")+")"}else{return"rgba("+[F.r,F.g,F.b,F.a].join(",")+")"}};F.normalize=function(){function G(I,J,H){return J<I?I:(J>H?H:J)}F.r=G(0,parseInt(F.r),255);F.g=G(0,parseInt(F.g),255);F.b=G(0,parseInt(F.b),255);F.a=G(0,F.a,1);return F};F.clone=function(){return jQuery.color.make(F.r,F.b,F.g,F.a)};return F.normalize()};jQuery.color.extract=function(C,B){var D;do{D=C.css(B).toLowerCase();if(D!=""&&D!="transparent"){break}C=C.parent()}while(!jQuery.nodeName(C.get(0),"body"));if(D=="rgba(0, 0, 0, 0)"){D="transparent"}return jQuery.color.parse(D)};jQuery.color.parse=function(E){var D,B=jQuery.color.make;if(D=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(E)){return B(parseInt(D[1],10),parseInt(D[2],10),parseInt(D[3],10))}if(D=/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(E)){return B(parseInt(D[1],10),parseInt(D[2],10),parseInt(D[3],10),parseFloat(D[4]))}if(D=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(E)){return B(parseFloat(D[1])*2.55,parseFloat(D[2])*2.55,parseFloat(D[3])*2.55)}if(D=/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(E)){return B(parseFloat(D[1])*2.55,parseFloat(D[2])*2.55,parseFloat(D[3])*2.55,parseFloat(D[4]))}if(D=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(E)){return B(parseInt(D[1],16),parseInt(D[2],16),parseInt(D[3],16))}if(D=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(E)){return B(parseInt(D[1]+D[1],16),parseInt(D[2]+D[2],16),parseInt(D[3]+D[3],16))}var C=jQuery.trim(E).toLowerCase();if(C=="transparent"){return B(255,255,255,0)}else{D=A[C];return B(D[0],D[1],D[2])}};var A={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})();

+ 156
- 0
flot/jquery.flot.crosshair.js 查看文件

@@ -0,0 +1,156 @@
1
+/*
2
+Flot plugin for showing a crosshair, thin lines, when the mouse hovers
3
+over the plot.
4
+
5
+  crosshair: {
6
+    mode: null or "x" or "y" or "xy"
7
+    color: color
8
+    lineWidth: number
9
+  }
10
+
11
+Set the mode to one of "x", "y" or "xy". The "x" mode enables a
12
+vertical crosshair that lets you trace the values on the x axis, "y"
13
+enables a horizontal crosshair and "xy" enables them both. "color" is
14
+the color of the crosshair (default is "rgba(170, 0, 0, 0.80)"),
15
+"lineWidth" is the width of the drawn lines (default is 1).
16
+
17
+The plugin also adds four public methods:
18
+
19
+  - setCrosshair(pos)
20
+
21
+    Set the position of the crosshair. Note that this is cleared if
22
+    the user moves the mouse. "pos" should be on the form { x: xpos,
23
+    y: ypos } (or x2 and y2 if you're using the secondary axes), which
24
+    is coincidentally the same format as what you get from a "plothover"
25
+    event. If "pos" is null, the crosshair is cleared.
26
+
27
+  - clearCrosshair()
28
+
29
+    Clear the crosshair.
30
+
31
+  - lockCrosshair(pos)
32
+
33
+    Cause the crosshair to lock to the current location, no longer
34
+    updating if the user moves the mouse. Optionally supply a position
35
+    (passed on to setCrosshair()) to move it to.
36
+
37
+    Example usage:
38
+      var myFlot = $.plot( $("#graph"), ..., { crosshair: { mode: "x" } } };
39
+      $("#graph").bind("plothover", function (evt, position, item) {
40
+        if (item) {
41
+          // Lock the crosshair to the data point being hovered
42
+          myFlot.lockCrosshair({ x: item.datapoint[0], y: item.datapoint[1] });
43
+        }
44
+        else {
45
+          // Return normal crosshair operation
46
+          myFlot.unlockCrosshair();
47
+        }
48
+      });
49
+
50
+  - unlockCrosshair()
51
+
52
+    Free the crosshair to move again after locking it.
53
+*/
54
+
55
+(function ($) {
56
+    var options = {
57
+        crosshair: {
58
+            mode: null, // one of null, "x", "y" or "xy",
59
+            color: "rgba(170, 0, 0, 0.80)",
60
+            lineWidth: 1
61
+        }
62
+    };
63
+    
64
+    function init(plot) {
65
+        // position of crosshair in pixels
66
+        var crosshair = { x: -1, y: -1, locked: false };
67
+
68
+        plot.setCrosshair = function setCrosshair(pos) {
69
+            if (!pos)
70
+                crosshair.x = -1;
71
+            else {
72
+                var axes = plot.getAxes();
73
+                
74
+                crosshair.x = Math.max(0, Math.min(pos.x != null ? axes.xaxis.p2c(pos.x) : axes.x2axis.p2c(pos.x2), plot.width()));
75
+                crosshair.y = Math.max(0, Math.min(pos.y != null ? axes.yaxis.p2c(pos.y) : axes.y2axis.p2c(pos.y2), plot.height()));
76
+            }
77
+            
78
+            plot.triggerRedrawOverlay();
79
+        };
80
+        
81
+        plot.clearCrosshair = plot.setCrosshair; // passes null for pos
82
+        
83
+        plot.lockCrosshair = function lockCrosshair(pos) {
84
+            if (pos)
85
+                plot.setCrosshair(pos);
86
+            crosshair.locked = true;
87
+        }
88
+
89
+        plot.unlockCrosshair = function unlockCrosshair() {
90
+            crosshair.locked = false;
91
+        }
92
+
93
+        plot.hooks.bindEvents.push(function (plot, eventHolder) {
94
+            if (!plot.getOptions().crosshair.mode)
95
+                return;
96
+
97
+            eventHolder.mouseout(function () {
98
+                if (crosshair.x != -1) {
99
+                    crosshair.x = -1;
100
+                    plot.triggerRedrawOverlay();
101
+                }
102
+            });
103
+            
104
+            eventHolder.mousemove(function (e) {
105
+                if (plot.getSelection && plot.getSelection()) {
106
+                    crosshair.x = -1; // hide the crosshair while selecting
107
+                    return;
108
+                }
109
+                
110
+                if (crosshair.locked)
111
+                    return;
112
+                
113
+                var offset = plot.offset();
114
+                crosshair.x = Math.max(0, Math.min(e.pageX - offset.left, plot.width()));
115
+                crosshair.y = Math.max(0, Math.min(e.pageY - offset.top, plot.height()));
116
+                plot.triggerRedrawOverlay();
117
+            });
118
+        });
119
+
120
+        plot.hooks.drawOverlay.push(function (plot, ctx) {
121
+            var c = plot.getOptions().crosshair;
122
+            if (!c.mode)
123
+                return;
124
+
125
+            var plotOffset = plot.getPlotOffset();
126
+            
127
+            ctx.save();
128
+            ctx.translate(plotOffset.left, plotOffset.top);
129
+
130
+            if (crosshair.x != -1) {
131
+                ctx.strokeStyle = c.color;
132
+                ctx.lineWidth = c.lineWidth;
133
+                ctx.lineJoin = "round";
134
+
135
+                ctx.beginPath();
136
+                if (c.mode.indexOf("x") != -1) {
137
+                    ctx.moveTo(crosshair.x, 0);
138
+                    ctx.lineTo(crosshair.x, plot.height());
139
+                }
140
+                if (c.mode.indexOf("y") != -1) {
141
+                    ctx.moveTo(0, crosshair.y);
142
+                    ctx.lineTo(plot.width(), crosshair.y);
143
+                }
144
+                ctx.stroke();
145
+            }
146
+            ctx.restore();
147
+        });
148
+    }
149
+    
150
+    $.plot.plugins.push({
151
+        init: init,
152
+        options: options,
153
+        name: 'crosshair',
154
+        version: '1.0'
155
+    });
156
+})(jQuery);

+ 1
- 0
flot/jquery.flot.crosshair.min.js 查看文件

@@ -0,0 +1 @@
1
+(function(B){var A={crosshair:{mode:null,color:"rgba(170, 0, 0, 0.80)",lineWidth:1}};function C(G){var H={x:-1,y:-1,locked:false};G.setCrosshair=function D(J){if(!J){H.x=-1}else{var I=G.getAxes();H.x=Math.max(0,Math.min(J.x!=null?I.xaxis.p2c(J.x):I.x2axis.p2c(J.x2),G.width()));H.y=Math.max(0,Math.min(J.y!=null?I.yaxis.p2c(J.y):I.y2axis.p2c(J.y2),G.height()))}G.triggerRedrawOverlay()};G.clearCrosshair=G.setCrosshair;G.lockCrosshair=function E(I){if(I){G.setCrosshair(I)}H.locked=true};G.unlockCrosshair=function F(){H.locked=false};G.hooks.bindEvents.push(function(J,I){if(!J.getOptions().crosshair.mode){return }I.mouseout(function(){if(H.x!=-1){H.x=-1;J.triggerRedrawOverlay()}});I.mousemove(function(K){if(J.getSelection&&J.getSelection()){H.x=-1;return }if(H.locked){return }var L=J.offset();H.x=Math.max(0,Math.min(K.pageX-L.left,J.width()));H.y=Math.max(0,Math.min(K.pageY-L.top,J.height()));J.triggerRedrawOverlay()})});G.hooks.drawOverlay.push(function(K,I){var L=K.getOptions().crosshair;if(!L.mode){return }var J=K.getPlotOffset();I.save();I.translate(J.left,J.top);if(H.x!=-1){I.strokeStyle=L.color;I.lineWidth=L.lineWidth;I.lineJoin="round";I.beginPath();if(L.mode.indexOf("x")!=-1){I.moveTo(H.x,0);I.lineTo(H.x,K.height())}if(L.mode.indexOf("y")!=-1){I.moveTo(0,H.y);I.lineTo(K.width(),H.y)}I.stroke()}I.restore()})}B.plot.plugins.push({init:C,options:A,name:"crosshair",version:"1.0"})})(jQuery);

+ 237
- 0
flot/jquery.flot.image.js 查看文件

@@ -0,0 +1,237 @@
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 draw(plot, ctx) {
116
+        var plotOffset = plot.getPlotOffset();
117
+        
118
+        $.each(plot.getData(), function (i, series) {
119
+            var points = series.datapoints.points,
120
+                ps = series.datapoints.pointsize;
121
+            
122
+            for (var i = 0; i < points.length; i += ps) {
123
+                var img = points[i],
124
+                    x1 = points[i + 1], y1 = points[i + 2],
125
+                    x2 = points[i + 3], y2 = points[i + 4],
126
+                    xaxis = series.xaxis, yaxis = series.yaxis,
127
+                    tmp;
128
+
129
+                // actually we should check img.complete, but it
130
+                // appears to be a somewhat unreliable indicator in
131
+                // IE6 (false even after load event)
132
+                if (!img || img.width <= 0 || img.height <= 0)
133
+                    continue;
134
+
135
+                if (x1 > x2) {
136
+                    tmp = x2;
137
+                    x2 = x1;
138
+                    x1 = tmp;
139
+                }
140
+                if (y1 > y2) {
141
+                    tmp = y2;
142
+                    y2 = y1;
143
+                    y1 = tmp;
144
+                }
145
+                
146
+                // if the anchor is at the center of the pixel, expand the 
147
+                // image by 1/2 pixel in each direction
148
+                if (series.images.anchor == "center") {
149
+                    tmp = 0.5 * (x2-x1) / (img.width - 1);
150
+                    x1 -= tmp;
151
+                    x2 += tmp;
152
+                    tmp = 0.5 * (y2-y1) / (img.height - 1);
153
+                    y1 -= tmp;
154
+                    y2 += tmp;
155
+                }
156
+                
157
+                // clip
158
+                if (x1 == x2 || y1 == y2 ||
159
+                    x1 >= xaxis.max || x2 <= xaxis.min ||
160
+                    y1 >= yaxis.max || y2 <= yaxis.min)
161
+                    continue;
162
+
163
+                var sx1 = 0, sy1 = 0, sx2 = img.width, sy2 = img.height;
164
+                if (x1 < xaxis.min) {
165
+                    sx1 += (sx2 - sx1) * (xaxis.min - x1) / (x2 - x1);
166
+                    x1 = xaxis.min;
167
+                }
168
+
169
+                if (x2 > xaxis.max) {
170
+                    sx2 += (sx2 - sx1) * (xaxis.max - x2) / (x2 - x1);
171
+                    x2 = xaxis.max;
172
+                }
173
+
174
+                if (y1 < yaxis.min) {
175
+                    sy2 += (sy1 - sy2) * (yaxis.min - y1) / (y2 - y1);
176
+                    y1 = yaxis.min;
177
+                }
178
+
179
+                if (y2 > yaxis.max) {
180
+                    sy1 += (sy1 - sy2) * (yaxis.max - y2) / (y2 - y1);
181
+                    y2 = yaxis.max;
182
+                }
183
+                
184
+                x1 = xaxis.p2c(x1);
185
+                x2 = xaxis.p2c(x2);
186
+                y1 = yaxis.p2c(y1);
187
+                y2 = yaxis.p2c(y2);
188
+                
189
+                // the transformation may have swapped us
190
+                if (x1 > x2) {
191
+                    tmp = x2;
192
+                    x2 = x1;
193
+                    x1 = tmp;
194
+                }
195
+                if (y1 > y2) {
196
+                    tmp = y2;
197
+                    y2 = y1;
198
+                    y1 = tmp;
199
+                }
200
+
201
+                tmp = ctx.globalAlpha;
202
+                ctx.globalAlpha *= series.images.alpha;
203
+                ctx.drawImage(img,
204
+                              sx1, sy1, sx2 - sx1, sy2 - sy1,
205
+                              x1 + plotOffset.left, y1 + plotOffset.top,
206
+                              x2 - x1, y2 - y1);
207
+                ctx.globalAlpha = tmp;
208
+            }
209
+        });
210
+    }
211
+
212
+    function processRawData(plot, series, data, datapoints) {
213
+        if (!series.images.show)
214
+            return;
215
+
216
+        // format is Image, x1, y1, x2, y2 (opposite corners)
217
+        datapoints.format = [
218
+            { required: true },
219
+            { x: true, number: true, required: true },
220
+            { y: true, number: true, required: true },
221
+            { x: true, number: true, required: true },
222
+            { y: true, number: true, required: true }
223
+        ];
224
+    }
225
+    
226
+    function init(plot) {
227
+        plot.hooks.processRawData.push(processRawData);
228
+        plot.hooks.draw.push(draw);
229
+    }
230
+    
231
+    $.plot.plugins.push({
232
+        init: init,
233
+        options: options,
234
+        name: 'image',
235
+        version: '1.1'
236
+    });
237
+})(jQuery);

+ 1
- 0
flot/jquery.flot.image.min.js 查看文件

@@ -0,0 +1 @@
1
+(function(D){var B={series:{images:{show:false,alpha:1,anchor:"corner"}}};D.plot.image={};D.plot.image.loadDataImages=function(G,F,K){var J=[],H=[];var I=F.series.images.show;D.each(G,function(L,M){if(!(I||M.images.show)){return }if(M.data){M=M.data}D.each(M,function(N,O){if(typeof O[0]=="string"){J.push(O[0]);H.push(O)}})});D.plot.image.load(J,function(L){D.each(H,function(N,O){var M=O[0];if(L[M]){O[0]=L[M]}});K()})};D.plot.image.load=function(H,I){var G=H.length,F={};if(G==0){I({})}D.each(H,function(K,J){var L=function(){--G;F[J]=this;if(G==0){I(F)}};D("<img />").load(L).error(L).attr("src",J)})};function A(H,F){var G=H.getPlotOffset();D.each(H.getData(),function(O,P){var X=P.datapoints.points,I=P.datapoints.pointsize;for(var O=0;O<X.length;O+=I){var Q=X[O],M=X[O+1],V=X[O+2],K=X[O+3],T=X[O+4],W=P.xaxis,S=P.yaxis,N;if(!Q||Q.width<=0||Q.height<=0){continue}if(M>K){N=K;K=M;M=N}if(V>T){N=T;T=V;V=N}if(P.images.anchor=="center"){N=0.5*(K-M)/(Q.width-1);M-=N;K+=N;N=0.5*(T-V)/(Q.height-1);V-=N;T+=N}if(M==K||V==T||M>=W.max||K<=W.min||V>=S.max||T<=S.min){continue}var L=0,U=0,J=Q.width,R=Q.height;if(M<W.min){L+=(J-L)*(W.min-M)/(K-M);M=W.min}if(K>W.max){J+=(J-L)*(W.max-K)/(K-M);K=W.max}if(V<S.min){R+=(U-R)*(S.min-V)/(T-V);V=S.min}if(T>S.max){U+=(U-R)*(S.max-T)/(T-V);T=S.max}M=W.p2c(M);K=W.p2c(K);V=S.p2c(V);T=S.p2c(T);if(M>K){N=K;K=M;M=N}if(V>T){N=T;T=V;V=N}N=F.globalAlpha;F.globalAlpha*=P.images.alpha;F.drawImage(Q,L,U,J-L,R-U,M+G.left,V+G.top,K-M,T-V);F.globalAlpha=N}})}function C(I,F,G,H){if(!F.images.show){return }H.format=[{required:true},{x:true,number:true,required:true},{y:true,number:true,required:true},{x:true,number:true,required:true},{y:true,number:true,required:true}]}function E(F){F.hooks.processRawData.push(C);F.hooks.draw.push(A)}D.plot.plugins.push({init:E,options:B,name:"image",version:"1.1"})})(jQuery);

+ 2119
- 0
flot/jquery.flot.js
文件差異過大導致無法顯示
查看文件


+ 1
- 0
flot/jquery.flot.min.js
文件差異過大導致無法顯示
查看文件


+ 272
- 0
flot/jquery.flot.navigate.js 查看文件

@@ -0,0 +1,272 @@
1
+/*
2
+Flot plugin for adding panning and zooming capabilities to a plot.
3
+
4
+The default behaviour is double click and scrollwheel up/down to zoom
5
+in, drag to pan. The plugin defines plot.zoom({ center }),
6
+plot.zoomOut() and plot.pan(offset) so you easily can add custom
7
+controls. It also fires a "plotpan" and "plotzoom" event when
8
+something happens, useful for synchronizing plots.
9
+
10
+Example usage:
11
+
12
+  plot = $.plot(...);
13
+  
14
+  // zoom default amount in on the pixel (100, 200) 
15
+  plot.zoom({ center: { left: 10, top: 20 } });
16
+
17
+  // zoom out again
18
+  plot.zoomOut({ center: { left: 10, top: 20 } });
19
+
20
+  // pan 100 pixels to the left and 20 down
21
+  plot.pan({ left: -100, top: 20 })
22
+
23
+
24
+Options:
25
+
26
+  zoom: {
27
+    interactive: false
28
+    trigger: "dblclick" // or "click" for single click
29
+    amount: 1.5         // 2 = 200% (zoom in), 0.5 = 50% (zoom out)
30
+  }
31
+  
32
+  pan: {
33
+    interactive: false
34
+  }
35
+
36
+  xaxis, yaxis, x2axis, y2axis: {
37
+    zoomRange: null  // or [number, number] (min range, max range)
38
+    panRange: null   // or [number, number] (min, max)
39
+  }
40
+  
41
+"interactive" enables the built-in drag/click behaviour. "amount" is
42
+the amount to zoom the viewport relative to the current range, so 1 is
43
+100% (i.e. no change), 1.5 is 150% (zoom in), 0.7 is 70% (zoom out).
44
+
45
+"zoomRange" is the interval in which zooming can happen, e.g. with
46
+zoomRange: [1, 100] the zoom will never scale the axis so that the
47
+difference between min and max is smaller than 1 or larger than 100.
48
+You can set either of them to null to ignore.
49
+
50
+"panRange" confines the panning to stay within a range, e.g. with
51
+panRange: [-10, 20] panning stops at -10 in one end and at 20 in the
52
+other. Either can be null.
53
+*/
54
+
55
+
56
+// First two dependencies, jquery.event.drag.js and
57
+// jquery.mousewheel.js, we put them inline here to save people the
58
+// effort of downloading them.
59
+
60
+/*
61
+jquery.event.drag.js ~ v1.5 ~ Copyright (c) 2008, Three Dub Media (http://threedubmedia.com)  
62
+Licensed under the MIT License ~ http://threedubmedia.googlecode.com/files/MIT-LICENSE.txt
63
+*/
64
+(function(E){E.fn.drag=function(L,K,J){if(K){this.bind("dragstart",L)}if(J){this.bind("dragend",J)}return !L?this.trigger("drag"):this.bind("drag",K?K:L)};var A=E.event,B=A.special,F=B.drag={not:":input",distance:0,which:1,dragging:false,setup:function(J){J=E.extend({distance:F.distance,which:F.which,not:F.not},J||{});J.distance=I(J.distance);A.add(this,"mousedown",H,J);if(this.attachEvent){this.attachEvent("ondragstart",D)}},teardown:function(){A.remove(this,"mousedown",H);if(this===F.dragging){F.dragging=F.proxy=false}G(this,true);if(this.detachEvent){this.detachEvent("ondragstart",D)}}};B.dragstart=B.dragend={setup:function(){},teardown:function(){}};function H(L){var K=this,J,M=L.data||{};if(M.elem){K=L.dragTarget=M.elem;L.dragProxy=F.proxy||K;L.cursorOffsetX=M.pageX-M.left;L.cursorOffsetY=M.pageY-M.top;L.offsetX=L.pageX-L.cursorOffsetX;L.offsetY=L.pageY-L.cursorOffsetY}else{if(F.dragging||(M.which>0&&L.which!=M.which)||E(L.target).is(M.not)){return }}switch(L.type){case"mousedown":E.extend(M,E(K).offset(),{elem:K,target:L.target,pageX:L.pageX,pageY:L.pageY});A.add(document,"mousemove mouseup",H,M);G(K,false);F.dragging=null;return false;case !F.dragging&&"mousemove":if(I(L.pageX-M.pageX)+I(L.pageY-M.pageY)<M.distance){break}L.target=M.target;J=C(L,"dragstart",K);if(J!==false){F.dragging=K;F.proxy=L.dragProxy=E(J||K)[0]}case"mousemove":if(F.dragging){J=C(L,"drag",K);if(B.drop){B.drop.allowed=(J!==false);B.drop.handler(L)}if(J!==false){break}L.type="mouseup"}case"mouseup":A.remove(document,"mousemove mouseup",H);if(F.dragging){if(B.drop){B.drop.handler(L)}C(L,"dragend",K)}G(K,true);F.dragging=F.proxy=M.elem=false;break}return true}function C(M,K,L){M.type=K;var J=E.event.handle.call(L,M);return J===false?false:J||M.result}function I(J){return Math.pow(J,2)}function D(){return(F.dragging===false)}function G(K,J){if(!K){return }K.unselectable=J?"off":"on";K.onselectstart=function(){return J};if(K.style){K.style.MozUserSelect=J?"":"none"}}})(jQuery);
65
+
66
+
67
+/* jquery.mousewheel.min.js
68
+ * Copyright (c) 2009 Brandon Aaron (http://brandonaaron.net)
69
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
70
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
71
+ * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
72
+ * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
73
+ *
74
+ * Version: 3.0.2
75
+ * 
76
+ * Requires: 1.2.2+
77
+ */
78
+(function(c){var a=["DOMMouseScroll","mousewheel"];c.event.special.mousewheel={setup:function(){if(this.addEventListener){for(var d=a.length;d;){this.addEventListener(a[--d],b,false)}}else{this.onmousewheel=b}},teardown:function(){if(this.removeEventListener){for(var d=a.length;d;){this.removeEventListener(a[--d],b,false)}}else{this.onmousewheel=null}}};c.fn.extend({mousewheel:function(d){return d?this.bind("mousewheel",d):this.trigger("mousewheel")},unmousewheel:function(d){return this.unbind("mousewheel",d)}});function b(f){var d=[].slice.call(arguments,1),g=0,e=true;f=c.event.fix(f||window.event);f.type="mousewheel";if(f.wheelDelta){g=f.wheelDelta/120}if(f.detail){g=-f.detail/3}d.unshift(f,g);return c.event.handle.apply(this,d)}})(jQuery);
79
+
80
+
81
+
82
+
83
+(function ($) {
84
+    var options = {
85
+        xaxis: {
86
+            zoomRange: null, // or [number, number] (min range, max range)
87
+            panRange: null // or [number, number] (min, max)
88
+        },
89
+        zoom: {
90
+            interactive: false,
91
+            trigger: "dblclick", // or "click" for single click
92
+            amount: 1.5 // how much to zoom relative to current position, 2 = 200% (zoom in), 0.5 = 50% (zoom out)
93
+        },
94
+        pan: {
95
+            interactive: false
96
+        }
97
+    };
98
+
99
+    function init(plot) {
100
+        function bindEvents(plot, eventHolder) {
101
+            var o = plot.getOptions();
102
+            if (o.zoom.interactive) {
103
+                function clickHandler(e, zoomOut) {
104
+                    var c = plot.offset();
105
+                    c.left = e.pageX - c.left;
106
+                    c.top = e.pageY - c.top;
107
+                    if (zoomOut)
108
+                        plot.zoomOut({ center: c });
109
+                    else
110
+                        plot.zoom({ center: c });
111
+                }
112
+                
113
+                eventHolder[o.zoom.trigger](clickHandler);
114
+
115
+                eventHolder.mousewheel(function (e, delta) {
116
+                    clickHandler(e, delta < 0);
117
+                    return false;
118
+                });
119
+            }
120
+            if (o.pan.interactive) {
121
+                var prevCursor = 'default', pageX = 0, pageY = 0;
122
+                
123
+                eventHolder.bind("dragstart", { distance: 10 }, function (e) {
124
+                    if (e.which != 1)  // only accept left-click
125
+                        return false;
126
+                    eventHolderCursor = eventHolder.css('cursor');
127
+                    eventHolder.css('cursor', 'move');
128
+                    pageX = e.pageX;
129
+                    pageY = e.pageY;
130
+                });
131
+                eventHolder.bind("drag", function (e) {
132
+                    // unused at the moment, but we need it here to
133
+                    // trigger the dragstart/dragend events
134
+                });
135
+                eventHolder.bind("dragend", function (e) {
136
+                    eventHolder.css('cursor', prevCursor);
137
+                    plot.pan({ left: pageX - e.pageX,
138
+                               top: pageY - e.pageY });
139
+                });
140
+            }
141
+        }
142
+
143
+        plot.zoomOut = function (args) {
144
+            if (!args)
145
+                args = {};
146
+            
147
+            if (!args.amount)
148
+                args.amount = plot.getOptions().zoom.amount
149
+
150
+            args.amount = 1 / args.amount;
151
+            plot.zoom(args);
152
+        }
153
+        
154
+        plot.zoom = function (args) {
155
+            if (!args)
156
+                args = {};
157
+            
158
+            var axes = plot.getAxes(),
159
+                options = plot.getOptions(),
160
+                c = args.center,
161
+                amount = args.amount ? args.amount : options.zoom.amount,
162
+                w = plot.width(), h = plot.height();
163
+
164
+            if (!c)
165
+                c = { left: w / 2, top: h / 2 };
166
+                
167
+            var xf = c.left / w,
168
+                x1 = c.left - xf * w / amount,
169
+                x2 = c.left + (1 - xf) * w / amount,
170
+                yf = c.top / h,
171
+                y1 = c.top - yf * h / amount,
172
+                y2 = c.top + (1 - yf) * h / amount;
173
+
174
+            function scaleAxis(min, max, name) {
175
+                var axis = axes[name],
176
+                    axisOptions = options[name];
177
+                
178
+                if (!axis.used)
179
+                    return;
180
+                    
181
+                min = axis.c2p(min);
182
+                max = axis.c2p(max);
183
+                if (max < min) { // make sure min < max
184
+                    var tmp = min
185
+                    min = max;
186
+                    max = tmp;
187
+                }
188
+
189
+                var range = max - min, zr = axisOptions.zoomRange;
190
+                if (zr &&
191
+                    ((zr[0] != null && range < zr[0]) ||
192
+                     (zr[1] != null && range > zr[1])))
193
+                    return;
194
+            
195
+                axisOptions.min = min;
196
+                axisOptions.max = max;
197
+            }
198
+
199
+            scaleAxis(x1, x2, 'xaxis');
200
+            scaleAxis(x1, x2, 'x2axis');
201
+            scaleAxis(y1, y2, 'yaxis');
202
+            scaleAxis(y1, y2, 'y2axis');
203
+            
204
+            plot.setupGrid();
205
+            plot.draw();
206
+            
207
+            if (!args.preventEvent)
208
+                plot.getPlaceholder().trigger("plotzoom", [ plot ]);
209
+        }
210
+
211
+        plot.pan = function (args) {
212
+            var l = +args.left, t = +args.top,
213
+                axes = plot.getAxes(), options = plot.getOptions();
214
+
215
+            if (isNaN(l))
216
+                l = 0;
217
+            if (isNaN(t))
218
+                t = 0;
219
+
220
+            function panAxis(delta, name) {
221
+                var axis = axes[name],
222
+                    axisOptions = options[name],
223
+                    min, max;
224
+                
225
+                if (!axis.used)
226
+                    return;
227
+
228
+                min = axis.c2p(axis.p2c(axis.min) + delta),
229
+                max = axis.c2p(axis.p2c(axis.max) + delta);
230
+
231
+                var pr = axisOptions.panRange;
232
+                if (pr) {
233
+                    // check whether we hit the wall
234
+                    if (pr[0] != null && pr[0] > min) {
235
+                        delta = pr[0] - min;
236
+                        min += delta;
237
+                        max += delta;
238
+                    }
239
+                    
240
+                    if (pr[1] != null && pr[1] < max) {
241
+                        delta = pr[1] - max;
242
+                        min += delta;
243
+                        max += delta;
244
+                    }
245
+                }
246
+                
247
+                axisOptions.min = min;
248
+                axisOptions.max = max;
249
+            }
250
+
251
+            panAxis(l, 'xaxis');
252
+            panAxis(l, 'x2axis');
253
+            panAxis(t, 'yaxis');
254
+            panAxis(t, 'y2axis');
255
+            
256
+            plot.setupGrid();
257
+            plot.draw();
258
+            
259
+            if (!args.preventEvent)
260
+                plot.getPlaceholder().trigger("plotpan", [ plot ]);
261
+        }
262
+        
263
+        plot.hooks.bindEvents.push(bindEvents);
264
+    }
265
+    
266
+    $.plot.plugins.push({
267
+        init: init,
268
+        options: options,
269
+        name: 'navigate',
270
+        version: '1.1'
271
+    });
272
+})(jQuery);

+ 1
- 0
flot/jquery.flot.navigate.min.js 查看文件

@@ -0,0 +1 @@
1
+(function(R){R.fn.drag=function(A,B,C){if(B){this.bind("dragstart",A)}if(C){this.bind("dragend",C)}return !A?this.trigger("drag"):this.bind("drag",B?B:A)};var M=R.event,L=M.special,Q=L.drag={not:":input",distance:0,which:1,dragging:false,setup:function(A){A=R.extend({distance:Q.distance,which:Q.which,not:Q.not},A||{});A.distance=N(A.distance);M.add(this,"mousedown",O,A);if(this.attachEvent){this.attachEvent("ondragstart",J)}},teardown:function(){M.remove(this,"mousedown",O);if(this===Q.dragging){Q.dragging=Q.proxy=false}P(this,true);if(this.detachEvent){this.detachEvent("ondragstart",J)}}};L.dragstart=L.dragend={setup:function(){},teardown:function(){}};function O(A){var B=this,C,D=A.data||{};if(D.elem){B=A.dragTarget=D.elem;A.dragProxy=Q.proxy||B;A.cursorOffsetX=D.pageX-D.left;A.cursorOffsetY=D.pageY-D.top;A.offsetX=A.pageX-A.cursorOffsetX;A.offsetY=A.pageY-A.cursorOffsetY}else{if(Q.dragging||(D.which>0&&A.which!=D.which)||R(A.target).is(D.not)){return }}switch(A.type){case"mousedown":R.extend(D,R(B).offset(),{elem:B,target:A.target,pageX:A.pageX,pageY:A.pageY});M.add(document,"mousemove mouseup",O,D);P(B,false);Q.dragging=null;return false;case !Q.dragging&&"mousemove":if(N(A.pageX-D.pageX)+N(A.pageY-D.pageY)<D.distance){break}A.target=D.target;C=K(A,"dragstart",B);if(C!==false){Q.dragging=B;Q.proxy=A.dragProxy=R(C||B)[0]}case"mousemove":if(Q.dragging){C=K(A,"drag",B);if(L.drop){L.drop.allowed=(C!==false);L.drop.handler(A)}if(C!==false){break}A.type="mouseup"}case"mouseup":M.remove(document,"mousemove mouseup",O);if(Q.dragging){if(L.drop){L.drop.handler(A)}K(A,"dragend",B)}P(B,true);Q.dragging=Q.proxy=D.elem=false;break}return true}function K(D,B,A){D.type=B;var C=R.event.handle.call(A,D);return C===false?false:C||D.result}function N(A){return Math.pow(A,2)}function J(){return(Q.dragging===false)}function P(A,B){if(!A){return }A.unselectable=B?"off":"on";A.onselectstart=function(){return B};if(A.style){A.style.MozUserSelect=B?"":"none"}}})(jQuery);(function(C){var B=["DOMMouseScroll","mousewheel"];C.event.special.mousewheel={setup:function(){if(this.addEventListener){for(var D=B.length;D;){this.addEventListener(B[--D],A,false)}}else{this.onmousewheel=A}},teardown:function(){if(this.removeEventListener){for(var D=B.length;D;){this.removeEventListener(B[--D],A,false)}}else{this.onmousewheel=null}}};C.fn.extend({mousewheel:function(D){return D?this.bind("mousewheel",D):this.trigger("mousewheel")},unmousewheel:function(D){return this.unbind("mousewheel",D)}});function A(E){var G=[].slice.call(arguments,1),D=0,F=true;E=C.event.fix(E||window.event);E.type="mousewheel";if(E.wheelDelta){D=E.wheelDelta/120}if(E.detail){D=-E.detail/3}G.unshift(E,D);return C.event.handle.apply(this,G)}})(jQuery);(function(B){var A={xaxis:{zoomRange:null,panRange:null},zoom:{interactive:false,trigger:"dblclick",amount:1.5},pan:{interactive:false}};function C(D){function E(J,F){var K=J.getOptions();if(K.zoom.interactive){function L(N,M){var O=J.offset();O.left=N.pageX-O.left;O.top=N.pageY-O.top;if(M){J.zoomOut({center:O})}else{J.zoom({center:O})}}F[K.zoom.trigger](L);F.mousewheel(function(M,N){L(M,N<0);return false})}if(K.pan.interactive){var I="default",H=0,G=0;F.bind("dragstart",{distance:10},function(M){if(M.which!=1){return false}eventHolderCursor=F.css("cursor");F.css("cursor","move");H=M.pageX;G=M.pageY});F.bind("drag",function(M){});F.bind("dragend",function(M){F.css("cursor",I);J.pan({left:H-M.pageX,top:G-M.pageY})})}}D.zoomOut=function(F){if(!F){F={}}if(!F.amount){F.amount=D.getOptions().zoom.amount}F.amount=1/F.amount;D.zoom(F)};D.zoom=function(M){if(!M){M={}}var L=D.getAxes(),S=D.getOptions(),N=M.center,J=M.amount?M.amount:S.zoom.amount,R=D.width(),I=D.height();if(!N){N={left:R/2,top:I/2}}var Q=N.left/R,G=N.left-Q*R/J,F=N.left+(1-Q)*R/J,H=N.top/I,P=N.top-H*I/J,O=N.top+(1-H)*I/J;function K(X,T,V){var Y=L[V],a=S[V];if(!Y.used){return }X=Y.c2p(X);T=Y.c2p(T);if(T<X){var W=X;X=T;T=W}var U=T-X,Z=a.zoomRange;if(Z&&((Z[0]!=null&&U<Z[0])||(Z[1]!=null&&U>Z[1]))){return }a.min=X;a.max=T}K(G,F,"xaxis");K(G,F,"x2axis");K(P,O,"yaxis");K(P,O,"y2axis");D.setupGrid();D.draw();if(!M.preventEvent){D.getPlaceholder().trigger("plotzoom",[D])}};D.pan=function(I){var F=+I.left,J=+I.top,K=D.getAxes(),H=D.getOptions();if(isNaN(F)){F=0}if(isNaN(J)){J=0}function G(R,M){var O=K[M],Q=H[M],N,L;if(!O.used){return }N=O.c2p(O.p2c(O.min)+R),L=O.c2p(O.p2c(O.max)+R);var P=Q.panRange;if(P){if(P[0]!=null&&P[0]>N){R=P[0]-N;N+=R;L+=R}if(P[1]!=null&&P[1]<L){R=P[1]-L;N+=R;L+=R}}Q.min=N;Q.max=L}G(F,"xaxis");G(F,"x2axis");G(J,"yaxis");G(J,"y2axis");D.setupGrid();D.draw();if(!I.preventEvent){D.getPlaceholder().trigger("plotpan",[D])}};D.hooks.bindEvents.push(E)}B.plot.plugins.push({init:C,options:A,name:"navigate",version:"1.1"})})(jQuery);

+ 750
- 0
flot/jquery.flot.pie.js 查看文件

@@ -0,0 +1,750 @@
1
+/*
2
+Flot plugin for rendering pie charts. The plugin assumes the data is 
3
+coming is as a single data value for each series, and each of those 
4
+values is a positive value or zero (negative numbers don't make 
5
+any sense and will cause strange effects). The data values do 
6
+NOT need to be passed in as percentage values because it 
7
+internally calculates the total and percentages.
8
+
9
+* Created by Brian Medendorp, June 2009
10
+* Updated November 2009 with contributions from: btburnett3, Anthony Aragues and Xavi Ivars
11
+
12
+* Changes:
13
+	2009-10-22: lineJoin set to round
14
+	2009-10-23: IE full circle fix, donut
15
+	2009-11-11: Added basic hover from btburnett3 - does not work in IE, and center is off in Chrome and Opera
16
+	2009-11-17: Added IE hover capability submitted by Anthony Aragues
17
+	2009-11-18: Added bug fix submitted by Xavi Ivars (issues with arrays when other JS libraries are included as well)
18
+		
19
+
20
+Available options are:
21
+series: {
22
+	pie: {
23
+		show: true/false
24
+		radius: 0-1 for percentage of fullsize, or a specified pixel length, or 'auto'
25
+		innerRadius: 0-1 for percentage of fullsize or a specified pixel length, for creating a donut effect
26
+		startAngle: 0-2 factor of PI used for starting angle (in radians) i.e 3/2 starts at the top, 0 and 2 have the same result
27
+		tilt: 0-1 for percentage to tilt the pie, where 1 is no tilt, and 0 is completely flat (nothing will show)
28
+		offset: {
29
+			top: integer value to move the pie up or down
30
+			left: integer value to move the pie left or right, or 'auto'
31
+		},
32
+		stroke: {
33
+			color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#FFF')
34
+			width: integer pixel width of the stroke
35
+		},
36
+		label: {
37
+			show: true/false, or 'auto'
38
+			formatter:  a user-defined function that modifies the text/style of the label text
39
+			radius: 0-1 for percentage of fullsize, or a specified pixel length
40
+			background: {
41
+				color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#000')
42
+				opacity: 0-1
43
+			},
44
+			threshold: 0-1 for the percentage value at which to hide labels (if they're too small)
45
+		},
46
+		combine: {
47
+			threshold: 0-1 for the percentage value at which to combine slices (if they're too small)
48
+			color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#CCC'), if null, the plugin will automatically use the color of the first slice to be combined
49
+			label: any text value of what the combined slice should be labeled
50
+		}
51
+		highlight: {
52
+			opacity: 0-1
53
+		}
54
+	}
55
+}
56
+
57
+More detail and specific examples can be found in the included HTML file.
58
+
59
+*/
60
+
61
+(function ($) 
62
+{
63
+	function init(plot) // this is the "body" of the plugin
64
+	{
65
+		var canvas = null;
66
+		var target = null;
67
+		var maxRadius = null;
68
+		var centerLeft = null;
69
+		var centerTop = null;
70
+		var total = 0;
71
+		var redraw = true;
72
+		var redrawAttempts = 10;
73
+		var shrink = 0.95;
74
+		var legendWidth = 0;
75
+		var processed = false;
76
+		var raw = false;
77
+		
78
+		// interactive variables	
79
+		var highlights = [];	
80
+	
81
+		// add hook to determine if pie plugin in enabled, and then perform necessary operations
82
+		plot.hooks.processOptions.push(checkPieEnabled);
83
+		plot.hooks.bindEvents.push(bindEvents);	
84
+
85
+		// check to see if the pie plugin is enabled
86
+		function checkPieEnabled(plot, options)
87
+		{
88
+			if (options.series.pie.show)
89
+			{
90
+				//disable grid
91
+				options.grid.show = false;
92
+				
93
+				// set labels.show
94
+				if (options.series.pie.label.show=='auto')
95
+					if (options.legend.show)
96
+						options.series.pie.label.show = false;
97
+					else
98
+						options.series.pie.label.show = true;
99
+				
100
+				// set radius
101
+				if (options.series.pie.radius=='auto')
102
+					if (options.series.pie.label.show)
103
+						options.series.pie.radius = 3/4;
104
+					else
105
+						options.series.pie.radius = 1;
106
+						
107
+				// ensure sane tilt
108
+				if (options.series.pie.tilt>1)
109
+					options.series.pie.tilt=1;
110
+				if (options.series.pie.tilt<0)
111
+					options.series.pie.tilt=0;
112
+			
113
+				// add processData hook to do transformations on the data
114
+				plot.hooks.processDatapoints.push(processDatapoints);
115
+				plot.hooks.drawOverlay.push(drawOverlay);	
116
+				
117
+				// add draw hook
118
+				plot.hooks.draw.push(draw);
119
+			}
120
+		}
121
+	
122
+		// bind hoverable events
123
+		function bindEvents(plot, eventHolder) 		
124
+		{		
125
+			var options = plot.getOptions();
126
+			
127
+			if (options.series.pie.show && options.grid.hoverable)
128
+				eventHolder.unbind('mousemove').mousemove(onMouseMove);
129
+				
130
+			if (options.series.pie.show && options.grid.clickable)
131
+				eventHolder.unbind('click').click(onClick);
132
+		}	
133
+		
134
+
135
+		// debugging function that prints out an object
136
+		function alertObject(obj)
137
+		{
138
+			var msg = '';
139
+			function traverse(obj, depth)
140
+			{
141
+				if (!depth)
142
+					depth = 0;
143
+				for (var i = 0; i < obj.length; ++i)
144
+				{
145
+					for (var j=0; j<depth; j++)
146
+						msg += '\t';
147
+				
148
+					if( typeof obj[i] == "object")
149
+					{	// its an object
150
+						msg += ''+i+':\n';
151
+						traverse(obj[i], depth+1);
152
+					}
153
+					else
154
+					{	// its a value
155
+						msg += ''+i+': '+obj[i]+'\n';
156
+					}
157
+				}
158
+			}
159
+			traverse(obj);
160
+			alert(msg);
161
+		}
162
+		
163
+		function calcTotal(data)
164
+		{
165
+			for (var i = 0; i < data.length; ++i)
166
+			{
167
+				var item = parseFloat(data[i].data[0][1]);
168
+				if (item)
169
+					total += item;
170
+			}
171
+		}	
172
+		
173
+		function processDatapoints(plot, series, data, datapoints) 
174
+		{	
175
+			if (!processed)
176
+			{
177
+				processed = true;
178
+			
179
+				canvas = plot.getCanvas();
180
+				target = $(canvas).parent();
181
+				options = plot.getOptions();
182
+			
183
+				plot.setData(combine(plot.getData()));
184
+			}
185
+		}
186
+		
187
+		function setupPie()
188
+		{
189
+			legendWidth = target.children().filter('.legend').children().width();
190
+		
191
+			// calculate maximum radius and center point
192
+			maxRadius =  Math.min(canvas.width,(canvas.height/options.series.pie.tilt))/2;
193
+			centerTop = (canvas.height/2)+options.series.pie.offset.top;
194
+			centerLeft = (canvas.width/2);
195
+			
196
+			if (options.series.pie.offset.left=='auto')
197
+				if (options.legend.position.match('w'))
198
+					centerLeft += legendWidth/2;
199
+				else
200
+					centerLeft -= legendWidth/2;
201
+			else
202
+				centerLeft += options.series.pie.offset.left;
203
+					
204
+			if (centerLeft<maxRadius)
205
+				centerLeft = maxRadius;
206
+			else if (centerLeft>canvas.width-maxRadius)
207
+				centerLeft = canvas.width-maxRadius;
208
+		}
209
+		
210
+		function fixData(data)
211
+		{
212
+			for (var i = 0; i < data.length; ++i)
213
+			{
214
+				if (typeof(data[i].data)=='number')
215
+					data[i].data = [[1,data[i].data]];
216
+				else if (typeof(data[i].data)=='undefined' || typeof(data[i].data[0])=='undefined')
217
+				{
218
+					if (typeof(data[i].data)!='undefined' && typeof(data[i].data.label)!='undefined')
219
+						data[i].label = data[i].data.label; // fix weirdness coming from flot
220
+					data[i].data = [[1,0]];
221
+					
222
+				}
223
+			}
224
+			return data;
225
+		}
226
+		
227
+		function combine(data)
228
+		{
229
+			data = fixData(data);
230
+			calcTotal(data);
231
+			var combined = 0;
232
+			var numCombined = 0;
233
+			var color = options.series.pie.combine.color;
234
+			
235
+			var newdata = [];
236
+			for (var i = 0; i < data.length; ++i)
237
+			{
238
+				// make sure its a number
239
+				data[i].data[0][1] = parseFloat(data[i].data[0][1]);
240
+				if (!data[i].data[0][1])
241
+					data[i].data[0][1] = 0;
242
+					
243
+				if (data[i].data[0][1]/total<=options.series.pie.combine.threshold)
244
+				{
245
+					combined += data[i].data[0][1];
246
+					numCombined++;
247
+					if (!color)
248
+						color = data[i].color;
249
+				}				
250
+				else
251
+				{
252
+					newdata.push({
253
+						data: [[1,data[i].data[0][1]]], 
254
+						color: data[i].color, 
255
+						label: data[i].label,
256
+						angle: (data[i].data[0][1]*(Math.PI*2))/total,
257
+						percent: (data[i].data[0][1]/total*100)
258
+					});
259
+				}
260
+			}
261
+			if (numCombined>0)
262
+				newdata.push({
263
+					data: [[1,combined]], 
264
+					color: color, 
265
+					label: options.series.pie.combine.label,
266
+					angle: (combined*(Math.PI*2))/total,
267
+					percent: (combined/total*100)
268
+				});
269
+			return newdata;
270
+		}		
271
+		
272
+		function draw(plot, newCtx)
273
+		{
274
+			if (!target) return; // if no series were passed
275
+			ctx = newCtx;
276
+		
277
+			setupPie();
278
+			var slices = plot.getData();
279
+		
280
+			var attempts = 0;
281
+			while (redraw && attempts<redrawAttempts)
282
+			{
283
+				redraw = false;
284
+				if (attempts>0)
285
+					maxRadius *= shrink;
286
+				attempts += 1;
287
+				clear();
288
+				if (options.series.pie.tilt<=0.8)
289
+					drawShadow();
290
+				drawPie();
291
+			}
292
+			if (attempts >= redrawAttempts) {
293
+				clear();
294
+				target.prepend('<div class="error">Could not draw pie with labels contained inside canvas</div>');
295
+			}
296
+			
297
+			if ( plot.setSeries && plot.insertLegend )
298
+			{
299
+				plot.setSeries(slices);
300
+				plot.insertLegend();
301
+			}
302
+			
303
+			// we're actually done at this point, just defining internal functions at this point
304
+			
305
+			function clear()
306
+			{
307
+				ctx.clearRect(0,0,canvas.width,canvas.height);
308
+				target.children().filter('.pieLabel, .pieLabelBackground').remove();
309
+			}
310
+			
311
+			function drawShadow()
312
+			{
313
+				var shadowLeft = 5;
314
+				var shadowTop = 15;
315
+				var edge = 10;
316
+				var alpha = 0.02;
317
+			
318
+				// set radius
319
+				if (options.series.pie.radius>1)
320
+					var radius = options.series.pie.radius;
321
+				else
322
+					var radius = maxRadius * options.series.pie.radius;
323
+					
324
+				if (radius>=(canvas.width/2)-shadowLeft || radius*options.series.pie.tilt>=(canvas.height/2)-shadowTop || radius<=edge)
325
+					return;	// shadow would be outside canvas, so don't draw it
326
+			
327
+				ctx.save();
328
+				ctx.translate(shadowLeft,shadowTop);
329
+				ctx.globalAlpha = alpha;
330
+				ctx.fillStyle = '#000';
331
+
332
+				// center and rotate to starting position
333
+				ctx.translate(centerLeft,centerTop);
334
+				ctx.scale(1, options.series.pie.tilt);
335
+				
336
+				//radius -= edge;
337
+				for (var i=1; i<=edge; i++)
338
+				{
339
+					ctx.beginPath();
340
+					ctx.arc(0,0,radius,0,Math.PI*2,false);
341
+					ctx.fill();
342
+					radius -= i;
343
+				}	
344
+				
345
+				ctx.restore();
346
+			}
347
+			
348
+			function drawPie()
349
+			{
350
+				startAngle = Math.PI*options.series.pie.startAngle;
351
+				
352
+				// set radius
353
+				if (options.series.pie.radius>1)
354
+					var radius = options.series.pie.radius;
355
+				else
356
+					var radius = maxRadius * options.series.pie.radius;
357
+				
358
+				// center and rotate to starting position
359
+				ctx.save();
360
+				ctx.translate(centerLeft,centerTop);
361
+				ctx.scale(1, options.series.pie.tilt);
362
+				//ctx.rotate(startAngle); // start at top; -- This doesn't work properly in Opera
363
+				
364
+				// draw slices
365
+				ctx.save();
366
+				var currentAngle = startAngle;
367
+				for (var i = 0; i < slices.length; ++i)
368
+				{
369
+					slices[i].startAngle = currentAngle;
370
+					drawSlice(slices[i].angle, slices[i].color, true);
371
+				}
372
+				ctx.restore();
373
+				
374
+				// draw slice outlines
375
+				ctx.save();
376
+				ctx.lineWidth = options.series.pie.stroke.width;
377
+				currentAngle = startAngle;
378
+				for (var i = 0; i < slices.length; ++i)
379
+					drawSlice(slices[i].angle, options.series.pie.stroke.color, false);
380
+				ctx.restore();
381
+					
382
+				// draw donut hole
383
+				drawDonutHole(ctx);
384
+				
385
+				// draw labels
386
+				if (options.series.pie.label.show)
387
+					drawLabels();
388
+				
389
+				// restore to original state
390
+				ctx.restore();
391
+				
392
+				function drawSlice(angle, color, fill)
393
+				{	
394
+					if (angle<=0)
395
+						return;
396
+				
397
+					if (fill)
398
+						ctx.fillStyle = color;
399
+					else
400
+					{
401
+						ctx.strokeStyle = color;
402
+						ctx.lineJoin = 'round';
403
+					}
404
+						
405
+					ctx.beginPath();
406
+					if (Math.abs(angle - Math.PI*2) > 0.000000001)
407
+						ctx.moveTo(0,0); // Center of the pie
408
+					else if ($.browser.msie)
409
+						angle -= 0.0001;
410
+					//ctx.arc(0,0,radius,0,angle,false); // This doesn't work properly in Opera
411
+					ctx.arc(0,0,radius,currentAngle,currentAngle+angle,false);
412
+					ctx.closePath();
413
+					//ctx.rotate(angle); // This doesn't work properly in Opera
414
+					currentAngle += angle;
415
+					
416
+					if (fill)
417
+						ctx.fill();
418
+					else
419
+						ctx.stroke();
420
+				}
421
+				
422
+				function drawLabels()
423
+				{
424
+					var currentAngle = startAngle;
425
+					
426
+					// set radius
427
+					if (options.series.pie.label.radius>1)
428
+						var radius = options.series.pie.label.radius;
429
+					else
430
+						var radius = maxRadius * options.series.pie.label.radius;
431
+					
432
+					for (var i = 0; i < slices.length; ++i)
433
+					{
434
+						if (slices[i].percent >= options.series.pie.label.threshold*100)
435
+							drawLabel(slices[i], currentAngle, i);
436
+						currentAngle += slices[i].angle;
437
+					}
438
+					
439
+					function drawLabel(slice, startAngle, index)
440
+					{
441
+						if (slice.data[0][1]==0)
442
+							return;
443
+							
444
+						// format label text
445
+						var lf = options.legend.labelFormatter, text, plf = options.series.pie.label.formatter;
446
+						if (lf)
447
+							text = lf(slice.label, slice);
448
+						else
449
+							text = slice.label;
450
+						if (plf)
451
+							text = plf(text, slice);
452
+							
453
+						var halfAngle = ((startAngle+slice.angle) + startAngle)/2;
454
+						var x = centerLeft + Math.round(Math.cos(halfAngle) * radius);
455
+						var y = centerTop + Math.round(Math.sin(halfAngle) * radius) * options.series.pie.tilt;
456
+						
457
+						var html = '<span class="pieLabel" id="pieLabel'+index+'" style="position:absolute;top:' + y + 'px;left:' + x + 'px;">' + text + "</span>";
458
+						target.append(html);
459
+						var label = target.children('#pieLabel'+index);
460
+						var labelTop = (y - label.height()/2);
461
+						var labelLeft = (x - label.width()/2);
462
+						label.css('top', labelTop);
463
+						label.css('left', labelLeft);
464
+						
465
+						// check to make sure that the label is not outside the canvas
466
+						if (0-labelTop>0 || 0-labelLeft>0 || canvas.height-(labelTop+label.height())<0 || canvas.width-(labelLeft+label.width())<0)
467
+							redraw = true;
468
+						
469
+						if (options.series.pie.label.background.opacity != 0) {
470
+							// put in the transparent background separately to avoid blended labels and label boxes
471
+							var c = options.series.pie.label.background.color;
472
+							if (c == null) {
473
+								c = slice.color;
474
+							}
475
+							var pos = 'top:'+labelTop+'px;left:'+labelLeft+'px;';
476
+							$('<div class="pieLabelBackground" style="position:absolute;width:' + label.width() + 'px;height:' + label.height() + 'px;' + pos +'background-color:' + c + ';"> </div>').insertBefore(label).css('opacity', options.series.pie.label.background.opacity);
477
+						}
478
+					} // end individual label function
479
+				} // end drawLabels function
480
+			} // end drawPie function
481
+		} // end draw function
482
+		
483
+		// Placed here because it needs to be accessed from multiple locations 
484
+		function drawDonutHole(layer)
485
+		{
486
+			// draw donut hole
487
+			if(options.series.pie.innerRadius > 0)
488
+			{
489
+				// subtract the center
490
+				layer.save();
491
+				innerRadius = options.series.pie.innerRadius > 1 ? options.series.pie.innerRadius : maxRadius * options.series.pie.innerRadius;
492
+				layer.globalCompositeOperation = 'destination-out'; // this does not work with excanvas, but it will fall back to using the stroke color
493
+				layer.beginPath();
494
+				layer.fillStyle = options.series.pie.stroke.color;
495
+				layer.arc(0,0,innerRadius,0,Math.PI*2,false);
496
+				layer.fill();
497
+				layer.closePath();
498
+				layer.restore();
499
+				
500
+				// add inner stroke
501
+				layer.save();
502
+				layer.beginPath();
503
+				layer.strokeStyle = options.series.pie.stroke.color;
504
+				layer.arc(0,0,innerRadius,0,Math.PI*2,false);
505
+				layer.stroke();
506
+				layer.closePath();
507
+				layer.restore();
508
+				// TODO: add extra shadow inside hole (with a mask) if the pie is tilted.
509
+			}
510
+		}
511
+		
512
+		//-- Additional Interactive related functions --
513
+		
514
+		function isPointInPoly(poly, pt)
515
+		{
516
+			for(var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
517
+				((poly[i][1] <= pt[1] && pt[1] < poly[j][1]) || (poly[j][1] <= pt[1] && pt[1]< poly[i][1]))
518
+				&& (pt[0] < (poly[j][0] - poly[i][0]) * (pt[1] - poly[i][1]) / (poly[j][1] - poly[i][1]) + poly[i][0])
519
+				&& (c = !c);
520
+			return c;
521
+		}
522
+		
523
+		function findNearbySlice(mouseX, mouseY)
524
+		{
525
+			var slices = plot.getData(),
526
+				options = plot.getOptions(),
527
+				radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
528
+			
529
+			for (var i = 0; i < slices.length; ++i) 
530
+			{
531
+				var s = slices[i];	
532
+				
533
+				if(s.pie.show)
534
+				{
535
+					ctx.save();
536
+					ctx.beginPath();
537
+					ctx.moveTo(0,0); // Center of the pie
538
+					//ctx.scale(1, options.series.pie.tilt);	// this actually seems to break everything when here.
539
+					ctx.arc(0,0,radius,s.startAngle,s.startAngle+s.angle,false);
540
+					ctx.closePath();
541
+					x = mouseX-centerLeft;
542
+					y = mouseY-centerTop;
543
+					if(ctx.isPointInPath)
544
+					{
545
+						if (ctx.isPointInPath(mouseX-centerLeft, mouseY-centerTop))
546
+						{
547
+							//alert('found slice!');
548
+							ctx.restore();
549
+							return {datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i};
550
+						}
551
+					}
552
+					else
553
+					{
554
+						// excanvas for IE doesn;t support isPointInPath, this is a workaround. 
555
+						p1X = (radius * Math.cos(s.startAngle));
556
+						p1Y = (radius * Math.sin(s.startAngle));
557
+						p2X = (radius * Math.cos(s.startAngle+(s.angle/4)));
558
+						p2Y = (radius * Math.sin(s.startAngle+(s.angle/4)));
559
+						p3X = (radius * Math.cos(s.startAngle+(s.angle/2)));
560
+						p3Y = (radius * Math.sin(s.startAngle+(s.angle/2)));
561
+						p4X = (radius * Math.cos(s.startAngle+(s.angle/1.5)));
562
+						p4Y = (radius * Math.sin(s.startAngle+(s.angle/1.5)));
563
+						p5X = (radius * Math.cos(s.startAngle+s.angle));
564
+						p5Y = (radius * Math.sin(s.startAngle+s.angle));
565
+						arrPoly = [[0,0],[p1X,p1Y],[p2X,p2Y],[p3X,p3Y],[p4X,p4Y],[p5X,p5Y]];
566
+						arrPoint = [x,y];
567
+						// TODO: perhaps do some mathmatical trickery here with the Y-coordinate to compensate for pie tilt?
568
+						if(isPointInPoly(arrPoly, arrPoint))
569
+						{
570
+							ctx.restore();
571
+							return {datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i};
572
+						}			
573
+					}
574
+					ctx.restore();
575
+				}
576
+			}
577
+			
578
+			return null;
579
+		}
580
+
581
+		function onMouseMove(e) 
582
+		{
583
+			triggerClickHoverEvent('plothover', e);
584
+		}
585
+		
586
+        function onClick(e) 
587
+		{
588
+			triggerClickHoverEvent('plotclick', e);
589
+        }
590
+
591
+		// trigger click or hover event (they send the same parameters so we share their code)
592
+		function triggerClickHoverEvent(eventname, e) 
593
+		{
594
+			var offset = plot.offset(),
595
+				canvasX = parseInt(e.pageX - offset.left),
596
+				canvasY =  parseInt(e.pageY - offset.top),
597
+				item = findNearbySlice(canvasX, canvasY);
598
+			
599
+			if (options.grid.autoHighlight) 
600
+			{
601
+				// clear auto-highlights
602
+				for (var i = 0; i < highlights.length; ++i) 
603
+				{
604
+					var h = highlights[i];
605
+					if (h.auto == eventname && !(item && h.series == item.series))
606
+						unhighlight(h.series);
607
+				}
608
+			}
609
+			
610
+			// highlight the slice
611
+			if (item) 
612
+			    highlight(item.series, eventname);
613
+				
614
+			// trigger any hover bind events
615
+			var pos = { pageX: e.pageX, pageY: e.pageY };
616
+			target.trigger(eventname, [ pos, item ]);	
617
+		}
618
+
619
+		function highlight(s, auto) 
620
+		{
621
+			if (typeof s == "number")
622
+				s = series[s];
623
+
624
+			var i = indexOfHighlight(s);
625
+			if (i == -1) 
626
+			{
627
+				highlights.push({ series: s, auto: auto });
628
+				plot.triggerRedrawOverlay();
629
+			}
630
+			else if (!auto)
631
+				highlights[i].auto = false;
632
+		}
633
+
634
+		function unhighlight(s) 
635
+		{
636
+			if (s == null) 
637
+			{
638
+				highlights = [];
639
+				plot.triggerRedrawOverlay();
640
+			}
641
+			
642
+			if (typeof s == "number")
643
+				s = series[s];
644
+
645
+			var i = indexOfHighlight(s);
646
+			if (i != -1) 
647
+			{
648
+				highlights.splice(i, 1);
649
+				plot.triggerRedrawOverlay();
650
+			}
651
+		}
652
+
653
+		function indexOfHighlight(s) 
654
+		{
655
+			for (var i = 0; i < highlights.length; ++i) 
656
+			{
657
+				var h = highlights[i];
658
+				if (h.series == s)
659
+					return i;
660
+			}
661
+			return -1;
662
+		}
663
+
664
+		function drawOverlay(plot, octx) 
665
+		{
666
+			//alert(options.series.pie.radius);
667
+			var options = plot.getOptions();
668
+			//alert(options.series.pie.radius);
669
+			
670
+			var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
671
+
672
+			octx.save();
673
+			octx.translate(centerLeft, centerTop);
674
+			octx.scale(1, options.series.pie.tilt);
675
+			
676
+			for (i = 0; i < highlights.length; ++i) 
677
+				drawHighlight(highlights[i].series);
678
+			
679
+			drawDonutHole(octx);
680
+
681
+			octx.restore();
682
+
683
+			function drawHighlight(series) 
684
+			{
685
+				if (series.angle < 0) return;
686
+				
687
+				//octx.fillStyle = parseColor(options.series.pie.highlight.color).scale(null, null, null, options.series.pie.highlight.opacity).toString();
688
+				octx.fillStyle = "rgba(255, 255, 255, "+options.series.pie.highlight.opacity+")"; // this is temporary until we have access to parseColor
689
+				
690
+				octx.beginPath();
691
+				if (Math.abs(series.angle - Math.PI*2) > 0.000000001)
692
+					octx.moveTo(0,0); // Center of the pie
693
+				octx.arc(0,0,radius,series.startAngle,series.startAngle+series.angle,false);
694
+				octx.closePath();
695
+				octx.fill();
696
+			}
697
+			
698
+		}	
699
+		
700
+	} // end init (plugin body)
701
+	
702
+	// define pie specific options and their default values
703
+	var options = {
704
+		series: {
705
+			pie: {
706
+				show: false,
707
+				radius: 'auto',	// actual radius of the visible pie (based on full calculated radius if <=1, or hard pixel value)
708
+				innerRadius:0, /* for donut */
709
+				startAngle: 3/2,
710
+				tilt: 1,
711
+				offset: {
712
+					top: 0,
713
+					left: 'auto'
714
+				},
715
+				stroke: {
716
+					color: '#FFF',
717
+					width: 1
718
+				},
719
+				label: {
720
+					show: 'auto',
721
+					formatter: function(label, slice){
722
+						return '<div style="font-size:x-small;text-align:center;padding:2px;color:'+slice.color+';">'+label+'<br/>'+Math.round(slice.percent)+'%</div>';
723
+					},	// formatter function
724
+					radius: 1,	// radius at which to place the labels (based on full calculated radius if <=1, or hard pixel value)
725
+					background: {
726
+						color: null,
727
+						opacity: 0
728
+					},
729
+					threshold: 0	// percentage at which to hide the label (i.e. the slice is too narrow)
730
+				},
731
+				combine: {
732
+					threshold: -1,	// percentage at which to combine little slices into one larger slice
733
+					color: null,	// color to give the new slice (auto-generated if null)
734
+					label: 'Other'	// label to give the new slice
735
+				},
736
+				highlight: {
737
+					//color: '#FFF',		// will add this functionality once parseColor is available
738
+					opacity: 0.5
739
+				}
740
+			}
741
+		}
742
+	};
743
+    
744
+	$.plot.plugins.push({
745
+		init: init,
746
+		options: options,
747
+		name: "pie",
748
+		version: "1.0"
749
+	});
750
+})(jQuery);

+ 299
- 0
flot/jquery.flot.selection.js 查看文件

@@ -0,0 +1,299 @@
1
+/*
2
+Flot plugin for selecting regions.
3
+
4
+The plugin defines the following options:
5
+
6
+  selection: {
7
+    mode: null or "x" or "y" or "xy",
8
+    color: color
9
+  }
10
+
11
+You enable selection support by setting the mode to one of "x", "y" or
12
+"xy". In "x" mode, the user will only be able to specify the x range,
13
+similarly for "y" mode. For "xy", the selection becomes a rectangle
14
+where both ranges can be specified. "color" is color of the selection.
15
+
16
+When selection support is enabled, a "plotselected" event will be emitted
17
+on the DOM element you passed into the plot function. The event
18
+handler gets one extra parameter with the ranges selected on the axes,
19
+like this:
20
+
21
+  placeholder.bind("plotselected", function(event, ranges) {
22
+    alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to)
23
+    // similar for yaxis, secondary axes are in x2axis
24
+    // and y2axis if present
25
+  });
26
+
27
+The "plotselected" event is only fired when the user has finished
28
+making the selection. A "plotselecting" event is fired during the
29
+process with the same parameters as the "plotselected" event, in case
30
+you want to know what's happening while it's happening,
31
+
32
+A "plotunselected" event with no arguments is emitted when the user
33
+clicks the mouse to remove the selection.
34
+
35
+The plugin allso adds the following methods to the plot object:
36
+
37
+- setSelection(ranges, preventEvent)
38
+
39
+  Set the selection rectangle. The passed in ranges is on the same
40
+  form as returned in the "plotselected" event. If the selection
41
+  mode is "x", you should put in either an xaxis (or x2axis) object,
42
+  if the mode is "y" you need to put in an yaxis (or y2axis) object
43
+  and both xaxis/x2axis and yaxis/y2axis if the selection mode is
44
+  "xy", like this:
45
+
46
+    setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } });
47
+
48
+  setSelection will trigger the "plotselected" event when called. If
49
+  you don't want that to happen, e.g. if you're inside a
50
+  "plotselected" handler, pass true as the second parameter.
51
+  
52
+- clearSelection(preventEvent)
53
+
54
+  Clear the selection rectangle. Pass in true to avoid getting a
55
+  "plotunselected" event.
56
+
57
+- getSelection()
58
+
59
+  Returns the current selection in the same format as the
60
+  "plotselected" event. If there's currently no selection, the
61
+  function returns null.
62
+
63
+*/
64
+
65
+(function ($) {
66
+    function init(plot) {
67
+        var selection = {
68
+                first: { x: -1, y: -1}, second: { x: -1, y: -1},
69
+                show: false,
70
+                active: false
71
+            };
72
+
73
+        // FIXME: The drag handling implemented here should be
74
+        // abstracted out, there's some similar code from a library in
75
+        // the navigation plugin, this should be massaged a bit to fit
76
+        // the Flot cases here better and reused. Doing this would
77
+        // make this plugin much slimmer.
78
+        var savedhandlers = {};
79
+
80
+        function onMouseMove(e) {
81
+            if (selection.active) {
82
+                plot.getPlaceholder().trigger("plotselecting", [ getSelection() ]);
83
+
84
+                updateSelection(e);
85
+            }
86
+        }
87
+
88
+        function onMouseDown(e) {
89
+            if (e.which != 1)  // only accept left-click
90
+                return;
91
+            
92
+            // cancel out any text selections
93
+            document.body.focus();
94
+
95
+            // prevent text selection and drag in old-school browsers
96
+            if (document.onselectstart !== undefined && savedhandlers.onselectstart == null) {
97
+                savedhandlers.onselectstart = document.onselectstart;
98
+                document.onselectstart = function () { return false; };
99
+            }
100
+            if (document.ondrag !== undefined && savedhandlers.ondrag == null) {
101
+                savedhandlers.ondrag = document.ondrag;
102
+                document.ondrag = function () { return false; };
103
+            }
104
+
105
+            setSelectionPos(selection.first, e);
106
+
107
+            selection.active = true;
108
+            
109
+            $(document).one("mouseup", onMouseUp);
110
+        }
111
+
112
+        function onMouseUp(e) {
113
+            // revert drag stuff for old-school browsers
114
+            if (document.onselectstart !== undefined)
115
+                document.onselectstart = savedhandlers.onselectstart;
116
+            if (document.ondrag !== undefined)
117
+                document.ondrag = savedhandlers.ondrag;
118
+
119
+            // no more draggy-dee-drag
120
+            selection.active = false;
121
+            updateSelection(e);
122
+
123
+            if (selectionIsSane())
124
+                triggerSelectedEvent();
125
+            else {
126
+                // this counts as a clear
127
+                plot.getPlaceholder().trigger("plotunselected", [ ]);
128
+                plot.getPlaceholder().trigger("plotselecting", [ null ]);
129
+            }
130
+
131
+            return false;
132
+        }
133
+
134
+        function getSelection() {
135
+            if (!selectionIsSane())
136
+                return null;
137
+
138
+            var x1 = Math.min(selection.first.x, selection.second.x),
139
+                x2 = Math.max(selection.first.x, selection.second.x),
140
+                y1 = Math.max(selection.first.y, selection.second.y),
141
+                y2 = Math.min(selection.first.y, selection.second.y);
142
+
143
+            var r = {};
144
+            var axes = plot.getAxes();
145
+            if (axes.xaxis.used)
146
+                r.xaxis = { from: axes.xaxis.c2p(x1), to: axes.xaxis.c2p(x2) };
147
+            if (axes.x2axis.used)
148
+                r.x2axis = { from: axes.x2axis.c2p(x1), to: axes.x2axis.c2p(x2) };
149
+            if (axes.yaxis.used)
150
+                r.yaxis = { from: axes.yaxis.c2p(y1), to: axes.yaxis.c2p(y2) };
151
+            if (axes.y2axis.used)
152
+                r.y2axis = { from: axes.y2axis.c2p(y1), to: axes.y2axis.c2p(y2) };
153
+            return r;
154
+        }
155
+
156
+        function triggerSelectedEvent() {
157
+            var r = getSelection();
158
+
159
+            plot.getPlaceholder().trigger("plotselected", [ r ]);
160
+
161
+            // backwards-compat stuff, to be removed in future
162
+            var axes = plot.getAxes();
163
+            if (axes.xaxis.used && axes.yaxis.used)
164
+                plot.getPlaceholder().trigger("selected", [ { x1: r.xaxis.from, y1: r.yaxis.from, x2: r.xaxis.to, y2: r.yaxis.to } ]);
165
+        }
166
+
167
+        function clamp(min, value, max) {
168
+            return value < min? min: (value > max? max: value);
169
+        }
170
+
171
+        function setSelectionPos(pos, e) {
172
+            var o = plot.getOptions();
173
+            var offset = plot.getPlaceholder().offset();
174
+            var plotOffset = plot.getPlotOffset();
175
+            pos.x = clamp(0, e.pageX - offset.left - plotOffset.left, plot.width());
176
+            pos.y = clamp(0, e.pageY - offset.top - plotOffset.top, plot.height());
177
+
178
+            if (o.selection.mode == "y")
179
+                pos.x = pos == selection.first? 0: plot.width();
180
+
181
+            if (o.selection.mode == "x")
182
+                pos.y = pos == selection.first? 0: plot.height();
183
+        }
184
+
185
+        function updateSelection(pos) {
186
+            if (pos.pageX == null)
187
+                return;
188
+
189
+            setSelectionPos(selection.second, pos);
190
+            if (selectionIsSane()) {
191
+                selection.show = true;
192
+                plot.triggerRedrawOverlay();
193
+            }
194
+            else
195
+                clearSelection(true);
196
+        }
197
+
198
+        function clearSelection(preventEvent) {
199
+            if (selection.show) {
200
+                selection.show = false;
201
+                plot.triggerRedrawOverlay();
202
+                if (!preventEvent)
203
+                    plot.getPlaceholder().trigger("plotunselected", [ ]);
204
+            }
205
+        }
206
+
207
+        function setSelection(ranges, preventEvent) {
208
+            var axis, range, axes = plot.getAxes();
209
+            var o = plot.getOptions();
210
+
211
+            if (o.selection.mode == "y") {
212
+                selection.first.x = 0;
213
+                selection.second.x = plot.width();
214
+            }
215
+            else {
216
+                axis = ranges["xaxis"]? axes["xaxis"]: (ranges["x2axis"]? axes["x2axis"]: axes["xaxis"]);
217
+                range = ranges["xaxis"] || ranges["x2axis"] || { from:ranges["x1"], to:ranges["x2"] }
218
+                selection.first.x = axis.p2c(Math.min(range.from, range.to));
219
+                selection.second.x = axis.p2c(Math.max(range.from, range.to));
220
+            }
221
+
222
+            if (o.selection.mode == "x") {
223
+                selection.first.y = 0;
224
+                selection.second.y = plot.height();
225
+            }
226
+            else {
227
+                axis = ranges["yaxis"]? axes["yaxis"]: (ranges["y2axis"]? axes["y2axis"]: axes["yaxis"]);
228
+                range = ranges["yaxis"] || ranges["y2axis"] || { from:ranges["y1"], to:ranges["y2"] }
229
+                selection.first.y = axis.p2c(Math.min(range.from, range.to));
230
+                selection.second.y = axis.p2c(Math.max(range.from, range.to));
231
+            }
232
+
233
+            selection.show = true;
234
+            plot.triggerRedrawOverlay();
235
+            if (!preventEvent)
236
+                triggerSelectedEvent();
237
+        }
238
+
239
+        function selectionIsSane() {
240
+            var minSize = 5;
241
+            return Math.abs(selection.second.x - selection.first.x) >= minSize &&
242
+                Math.abs(selection.second.y - selection.first.y) >= minSize;
243
+        }
244
+
245
+        plot.clearSelection = clearSelection;
246
+        plot.setSelection = setSelection;
247
+        plot.getSelection = getSelection;
248
+
249
+        plot.hooks.bindEvents.push(function(plot, eventHolder) {
250
+            var o = plot.getOptions();
251
+            if (o.selection.mode != null)
252
+                eventHolder.mousemove(onMouseMove);
253
+
254
+            if (o.selection.mode != null)
255
+                eventHolder.mousedown(onMouseDown);
256
+        });
257
+
258
+
259
+        plot.hooks.drawOverlay.push(function (plot, ctx) {
260
+            // draw selection
261
+            if (selection.show && selectionIsSane()) {
262
+                var plotOffset = plot.getPlotOffset();
263
+                var o = plot.getOptions();
264
+
265
+                ctx.save();
266
+                ctx.translate(plotOffset.left, plotOffset.top);
267
+
268
+                var c = $.color.parse(o.selection.color);
269
+
270
+                ctx.strokeStyle = c.scale('a', 0.8).toString();
271
+                ctx.lineWidth = 1;
272
+                ctx.lineJoin = "round";
273
+                ctx.fillStyle = c.scale('a', 0.4).toString();
274
+
275
+                var x = Math.min(selection.first.x, selection.second.x),
276
+                    y = Math.min(selection.first.y, selection.second.y),
277
+                    w = Math.abs(selection.second.x - selection.first.x),
278
+                    h = Math.abs(selection.second.y - selection.first.y);
279
+
280
+                ctx.fillRect(x, y, w, h);
281
+                ctx.strokeRect(x, y, w, h);
282
+
283
+                ctx.restore();
284
+            }
285
+        });
286
+    }
287
+
288
+    $.plot.plugins.push({
289
+        init: init,
290
+        options: {
291
+            selection: {
292
+                mode: null, // one of null, "x", "y" or "xy"
293
+                color: "#e8cfac"
294
+            }
295
+        },
296
+        name: 'selection',
297
+        version: '1.0'
298
+    });
299
+})(jQuery);

+ 1
- 0
flot/jquery.flot.selection.min.js 查看文件

@@ -0,0 +1 @@
1
+(function(A){function B(J){var O={first:{x:-1,y:-1},second:{x:-1,y:-1},show:false,active:false};var L={};function D(Q){if(O.active){J.getPlaceholder().trigger("plotselecting",[F()]);K(Q)}}function M(Q){if(Q.which!=1){return }document.body.focus();if(document.onselectstart!==undefined&&L.onselectstart==null){L.onselectstart=document.onselectstart;document.onselectstart=function(){return false}}if(document.ondrag!==undefined&&L.ondrag==null){L.ondrag=document.ondrag;document.ondrag=function(){return false}}C(O.first,Q);O.active=true;A(document).one("mouseup",I)}function I(Q){if(document.onselectstart!==undefined){document.onselectstart=L.onselectstart}if(document.ondrag!==undefined){document.ondrag=L.ondrag}O.active=false;K(Q);if(E()){H()}else{J.getPlaceholder().trigger("plotunselected",[]);J.getPlaceholder().trigger("plotselecting",[null])}return false}function F(){if(!E()){return null}var R=Math.min(O.first.x,O.second.x),Q=Math.max(O.first.x,O.second.x),T=Math.max(O.first.y,O.second.y),S=Math.min(O.first.y,O.second.y);var U={};var V=J.getAxes();if(V.xaxis.used){U.xaxis={from:V.xaxis.c2p(R),to:V.xaxis.c2p(Q)}}if(V.x2axis.used){U.x2axis={from:V.x2axis.c2p(R),to:V.x2axis.c2p(Q)}}if(V.yaxis.used){U.yaxis={from:V.yaxis.c2p(T),to:V.yaxis.c2p(S)}}if(V.y2axis.used){U.y2axis={from:V.y2axis.c2p(T),to:V.y2axis.c2p(S)}}return U}function H(){var Q=F();J.getPlaceholder().trigger("plotselected",[Q]);var R=J.getAxes();if(R.xaxis.used&&R.yaxis.used){J.getPlaceholder().trigger("selected",[{x1:Q.xaxis.from,y1:Q.yaxis.from,x2:Q.xaxis.to,y2:Q.yaxis.to}])}}function G(R,S,Q){return S<R?R:(S>Q?Q:S)}function C(U,R){var T=J.getOptions();var S=J.getPlaceholder().offset();var Q=J.getPlotOffset();U.x=G(0,R.pageX-S.left-Q.left,J.width());U.y=G(0,R.pageY-S.top-Q.top,J.height());if(T.selection.mode=="y"){U.x=U==O.first?0:J.width()}if(T.selection.mode=="x"){U.y=U==O.first?0:J.height()}}function K(Q){if(Q.pageX==null){return }C(O.second,Q);if(E()){O.show=true;J.triggerRedrawOverlay()}else{P(true)}}function P(Q){if(O.show){O.show=false;J.triggerRedrawOverlay();if(!Q){J.getPlaceholder().trigger("plotunselected",[])}}}function N(R,Q){var T,S,U=J.getAxes();var V=J.getOptions();if(V.selection.mode=="y"){O.first.x=0;O.second.x=J.width()}else{T=R.xaxis?U.xaxis:(R.x2axis?U.x2axis:U.xaxis);S=R.xaxis||R.x2axis||{from:R.x1,to:R.x2};O.first.x=T.p2c(Math.min(S.from,S.to));O.second.x=T.p2c(Math.max(S.from,S.to))}if(V.selection.mode=="x"){O.first.y=0;O.second.y=J.height()}else{T=R.yaxis?U.yaxis:(R.y2axis?U.y2axis:U.yaxis);S=R.yaxis||R.y2axis||{from:R.y1,to:R.y2};O.first.y=T.p2c(Math.min(S.from,S.to));O.second.y=T.p2c(Math.max(S.from,S.to))}O.show=true;J.triggerRedrawOverlay();if(!Q){H()}}function E(){var Q=5;return Math.abs(O.second.x-O.first.x)>=Q&&Math.abs(O.second.y-O.first.y)>=Q}J.clearSelection=P;J.setSelection=N;J.getSelection=F;J.hooks.bindEvents.push(function(R,Q){var S=R.getOptions();if(S.selection.mode!=null){Q.mousemove(D)}if(S.selection.mode!=null){Q.mousedown(M)}});J.hooks.drawOverlay.push(function(T,Y){if(O.show&&E()){var R=T.getPlotOffset();var Q=T.getOptions();Y.save();Y.translate(R.left,R.top);var U=A.color.parse(Q.selection.color);Y.strokeStyle=U.scale("a",0.8).toString();Y.lineWidth=1;Y.lineJoin="round";Y.fillStyle=U.scale("a",0.4).toString();var W=Math.min(O.first.x,O.second.x),V=Math.min(O.first.y,O.second.y),X=Math.abs(O.second.x-O.first.x),S=Math.abs(O.second.y-O.first.y);Y.fillRect(W,V,X,S);Y.strokeRect(W,V,X,S);Y.restore()}})}A.plot.plugins.push({init:B,options:{selection:{mode:null,color:"#e8cfac"}},name:"selection",version:"1.0"})})(jQuery);

+ 152
- 0
flot/jquery.flot.stack.js 查看文件

@@ -0,0 +1,152 @@
1
+/*
2
+Flot plugin for stacking data sets, i.e. putting them on top of each
3
+other, for accumulative graphs. Note that the plugin assumes the data
4
+is sorted on x. Also note that stacking a mix of positive and negative
5
+values in most instances doesn't make sense (so it looks weird).
6
+
7
+Two or more series are stacked when their "stack" attribute is set to
8
+the same key (which can be any number or string or just "true"). To
9
+specify the default stack, you can set
10
+
11
+  series: {
12
+    stack: null or true or key (number/string)
13
+  }
14
+
15
+or specify it for a specific series
16
+
17
+  $.plot($("#placeholder"), [{ data: [ ... ], stack: true ])
18
+  
19
+The stacking order is determined by the order of the data series in
20
+the array (later series end up on top of the previous).
21
+
22
+Internally, the plugin modifies the datapoints in each series, adding
23
+an offset to the y value. For line series, extra data points are
24
+inserted through interpolation. For bar charts, the second y value is
25
+also adjusted.
26
+*/
27
+
28
+(function ($) {
29
+    var options = {
30
+        series: { stack: null } // or number/string
31
+    };
32
+    
33
+    function init(plot) {
34
+        function findMatchingSeries(s, allseries) {
35
+            var res = null
36
+            for (var i = 0; i < allseries.length; ++i) {
37
+                if (s == allseries[i])
38
+                    break;
39
+                
40
+                if (allseries[i].stack == s.stack)
41
+                    res = allseries[i];
42
+            }
43
+            
44
+            return res;
45
+        }
46
+        
47
+        function stackData(plot, s, datapoints) {
48
+            if (s.stack == null)
49
+                return;
50
+
51
+            var other = findMatchingSeries(s, plot.getData());
52
+            if (!other)
53
+                return;
54
+            
55
+            var ps = datapoints.pointsize,
56
+                points = datapoints.points,
57
+                otherps = other.datapoints.pointsize,
58
+                otherpoints = other.datapoints.points,
59
+                newpoints = [],
60
+                px, py, intery, qx, qy, bottom,
61
+                withlines = s.lines.show, withbars = s.bars.show,
62
+                withsteps = withlines && s.lines.steps,
63
+                i = 0, j = 0, l;
64
+
65
+            while (true) {
66
+                if (i >= points.length)
67
+                    break;
68
+
69
+                l = newpoints.length;
70
+
71
+                if (j >= otherpoints.length
72
+                    || otherpoints[j] == null
73
+                    || points[i] == null) {
74
+                    // degenerate cases
75
+                    for (m = 0; m < ps; ++m)
76
+                        newpoints.push(points[i + m]);
77
+                    i += ps;
78
+                }
79
+                else {
80
+                    // cases where we actually got two points
81
+                    px = points[i];
82
+                    py = points[i + 1];
83
+                    qx = otherpoints[j];
84
+                    qy = otherpoints[j + 1];
85
+                    bottom = 0;
86
+
87
+                    if (px == qx) {
88
+                        for (m = 0; m < ps; ++m)
89
+                            newpoints.push(points[i + m]);
90
+
91
+                        newpoints[l + 1] += qy;
92
+                        bottom = qy;
93
+                        
94
+                        i += ps;
95
+                        j += otherps;
96
+                    }
97
+                    else if (px > qx) {
98
+                        // we got past point below, might need to
99
+                        // insert interpolated extra point
100
+                        if (withlines && i > 0 && points[i - ps] != null) {
101
+                            intery = py + (points[i - ps + 1] - py) * (qx - px) / (points[i - ps] - px);
102
+                            newpoints.push(qx);
103
+                            newpoints.push(intery + qy)
104
+                            for (m = 2; m < ps; ++m)
105
+                                newpoints.push(points[i + m]);
106
+                            bottom = qy; 
107
+                        }
108
+
109
+                        j += otherps;
110
+                    }
111
+                    else {
112
+                        for (m = 0; m < ps; ++m)
113
+                            newpoints.push(points[i + m]);
114
+                        
115
+                        // we might be able to interpolate a point below,
116
+                        // this can give us a better y
117
+                        if (withlines && j > 0 && otherpoints[j - ps] != null)
118
+                            bottom = qy + (otherpoints[j - ps + 1] - qy) * (px - qx) / (otherpoints[j - ps] - qx);
119
+
120
+                        newpoints[l + 1] += bottom;
121
+                        
122
+                        i += ps;
123
+                    }
124
+                    
125
+                    if (l != newpoints.length && withbars)
126
+                        newpoints[l + 2] += bottom;
127
+                }
128
+
129
+                // maintain the line steps invariant
130
+                if (withsteps && l != newpoints.length && l > 0
131
+                    && newpoints[l] != null
132
+                    && newpoints[l] != newpoints[l - ps]
133
+                    && newpoints[l + 1] != newpoints[l - ps + 1]) {
134
+                    for (m = 0; m < ps; ++m)
135
+                        newpoints[l + ps + m] = newpoints[l + m];
136
+                    newpoints[l + 1] = newpoints[l - ps + 1];
137
+                }
138
+            }
139
+            
140
+            datapoints.points = newpoints;
141
+        }
142
+        
143
+        plot.hooks.processDatapoints.push(stackData);
144
+    }
145
+    
146
+    $.plot.plugins.push({
147
+        init: init,
148
+        options: options,
149
+        name: 'stack',
150
+        version: '1.0'
151
+    });
152
+})(jQuery);

+ 1
- 0
flot/jquery.flot.stack.min.js 查看文件

@@ -0,0 +1 @@
1
+(function(B){var A={series:{stack:null}};function C(F){function D(J,I){var H=null;for(var G=0;G<I.length;++G){if(J==I[G]){break}if(I[G].stack==J.stack){H=I[G]}}return H}function E(W,P,G){if(P.stack==null){return }var L=D(P,W.getData());if(!L){return }var T=G.pointsize,Y=G.points,H=L.datapoints.pointsize,S=L.datapoints.points,N=[],R,Q,I,a,Z,M,O=P.lines.show,K=P.bars.show,J=O&&P.lines.steps,X=0,V=0,U;while(true){if(X>=Y.length){break}U=N.length;if(V>=S.length||S[V]==null||Y[X]==null){for(m=0;m<T;++m){N.push(Y[X+m])}X+=T}else{R=Y[X];Q=Y[X+1];a=S[V];Z=S[V+1];M=0;if(R==a){for(m=0;m<T;++m){N.push(Y[X+m])}N[U+1]+=Z;M=Z;X+=T;V+=H}else{if(R>a){if(O&&X>0&&Y[X-T]!=null){I=Q+(Y[X-T+1]-Q)*(a-R)/(Y[X-T]-R);N.push(a);N.push(I+Z);for(m=2;m<T;++m){N.push(Y[X+m])}M=Z}V+=H}else{for(m=0;m<T;++m){N.push(Y[X+m])}if(O&&V>0&&S[V-T]!=null){M=Z+(S[V-T+1]-Z)*(R-a)/(S[V-T]-a)}N[U+1]+=M;X+=T}}if(U!=N.length&&K){N[U+2]+=M}}if(J&&U!=N.length&&U>0&&N[U]!=null&&N[U]!=N[U-T]&&N[U+1]!=N[U-T+1]){for(m=0;m<T;++m){N[U+T+m]=N[U+m]}N[U+1]=N[U-T+1]}}G.points=N}F.hooks.processDatapoints.push(E)}B.plot.plugins.push({init:C,options:A,name:"stack",version:"1.0"})})(jQuery);

+ 103
- 0
flot/jquery.flot.threshold.js 查看文件

@@ -0,0 +1,103 @@
1
+/*
2
+Flot plugin for thresholding data. Controlled through the option
3
+"threshold" in either the global series options
4
+
5
+  series: {
6
+    threshold: {
7
+      below: number
8
+      color: colorspec
9
+    }
10
+  }
11
+
12
+or in a specific series
13
+
14
+  $.plot($("#placeholder"), [{ data: [ ... ], threshold: { ... }}])
15
+
16
+The data points below "below" are drawn with the specified color. This
17
+makes it easy to mark points below 0, e.g. for budget data.
18
+
19
+Internally, the plugin works by splitting the data into two series,
20
+above and below the threshold. The extra series below the threshold
21
+will have its label cleared and the special "originSeries" attribute
22
+set to the original series. You may need to check for this in hover
23
+events.
24
+*/
25
+
26
+(function ($) {
27
+    var options = {
28
+        series: { threshold: null } // or { below: number, color: color spec}
29
+    };
30
+    
31
+    function init(plot) {
32
+        function thresholdData(plot, s, datapoints) {
33
+            if (!s.threshold)
34
+                return;
35
+            
36
+            var ps = datapoints.pointsize, i, x, y, p, prevp,
37
+                thresholded = $.extend({}, s); // note: shallow copy
38
+
39
+            thresholded.datapoints = { points: [], pointsize: ps };
40
+            thresholded.label = null;
41
+            thresholded.color = s.threshold.color;
42
+            thresholded.threshold = null;
43
+            thresholded.originSeries = s;
44
+            thresholded.data = [];
45
+
46
+            var below = s.threshold.below,
47
+                origpoints = datapoints.points,
48
+                addCrossingPoints = s.lines.show;
49
+
50
+            threspoints = [];
51
+            newpoints = [];
52
+
53
+            for (i = 0; i < origpoints.length; i += ps) {
54
+                x = origpoints[i]
55
+                y = origpoints[i + 1];
56
+
57
+                prevp = p;
58
+                if (y < below)
59
+                    p = threspoints;
60
+                else
61
+                    p = newpoints;
62
+
63
+                if (addCrossingPoints && prevp != p && x != null
64
+                    && i > 0 && origpoints[i - ps] != null) {
65
+                    var interx = (x - origpoints[i - ps]) / (y - origpoints[i - ps + 1]) * (below - y) + x;
66
+                    prevp.push(interx);
67
+                    prevp.push(below);
68
+                    for (m = 2; m < ps; ++m)
69
+                        prevp.push(origpoints[i + m]);
70
+                    
71
+                    p.push(null); // start new segment
72
+                    p.push(null);
73
+                    for (m = 2; m < ps; ++m)
74
+                        p.push(origpoints[i + m]);
75
+                    p.push(interx);
76
+                    p.push(below);
77
+                    for (m = 2; m < ps; ++m)
78
+                        p.push(origpoints[i + m]);
79
+                }
80
+
81
+                p.push(x);
82
+                p.push(y);
83
+            }
84
+
85
+            datapoints.points = newpoints;
86
+            thresholded.datapoints.points = threspoints;
87
+            
88
+            if (thresholded.datapoints.points.length > 0)
89
+                plot.getData().push(thresholded);
90
+                
91
+            // FIXME: there are probably some edge cases left in bars
92
+        }
93
+        
94
+        plot.hooks.processDatapoints.push(thresholdData);
95
+    }
96
+    
97
+    $.plot.plugins.push({
98
+        init: init,
99
+        options: options,
100
+        name: 'threshold',
101
+        version: '1.0'
102
+    });
103
+})(jQuery);

+ 1
- 0
flot/jquery.flot.threshold.min.js 查看文件

@@ -0,0 +1 @@
1
+(function(B){var A={series:{threshold:null}};function C(D){function E(L,S,M){if(!S.threshold){return }var F=M.pointsize,I,O,N,G,K,H=B.extend({},S);H.datapoints={points:[],pointsize:F};H.label=null;H.color=S.threshold.color;H.threshold=null;H.originSeries=S;H.data=[];var P=S.threshold.below,Q=M.points,R=S.lines.show;threspoints=[];newpoints=[];for(I=0;I<Q.length;I+=F){O=Q[I];N=Q[I+1];K=G;if(N<P){G=threspoints}else{G=newpoints}if(R&&K!=G&&O!=null&&I>0&&Q[I-F]!=null){var J=(O-Q[I-F])/(N-Q[I-F+1])*(P-N)+O;K.push(J);K.push(P);for(m=2;m<F;++m){K.push(Q[I+m])}G.push(null);G.push(null);for(m=2;m<F;++m){G.push(Q[I+m])}G.push(J);G.push(P);for(m=2;m<F;++m){G.push(Q[I+m])}}G.push(O);G.push(N)}M.points=newpoints;H.datapoints.points=threspoints;if(H.datapoints.points.length>0){L.getData().push(H)}}D.hooks.processDatapoints.push(E)}B.plot.plugins.push({init:C,options:A,name:"threshold",version:"1.0"})})(jQuery);

+ 4376
- 0
flot/jquery.js
文件差異過大導致無法顯示
查看文件


+ 19
- 0
flot/jquery.min.js
文件差異過大導致無法顯示
查看文件


+ 123
- 0
index.html 查看文件

@@ -0,0 +1,123 @@
1
+<!DOCTYPE html>
2
+<html>
3
+ <head>
4
+  <title>Spending Analyser</title>
5
+  <script src="flot/jquery.min.js" type="text/javascript"></script>
6
+  <script src="flot/jquery.flot.min.js" type="text/javascript"></script>
7
+  <script src="flot/jquery.flot.pie.js" type="text/javascript"></script>
8
+  <script src="data.php" type="text/javascript"></script>
9
+  <script type="text/javascript">
10
+   var previousPoint = null;
11
+   var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
12
+
13
+   function showTooltip(x, y, contents) {
14
+    $('<div id="tooltip">' + contents + '</div>').css( {
15
+     position: 'absolute',
16
+     display: 'none',
17
+     top: y + 5,
18
+     left: x + 5,
19
+     border: '1px solid #fdd',
20
+     padding: '2px',
21
+     'background-color': '#fee',
22
+    }).appendTo("body").fadeIn(200);
23
+   }
24
+
25
+   $(function() {
26
+    $.plot($('#history'), transData, {
27
+      xaxis: { mode: 'time', timeformat: '%y/%m'},
28
+      series: {
29
+        lines: { show: true },
30
+        points: { show: true }
31
+      },
32
+      grid: { hoverable: true, clickable: true },
33
+    });
34
+
35
+    $("#history").bind("plothover", function (event, pos, item) {
36
+     if (item) {
37
+      var id = {dataIndex: item.dataIndex, seriesIndex: item.seriesIndex};
38
+
39
+      if (previousPoint == null || previousPoint.dataIndex != id.dataIndex || previousPoint.seriesIndex != id.seriesIndex) {
40
+       previousPoint = id;
41
+                
42
+       $("#tooltip").remove();
43
+       var x = item.datapoint[0],
44
+           y = item.datapoint[1].toFixed(2);
45
+                    
46
+       var date = new Date(x);
47
+
48
+       showTooltip(item.pageX, item.pageY,
49
+                   (item.seriesIndex == 0 ? "Money in" : "Money out") + " during " + months[date.getMonth()] + " " + date.getFullYear() + " = " + y);
50
+      }
51
+     } else {
52
+      $("#tooltip").remove();
53
+      previousPoint = null;            
54
+     }
55
+    });
56
+
57
+    $('#history').bind('plotclick', function(event, pos, item) {
58
+     if (item) {
59
+      var incoming = item.seriesIndex == 0;
60
+      var dateOb = new Date(item.datapoint[0]);
61
+      var date = dateOb.getFullYear() + '-' + (dateOb.getMonth() < 9 ? '0' : '') + (dateOb.getMonth() + 1);
62
+
63
+      $('#historytable tr.data').remove();
64
+      $('#historytable').show();
65
+
66
+      $('#historytable h3').text('Transactions for ' + months[dateOb.getMonth()] + ' ' + dateOb.getFullYear());
67
+
68
+      var pieData = {};
69
+      var table = $('#historytable table');
70
+      $.each(monthData[date], function(index, trans) {
71
+       if (incoming != trans.Amount > 0) { return; }
72
+
73
+       var tr = $('<tr/>').addClass('data').appendTo(table);
74
+
75
+       trans.Category && trans.Category == '(Ignored)' && tr.addClass('ignored');
76
+       
77
+       $('<td/>').text(trans.Date.date.split(' ')[0]).appendTo(tr);
78
+       $('<td/>').text(trans.Type ? trans.Type : 'Other').appendTo(tr);
79
+       $('<td/>').text(trans.Category ? trans.Category : '').appendTo(tr);
80
+       $('<td/>').text(trans.Description).appendTo(tr);
81
+       $('<td/>').text(trans.Amount).appendTo(tr);
82
+
83
+       var category = trans.Category ? trans.Category : 'Unsorted';
84
+
85
+       if (category != '(Ignored)') {
86
+        if (!pieData[category]) { pieData[category] = 0; }
87
+        pieData[category] += Math.abs(trans.Amount);
88
+       }
89
+      });
90
+
91
+      var data = [];
92
+      $.each(pieData, function(category, amount) {
93
+       data.push({ label: category + ' (' + Math.round(amount) + ')', data: amount });
94
+      });
95
+
96
+      data.sort(function(a, b) { return b.data - a.data; });
97
+
98
+      $.plot($('#expense'), data, {
99
+        series: { pie: { show: true, innerRadius: 0.5 } }
100
+      });
101
+     }
102
+    });
103
+   });
104
+  </script>
105
+  <style type="text/css">
106
+   .ignored td { color: gray; }
107
+   .left { width: 45%; float: left; }
108
+   .right { margin-left: 50%; }
109
+   h2 { margin-top: 0; }
110
+  </style>
111
+ </head>
112
+ <body>
113
+  <div class="left">
114
+   <h2>Transaction History</h2>
115
+   <div id="history" style="width: 600px; height: 300px;"></div>
116
+   <div id="historytable" style="display: none;"><h3>Transactions for ??</h3><table><tr><th>Date</th><th>Type</th><th>Category</th><th>Description</th><th>Amount</th></tr></table></div>
117
+  </div>
118
+  <div class="right">
119
+   <h2>Categories</h2>
120
+   <div id="expense" style="width: 600px; height: 300px;"></div>
121
+  </div>
122
+ </body>
123
+</html>

Loading…
取消
儲存