Merge lp:~openerp-dev/openerp-web/trunk-new-graphview-ged into lp:openerp-web

Proposed by Géry Debongnie
Status: Merged
Merged at revision: 3918
Proposed branch: lp:~openerp-dev/openerp-web/trunk-new-graphview-ged
Merge into: lp:openerp-web
Diff against target: 51541 lines (+25106/-26000)
69 files modified
addons/web/static/src/js/data.js (+7/-2)
addons/web/static/src/js/pyeval.js (+7/-4)
addons/web/static/src/js/search.js (+1/-1)
addons/web/static/test/search.js (+8/-2)
addons/web_graph/__openerp__.py (+5/-31)
addons/web_graph/static/lib/flotr2/LICENSE (+0/-19)
addons/web_graph/static/lib/flotr2/Makefile (+0/-40)
addons/web_graph/static/lib/flotr2/README.md (+0/-89)
addons/web_graph/static/lib/flotr2/dev/notes.txt (+0/-86)
addons/web_graph/static/lib/flotr2/flotr2.examples.min.js (+0/-2)
addons/web_graph/static/lib/flotr2/flotr2.examples.types.js (+0/-1425)
addons/web_graph/static/lib/flotr2/flotr2.ie.min.js (+0/-33)
addons/web_graph/static/lib/flotr2/flotr2.js (+0/-6865)
addons/web_graph/static/lib/flotr2/flotr2.min.js (+0/-27)
addons/web_graph/static/lib/flotr2/js/Axis.js (+0/-303)
addons/web_graph/static/lib/flotr2/js/Color.js (+0/-163)
addons/web_graph/static/lib/flotr2/js/DOM.js (+0/-88)
addons/web_graph/static/lib/flotr2/js/Date.js (+0/-207)
addons/web_graph/static/lib/flotr2/js/DefaultOptions.js (+0/-98)
addons/web_graph/static/lib/flotr2/js/EventAdapter.js (+0/-52)
addons/web_graph/static/lib/flotr2/js/Flotr.js (+0/-250)
addons/web_graph/static/lib/flotr2/js/Graph.js (+0/-745)
addons/web_graph/static/lib/flotr2/js/Series.js (+0/-74)
addons/web_graph/static/lib/flotr2/js/Text.js (+0/-88)
addons/web_graph/static/lib/flotr2/js/plugins/crosshair.js (+0/-84)
addons/web_graph/static/lib/flotr2/js/plugins/download.js (+0/-51)
addons/web_graph/static/lib/flotr2/js/plugins/grid.js (+0/-208)
addons/web_graph/static/lib/flotr2/js/plugins/handles.js (+0/-199)
addons/web_graph/static/lib/flotr2/js/plugins/hit.js (+0/-337)
addons/web_graph/static/lib/flotr2/js/plugins/labels.js (+0/-227)
addons/web_graph/static/lib/flotr2/js/plugins/legend.js (+0/-179)
addons/web_graph/static/lib/flotr2/js/plugins/selection.js (+0/-278)
addons/web_graph/static/lib/flotr2/js/plugins/spreadsheet.js (+0/-296)
addons/web_graph/static/lib/flotr2/js/plugins/titles.js (+0/-177)
addons/web_graph/static/lib/flotr2/js/types/bars.js (+0/-274)
addons/web_graph/static/lib/flotr2/js/types/bubbles.js (+0/-119)
addons/web_graph/static/lib/flotr2/js/types/candles.js (+0/-127)
addons/web_graph/static/lib/flotr2/js/types/gantt.js (+0/-229)
addons/web_graph/static/lib/flotr2/js/types/lines.js (+0/-275)
addons/web_graph/static/lib/flotr2/js/types/markers.js (+0/-140)
addons/web_graph/static/lib/flotr2/js/types/pie.js (+0/-210)
addons/web_graph/static/lib/flotr2/js/types/points.js (+0/-66)
addons/web_graph/static/lib/flotr2/js/types/radar.js (+0/-60)
addons/web_graph/static/lib/flotr2/js/types/timeline.js (+0/-90)
addons/web_graph/static/lib/flotr2/lib/base64.js (+0/-113)
addons/web_graph/static/lib/flotr2/lib/bean-min.js (+0/-10)
addons/web_graph/static/lib/flotr2/lib/bean.js (+0/-501)
addons/web_graph/static/lib/flotr2/lib/canvas2image.js (+0/-198)
addons/web_graph/static/lib/flotr2/lib/canvastext.js (+0/-429)
addons/web_graph/static/lib/flotr2/lib/excanvas.js (+0/-1425)
addons/web_graph/static/lib/flotr2/lib/imagediff.js (+0/-343)
addons/web_graph/static/lib/flotr2/lib/jasmine/MIT.LICENSE (+0/-20)
addons/web_graph/static/lib/flotr2/lib/jasmine/jasmine-html.js (+0/-190)
addons/web_graph/static/lib/flotr2/lib/jasmine/jasmine.css (+0/-166)
addons/web_graph/static/lib/flotr2/lib/jasmine/jasmine.js (+0/-2476)
addons/web_graph/static/lib/flotr2/lib/prototype.js (+0/-4320)
addons/web_graph/static/lib/flotr2/lib/underscore-min.js (+0/-27)
addons/web_graph/static/lib/flotr2/lib/underscore.js (+0/-839)
addons/web_graph/static/lib/flotr2/lib/yepnope.js (+0/-1)
addons/web_graph/static/lib/nvd3/d3.v3.js (+8436/-0)
addons/web_graph/static/lib/nvd3/nv.d3.js (+14303/-0)
addons/web_graph/static/src/css/flotr2.css (+0/-69)
addons/web_graph/static/src/css/graph.css (+89/-78)
addons/web_graph/static/src/css/nv.d3.css (+769/-0)
addons/web_graph/static/src/js/graph.js (+0/-434)
addons/web_graph/static/src/js/graph_view.js (+199/-0)
addons/web_graph/static/src/js/graph_widget.js (+711/-0)
addons/web_graph/static/src/js/pivot_table.js (+462/-0)
addons/web_graph/static/src/xml/web_graph.xml (+109/-41)
To merge this branch: bzr merge lp:~openerp-dev/openerp-web/trunk-new-graphview-ged
Reviewer Review Type Date Requested Status
Xavier (Open ERP) Pending
Review via email: mp+202054@code.launchpad.net

Description of the change

New graph view, Pivot table and stuff.

To post a comment you must log in.
4081. By Géry Debongnie

[FIX] fixes a typo 'widet_config' => 'widget_config' (it previously crashed the graph view) (addon web_graph)

4082. By Géry Debongnie

[IMP] change the icon and tooltip of heat map (column) in graph view (addon web_graph)

4083. By Géry Debongnie

[IMP] makes sure that the graph view does not reload data if the user removes a measure. Also, display the 'no data' screen if there are no current measure in graph view (addon web_graph)

4084. By Géry Debongnie

[IMP] adds checkmarks next to measures when they are used in graph view (addon web_graph)

4085. By Géry Debongnie

[IMP] display bar chart controls when the size is large enough and when it makes sense (dim x + dim y >= 2) in grap view (addon web_graph)

4086. By Géry Debongnie

[IMP] keeps the dropdown open when the user selects some measures in graph view (addon web_graph)

4087. By Géry Debongnie

[FIX] fixes a typo (nodata => no_data), which prevents a crash in graph_view, addon web_graph)

4088. By Géry Debongnie

[FIX] fix crash happening when user goes to graph view, switch to other view, changes groupby and goes back to graph view. (addon web_graph)

4089. By Géry Debongnie

[IMP] optimizes pivot table so that it doesn't reload data when the groupbys have been changed in such a way that it should only fold some headers (addon web_graph)

4090. By Géry Debongnie

[REF] large refactoring in graph view: changes the flow of the program to make it much simpler (addon web_graph)

4091. By Géry Debongnie

[MERGE] merge trunk into local branch

4092. By Géry Debongnie

[IMP] two small tweaks to improve the code quality in addon web_graph

4093. By Géry Debongnie

[FIX] makes the querygroup methods compatible with the 'field:interval' format of groupbys accepted by read_group

4094. By Géry Debongnie

[IMP] changes the backend code of graph view to use the new functionality of read_group (use 'field_name:interval' in readgroup instead of context (addon web_graph)

4095. By Géry Debongnie

[REF] refactoring: removes the 'interval' attributes in groupbys and improves searchbar integration (addon web_graph)

4096. By Géry Debongnie

[FIX] fixes a crash happening when in dashboards, the graph view was trying to access undefined attributes (addon web_graph)

4097. By Géry Debongnie

[FIX] fixes a problem with fields selection : the string was not correctly displayed (addon web_graph)

4098. By Géry Debongnie

[IMP] graph_view now properly honors the 'interval' attribute of field names in the xml description (addon web_graph)

4099. By Géry Debongnie

[FIX] fixes two small issues concerning the groupby dates in graph view (addon web_graph)

4100. By Géry Debongnie

[REF] lots of small tweaks to improve the code, and some small fixes, after xmo's code review (addon web_graph)

4101. By Géry Debongnie

[FIX] fixes a crash in line chart mode when the view had more than one measure (addon web_graph)

4102. By Géry Debongnie

[FIX] fixes a typo, causing crashes when selecting date fields in groupbys (addon web_graph)

4103. By Géry Debongnie

[MERGE] merge trunk into local branch

4104. By Géry Debongnie

[FIX] fixes a crash happening when the context has a groupby attributes which is an array (addon web_graph)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'addons/web/static/src/js/data.js'
2--- addons/web/static/src/js/data.js 2014-01-15 22:13:49 +0000
3+++ addons/web/static/src/js/data.js 2014-01-27 15:23:42 +0000
4@@ -129,11 +129,14 @@
5 if (_.isEmpty(grouping) && !ctx['group_by_no_leaf']) {
6 return null;
7 }
8+ var raw_fields = _.map(grouping.concat(this._fields || []), function (field) {
9+ return (_.contains(field, ':')) ? field.split(':')[0] : field;
10+ });
11
12 var self = this;
13 return this._model.call('read_group', {
14 groupby: grouping,
15- fields: _.uniq(grouping.concat(this._fields || [])),
16+ fields: _.uniq(raw_fields),
17 domain: this._model.domain(this._filter),
18 context: ctx,
19 offset: this._offset,
20@@ -233,12 +236,14 @@
21
22 var group_size = fixed_group[grouping_field + '_count'] || fixed_group.__count || 0;
23 var leaf_group = fixed_group.__context.group_by.length === 0;
24+ var raw_field = (_.contains(grouping_field, ':')) ? grouping_field.split(':')[0] : grouping_field;
25+
26 this.attributes = {
27 folded: !!(fixed_group.__fold),
28 grouped_on: grouping_field,
29 // if terminal group (or no group) and group_by_no_leaf => use group.__count
30 length: group_size,
31- value: fixed_group[grouping_field],
32+ value: fixed_group[raw_field],
33 // A group is open-able if it's not a leaf in group_by_no_leaf mode
34 has_children: !(leaf_group && fixed_group.__context['group_by_no_leaf']),
35
36
37=== modified file 'addons/web/static/src/js/pyeval.js'
38--- addons/web/static/src/js/pyeval.js 2013-08-06 12:50:22 +0000
39+++ addons/web/static/src/js/pyeval.js 2014-01-27 15:23:42 +0000
40@@ -845,16 +845,18 @@
41 };
42 instance.web.pyeval.eval_domains_and_contexts = function (source) {
43 return new $.Deferred(function (d) {setTimeout(function () {
44+ var result;
45 try {
46 var contexts = ([instance.session.user_context] || []).concat(source.contexts);
47 // see Session.eval_context in Python
48- d.resolve({
49+ result = {
50 context: instance.web.pyeval.eval('contexts', contexts),
51 domain: instance.web.pyeval.eval('domains', source.domains),
52 group_by: instance.web.pyeval.eval('groupbys', source.group_by_seq || [])
53- });
54+ };
55+
56 } catch (e) {
57- d.resolve({ error: {
58+ result = { error: {
59 code: 400,
60 message: instance.web._t("Evaluation Error"),
61 data: {
62@@ -863,8 +865,9 @@
63 instance.web._t("Local evaluation failure\n%s\n\n%s"),
64 e.message, JSON.stringify(source))
65 }
66- }});
67+ }};
68 }
69+ d.resolve(result);
70 }, 0); });
71 };
72 })();
73
74=== modified file 'addons/web/static/src/js/search.js'
75--- addons/web/static/src/js/search.js 2014-01-15 22:13:49 +0000
76+++ addons/web/static/src/js/search.js 2014-01-27 15:23:42 +0000
77@@ -85,7 +85,7 @@
78 && facet.get('field') === model.get('field');
79 });
80 if (previous) {
81- previous.values.add(model.get('values'));
82+ previous.values.add(model.get('values'), _.omit(options, 'at', 'merge'));
83 return;
84 }
85 B.Collection.prototype.add.call(this, model, options);
86
87=== modified file 'addons/web/static/test/search.js'
88--- addons/web/static/test/search.js 2013-11-07 11:12:31 +0000
89+++ addons/web/static/test/search.js 2014-01-27 15:23:42 +0000
90@@ -425,7 +425,7 @@
91 "should have the right facet in the query");
92 });
93 });
94- test('facet selection: new value existing facet', {asserts: 3}, function (instance, $s) {
95+ test('facet selection: new value existing facet', {asserts: 8}, function (instance, $s) {
96 var field = {
97 get_domain: openerp.testing.noop,
98 get_context: openerp.testing.noop,
99@@ -451,8 +451,14 @@
100 {item: completion});
101 equal(view.query.length, 1, "should still have only one facet");
102 var facet = view.query.at(0);
103+ var values = facet.get('values');
104+ equal(values.length, 2, 'should have two values');
105+ equal(values[0].label, 'previous');
106+ equal(values[0].value, 41);
107+ equal(values[1].label, 'dummy');
108+ equal(values[1].value, 42);
109 deepEqual(
110- facet.get('values'),
111+ values,
112 [{label: 'previous', value: 41}, {label: 'dummy', value: 42}],
113 "should have added selected value to old one");
114 });
115
116=== modified file 'addons/web_graph/__openerp__.py'
117--- addons/web_graph/__openerp__.py 2013-12-12 09:45:18 +0000
118+++ addons/web_graph/__openerp__.py 2014-01-27 15:23:42 +0000
119@@ -15,37 +15,11 @@
120 'version': '3.0',
121 'depends': ['web'],
122 'js': [
123- 'static/lib/flotr2/lib/bean.js',
124- 'static/lib/flotr2/js/Flotr.js',
125- 'static/lib/flotr2/js/DefaultOptions.js',
126- 'static/lib/flotr2/js/Color.js',
127- 'static/lib/flotr2/js/Date.js',
128- 'static/lib/flotr2/js/DOM.js',
129- 'static/lib/flotr2/js/EventAdapter.js',
130- 'static/lib/flotr2/js/Text.js',
131- 'static/lib/flotr2/js/Graph.js',
132- 'static/lib/flotr2/js/Axis.js',
133- 'static/lib/flotr2/js/Series.js',
134- 'static/lib/flotr2/js/types/lines.js',
135- 'static/lib/flotr2/js/types/bars.js',
136- 'static/lib/flotr2/js/types/bubbles.js',
137- 'static/lib/flotr2/js/types/candles.js',
138- 'static/lib/flotr2/js/types/gantt.js',
139- 'static/lib/flotr2/js/types/markers.js',
140- 'static/lib/flotr2/js/types/pie.js',
141- 'static/lib/flotr2/js/types/points.js',
142- 'static/lib/flotr2/js/types/radar.js',
143- 'static/lib/flotr2/js/types/timeline.js',
144- 'static/lib/flotr2/js/plugins/crosshair.js',
145- 'static/lib/flotr2/js/plugins/download.js',
146- 'static/lib/flotr2/js/plugins/grid.js',
147- 'static/lib/flotr2/js/plugins/hit.js',
148- 'static/lib/flotr2/js/plugins/selection.js',
149- 'static/lib/flotr2/js/plugins/labels.js',
150- 'static/lib/flotr2/js/plugins/legend.js',
151- 'static/lib/flotr2/js/plugins/spreadsheet.js',
152- 'static/lib/flotr2/js/plugins/titles.js',
153- 'static/src/js/graph.js'
154+ 'static/lib/nvd3/d3.v3.js',
155+ 'static/lib/nvd3/nv.d3.js',
156+ 'static/src/js/graph_view.js',
157+ 'static/src/js/pivot_table.js',
158+ 'static/src/js/graph_widget.js',
159 ],
160 'css': [
161 'static/src/css/*.css',
162
163=== removed directory 'addons/web_graph/static/lib/flotr2'
164=== removed file 'addons/web_graph/static/lib/flotr2/LICENSE'
165--- addons/web_graph/static/lib/flotr2/LICENSE 2012-05-07 08:19:08 +0000
166+++ addons/web_graph/static/lib/flotr2/LICENSE 1970-01-01 00:00:00 +0000
167@@ -1,19 +0,0 @@
168-Copyright (c) 2012 Carl Sutherland
169-
170-Permission is hereby granted, free of charge, to any person obtaining a copy
171-of this software and associated documentation files (the "Software"), to deal
172-in the Software without restriction, including without limitation the rights
173-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
174-copies of the Software, and to permit persons to whom the Software is
175-furnished to do so, subject to the following conditions:
176-
177-The above copyright notice and this permission notice shall be included in
178-all copies or substantial portions of the Software.
179-
180-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
181-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
182-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
183-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
184-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
185-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
186-THE SOFTWARE.
187
188=== removed file 'addons/web_graph/static/lib/flotr2/Makefile'
189--- addons/web_graph/static/lib/flotr2/Makefile 2012-05-07 10:34:07 +0000
190+++ addons/web_graph/static/lib/flotr2/Makefile 1970-01-01 00:00:00 +0000
191@@ -1,40 +0,0 @@
192-all: test flotr2
193-
194-test:
195- cd spec; jasmine-headless-webkit -j jasmine.yml -c
196-
197-libraries:
198- smoosh make/lib.json
199- cat ./build/bean.js > build/lib.js
200- cat ./build/underscore.js >> build/lib.js
201- cat ./build/bean.min.js > build/lib.min.js
202- echo ";" >> build/lib.min.js
203- cat ./build/underscore.min.js >> build/lib.min.js
204- echo ";" >> build/lib.min.js
205-
206-ie:
207- smoosh make/ie.json
208-
209-flotr2: libraries ie
210- smoosh make/flotr2.json
211- cat build/lib.js build/flotr2.js > flotr2.js
212- cat build/lib.min.js > flotr2.min.js
213- cat build/flotr2.min.js >> flotr2.min.js
214- echo ';' >> flotr2.min.js
215- cp build/ie.min.js flotr2.ie.min.js
216-
217-flotr2-basic: libraries ie
218- smoosh make/basic.json
219- cat build/lib.min.js > flotr2-basic.min.js
220- cat build/flotr2-basic.min.js >> flotr2-basic.min.js
221-
222-flotr2-standalone: ie
223- smoosh make/flotr2.json
224- cat build/flotr2.js > flotr2.js
225- cp build/ie.min.js flotr2.ie.min.js
226-
227-flotr-examples:
228- smoosh make/examples.json
229- cp build/examples.min.js flotr2.examples.min.js
230- cp build/examples-types.js flotr2.examples.types.js
231-
232
233=== removed file 'addons/web_graph/static/lib/flotr2/README.md'
234--- addons/web_graph/static/lib/flotr2/README.md 2012-05-07 08:19:08 +0000
235+++ addons/web_graph/static/lib/flotr2/README.md 1970-01-01 00:00:00 +0000
236@@ -1,89 +0,0 @@
237-Flotr2
238-======
239-
240-The Canvas graphing library.
241-
242-![Google Groups](http://groups.google.com/intl/en/images/logos/groups_logo_sm.gif)
243-
244-http://groups.google.com/group/flotr2/
245-
246-Please fork http://jsfiddle.net/cesutherland/ZFBj5/ with your question or bug reproduction case.
247-
248-
249-API
250----
251-
252-The API consists of a primary draw method which accepts a configuration object, helper methods, and several microlibs.
253-
254-### Example
255-
256-```javascript
257- var
258- // Container div:
259- container = document.getElementById("flotr-example-graph"),
260- // First data series:
261- d1 = [[0, 3], [4, 8], [8, 5], [9, 13]],
262- // Second data series:
263- d2 = [],
264- // A couple flotr configuration options:
265- options = {
266- xaxis: {
267- minorTickFreq: 4
268- },
269- grid: {
270- minorVerticalLines: true
271- }
272- },
273- i, graph;
274-
275- // Generated second data set:
276- for (i = 0; i < 14; i += 0.5) {
277- d2.push([i, Math.sin(i)]);
278- }
279-
280- // Draw the graph:
281- graph = Flotr.draw(
282- container, // Container element
283- [ d1, d2 ], // Array of data series
284- options // Configuration options
285- );
286-```
287-
288-### Microlibs
289-
290-* [underscore.js](http://documentcloud.github.com/underscore/)
291-* [bean.js](https://github.com/fat/bean)
292-
293-Extending
294----------
295-
296-Flotr may be extended by adding new plugins and graph types.
297-
298-### Graph Types
299-
300-Graph types define how a particular chart is rendered. Examples include line, bar, pie.
301-
302-Existing graph types are found in `js/types/`.
303-
304-### Plugins
305-
306-Plugins extend the core of flotr with new functionality. They can add interactions, new decorations, etc. Examples
307-include titles, labels and selection.
308-
309-The plugins included are found in `js/plugins/`.
310-
311-Development
312------------
313-
314-This project uses [smoosh](https://github.com/fat/smoosh) to build and [jasmine](http://pivotal.github.com/jasmine/)
315-with [js-imagediff](https://github.com/HumbleSoftware/js-imagediff) to test. Tests may be executed by
316-[jasmine-headless-webkit](http://johnbintz.github.com/jasmine-headless-webkit/) with
317-`cd spec; jasmine-headless-webkit -j jasmine.yml -c` or by a browser by navigating to
318-`flotr2/spec/SpecRunner.html`.
319-
320-Shoutouts
321----------
322-
323-Thanks to Bas Wenneker, Fabien Ménager and others for all the work on the original Flotr.
324-Thanks to Jochen Berger and Jordan Santell for their contributions to Flotr2.
325-
326
327=== removed directory 'addons/web_graph/static/lib/flotr2/dev'
328=== removed file 'addons/web_graph/static/lib/flotr2/dev/notes.txt'
329--- addons/web_graph/static/lib/flotr2/dev/notes.txt 2012-05-07 08:19:08 +0000
330+++ addons/web_graph/static/lib/flotr2/dev/notes.txt 1970-01-01 00:00:00 +0000
331@@ -1,86 +0,0 @@
332-Flotr 2 Architecture Notes
333-
334-
335-Global:
336-======
337-
338-Flotr.js -
339- versioning information
340- browser detection
341- extension (plugins, graph types)
342- draw
343- clone / merge
344- tick size
345- tick formatter
346- engineering notation
347- magnitude
348- rad, pixel, floor
349- drawText
350- measureText
351- getBestTextAlign
352- align map
353- compatibility
354-
355-
356-Graph Architecture:
357-===================
358-
359-Axis -
360- all series
361- orientation
362- ticks (major, minor)
363- scale (d2p, p2d, logarithmic)
364- notion of stacks
365-
366-Series -
367- per 'data'
368- notion of range (x, y, min, max)
369-
370-Graph -
371- DOM constructon
372- event attachment
373- options initialization
374- data range calculations
375- canvas spacing calculations
376- event normalization
377- draw methods
378- DOM cleanup
379- event cleanup
380-
381-
382-Utilities:
383-==========
384-
385-Color
386- build colors
387- parse textual color data
388- convert colors
389- clone colors
390-
391-Text
392- calculate text size
393- canvas size
394- html size
395-
396-Date
397- formatting
398- constants
399-
400-
401-Spacing Calculation
402-===================
403-
404-Flotr
405- calculate data
406- calculate margins
407-
408-Chart
409- calculate Data Ranges - Explicit or auto data minimum, maximums
410- calculate Data Range Extensions - By chart type, extend data range with needs of chart type (ie. stacked bars, stacked lines)
411- add Chart Padding - By chart type
412-
413-Text
414- use explicit margins
415- calculate label margins
416- calculate title margins
417-
418
419=== removed file 'addons/web_graph/static/lib/flotr2/flotr2.examples.min.js'
420--- addons/web_graph/static/lib/flotr2/flotr2.examples.min.js 2012-05-07 08:19:08 +0000
421+++ addons/web_graph/static/lib/flotr2/flotr2.examples.min.js 1970-01-01 00:00:00 +0000
422@@ -1,2 +0,0 @@
423-
424-(function(){var a=Flotr.EventAdapter,b=Flotr._,c="click",d="example",e="mouseenter",f="mouseleave",g=".",h="flotr-examples",i="flotr-examples-container",j="flotr-examples-reset",k="flotr-examples-thumbs",l="flotr-examples-thumb",m="flotr-examples-collapsed",n="flotr-examples-highlight",o="flotr-examples-large",p="flotr-examples-medium",q="flotr-examples-small",r="flotr-examples-mobile",s='<div class="'+l+'"></div>',t='<div class="'+h+'">'+'<div class="'+j+'">View All</div>'+'<div class="'+k+'"></div>'+'<div class="'+i+'"></div>'+"</div>";Examples=function(a){if(b.isUndefined(Flotr.ExampleList))throw"Flotr.ExampleList not defined.";this.options=a,this.list=Flotr.ExampleList,this.current=null,this.single=!1,this._initNodes(),this._example=new Flotr.Examples.Example({node:this._exampleNode}),this._initExamples()},Examples.prototype={examples:function(){function f(b){var c=$(b.currentTarget),e=c.data("example"),f=b.data.orientation;f^c.hasClass(n)&&(c.toggleClass(n).css(a),d._example.executeCallback(e,c))}var a={cursor:"pointer"},b=this._thumbsNode,c=this.list.get(),d=this,e=["basic","basic-axis","basic-bars","basic-bars-horizontal","basic-bar-stacked","basic-stacked-horizontal","basic-pie","basic-radar","basic-bubble","basic-candle","basic-legend","mouse-tracking","mouse-zoom","mouse-drag","basic-time","negative-values","click-example","download-image","download-data","advanced-titles","color-gradients","basic-timeline","advanced-markers"];(function h(){var a=e.shift(),f=c[a];if(f.type==="profile"||f.type==="test")return;var g=$(s);g.data("example",f),b.append(g),d._example.executeCallback(f,g),g.click(function(){d._loadExample(f)}),e.length&&setTimeout(h,20)})(),b.delegate(g+l,"mouseenter",{orientation:!0},f),b.delegate(g+l,"mouseleave",{orientation:!1},f)},_loadExample:function(a){a&&(window.location.hash="!"+(this.single?"single/":"")+a.key,u||(this._thumbsNode.css({position:"absolute",height:"0px",overflow:"hidden",width:"0px"}),this._resetNode.css({top:"16px"})),this._examplesNode.addClass(m),this._exampleNode.show(),this._example.setExample(a),this._resize(),$(document).scrollTop(0))},_reset:function(){window.location.hash="",u||this._thumbsNode.css({position:"",height:"",overflow:"",width:""}),this._examplesNode.removeClass(m),this._thumbsNode.height(""),this._exampleNode.hide()},_initNodes:function(){var a=$(this.options.node),b=this,c=$(t);b._resetNode=c.find(g+j),b._exampleNode=c.find(g+i),b._thumbsNode=c.find(g+k),b._examplesNode=c,b._resetNode.click(function(){b._reset()}),a.append(c),this._initResizer()},_initResizer:function(){function e(){var b=c.height()-(a.options.thumbPadding||0),e=c.width(),f;e>1760?(f=o,a._thumbsNode.height(b)):e>1140?(f=p,a._thumbsNode.height(b)):(f=q,a._thumbsNode.height("")),d!==f&&(d&&a._examplesNode.removeClass(d),a._examplesNode.addClass(f),d=f)}var a=this,b=a._examplesNode,c=$(window),d;$(window).resize(e),e(),this._resize=e},_initExamples:function(){var a=window.location.hash,b,c;a?(a=a.substring(2),c=a.split("/"),c.length==1?(b=this.list.get(a),this.examples()):c[0]=="single"&&(this.single=!0,b=this.list.get(c[1])),this._loadExample(b)):this.examples()}};var u=function(){var a=!!(navigator.userAgent.match(/Android/i)||navigator.userAgent.match(/webOS/i)||navigator.userAgent.match(/iPhone/i)||navigator.userAgent.match(/iPod/i)),b=!!$.browser.mozilla;return!a||b}();Flotr.Examples=Examples})(),function(){var a=Flotr._,b=".",c="flotr-example",d="flotr-example-label",e="flotr-example-title",f="flotr-example-description",g="flotr-example-editor",h="flotr-example-graph",i='<div class="'+c+'">'+'<div class="'+d+" "+e+'"></div>'+'<div class="'+f+'"></div>'+'<div class="'+g+'"></div>'+"</div>",j=function(a){this.options=a,this.example=null,this._initNodes()};j.prototype={setExample:function(a){var b=this.getSource(a),c=this._editorNode;this.example=a,Math.seedrandom(a.key),this._exampleNode.css({display:"block"}),this._titleNode.html(a.name||""),this._markupNode.html(a.description||""),this._editor?this._editor.setExample(b):this._editor=new Flotr.Examples.Editor(c,{example:b,teardown:function(){Flotr.EventAdapter.stopObserving($(c).find(".render")[0]),$(c).find("canvas").each(function(a,b){Flotr.EventAdapter.stopObserving(b)})}})},getSource:function(a){var b=a.callback.toString();return navigator.userAgent.search(/firefox/i)!==-1&&(b=js_beautify(b)),b},executeCallback:function(b,c){a.isElement(c)||(c=c[0]);var d=b.args?[c].concat(b.args):[c];return Math.seedrandom(b.key),b.callback.apply(this,d)},_initNodes:function(){var a=this.options.node,c=$(i);this._titleNode=c.find(b+e),this._markupNode=c.find(b+f),this._editorNode=c.find(b+g),this._exampleNode=c,a.append(c)}},Flotr.Examples.Example=j}(),function(){function Editor(a,b){function o(){i.hide(),f&&f.call(),m.render({example:d,render:h})}function p(a,b,c){var d=!1,e='<span class="error">Error: </span>',f,g;e+='<span class="message">'+a+"</span>",typeof c!="undefined"&&(e+='<span class="position">',e+='Line <span class="line">'+c+"</span>",console.log(b),b&&(e+=" of ",b==window.location?(e+='<span class="url">script</span>',!d):e+='<span class="url">'+b+"</span>"),e+=".</span>"),i.show(),i.html(e)}var c=b.type||"javascript",d=b.example||"",e=b.noRun||!1,f=b.teardown||!1,g=$(T_CONTROLS),h=$(T_RENDER),i=$(T_ERRORS),j=$(T_SOURCE),k=$(T_EDITOR),l="editor-render-"+COUNT,m,h,n;m=new TYPES[c]({onerror:p});if(!m)throw"Invalid type: API not found for type `"+c+"`.";h.attr("id",l),i.hide(),k.append(h).append(g).append(j).addClass(c).addClass(e?"no-run":""),a=$(a),a.append(k),j.append(i),d=m.example({example:d,render:h}),n=CodeMirror(j[0],{value:d,readOnly:e,lineNumbers:!0,mode:m.codeMirrorType}),e||(g.delegate(".run","click",function(){d=n.getValue(),o()}),o()),window.onerror=function(a,b,c){return p(a,b,c),console.log(a),ONERROR&&$.isFunction(ONERROR)?ONERROR(a,b,c):!1},COUNT++,this.setExample=function(a){d=m.example({example:a,render:h}),n.setValue(d),n.refresh(),o()}}var ONERROR=window.onerror,COUNT=0,TYPES={},T_CONTROLS='<div class="controls"><button class="run btn large primary">Run</button></div>',T_EDITOR='<div class="editor"></div>',T_SOURCE='<div class="source"></div>',T_ERRORS='<div class="errors"></div>',T_RENDER='<div class="render"></div>',T_IFRAME="<iframe></iframe>";TYPES.javascript=function(b){this.onerror=b.onerror},TYPES.javascript.prototype={codeMirrorType:"javascript",example:function(a){var b=a.example,c=a.render,d=$(c).attr("id");return"("+b+')(document.getElementById("'+d+'"));'},render:function(o){eval(o.example)}},TYPES.html=function(b){this.onerror=b.onerror},TYPES.html.prototype={codeMirrorType:"htmlmixed",example:function(a){return $.trim(a.example)},render:function(a){var b=a.example,c=a.render,d=$(T_IFRAME),e=this,f,g;c.html(d),f=d[0].contentWindow,g=f.document,g.open(),f.onerror=d.onerror=function(){e.onerror.apply(null,arguments)},g.write(b),g.close()}},typeof Flotr.Examples=="undefined"&&(Flotr.Examples={}),Flotr.Examples.Editor=Editor}(),function(){var a=Flotr.DOM,b=Flotr.EventAdapter,c=Flotr._,d="click",e="example-profile",f="examples",g=function(a){if(c.isUndefined(Flotr.ExampleList))throw"Flotr.ExampleList not defined.";this.editMode="off",this.list=Flotr.ExampleList,this.current=null,this.single=!1,this.init()};g.prototype=c.extend({},Flotr.Examples.prototype,{examples:function(){var e=document.getElementById(f),g=a.node("<ul></ul>"),h;c.each(this.list.getType("profile"),function(e){h=a.node("<li>"+e.name+"</li>"),a.insert(g,h),b.observe(h,d,c.bind(function(){this.example(e)},this))},this),a.insert(e,g)},example:function(a){this._renderSource(a),this.profileStart(a),setTimeout(c.bind(function(){this._renderGraph(a),this.profileEnd()},this),50)},profileStart:function(a){var b=document.getElementById(e);this._startTime=new Date,b.innerHTML='<div>Profile started for "'+a.name+'"...</div>'},profileEnd:function(a){var b=document.getElementById(e);profileTime=new Date-this._startTime,this._startTime=null,b.innerHTML+="<div>Profile complete: "+profileTime+"ms<div>"}}),Flotr.Profile=g}()
425\ No newline at end of file
426
427=== removed file 'addons/web_graph/static/lib/flotr2/flotr2.examples.types.js'
428--- addons/web_graph/static/lib/flotr2/flotr2.examples.types.js 2012-05-07 08:19:08 +0000
429+++ addons/web_graph/static/lib/flotr2/flotr2.examples.types.js 1970-01-01 00:00:00 +0000
430@@ -1,1425 +0,0 @@
431-(function () {
432-
433-var ExampleList = function () {
434-
435- // Map of examples.
436- this.examples = {};
437-
438-};
439-
440-ExampleList.prototype = {
441-
442- add : function (example) {
443- this.examples[example.key] = example;
444- },
445-
446- get : function (key) {
447- return key ? (this.examples[key] || null) : this.examples;
448- },
449-
450- getType : function (type) {
451- return Flotr._.select(this.examples, function (example) {
452- return (example.type === type);
453- });
454- }
455-}
456-
457-Flotr.ExampleList = new ExampleList();
458-
459-})();
460-
461-(function () {
462-
463-Flotr.ExampleList.add({
464- key : 'basic',
465- name : 'Basic',
466- callback : basic
467-});
468-
469-function basic (container) {
470-
471- var
472- d1 = [[0, 3], [4, 8], [8, 5], [9, 13]], // First data series
473- d2 = [], // Second data series
474- i, graph;
475-
476- // Generate first data set
477- for (i = 0; i < 14; i += 0.5) {
478- d2.push([i, Math.sin(i)]);
479- }
480-
481- // Draw Graph
482- graph = Flotr.draw(container, [ d1, d2 ], {
483- xaxis: {
484- minorTickFreq: 4
485- },
486- grid: {
487- minorVerticalLines: true
488- }
489- });
490-}
491-
492-})();
493-
494-(function () {
495-
496-Flotr.ExampleList.add({
497- key : 'basic-stacked',
498- name : 'Basic Stacked',
499- callback : basic_stacked,
500- type : 'test'
501-});
502-
503-function basic_stacked (container) {
504-
505- var
506- d1 = [[0, 3], [4, 8], [8, 2], [9, 3]], // First data series
507- d2 = [[0, 2], [4, 3], [8, 8], [9, 4]], // Second data series
508- i, graph;
509-
510- // Draw Graph
511- graph = Flotr.draw(container, [ d1, d2 ], {
512- lines: {
513- show : true,
514- stacked: true
515- },
516- xaxis: {
517- minorTickFreq: 4
518- },
519- grid: {
520- minorVerticalLines: true
521- }
522- });
523-}
524-
525-})();
526-
527-(function () {
528-
529-Flotr.ExampleList.add({
530- key : 'basic-stepped',
531- name : 'Basic Stepped',
532- callback : basic_stepped,
533- type : 'test'
534-});
535-
536-function basic_stepped (container) {
537-
538- var
539- d1 = [[0, 3], [4, 8], [8, 5], [9, 13]], // First data series
540- d2 = [], // Second data series
541- i, graph;
542-
543- // Generate first data set
544- for (i = 0; i < 14; i += 0.5) {
545- d2.push([i, Math.sin(i)]);
546- }
547-
548- // Draw Graph
549- graph = Flotr.draw(container, [ d1, d2 ], {
550- lines: {
551- steps : true,
552- show : true
553- },
554- xaxis: {
555- minorTickFreq: 4
556- },
557- yaxis: {
558- autoscale: true
559- },
560- grid: {
561- minorVerticalLines: true
562- },
563- mouse : {
564- track : true,
565- relative : true
566- }
567- });
568-}
569-
570-})();
571-
572-(function () {
573-
574-Flotr.ExampleList.add({
575- key : 'basic-axis',
576- name : 'Basic Axis',
577- callback : basic_axis
578-});
579-
580-function basic_axis (container) {
581-
582- var
583- d1 = [],
584- d2 = [],
585- d3 = [],
586- d4 = [],
587- d5 = [], // Data
588- ticks = [[ 0, "Lower"], 10, 20, 30, [40, "Upper"]], // Ticks for the Y-Axis
589- graph;
590-
591- for(var i = 0; i <= 10; i += 0.1){
592- d1.push([i, 4 + Math.pow(i,1.5)]);
593- d2.push([i, Math.pow(i,3)]);
594- d3.push([i, i*5+3*Math.sin(i*4)]);
595- d4.push([i, i]);
596- if( i.toFixed(1)%1 == 0 ){
597- d5.push([i, 2*i]);
598- }
599- }
600-
601- d3[30][1] = null;
602- d3[31][1] = null;
603-
604- function ticksFn (n) { return '('+n+')'; }
605-
606- graph = Flotr.draw(container, [
607- { data : d1, label : 'y = 4 + x^(1.5)', lines : { fill : true } },
608- { data : d2, label : 'y = x^3'},
609- { data : d3, label : 'y = 5x + 3sin(4x)'},
610- { data : d4, label : 'y = x'},
611- { data : d5, label : 'y = 2x', lines : { show : true }, points : { show : true } }
612- ], {
613- xaxis : {
614- noTicks : 7, // Display 7 ticks.
615- tickFormatter : ticksFn, // Displays tick values between brackets.
616- min : 1, // Part of the series is not displayed.
617- max : 7.5 // Part of the series is not displayed.
618- },
619- yaxis : {
620- ticks : ticks, // Set Y-Axis ticks
621- max : 40 // Maximum value along Y-Axis
622- },
623- grid : {
624- verticalLines : false,
625- backgroundColor : {
626- colors : [[0,'#fff'], [1,'#ccc']],
627- start : 'top',
628- end : 'bottom'
629- }
630- },
631- legend : {
632- position : 'nw'
633- },
634- title : 'Basic Axis example',
635- subtitle : 'This is a subtitle'
636- });
637-}
638-
639-})();
640-
641-(function () {
642-
643-Flotr.ExampleList.add({
644- key : 'basic-bars',
645- name : 'Basic Bars',
646- callback : basic_bars
647-});
648-
649-Flotr.ExampleList.add({
650- key : 'basic-bars-horizontal',
651- name : 'Horizontal Bars',
652- args : [true],
653- callback : basic_bars,
654- tolerance : 5
655-});
656-
657-function basic_bars (container, horizontal) {
658-
659- var
660- horizontal = (horizontal ? true : false), // Show horizontal bars
661- d1 = [], // First data series
662- d2 = [], // Second data series
663- point, // Data point variable declaration
664- i;
665-
666- for (i = 0; i < 4; i++) {
667-
668- if (horizontal) {
669- point = [Math.ceil(Math.random()*10), i];
670- } else {
671- point = [i, Math.ceil(Math.random()*10)];
672- }
673-
674- d1.push(point);
675-
676- if (horizontal) {
677- point = [Math.ceil(Math.random()*10), i+0.5];
678- } else {
679- point = [i+0.5, Math.ceil(Math.random()*10)];
680- }
681-
682- d2.push(point);
683- };
684-
685- // Draw the graph
686- Flotr.draw(
687- container,
688- [d1, d2],
689- {
690- bars : {
691- show : true,
692- horizontal : horizontal,
693- shadowSize : 0,
694- barWidth : 0.5
695- },
696- mouse : {
697- track : true,
698- relative : true
699- },
700- yaxis : {
701- min : 0,
702- autoscaleMargin : 1
703- }
704- }
705- );
706-}
707-
708-})();
709-
710-(function () {
711-
712-Flotr.ExampleList.add({
713- key : 'basic-bar-stacked',
714- name : 'Stacked Bars',
715- callback : bars_stacked
716-});
717-
718-Flotr.ExampleList.add({
719- key : 'basic-stacked-horizontal',
720- name : 'Stacked Horizontal Bars',
721- args : [true],
722- callback : bars_stacked,
723- tolerance : 5
724-});
725-
726-function bars_stacked (container, horizontal) {
727-
728- var
729- d1 = [],
730- d2 = [],
731- d3 = [],
732- graph, i;
733-
734- for (i = -10; i < 10; i++) {
735- if (horizontal) {
736- d1.push([Math.random(), i]);
737- d2.push([Math.random(), i]);
738- d3.push([Math.random(), i]);
739- } else {
740- d1.push([i, Math.random()]);
741- d2.push([i, Math.random()]);
742- d3.push([i, Math.random()]);
743- }
744- }
745-
746- graph = Flotr.draw(container,[
747- { data : d1, label : 'Serie 1' },
748- { data : d2, label : 'Serie 2' },
749- { data : d3, label : 'Serie 3' }
750- ], {
751- legend : {
752- backgroundColor : '#D2E8FF' // Light blue
753- },
754- bars : {
755- show : true,
756- stacked : true,
757- horizontal : horizontal,
758- barWidth : 0.6,
759- lineWidth : 1,
760- shadowSize : 0
761- },
762- grid : {
763- verticalLines : horizontal,
764- horizontalLines : !horizontal
765- }
766- });
767-}
768-
769-})();
770-
771-(function () {
772-
773-Flotr.ExampleList.add({
774- key : 'basic-pie',
775- name : 'Basic Pie',
776- callback : basic_pie
777-});
778-
779-function basic_pie (container) {
780-
781- var
782- d1 = [[0, 4]],
783- d2 = [[0, 3]],
784- d3 = [[0, 1.03]],
785- d4 = [[0, 3.5]],
786- graph;
787-
788- graph = Flotr.draw(container, [
789- { data : d1, label : 'Comedy' },
790- { data : d2, label : 'Action' },
791- { data : d3, label : 'Romance',
792- pie : {
793- explode : 50
794- }
795- },
796- { data : d4, label : 'Drama' }
797- ], {
798- HtmlText : false,
799- grid : {
800- verticalLines : false,
801- horizontalLines : false
802- },
803- xaxis : { showLabels : false },
804- yaxis : { showLabels : false },
805- pie : {
806- show : true,
807- explode : 6
808- },
809- mouse : { track : true },
810- legend : {
811- position : 'se',
812- backgroundColor : '#D2E8FF'
813- }
814- });
815-}
816-
817-})();
818-
819-(function () {
820-
821-Flotr.ExampleList.add({
822- key : 'basic-radar',
823- name : 'Basic Radar',
824- callback : basic_radar
825-});
826-
827-function basic_radar (container) {
828-
829- // Fill series s1 and s2.
830- var
831- s1 = { label : 'Actual', data : [[0, 3], [1, 8], [2, 5], [3, 5], [4, 3], [5, 9]] },
832- s2 = { label : 'Target', data : [[0, 8], [1, 7], [2, 8], [3, 2], [4, 4], [5, 7]] },
833- graph, ticks;
834-
835- // Radar Labels
836- ticks = [
837- [0, "Statutory"],
838- [1, "External"],
839- [2, "Videos"],
840- [3, "Yippy"],
841- [4, "Management"],
842- [5, "oops"]
843- ];
844-
845- // Draw the graph.
846- graph = Flotr.draw(container, [ s1, s2 ], {
847- radar : { show : true},
848- grid : { circular : true, minorHorizontalLines : true},
849- yaxis : { min : 0, max : 10, minorTickFreq : 2},
850- xaxis : { ticks : ticks}
851- });
852-}
853-
854-})();
855-
856-(function () {
857-
858-Flotr.ExampleList.add({
859- key : 'basic-bubble',
860- name : 'Basic Bubble',
861- callback : basic_bubble
862-});
863-
864-function basic_bubble (container) {
865-
866- var
867- d1 = [],
868- d2 = [],
869- point, graph, i;
870-
871- for (i = 0; i < 10; i++ ){
872- point = [i, Math.ceil(Math.random()*10), Math.ceil(Math.random()*10)];
873- d1.push(point);
874-
875- point = [i, Math.ceil(Math.random()*10), Math.ceil(Math.random()*10)];
876- d2.push(point);
877- }
878-
879- // Draw the graph
880- graph = Flotr.draw(container, [d1, d2], {
881- bubbles : { show : true, baseRadius : 5 },
882- xaxis : { min : -4, max : 14 },
883- yaxis : { min : -4, max : 14 }
884- });
885-}
886-
887-})();
888-
889-(function () {
890-
891-Flotr.ExampleList.add({
892- key : 'basic-candle',
893- name : 'Basic Candle',
894- callback : basic_candle
895-});
896-
897-function basic_candle (container) {
898-
899- var
900- d1 = [],
901- price = 3.206,
902- graph,
903- i, a, b, c;
904-
905- for (i = 0; i < 50; i++) {
906- a = Math.random();
907- b = Math.random();
908- c = (Math.random() * (a + b)) - b;
909- d1.push([i, price, price + a, price - b, price + c]);
910- price = price + c;
911- }
912-
913- // Graph
914- graph = Flotr.draw(container, [ d1 ], {
915- candles : { show : true, candleWidth : 0.6 },
916- xaxis : { noTicks : 10 }
917- });
918-}
919-
920-})();
921-
922-
923-(function () {
924-
925-Flotr.ExampleList.add({
926- key : 'basic-legend',
927- name : 'Basic Legend',
928- callback : basic_legend
929-});
930-
931-function basic_legend (container) {
932-
933- var
934- d1 = [],
935- d2 = [],
936- d3 = [],
937- data,
938- graph, i;
939-
940- // Data Generation
941- for (i = 0; i < 15; i += 0.5) {
942- d1.push([i, i + Math.sin(i+Math.PI)]);
943- d2.push([i, i]);
944- d3.push([i, 15-Math.cos(i)]);
945- }
946-
947- data = [
948- { data : d1, label :'x + sin(x+&pi;)' },
949- { data : d2, label :'x' },
950- { data : d3, label :'15 - cos(x)' }
951- ];
952-
953-
954- // This function prepend each label with 'y = '
955- function labelFn (label) {
956- return 'y = ' + label;
957- }
958-
959- // Draw graph
960- graph = Flotr.draw(container, data, {
961- legend : {
962- position : 'se', // Position the legend 'south-east'.
963- labelFormatter : labelFn, // Format the labels.
964- backgroundColor : '#D2E8FF' // A light blue background color.
965- },
966- HtmlText : false
967- });
968-}
969-
970-})();
971-
972-(function () {
973-
974-Flotr.ExampleList.add({
975- key : 'mouse-tracking',
976- name : 'Mouse Tracking',
977- callback : mouse_tracking
978-});
979-
980-function mouse_tracking (container) {
981-
982- var
983- d1 = [],
984- d2 = [],
985- d3 = [],
986- graph, i;
987-
988- for (i = 0; i < 20; i += 0.5) {
989- d1.push([i, 2*i]);
990- d2.push([i, i*1.5+1.5*Math.sin(i)]);
991- d3.push([i, 3*Math.cos(i)+10]);
992- }
993-
994- graph = Flotr.draw(
995- container,
996- [
997- {
998- data : d1,
999- mouse : { track : false } // Disable mouse tracking for d1
1000- },
1001- d2,
1002- d3
1003- ],
1004- {
1005- mouse : {
1006- track : true, // Enable mouse tracking
1007- lineColor : 'purple',
1008- relative : true,
1009- position : 'ne',
1010- sensibility : 1,
1011- trackDecimals : 2,
1012- trackFormatter : function (o) { return 'x = ' + o.x +', y = ' + o.y; }
1013- },
1014- crosshair : {
1015- mode : 'xy'
1016- }
1017- }
1018- );
1019-
1020-};
1021-
1022-})();
1023-
1024-(function () {
1025-
1026-Flotr.ExampleList.add({
1027- key : 'mouse-zoom',
1028- name : 'Mouse Zoom',
1029- callback : mouse_zoom,
1030- description : "<p>Select an area of the graph to zoom. Click to reset the chart.</p>"
1031-});
1032-
1033-function mouse_zoom (container) {
1034-
1035- var
1036- d1 = [],
1037- d2 = [],
1038- d3 = [],
1039- options,
1040- graph,
1041- i;
1042-
1043- for (i = 0; i < 40; i += 0.5) {
1044- d1.push([i, Math.sin(i)+3*Math.cos(i)]);
1045- d2.push([i, Math.pow(1.1, i)]);
1046- d3.push([i, 40 - i+Math.random()*10]);
1047- }
1048-
1049- options = {
1050- selection : { mode : 'x', fps : 30 },
1051- title : 'Mouse Zoom'
1052- };
1053-
1054- // Draw graph with default options, overwriting with passed options
1055- function drawGraph (opts) {
1056-
1057- // Clone the options, so the 'options' variable always keeps intact.
1058- var o = Flotr._.extend(Flotr._.clone(options), opts || {});
1059-
1060- // Return a new graph.
1061- return Flotr.draw(
1062- container,
1063- [ d1, d2, d3 ],
1064- o
1065- );
1066- }
1067-
1068- // Actually draw the graph.
1069- graph = drawGraph();
1070-
1071- // Hook into the 'flotr:select' event.
1072- Flotr.EventAdapter.observe(container, 'flotr:select', function (area) {
1073-
1074- // Draw graph with new area
1075- f = drawGraph({
1076- xaxis: {min:area.x1, max:area.x2},
1077- yaxis: {min:area.y1, max:area.y2}
1078- });
1079-
1080- });
1081-
1082- // When graph is clicked, draw the graph with default area.
1083- Flotr.EventAdapter.observe(container, 'flotr:click', function () { drawGraph(); });
1084-};
1085-
1086-})();
1087-
1088-
1089-(function () {
1090-
1091-Flotr.ExampleList.add({
1092- key : 'mouse-drag',
1093- name : 'Mouse Drag',
1094- callback : mouse_drag
1095-});
1096-
1097-function mouse_drag (container) {
1098-
1099- var
1100- d1 = [],
1101- d2 = [],
1102- d3 = [],
1103- options,
1104- graph,
1105- start,
1106- i;
1107-
1108- for (i = -40; i < 40; i += 0.5) {
1109- d1.push([i, Math.sin(i)+3*Math.cos(i)]);
1110- d2.push([i, Math.pow(1.1, i)]);
1111- d3.push([i, 40 - i+Math.random()*10]);
1112- }
1113-
1114- options = {
1115- xaxis: {min: 0, max: 20},
1116- title : 'Mouse Drag'
1117- };
1118-
1119- // Draw graph with default options, overwriting with passed options
1120- function drawGraph (opts) {
1121-
1122- // Clone the options, so the 'options' variable always keeps intact.
1123- var o = Flotr._.extend(Flotr._.clone(options), opts || {});
1124-
1125- // Return a new graph.
1126- return Flotr.draw(
1127- container,
1128- [ d1, d2, d3 ],
1129- o
1130- );
1131- }
1132-
1133- graph = drawGraph();
1134-
1135- function initializeDrag (e) {
1136- start = graph.getEventPosition(e);
1137- Flotr.EventAdapter.observe(document, 'mousemove', move);
1138- Flotr.EventAdapter.observe(document, 'mouseup', stopDrag);
1139- }
1140-
1141- function move (e) {
1142- var
1143- end = graph.getEventPosition(e),
1144- xaxis = graph.axes.x,
1145- offset = start.x - end.x;
1146-
1147- graph = drawGraph({
1148- xaxis : {
1149- min : xaxis.min + offset,
1150- max : xaxis.max + offset
1151- }
1152- });
1153- // @todo: refector initEvents in order not to remove other observed events
1154- Flotr.EventAdapter.observe(graph.overlay, 'mousedown', initializeDrag);
1155- }
1156-
1157- function stopDrag () {
1158- Flotr.EventAdapter.stopObserving(document, 'mousemove', move);
1159- }
1160-
1161- Flotr.EventAdapter.observe(graph.overlay, 'mousedown', initializeDrag);
1162-
1163-};
1164-
1165-})();
1166-
1167-(function () {
1168-
1169-Flotr.ExampleList.add({
1170- key : 'basic-time',
1171- name : 'Basic Time',
1172- callback : basic_time,
1173- description : "<p>Select an area of the graph to zoom. Click to reset the chart.</p>"
1174-});
1175-
1176-function basic_time (container) {
1177-
1178- var
1179- d1 = [],
1180- start = new Date("2009/01/01 01:00").getTime(),
1181- options,
1182- graph,
1183- i, x, o;
1184-
1185- for (i = 0; i < 100; i++) {
1186- x = start+(i*1000*3600*24*36.5);
1187- d1.push([x, i+Math.random()*30+Math.sin(i/20+Math.random()*2)*20+Math.sin(i/10+Math.random())*10]);
1188- }
1189-
1190- options = {
1191- xaxis : {
1192- mode : 'time',
1193- labelsAngle : 45
1194- },
1195- selection : {
1196- mode : 'x'
1197- },
1198- HtmlText : false,
1199- title : 'Time'
1200- };
1201-
1202- // Draw graph with default options, overwriting with passed options
1203- function drawGraph (opts) {
1204-
1205- // Clone the options, so the 'options' variable always keeps intact.
1206- o = Flotr._.extend(Flotr._.clone(options), opts || {});
1207-
1208- // Return a new graph.
1209- return Flotr.draw(
1210- container,
1211- [ d1 ],
1212- o
1213- );
1214- }
1215-
1216- graph = drawGraph();
1217-
1218- Flotr.EventAdapter.observe(container, 'flotr:select', function(area){
1219- // Draw selected area
1220- graph = drawGraph({
1221- xaxis : { min : area.x1, max : area.x2, mode : 'time', labelsAngle : 45 },
1222- yaxis : { min : area.y1, max : area.y2 }
1223- });
1224- });
1225-
1226- // When graph is clicked, draw the graph with default area.
1227- Flotr.EventAdapter.observe(container, 'flotr:click', function () { graph = drawGraph(); });
1228-};
1229-
1230-})();
1231-
1232-(function () {
1233-
1234-Flotr.ExampleList.add({
1235- key : 'negative-values',
1236- name : 'Negative Values',
1237- callback : negative_values
1238-});
1239-
1240-function negative_values (container) {
1241-
1242- var
1243- d0 = [], // Line through y = 0
1244- d1 = [], // Random data presented as a scatter plot.
1245- d2 = [], // A regression line for the scatter.
1246- sx = 0,
1247- sy = 0,
1248- sxy = 0,
1249- sxsq = 0,
1250- xmean,
1251- ymean,
1252- alpha,
1253- beta,
1254- n, x, y;
1255-
1256- for (n = 0; n < 20; n++){
1257-
1258- x = n;
1259- y = x + Math.random()*8 - 15;
1260-
1261- d0.push([x, 0]);
1262- d1.push([x, y]);
1263-
1264- // Computations used for regression line
1265- sx += x;
1266- sy += y;
1267- sxy += x*y;
1268- sxsq += Math.pow(x,2);
1269- }
1270-
1271- xmean = sx/n;
1272- ymean = sy/n;
1273- beta = ((n*sxy) - (sx*sy))/((n*sxsq)-(Math.pow(sx,2)));
1274- alpha = ymean - (beta * xmean);
1275-
1276- // Compute the regression line.
1277- for (n = 0; n < 20; n++){
1278- d2.push([n, alpha + beta*n])
1279- }
1280-
1281- // Draw the graph
1282- graph = Flotr.draw(
1283- container, [
1284- { data : d0, shadowSize : 0, color : '#545454' }, // Horizontal
1285- { data : d1, label : 'y = x + (Math.random() * 8) - 15', points : { show : true } }, // Scatter
1286- { data : d2, label : 'y = ' + alpha.toFixed(2) + ' + ' + beta.toFixed(2) + '*x' } // Regression
1287- ],
1288- {
1289- legend : { position : 'se', backgroundColor : '#D2E8FF' },
1290- title : 'Negative Values'
1291- }
1292- );
1293-};
1294-
1295-})();
1296-
1297-(function () {
1298-
1299-Flotr.ExampleList.add({
1300- key : 'click-example',
1301- name : 'Click Example',
1302- callback : click_example
1303-});
1304-
1305-function click_example (container) {
1306-
1307- var
1308- d1 = [[0,0]], // Point at origin
1309- options,
1310- graph;
1311-
1312- options = {
1313- xaxis: {min: 0, max: 15},
1314- yaxis: {min: 0, max: 15},
1315- lines: {show: true},
1316- points: {show: true},
1317- mouse: {track:true},
1318- title: 'Click Example'
1319- };
1320-
1321- graph = Flotr.draw(container, [d1], options);
1322-
1323- // Add a point to the series and redraw the graph
1324- Flotr.EventAdapter.observe(container, 'flotr:click', function(position){
1325-
1326- // Add a point to the series at the location of the click
1327- d1.push([position.x, position.y]);
1328-
1329- // Sort the series.
1330- d1 = d1.sort(function (a, b) { return a[0] - b[0]; });
1331-
1332- // Redraw the graph, with the new series.
1333- graph = Flotr.draw(container, [d1], options);
1334- });
1335-};
1336-
1337-})();
1338-
1339-(function () {
1340-
1341-Flotr.ExampleList.add({
1342- key : 'download-image',
1343- name : 'Download Image',
1344- callback : download_image,
1345- description : '' +
1346- '<form name="image-download" id="image-download" action="" onsubmit="return false">' +
1347- '<label><input type="radio" name="format" value="png" checked="checked" /> PNG</label>' +
1348- '<label><input type="radio" name="format" value="jpeg" /> JPEG</label>' +
1349-
1350- '<button name="to-image" onclick="CurrentExample(\'to-image\')">To Image</button>' +
1351- '<button name="download" onclick="CurrentExample(\'download\')">Download</button>' +
1352- '<button name="reset" onclick="CurrentExample(\'reset\')">Reset</button>' +
1353- '</form>'
1354-});
1355-
1356-function download_image (container) {
1357-
1358- var
1359- d1 = [],
1360- d2 = [],
1361- d3 = [],
1362- d4 = [],
1363- d5 = [],
1364- graph,
1365- i;
1366-
1367- for (i = 0; i <= 10; i += 0.1) {
1368- d1.push([i, 4 + Math.pow(i,1.5)]);
1369- d2.push([i, Math.pow(i,3)]);
1370- d3.push([i, i*5+3*Math.sin(i*4)]);
1371- d4.push([i, i]);
1372- if( i.toFixed(1)%1 == 0 ){
1373- d5.push([i, 2*i]);
1374- }
1375- }
1376-
1377- // Draw the graph
1378- graph = Flotr.draw(
1379- container,[
1380- {data:d1, label:'y = 4 + x^(1.5)', lines:{fill:true}},
1381- {data:d2, label:'y = x^3', yaxis:2},
1382- {data:d3, label:'y = 5x + 3sin(4x)'},
1383- {data:d4, label:'y = x'},
1384- {data:d5, label:'y = 2x', lines: {show: true}, points: {show: true}}
1385- ],{
1386- title: 'Download Image Example',
1387- subtitle: 'You can save me as an image',
1388- xaxis:{
1389- noTicks: 7, // Display 7 ticks.
1390- tickFormatter: function(n){ return '('+n+')'; }, // => displays tick values between brackets.
1391- min: 1, // => part of the series is not displayed.
1392- max: 7.5, // => part of the series is not displayed.
1393- labelsAngle: 45,
1394- title: 'x Axis'
1395- },
1396- yaxis:{
1397- ticks: [[0, "Lower"], 10, 20, 30, [40, "Upper"]],
1398- max: 40,
1399- title: 'y = f(x)'
1400- },
1401- y2axis:{color:'#FF0000', max: 500, title: 'y = x^3'},
1402- grid:{
1403- verticalLines: false,
1404- backgroundColor: 'white'
1405- },
1406- HtmlText: false,
1407- legend: {
1408- position: 'nw'
1409- }
1410- });
1411-
1412- this.CurrentExample = function (operation) {
1413-
1414- var
1415- format = $('#image-download input:radio[name=format]:checked').val();
1416- if (Flotr.isIE && Flotr.isIE < 9) {
1417- alert(
1418- "Your browser doesn't allow you to get a bitmap image from the plot, " +
1419- "you can only get a VML image that you can use in Microsoft Office.<br />"
1420- );
1421- }
1422-
1423- if (operation == 'to-image') {
1424- graph.download.saveImage(format, null, null, true)
1425- } else if (operation == 'download') {
1426- graph.download.saveImage(format);
1427- } else if (operation == 'reset') {
1428- graph.download.restoreCanvas();
1429- }
1430- };
1431-
1432- return graph;
1433-};
1434-
1435-})();
1436-
1437-(function () {
1438-
1439-Flotr.ExampleList.add({
1440- key : 'download-data',
1441- name : 'Download Data',
1442- callback : download_data
1443-});
1444-
1445-function download_data (container) {
1446-
1447- var
1448- d1 = [],
1449- d2 = [],
1450- d3 = [],
1451- d4 = [],
1452- d5 = [],
1453- graph,
1454- i,x;
1455-
1456- for (i = 0; i <= 100; i += 1) {
1457- x = i / 10;
1458- d1.push([x, 4 + Math.pow(x,1.5)]);
1459- d2.push([x, Math.pow(x,3)]);
1460- d3.push([x, i*5+3*Math.sin(x*4)]);
1461- d4.push([x, x]);
1462- if(x%1 === 0 ){
1463- d5.push([x, 2*x]);
1464- }
1465- }
1466-
1467- // Draw the graph.
1468- graph = Flotr.draw(
1469- container, [
1470- { data : d1, label : 'y = 4 + x^(1.5)', lines : { fill : true } },
1471- { data : d2, label : 'y = x^3' },
1472- { data : d3, label : 'y = 5x + 3sin(4x)' },
1473- { data : d4, label : 'y = x' },
1474- { data : d5, label : 'y = 2x', lines : { show : true }, points : { show : true } }
1475- ],{
1476- xaxis : {
1477- noTicks : 7,
1478- tickFormatter : function (n) { return '('+n+')'; },
1479- min: 1, // Part of the series is not displayed.
1480- max: 7.5
1481- },
1482- yaxis : {
1483- ticks : [[ 0, "Lower"], 10, 20, 30, [40, "Upper"]],
1484- max : 40
1485- },
1486- grid : {
1487- verticalLines : false,
1488- backgroundColor : 'white'
1489- },
1490- legend : {
1491- position : 'nw'
1492- },
1493- spreadsheet : {
1494- show : true,
1495- tickFormatter : function (e) { return e+''; }
1496- }
1497- });
1498-};
1499-
1500-})();
1501-
1502-(function () {
1503-
1504-Flotr.ExampleList.add({
1505- key : 'advanced-titles',
1506- name : 'Advanced Titles',
1507- callback : advanced_titles
1508-});
1509-
1510-function advanced_titles (container) {
1511-
1512- var
1513- d1 = [],
1514- d2 = [],
1515- d3 = [],
1516- d4 = [],
1517- d5 = [],
1518- graph,
1519- i;
1520-
1521- for (i = 0; i <= 10; i += 0.1) {
1522- d1.push([i, 4 + Math.pow(i,1.5)]);
1523- d2.push([i, Math.pow(i,3)]);
1524- d3.push([i, i*5+3*Math.sin(i*4)]);
1525- d4.push([i, i]);
1526- if (i.toFixed(1)%1 == 0) {
1527- d5.push([i, 2*i]);
1528- }
1529- }
1530-
1531- // Draw the graph.
1532- graph = Flotr.draw(
1533- container,[
1534- { data : d1, label : 'y = 4 + x^(1.5)', lines : { fill : true } },
1535- { data : d2, label : 'y = x^3', yaxis : 2 },
1536- { data : d3, label : 'y = 5x + 3sin(4x)' },
1537- { data : d4, label : 'y = x' },
1538- { data : d5, label : 'y = 2x', lines : { show : true }, points : { show : true } }
1539- ], {
1540- title : 'Advanced Titles Example',
1541- subtitle : 'You can save me as an image',
1542- xaxis : {
1543- noTicks : 7,
1544- tickFormatter : function (n) { return '('+n+')'; },
1545- min : 1,
1546- max : 7.5,
1547- labelsAngle : 45,
1548- title : 'x Axis'
1549- },
1550- yaxis : {
1551- ticks : [[0, "Lower"], 10, 20, 30, [40, "Upper"]],
1552- max : 40,
1553- title : 'y = f(x)'
1554- },
1555- y2axis : { color : '#FF0000', max : 500, title : 'y = x^3' },
1556- grid : {
1557- verticalLines : false,
1558- backgroundColor : 'white'
1559- },
1560- HtmlText : false,
1561- legend : {
1562- position : 'nw'
1563- }
1564- });
1565-};
1566-
1567-})();
1568-
1569-(function () {
1570-
1571-Flotr.ExampleList.add({
1572- key : 'color-gradients',
1573- name : 'Color Gradients',
1574- callback : color_gradients
1575-});
1576-
1577-function color_gradients (container) {
1578-
1579- var
1580- bars = {
1581- data: [],
1582- bars: {
1583- show: true,
1584- barWidth: 0.8,
1585- lineWidth: 0,
1586- fillColor: {
1587- colors: ['#CB4B4B', '#fff'],
1588- start: 'top',
1589- end: 'bottom'
1590- },
1591- fillOpacity: 0.8
1592- }
1593- }, markers = {
1594- data: [],
1595- markers: {
1596- show: true,
1597- position: 'ct'
1598- }
1599- }, lines = {
1600- data: [],
1601- lines: {
1602- show: true,
1603- fillColor: ['#00A8F0', '#fff'],
1604- fill: true,
1605- fillOpacity: 1
1606- }
1607- },
1608- point,
1609- graph,
1610- i;
1611-
1612- for (i = 0; i < 8; i++) {
1613- point = [i, Math.ceil(Math.random() * 10)];
1614- bars.data.push(point);
1615- markers.data.push(point);
1616- }
1617-
1618- for (i = -1; i < 9; i += 0.01){
1619- lines.data.push([i, i*i/8+2]);
1620- }
1621-
1622- graph = Flotr.draw(
1623- container,
1624- [lines, bars, markers], {
1625- yaxis: {
1626- min: 0,
1627- max: 11
1628- },
1629- xaxis: {
1630- min: -0.5,
1631- max: 7.5
1632- },
1633- grid: {
1634- verticalLines: false,
1635- backgroundColor: ['#fff', '#ccc']
1636- }
1637- }
1638- );
1639-};
1640-
1641-})();
1642-
1643-
1644-(function () {
1645-
1646-Flotr.ExampleList.add({
1647- key : 'profile-bars',
1648- name : 'Profile Bars',
1649- type : 'profile',
1650- callback : profile_bars
1651-});
1652-
1653-/*
1654-Flotr.ExampleList.add({
1655- key : 'basic-bars-horizontal',
1656- name : 'Horizontal Bars',
1657- args : [true],
1658- callback : basic_bars
1659-});
1660-*/
1661-
1662-function profile_bars (container, horizontal) {
1663-
1664- var
1665- horizontal = (horizontal ? true : false), // Show horizontal bars
1666- d1 = [], // First data series
1667- d2 = [], // Second data series
1668- point, // Data point variable declaration
1669- i;
1670-
1671- for (i = 0; i < 5000; i++) {
1672-
1673- if (horizontal) {
1674- point = [Math.ceil(Math.random()*10), i];
1675- } else {
1676- point = [i, Math.ceil(Math.random()*10)];
1677- }
1678-
1679- d1.push(point);
1680-
1681- if (horizontal) {
1682- point = [Math.ceil(Math.random()*10), i+0.5];
1683- } else {
1684- point = [i+0.5, Math.ceil(Math.random()*10)];
1685- }
1686-
1687- d2.push(point);
1688- };
1689-
1690- // Draw the graph
1691- Flotr.draw(
1692- container,
1693- [d1, d2],
1694- {
1695- bars : {
1696- show : true,
1697- horizontal : horizontal,
1698- barWidth : 0.5
1699- },
1700- mouse : {
1701- track : true,
1702- relative : true
1703- },
1704- yaxis : {
1705- min : 0,
1706- autoscaleMargin : 1
1707- }
1708- }
1709- );
1710-}
1711-
1712-})();
1713-
1714-(function () {
1715-
1716-Flotr.ExampleList.add({
1717- key : 'basic-timeline',
1718- name : 'Basic Timeline',
1719- callback : basic_timeline
1720-});
1721-
1722-function basic_timeline (container) {
1723-
1724- var
1725- d1 = [[1, 4, 5]],
1726- d2 = [[3.2, 3, 4]],
1727- d3 = [[1.9, 2, 2], [5, 2, 3.3]],
1728- d4 = [[1.55, 1, 9]],
1729- d5 = [[5, 0, 2.3]],
1730- data = [],
1731- timeline = { show : true, barWidth : .5 },
1732- markers = [],
1733- labels = ['Obama', 'Bush', 'Clinton', 'Palin', 'McCain'],
1734- i, graph, point;
1735-
1736- // Timeline
1737- Flotr._.each([d1, d2, d3, d4, d5], function (d) {
1738- data.push({
1739- data : d,
1740- timeline : Flotr._.clone(timeline)
1741- });
1742- });
1743-
1744- // Markers
1745- Flotr._.each([d1, d2, d3, d4, d5], function (d) {
1746- point = d[0];
1747- markers.push([point[0], point[1]]);
1748- });
1749- data.push({
1750- data: markers,
1751- markers: {
1752- show: true,
1753- position: 'rm',
1754- fontSize: 11,
1755- labelFormatter : function (o) { return labels[o.index]; }
1756- }
1757- });
1758-
1759- // Draw Graph
1760- graph = Flotr.draw(container, data, {
1761- xaxis: {
1762- noTicks: 3,
1763- tickFormatter: function (x) {
1764- var
1765- x = parseInt(x),
1766- months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
1767- return months[(x-1)%12];
1768- }
1769- },
1770- yaxis: {
1771- showLabels : false
1772- },
1773- grid: {
1774- horizontalLines : false
1775- }
1776- });
1777-}
1778-
1779-})();
1780-
1781-(function () {
1782-
1783-Flotr.ExampleList.add({
1784- key : 'advanced-markers',
1785- name : 'Advanced Markers',
1786- callback : advanced_markers,
1787- timeout : 150
1788-});
1789-
1790-function advanced_markers (container) {
1791-
1792- var
1793- xmark = new Image(),
1794- checkmark = new Image(),
1795- bars = {
1796- data: [],
1797- bars: {
1798- show: true,
1799- barWidth: 0.6,
1800- lineWidth: 0,
1801- fillOpacity: 0.8
1802- }
1803- }, markers = {
1804- data: [],
1805- markers: {
1806- show: true,
1807- position: 'ct',
1808- labelFormatter: function (o) {
1809- return (o.y >= 5) ? checkmark : xmark;
1810- }
1811- }
1812- },
1813- flotr = Flotr,
1814- point,
1815- graph,
1816- i;
1817-
1818-
1819- for (i = 0; i < 8; i++) {
1820- point = [i, Math.ceil(Math.random() * 10)];
1821- bars.data.push(point);
1822- markers.data.push(point);
1823- }
1824-
1825- var runner = function () {
1826- if (!xmark.complete || !checkmark.complete) {
1827- setTimeout(runner, 50);
1828- return;
1829- }
1830-
1831- graph = flotr.draw(
1832- container,
1833- [bars, markers], {
1834- yaxis: {
1835- min: 0,
1836- max: 11
1837- },
1838- xaxis: {
1839- min: -0.5,
1840- max: 7.5
1841- },
1842- grid: {
1843- verticalLines: false
1844- }
1845- }
1846- );
1847- }
1848-
1849- xmark.onload = runner;
1850- xmark.src = 'images/xmark.png';
1851- checkmark.src = 'images/checkmark.png';
1852-};
1853-
1854-})();
1855-
1856
1857=== removed file 'addons/web_graph/static/lib/flotr2/flotr2.ie.min.js'
1858--- addons/web_graph/static/lib/flotr2/flotr2.ie.min.js 2012-05-07 08:19:08 +0000
1859+++ addons/web_graph/static/lib/flotr2/flotr2.ie.min.js 1970-01-01 00:00:00 +0000
1860@@ -1,33 +0,0 @@
1861-// Copyright 2006 Google Inc.
1862-//
1863-// Licensed under the Apache License, Version 2.0 (the "License");
1864-// you may not use this file except in compliance with the License.
1865-// You may obtain a copy of the License at
1866-//
1867-// http://www.apache.org/licenses/LICENSE-2.0
1868-//
1869-// Unless required by applicable law or agreed to in writing, software
1870-// distributed under the License is distributed on an "AS IS" BASIS,
1871-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1872-// See the License for the specific language governing permissions and
1873-// limitations under the License.
1874-// Known Issues:
1875-//
1876-// * Patterns only support repeat.
1877-// * Radial gradient are not implemented. The VML version of these look very
1878-// different from the canvas one.
1879-// * Clipping paths are not implemented.
1880-// * Coordsize. The width and height attribute have higher priority than the
1881-// width and height style values which isn't correct.
1882-// * Painting mode isn't implemented.
1883-// * Canvas width/height should is using content-box by default. IE in
1884-// Quirks mode will draw the canvas using border-box. Either change your
1885-// doctype to HTML5
1886-// (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
1887-// or use Box Sizing Behavior from WebFX
1888-// (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
1889-// * Non uniform scaling does not correctly scale strokes.
1890-// * Optimize. There is always room for speed improvements.
1891-// Only add this code if we do not already have a canvas implementation
1892-
1893-document.createElement("canvas").getContext||function(){function j(){return this.context_||(this.context_=new N(this))}function l(a,b,c){var d=k.call(arguments,2);return function(){return a.apply(b,d.concat(k.call(arguments)))}}function m(a){return String(a).replace(/&/g,"&amp;").replace(/"/g,"&quot;")}function n(a,b,c){a.namespaces[b]||a.namespaces.add(b,c,"#default#VML")}function o(a){n(a,"g_vml_","urn:schemas-microsoft-com:vml"),n(a,"g_o_","urn:schemas-microsoft-com:office:office");if(!a.styleSheets.ex_canvas_){var b=a.createStyleSheet();b.owningElement.id="ex_canvas_",b.cssText="canvas{display:inline-block;overflow:hidden;text-align:left;width:300px;height:150px}"}}function q(a){var b=a.srcElement;switch(a.propertyName){case"width":b.getContext().clearRect(),b.style.width=b.attributes.width.nodeValue+"px",b.firstChild&&(b.firstChild.style.width=b.clientWidth+"px");break;case"height":b.getContext().clearRect(),b.style.height=b.attributes.height.nodeValue+"px",b.firstChild&&(b.firstChild.style.height=b.clientHeight+"px")}}function r(a){var b=a.srcElement;b.firstChild&&(b.firstChild.style.width=b.clientWidth+"px",b.firstChild.style.height=b.clientHeight+"px")}function v(){return[[1,0,0],[0,1,0],[0,0,1]]}function w(a,b){var c=v();for(var d=0;d<3;d++)for(var e=0;e<3;e++){var f=0;for(var g=0;g<3;g++)f+=a[d][g]*b[g][e];c[d][e]=f}return c}function x(a,b){b.fillStyle=a.fillStyle,b.lineCap=a.lineCap,b.lineJoin=a.lineJoin,b.lineWidth=a.lineWidth,b.miterLimit=a.miterLimit,b.shadowBlur=a.shadowBlur,b.shadowColor=a.shadowColor,b.shadowOffsetX=a.shadowOffsetX,b.shadowOffsetY=a.shadowOffsetY,b.strokeStyle=a.strokeStyle,b.globalAlpha=a.globalAlpha,b.font=a.font,b.textAlign=a.textAlign,b.textBaseline=a.textBaseline,b.arcScaleX_=a.arcScaleX_,b.arcScaleY_=a.arcScaleY_,b.lineScale_=a.lineScale_}function z(a){var b=a.indexOf("(",3),c=a.indexOf(")",b+1),d=a.substring(b+1,c).split(",");if(d.length!=4||a.charAt(3)!="a")d[3]=1;return d}function A(a){return parseFloat(a)/100}function B(a,b,c){return Math.min(c,Math.max(b,a))}function C(a){var b,c,d,e,f,g;e=parseFloat(a[0])/360%360,e<0&&e++,f=B(A(a[1]),0,1),g=B(A(a[2]),0,1);if(f==0)b=c=d=g;else{var h=g<.5?g*(1+f):g+f-g*f,i=2*g-h;b=D(i,h,e+1/3),c=D(i,h,e),d=D(i,h,e-1/3)}return"#"+s[Math.floor(b*255)]+s[Math.floor(c*255)]+s[Math.floor(d*255)]}function D(a,b,c){return c<0&&c++,c>1&&c--,6*c<1?a+(b-a)*6*c:2*c<1?b:3*c<2?a+(b-a)*(2/3-c)*6:a}function F(a){if(a in E)return E[a];var b,c=1;a=String(a);if(a.charAt(0)=="#")b=a;else if(/^rgb/.test(a)){var d=z(a),b="#",e;for(var f=0;f<3;f++)d[f].indexOf("%")!=-1?e=Math.floor(A(d[f])*255):e=+d[f],b+=s[B(e,0,255)];c=+d[3]}else if(/^hsl/.test(a)){var d=z(a);b=C(d),c=d[3]}else b=y[a]||a;return E[a]={color:b,alpha:c}}function I(a){if(H[a])return H[a];var b=document.createElement("div"),c=b.style;try{c.font=a}catch(d){}return H[a]={style:c.fontStyle||G.style,variant:c.fontVariant||G.variant,weight:c.fontWeight||G.weight,size:c.fontSize||G.size,family:c.fontFamily||G.family}}function J(a,b){var c={};for(var d in a)c[d]=a[d];var e=parseFloat(b.currentStyle.fontSize),f=parseFloat(a.size);return typeof a.size=="number"?c.size=a.size:a.size.indexOf("px")!=-1?c.size=f:a.size.indexOf("em")!=-1?c.size=e*f:a.size.indexOf("%")!=-1?c.size=e/100*f:a.size.indexOf("pt")!=-1?c.size=f/.75:c.size=e,c}function K(a){return a.style+" "+a.variant+" "+a.weight+" "+a.size+"px "+a.family}function M(a){return L[a]||"square"}function N(a){this.m_=v(),this.mStack_=[],this.aStack_=[],this.currentPath_=[],this.strokeStyle="#000",this.fillStyle="#000",this.lineWidth=1,this.lineJoin="miter",this.lineCap="butt",this.miterLimit=g*1,this.globalAlpha=1,this.font="10px sans-serif",this.textAlign="left",this.textBaseline="alphabetic",this.canvas=a;var b="width:"+a.clientWidth+"px;height:"+a.clientHeight+"px;overflow:hidden;position:absolute",c=a.ownerDocument.createElement("div");c.style.cssText=b,a.appendChild(c);var d=c.cloneNode(!1);d.style.backgroundColor="red",d.style.filter="alpha(opacity=0)",a.appendChild(d),this.element_=c,this.arcScaleX_=1,this.arcScaleY_=1,this.lineScale_=1}function P(a,b,c,d){a.currentPath_.push({type:"bezierCurveTo",cp1x:b.x,cp1y:b.y,cp2x:c.x,cp2y:c.y,x:d.x,y:d.y}),a.currentX_=d.x,a.currentY_=d.y}function Q(a,b){var c=F(a.strokeStyle),d=c.color,e=c.alpha*a.globalAlpha,f=a.lineScale_*a.lineWidth;f<1&&(e*=f),b.push("<g_vml_:stroke",' opacity="',e,'"',' joinstyle="',a.lineJoin,'"',' miterlimit="',a.miterLimit,'"',' endcap="',M(a.lineCap),'"',' weight="',f,'px"',' color="',d,'" />')}function R(b,c,d,e){var f=b.fillStyle,h=b.arcScaleX_,i=b.arcScaleY_,j=e.x-d.x,k=e.y-d.y;if(f instanceof V){var l=0,m={x:0,y:0},n=0,o=1;if(f.type_=="gradient"){var p=f.x0_/h,q=f.y0_/i,r=f.x1_/h,s=f.y1_/i,t=S(b,p,q),u=S(b,r,s),v=u.x-t.x,w=u.y-t.y;l=Math.atan2(v,w)*180/Math.PI,l<0&&(l+=360),l<1e-6&&(l=0)}else{var t=S(b,f.x0_,f.y0_);m={x:(t.x-d.x)/j,y:(t.y-d.y)/k},j/=h*g,k/=i*g;var x=a.max(j,k);n=2*f.r0_/x,o=2*f.r1_/x-n}var y=f.colors_;y.sort(function(a,b){return a.offset-b.offset});var z=y.length,A=y[0].color,B=y[z-1].color,C=y[0].alpha*b.globalAlpha,D=y[z-1].alpha*b.globalAlpha,E=[];for(var G=0;G<z;G++){var H=y[G];E.push(H.offset*o+n+" "+H.color)}c.push('<g_vml_:fill type="',f.type_,'"',' method="none" focus="100%"',' color="',A,'"',' color2="',B,'"',' colors="',E.join(","),'"',' opacity="',D,'"',' g_o_:opacity2="',C,'"',' angle="',l,'"',' focusposition="',m.x,",",m.y,'" />')}else if(f instanceof W){if(j&&k){var I=-d.x,J=-d.y;c.push("<g_vml_:fill",' position="',I/j*h*h,",",J/k*i*i,'"',' type="tile"',' src="',f.src_,'" />')}}else{var K=F(b.fillStyle),L=K.color,M=K.alpha*b.globalAlpha;c.push('<g_vml_:fill color="',L,'" opacity="',M,'" />')}}function S(a,b,c){var d=a.m_;return{x:g*(b*d[0][0]+c*d[1][0]+d[2][0])-h,y:g*(b*d[0][1]+c*d[1][1]+d[2][1])-h}}function T(a){return isFinite(a[0][0])&&isFinite(a[0][1])&&isFinite(a[1][0])&&isFinite(a[1][1])&&isFinite(a[2][0])&&isFinite(a[2][1])}function U(a,b,c){if(!T(b))return;a.m_=b;if(c){var d=b[0][0]*b[1][1]-b[0][1]*b[1][0];a.lineScale_=f(e(d))}}function V(a){this.type_=a,this.x0_=0,this.y0_=0,this.r0_=0,this.x1_=0,this.y1_=0,this.r1_=0,this.colors_=[]}function W(a,b){Y(a);switch(b){case"repeat":case null:case"":this.repetition_="repeat";break;case"repeat-x":case"repeat-y":case"no-repeat":this.repetition_=b;break;default:X("SYNTAX_ERR")}this.src_=a.src,this.width_=a.width,this.height_=a.height}function X(a){throw new Z(a)}function Y(a){(!a||a.nodeType!=1||a.tagName!="IMG")&&X("TYPE_MISMATCH_ERR"),a.readyState!="complete"&&X("INVALID_STATE_ERR")}function Z(a){this.code=this[a],this.message=a+": DOM Exception "+this.code}var a=Math,b=a.round,c=a.sin,d=a.cos,e=a.abs,f=a.sqrt,g=10,h=g/2,i=+navigator.userAgent.match(/MSIE ([\d.]+)?/)[1],k=Array.prototype.slice;o(document);var p={init:function(a){var b=a||document;b.createElement("canvas"),b.attachEvent("onreadystatechange",l(this.init_,this,b))},init_:function(a){var b=a.getElementsByTagName("canvas");for(var c=0;c<b.length;c++)this.initElement(b[c])},initElement:function(a){if(!a.getContext){a.getContext=j,o(a.ownerDocument),a.innerHTML="",a.attachEvent("onpropertychange",q),a.attachEvent("onresize",r);var b=a.attributes;b.width&&b.width.specified?a.style.width=b.width.nodeValue+"px":a.width=a.clientWidth,b.height&&b.height.specified?a.style.height=b.height.nodeValue+"px":a.height=a.clientHeight}return a}};p.init();var s=[];for(var t=0;t<16;t++)for(var u=0;u<16;u++)s[t*16+u]=t.toString(16)+u.toString(16);var y={aliceblue:"#F0F8FF",antiquewhite:"#FAEBD7",aquamarine:"#7FFFD4",azure:"#F0FFFF",beige:"#F5F5DC",bisque:"#FFE4C4",black:"#000000",blanchedalmond:"#FFEBCD",blueviolet:"#8A2BE2",brown:"#A52A2A",burlywood:"#DEB887",cadetblue:"#5F9EA0",chartreuse:"#7FFF00",chocolate:"#D2691E",coral:"#FF7F50",cornflowerblue:"#6495ED",cornsilk:"#FFF8DC",crimson:"#DC143C",cyan:"#00FFFF",darkblue:"#00008B",darkcyan:"#008B8B",darkgoldenrod:"#B8860B",darkgray:"#A9A9A9",darkgreen:"#006400",darkgrey:"#A9A9A9",darkkhaki:"#BDB76B",darkmagenta:"#8B008B",darkolivegreen:"#556B2F",darkorange:"#FF8C00",darkorchid:"#9932CC",darkred:"#8B0000",darksalmon:"#E9967A",darkseagreen:"#8FBC8F",darkslateblue:"#483D8B",darkslategray:"#2F4F4F",darkslategrey:"#2F4F4F",darkturquoise:"#00CED1",darkviolet:"#9400D3",deeppink:"#FF1493",deepskyblue:"#00BFFF",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1E90FF",firebrick:"#B22222",floralwhite:"#FFFAF0",forestgreen:"#228B22",gainsboro:"#DCDCDC",ghostwhite:"#F8F8FF",gold:"#FFD700",goldenrod:"#DAA520",grey:"#808080",greenyellow:"#ADFF2F",honeydew:"#F0FFF0",hotpink:"#FF69B4",indianred:"#CD5C5C",indigo:"#4B0082",ivory:"#FFFFF0",khaki:"#F0E68C",lavender:"#E6E6FA",lavenderblush:"#FFF0F5",lawngreen:"#7CFC00",lemonchiffon:"#FFFACD",lightblue:"#ADD8E6",lightcoral:"#F08080",lightcyan:"#E0FFFF",lightgoldenrodyellow:"#FAFAD2",lightgreen:"#90EE90",lightgrey:"#D3D3D3",lightpink:"#FFB6C1",lightsalmon:"#FFA07A",lightseagreen:"#20B2AA",lightskyblue:"#87CEFA",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#B0C4DE",lightyellow:"#FFFFE0",limegreen:"#32CD32",linen:"#FAF0E6",magenta:"#FF00FF",mediumaquamarine:"#66CDAA",mediumblue:"#0000CD",mediumorchid:"#BA55D3",mediumpurple:"#9370DB",mediumseagreen:"#3CB371",mediumslateblue:"#7B68EE",mediumspringgreen:"#00FA9A",mediumturquoise:"#48D1CC",mediumvioletred:"#C71585",midnightblue:"#191970",mintcream:"#F5FFFA",mistyrose:"#FFE4E1",moccasin:"#FFE4B5",navajowhite:"#FFDEAD",oldlace:"#FDF5E6",olivedrab:"#6B8E23",orange:"#FFA500",orangered:"#FF4500",orchid:"#DA70D6",palegoldenrod:"#EEE8AA",palegreen:"#98FB98",paleturquoise:"#AFEEEE",palevioletred:"#DB7093",papayawhip:"#FFEFD5",peachpuff:"#FFDAB9",peru:"#CD853F",pink:"#FFC0CB",plum:"#DDA0DD",powderblue:"#B0E0E6",rosybrown:"#BC8F8F",royalblue:"#4169E1",saddlebrown:"#8B4513",salmon:"#FA8072",sandybrown:"#F4A460",seagreen:"#2E8B57",seashell:"#FFF5EE",sienna:"#A0522D",skyblue:"#87CEEB",slateblue:"#6A5ACD",slategray:"#708090",slategrey:"#708090",snow:"#FFFAFA",springgreen:"#00FF7F",steelblue:"#4682B4",tan:"#D2B48C",thistle:"#D8BFD8",tomato:"#FF6347",turquoise:"#40E0D0",violet:"#EE82EE",wheat:"#F5DEB3",whitesmoke:"#F5F5F5",yellowgreen:"#9ACD32"},E={},G={style:"normal",variant:"normal",weight:"normal",size:10,family:"sans-serif"},H={},L={butt:"flat",round:"round"},O=N.prototype;O.clearRect=function(){this.textMeasureEl_&&(this.textMeasureEl_.removeNode(!0),this.textMeasureEl_=null),this.element_.innerHTML=""},O.beginPath=function(){this.currentPath_=[]},O.moveTo=function(a,b){var c=S(this,a,b);this.currentPath_.push({type:"moveTo",x:c.x,y:c.y}),this.currentX_=c.x,this.currentY_=c.y},O.lineTo=function(a,b){var c=S(this,a,b);this.currentPath_.push({type:"lineTo",x:c.x,y:c.y}),this.currentX_=c.x,this.currentY_=c.y},O.bezierCurveTo=function(a,b,c,d,e,f){var g=S(this,e,f),h=S(this,a,b),i=S(this,c,d);P(this,h,i,g)},O.quadraticCurveTo=function(a,b,c,d){var e=S(this,a,b),f=S(this,c,d),g={x:this.currentX_+2/3*(e.x-this.currentX_),y:this.currentY_+2/3*(e.y-this.currentY_)},h={x:g.x+(f.x-this.currentX_)/3,y:g.y+(f.y-this.currentY_)/3};P(this,g,h,f)},O.arc=function(a,b,f,i,j,k){f*=g;var l=k?"at":"wa",m=a+d(i)*f-h,n=b+c(i)*f-h,o=a+d(j)*f-h,p=b+c(j)*f-h;e(m-o)<1e-7&&!k&&(m+=.125),e(n-p)<1e-7&&k&&(n-=.125);var q=S(this,a,b),r=S(this,m,n),s=S(this,o,p);this.currentPath_.push({type:l,x:q.x,y:q.y,radius:f,xStart:r.x,yStart:r.y,xEnd:s.x,yEnd:s.y})},O.rect=function(a,b,c,d){this.moveTo(a,b),this.lineTo(a+c,b),this.lineTo(a+c,b+d),this.lineTo(a,b+d),this.closePath()},O.strokeRect=function(a,b,c,d){var e=this.currentPath_;this.beginPath(),this.moveTo(a,b),this.lineTo(a+c,b),this.lineTo(a+c,b+d),this.lineTo(a,b+d),this.closePath(),this.stroke(),this.currentPath_=e},O.fillRect=function(a,b,c,d){var e=this.currentPath_;this.beginPath(),this.moveTo(a,b),this.lineTo(a+c,b),this.lineTo(a+c,b+d),this.lineTo(a,b+d),this.closePath(),this.fill(),this.currentPath_=e},O.createLinearGradient=function(a,b,c,d){var e=new V("gradient");return e.x0_=a,e.y0_=b,e.x1_=c,e.y1_=d,e},O.createRadialGradient=function(a,b,c,d,e,f){var g=new V("gradientradial");return g.x0_=a,g.y0_=b,g.r0_=c,g.x1_=d,g.y1_=e,g.r1_=f,g},O.drawImage=function(c,d){var e,f,h,i,j,k,l,m,n=c.runtimeStyle.width,o=c.runtimeStyle.height;c.runtimeStyle.width="auto",c.runtimeStyle.height="auto";var p=c.width,q=c.height;c.runtimeStyle.width=n,c.runtimeStyle.height=o;if(arguments.length==3)e=arguments[1],f=arguments[2],j=k=0,l=h=p,m=i=q;else if(arguments.length==5)e=arguments[1],f=arguments[2],h=arguments[3],i=arguments[4],j=k=0,l=p,m=q;else if(arguments.length==9)j=arguments[1],k=arguments[2],l=arguments[3],m=arguments[4],e=arguments[5],f=arguments[6],h=arguments[7],i=arguments[8];else throw Error("Invalid number of arguments");var r=S(this,e,f),s=l/2,t=m/2,u=[],v=10,w=10;u.push(" <g_vml_:group",' coordsize="',g*v,",",g*w,'"',' coordorigin="0,0"',' style="width:',v,"px;height:",w,"px;position:absolute;");if(this.m_[0][0]!=1||this.m_[0][1]||this.m_[1][1]!=1||this.m_[1][0]){var x=[];x.push("M11=",this.m_[0][0],",","M12=",this.m_[1][0],",","M21=",this.m_[0][1],",","M22=",this.m_[1][1],",","Dx=",b(r.x/g),",","Dy=",b(r.y/g),"");var y=r,z=S(this,e+h,f),A=S(this,e,f+i),B=S(this,e+h,f+i);y.x=a.max(y.x,z.x,A.x,B.x),y.y=a.max(y.y,z.y,A.y,B.y),u.push("padding:0 ",b(y.x/g),"px ",b(y.y/g),"px 0;filter:progid:DXImageTransform.Microsoft.Matrix(",x.join(""),", sizingmethod='clip');")}else u.push("top:",b(r.y/g),"px;left:",b(r.x/g),"px;");u.push(' ">','<g_vml_:image src="',c.src,'"',' style="width:',g*h,"px;"," height:",g*i,'px"',' cropleft="',j/p,'"',' croptop="',k/q,'"',' cropright="',(p-j-l)/p,'"',' cropbottom="',(q-k-m)/q,'"'," />","</g_vml_:group>"),this.element_.insertAdjacentHTML("BeforeEnd",u.join(""))},O.stroke=function(a){var c=[],d=!1,e=10,f=10;c.push("<g_vml_:shape",' filled="',!!a,'"',' style="position:absolute;width:',e,"px;height:",f,'px;"',' coordorigin="0,0"',' coordsize="',g*e,",",g*f,'"',' stroked="',!a,'"',' path="');var h=!1,i={x:null,y:null},j={x:null,y:null};for(var k=0;k<this.currentPath_.length;k++){var l=this.currentPath_[k],m;switch(l.type){case"moveTo":m=l,c.push(" m ",b(l.x),",",b(l.y));break;case"lineTo":c.push(" l ",b(l.x),",",b(l.y));break;case"close":c.push(" x "),l=null;break;case"bezierCurveTo":c.push(" c ",b(l.cp1x),",",b(l.cp1y),",",b(l.cp2x),",",b(l.cp2y),",",b(l.x),",",b(l.y));break;case"at":case"wa":c.push(" ",l.type," ",b(l.x-this.arcScaleX_*l.radius),",",b(l.y-this.arcScaleY_*l.radius)," ",b(l.x+this.arcScaleX_*l.radius),",",b(l.y+this.arcScaleY_*l.radius)," ",b(l.xStart),",",b(l.yStart)," ",b(l.xEnd),",",b(l.yEnd))}if(l){if(i.x==null||l.x<i.x)i.x=l.x;if(j.x==null||l.x>j.x)j.x=l.x;if(i.y==null||l.y<i.y)i.y=l.y;if(j.y==null||l.y>j.y)j.y=l.y}}c.push(' ">'),a?R(this,c,i,j):Q(this,c),c.push("</g_vml_:shape>"),this.element_.insertAdjacentHTML("beforeEnd",c.join(""))},O.fill=function(){this.stroke(!0)},O.closePath=function(){this.currentPath_.push({type:"close"})},O.save=function(){var a={};x(this,a),this.aStack_.push(a),this.mStack_.push(this.m_),this.m_=w(v(),this.m_)},O.restore=function(){this.aStack_.length&&(x(this.aStack_.pop(),this),this.m_=this.mStack_.pop())},O.translate=function(a,b){var c=[[1,0,0],[0,1,0],[a,b,1]];U(this,w(c,this.m_),!1)},O.rotate=function(a){var b=d(a),e=c(a),f=[[b,e,0],[-e,b,0],[0,0,1]];U(this,w(f,this.m_),!1)},O.scale=function(a,b){this.arcScaleX_*=a,this.arcScaleY_*=b;var c=[[a,0,0],[0,b,0],[0,0,1]];U(this,w(c,this.m_),!0)},O.transform=function(a,b,c,d,e,f){var g=[[a,b,0],[c,d,0],[e,f,1]];U(this,w(g,this.m_),!0)},O.setTransform=function(a,b,c,d,e,f){var g=[[a,b,0],[c,d,0],[e,f,1]];U(this,g,!0)},O.drawText_=function(a,c,d,e,f){var h=this.m_,i=1e3,j=0,k=i,l={x:0,y:0},n=[],o=J(I(this.font),this.element_),p=K(o),q=this.element_.currentStyle,r=this.textAlign.toLowerCase();switch(r){case"left":case"center":case"right":break;case"end":r=q.direction=="ltr"?"right":"left";break;case"start":r=q.direction=="rtl"?"right":"left";break;default:r="left"}switch(this.textBaseline){case"hanging":case"top":l.y=o.size/1.75;break;case"middle":break;default:case null:case"alphabetic":case"ideographic":case"bottom":l.y=-o.size/2.25}switch(r){case"right":j=i,k=.05;break;case"center":j=k=i/2}var s=S(this,c+l.x,d+l.y);n.push('<g_vml_:line from="',-j,' 0" to="',k,' 0.05" ',' coordsize="100 100" coordorigin="0 0"',' filled="',!f,'" stroked="',!!f,'" style="position:absolute;width:1px;height:1px;">'),f?Q(this,n):R(this,n,{x:-j,y:0},{x:k,y:o.size});var t=h[0][0].toFixed(3)+","+h[1][0].toFixed(3)+","+h[0][1].toFixed(3)+","+h[1][1].toFixed(3)+",0,0",u=b(s.x/g)+","+b(s.y/g);n.push('<g_vml_:skew on="t" matrix="',t,'" ',' offset="',u,'" origin="',j,' 0" />','<g_vml_:path textpathok="true" />','<g_vml_:textpath on="true" string="',m(a),'" style="v-text-align:',r,";font:",m(p),'" /></g_vml_:line>'),this.element_.insertAdjacentHTML("beforeEnd",n.join(""))},O.fillText=function(a,b,c,d){this.drawText_(a,b,c,d,!1)},O.strokeText=function(a,b,c,d){this.drawText_(a,b,c,d,!0)},O.measureText=function(a){if(!this.textMeasureEl_){var b='<span style="position:absolute;top:-20000px;left:0;padding:0;margin:0;border:none;white-space:pre;"></span>';this.element_.insertAdjacentHTML("beforeEnd",b),this.textMeasureEl_=this.element_.lastChild}var c=this.element_.ownerDocument;return this.textMeasureEl_.innerHTML="",this.textMeasureEl_.style.font=this.font,this.textMeasureEl_.appendChild(c.createTextNode(a)),{width:this.textMeasureEl_.offsetWidth}},O.clip=function(){},O.arcTo=function(){},O.createPattern=function(a,b){return new W(a,b)},V.prototype.addColorStop=function(a,b){b=F(b),this.colors_.push({offset:a,color:b.color,alpha:b.alpha})};var $=Z.prototype=new Error;$.INDEX_SIZE_ERR=1,$.DOMSTRING_SIZE_ERR=2,$.HIERARCHY_REQUEST_ERR=3,$.WRONG_DOCUMENT_ERR=4,$.INVALID_CHARACTER_ERR=5,$.NO_DATA_ALLOWED_ERR=6,$.NO_MODIFICATION_ALLOWED_ERR=7,$.NOT_FOUND_ERR=8,$.NOT_SUPPORTED_ERR=9,$.INUSE_ATTRIBUTE_ERR=10,$.INVALID_STATE_ERR=11,$.SYNTAX_ERR=12,$.INVALID_MODIFICATION_ERR=13,$.NAMESPACE_ERR=14,$.INVALID_ACCESS_ERR=15,$.VALIDATION_ERR=16,$.TYPE_MISMATCH_ERR=17,G_vmlCanvasManager=p,CanvasRenderingContext2D=N,CanvasGradient=V,CanvasPattern=W,DOMException=Z}(),function(){function c(b){var c,d,e,f,g,h;e=b.length,d=0,c="";while(d<e){f=b.charCodeAt(d++)&255;if(d==e){c+=a.charAt(f>>2),c+=a.charAt((f&3)<<4),c+="==";break}g=b.charCodeAt(d++);if(d==e){c+=a.charAt(f>>2),c+=a.charAt((f&3)<<4|(g&240)>>4),c+=a.charAt((g&15)<<2),c+="=";break}h=b.charCodeAt(d++),c+=a.charAt(f>>2),c+=a.charAt((f&3)<<4|(g&240)>>4),c+=a.charAt((g&15)<<2|(h&192)>>6),c+=a.charAt(h&63)}return c}function d(a){var c,d,e,f,g,h,i;h=a.length,g=0,i="";while(g<h){do c=b[a.charCodeAt(g++)&255];while(g<h&&c==-1);if(c==-1)break;do d=b[a.charCodeAt(g++)&255];while(g<h&&d==-1);if(d==-1)break;i+=String.fromCharCode(c<<2|(d&48)>>4);do{e=a.charCodeAt(g++)&255;if(e==61)return i;e=b[e]}while(g<h&&e==-1);if(e==-1)break;i+=String.fromCharCode((d&15)<<4|(e&60)>>2);do{f=a.charCodeAt(g++)&255;if(f==61)return i;f=b[f]}while(g<h&&f==-1);if(f==-1)break;i+=String.fromCharCode((e&3)<<6|f)}return i}var a="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",b=[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1];window.btoa||(window.btoa=c),window.atob||(window.atob=d)}();var CanvasText={letters:{"\n":{width:-1,points:[]}," ":{width:10,points:[]},"!":{width:10,points:[[5,21],[5,7],null,[5,2],[4,1],[5,0],[6,1],[5,2]]},'"':{width:16,points:[[4,21],[4,14],null,[12,21],[12,14]]},"#":{width:21,points:[[11,25],[4,-7],null,[17,25],[10,-7],null,[4,12],[18,12],null,[3,6],[17,6]]},$:{width:20,points:[[8,25],[8,-4],null,[12,25],[12,-4],null,[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]]},"%":{width:24,points:[[21,21],[3,0],null,[8,21],[10,19],[10,17],[9,15],[7,14],[5,14],[3,16],[3,18],[4,20],[6,21],[8,21],null,[17,7],[15,6],[14,4],[14,2],[16,0],[18,0],[20,1],[21,3],[21,5],[19,7],[17,7]]},"&":{width:26,points:[[23,12],[23,13],[22,14],[21,14],[20,13],[19,11],[17,6],[15,3],[13,1],[11,0],[7,0],[5,1],[4,2],[3,4],[3,6],[4,8],[5,9],[12,13],[13,14],[14,16],[14,18],[13,20],[11,21],[9,20],[8,18],[8,16],[9,13],[11,10],[16,3],[18,1],[20,0],[22,0],[23,1],[23,2]]},"'":{width:10,points:[[5,19],[4,20],[5,21],[6,20],[6,18],[5,16],[4,15]]},"(":{width:14,points:[[11,25],[9,23],[7,20],[5,16],[4,11],[4,7],[5,2],[7,-2],[9,-5],[11,-7]]},")":{width:14,points:[[3,25],[5,23],[7,20],[9,16],[10,11],[10,7],[9,2],[7,-2],[5,-5],[3,-7]]},"*":{width:16,points:[[8,21],[8,9],null,[3,18],[13,12],null,[13,18],[3,12]]},"+":{width:26,points:[[13,18],[13,0],null,[4,9],[22,9]]},",":{width:10,points:[[6,1],[5,0],[4,1],[5,2],[6,1],[6,-1],[5,-3],[4,-4]]},"-":{width:26,points:[[4,9],[22,9]]},".":{width:10,points:[[5,2],[4,1],[5,0],[6,1],[5,2]]},"/":{width:22,points:[[20,25],[2,-7]]},0:{width:20,points:[[9,21],[6,20],[4,17],[3,12],[3,9],[4,4],[6,1],[9,0],[11,0],[14,1],[16,4],[17,9],[17,12],[16,17],[14,20],[11,21],[9,21]]},1:{width:20,points:[[6,17],[8,18],[11,21],[11,0]]},2:{width:20,points:[[4,16],[4,17],[5,19],[6,20],[8,21],[12,21],[14,20],[15,19],[16,17],[16,15],[15,13],[13,10],[3,0],[17,0]]},3:{width:20,points:[[5,21],[16,21],[10,13],[13,13],[15,12],[16,11],[17,8],[17,6],[16,3],[14,1],[11,0],[8,0],[5,1],[4,2],[3,4]]},4:{width:20,points:[[13,21],[3,7],[18,7],null,[13,21],[13,0]]},5:{width:20,points:[[15,21],[5,21],[4,12],[5,13],[8,14],[11,14],[14,13],[16,11],[17,8],[17,6],[16,3],[14,1],[11,0],[8,0],[5,1],[4,2],[3,4]]},6:{width:20,points:[[16,18],[15,20],[12,21],[10,21],[7,20],[5,17],[4,12],[4,7],[5,3],[7,1],[10,0],[11,0],[14,1],[16,3],[17,6],[17,7],[16,10],[14,12],[11,13],[10,13],[7,12],[5,10],[4,7]]},7:{width:20,points:[[17,21],[7,0],null,[3,21],[17,21]]},8:{width:20,points:[[8,21],[5,20],[4,18],[4,16],[5,14],[7,13],[11,12],[14,11],[16,9],[17,7],[17,4],[16,2],[15,1],[12,0],[8,0],[5,1],[4,2],[3,4],[3,7],[4,9],[6,11],[9,12],[13,13],[15,14],[16,16],[16,18],[15,20],[12,21],[8,21]]},9:{width:20,points:[[16,14],[15,11],[13,9],[10,8],[9,8],[6,9],[4,11],[3,14],[3,15],[4,18],[6,20],[9,21],[10,21],[13,20],[15,18],[16,14],[16,9],[15,4],[13,1],[10,0],[8,0],[5,1],[4,3]]},":":{width:10,points:[[5,14],[4,13],[5,12],[6,13],[5,14],null,[5,2],[4,1],[5,0],[6,1],[5,2]]},";":{width:10,points:[[5,14],[4,13],[5,12],[6,13],[5,14],null,[6,1],[5,0],[4,1],[5,2],[6,1],[6,-1],[5,-3],[4,-4]]},"<":{width:24,points:[[20,18],[4,9],[20,0]]},"=":{width:26,points:[[4,12],[22,12],null,[4,6],[22,6]]},">":{width:24,points:[[4,18],[20,9],[4,0]]},"?":{width:18,points:[[3,16],[3,17],[4,19],[5,20],[7,21],[11,21],[13,20],[14,19],[15,17],[15,15],[14,13],[13,12],[9,10],[9,7],null,[9,2],[8,1],[9,0],[10,1],[9,2]]},"@":{width:27,points:[[18,13],[17,15],[15,16],[12,16],[10,15],[9,14],[8,11],[8,8],[9,6],[11,5],[14,5],[16,6],[17,8],null,[12,16],[10,14],[9,11],[9,8],[10,6],[11,5],null,[18,16],[17,8],[17,6],[19,5],[21,5],[23,7],[24,10],[24,12],[23,15],[22,17],[20,19],[18,20],[15,21],[12,21],[9,20],[7,19],[5,17],[4,15],[3,12],[3,9],[4,6],[5,4],[7,2],[9,1],[12,0],[15,0],[18,1],[20,2],[21,3],null,[19,16],[18,8],[18,6],[19,5]]},A:{width:18,points:[[9,21],[1,0],null,[9,21],[17,0],null,[4,7],[14,7]]},B:{width:21,points:[[4,21],[4,0],null,[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],null,[4,11],[13,11],[16,10],[17,9],[18,7],[18,4],[17,2],[16,1],[13,0],[4,0]]},C:{width:21,points:[[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5]]},D:{width:21,points:[[4,21],[4,0],null,[4,21],[11,21],[14,20],[16,18],[17,16],[18,13],[18,8],[17,5],[16,3],[14,1],[11,0],[4,0]]},E:{width:19,points:[[4,21],[4,0],null,[4,21],[17,21],null,[4,11],[12,11],null,[4,0],[17,0]]},F:{width:18,points:[[4,21],[4,0],null,[4,21],[17,21],null,[4,11],[12,11]]},G:{width:21,points:[[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[18,8],null,[13,8],[18,8]]},H:{width:22,points:[[4,21],[4,0],null,[18,21],[18,0],null,[4,11],[18,11]]},I:{width:8,points:[[4,21],[4,0]]},J:{width:16,points:[[12,21],[12,5],[11,2],[10,1],[8,0],[6,0],[4,1],[3,2],[2,5],[2,7]]},K:{width:21,points:[[4,21],[4,0],null,[18,21],[4,7],null,[9,12],[18,0]]},L:{width:17,points:[[4,21],[4,0],null,[4,0],[16,0]]},M:{width:24,points:[[4,21],[4,0],null,[4,21],[12,0],null,[20,21],[12,0],null,[20,21],[20,0]]},N:{width:22,points:[[4,21],[4,0],null,[4,21],[18,0],null,[18,21],[18,0]]},O:{width:22,points:[[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21]]},P:{width:21,points:[[4,21],[4,0],null,[4,21],[13,21],[16,20],[17,19],[18,17],[18,14],[17,12],[16,11],[13,10],[4,10]]},Q:{width:22,points:[[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21],null,[12,4],[18,-2]]},R:{width:21,points:[[4,21],[4,0],null,[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],[4,11],null,[11,11],[18,0]]},S:{width:20,points:[[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]]},T:{width:16,points:[[8,21],[8,0],null,[1,21],[15,21]]},U:{width:22,points:[[4,21],[4,6],[5,3],[7,1],[10,0],[12,0],[15,1],[17,3],[18,6],[18,21]]},V:{width:18,points:[[1,21],[9,0],null,[17,21],[9,0]]},W:{width:24,points:[[2,21],[7,0],null,[12,21],[7,0],null,[12,21],[17,0],null,[22,21],[17,0]]},X:{width:20,points:[[3,21],[17,0],null,[17,21],[3,0]]},Y:{width:18,points:[[1,21],[9,11],[9,0],null,[17,21],[9,11]]},Z:{width:20,points:[[17,21],[3,0],null,[3,21],[17,21],null,[3,0],[17,0]]},"[":{width:14,points:[[4,25],[4,-7],null,[5,25],[5,-7],null,[4,25],[11,25],null,[4,-7],[11,-7]]},"\\":{width:14,points:[[0,21],[14,-3]]},"]":{width:14,points:[[9,25],[9,-7],null,[10,25],[10,-7],null,[3,25],[10,25],null,[3,-7],[10,-7]]},"^":{width:14,points:[[3,10],[8,18],[13,10]]},_:{width:16,points:[[0,-2],[16,-2]]},"`":{width:10,points:[[6,21],[5,20],[4,18],[4,16],[5,15],[6,16],[5,17]]},a:{width:19,points:[[15,14],[15,0],null,[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]]},b:{width:19,points:[[4,21],[4,0],null,[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]]},c:{width:18,points:[[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]]},d:{width:19,points:[[15,21],[15,0],null,[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]]},e:{width:18,points:[[3,8],[15,8],[15,10],[14,12],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]]},f:{width:12,points:[[10,21],[8,21],[6,20],[5,17],[5,0],null,[2,14],[9,14]]},g:{width:19,points:[[15,14],[15,-2],[14,-5],[13,-6],[11,-7],[8,-7],[6,-6],null,[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]]},h:{width:19,points:[[4,21],[4,0],null,[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]]},i:{width:8,points:[[3,21],[4,20],[5,21],[4,22],[3,21],null,[4,14],[4,0]]},j:{width:10,points:[[5,21],[6,20],[7,21],[6,22],[5,21],null,[6,14],[6,-3],[5,-6],[3,-7],[1,-7]]},k:{width:17,points:[[4,21],[4,0],null,[14,14],[4,4],null,[8,8],[15,0]]},l:{width:8,points:[[4,21],[4,0]]},m:{width:30,points:[[4,14],[4,0],null,[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0],null,[15,10],[18,13],[20,14],[23,14],[25,13],[26,10],[26,0]]},n:{width:19,points:[[4,14],[4,0],null,[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]]},o:{width:19,points:[[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3],[16,6],[16,8],[15,11],[13,13],[11,14],[8,14]]},p:{width:19,points:[[4,14],[4,-7],null,[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]]},q:{width:19,points:[[15,14],[15,-7],null,[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]]},r:{width:13,points:[[4,14],[4,0],null,[4,8],[5,11],[7,13],[9,14],[12,14]]},s:{width:17,points:[[14,11],[13,13],[10,14],[7,14],[4,13],[3,11],[4,9],[6,8],[11,7],[13,6],[14,4],[14,3],[13,1],[10,0],[7,0],[4,1],[3,3]]},t:{width:12,points:[[5,21],[5,4],[6,1],[8,0],[10,0],null,[2,14],[9,14]]},u:{width:19,points:[[4,14],[4,4],[5,1],[7,0],[10,0],[12,1],[15,4],null,[15,14],[15,0]]},v:{width:16,points:[[2,14],[8,0],null,[14,14],[8,0]]},w:{width:22,points:[[3,14],[7,0],null,[11,14],[7,0],null,[11,14],[15,0],null,[19,14],[15,0]]},x:{width:17,points:[[3,14],[14,0],null,[14,14],[3,0]]},y:{width:16,points:[[2,14],[8,0],null,[14,14],[8,0],[6,-4],[4,-6],[2,-7],[1,-7]]},z:{width:17,points:[[14,14],[3,0],null,[3,14],[14,14],null,[3,0],[14,0]]},"{":{width:14,points:[[9,25],[7,24],[6,23],[5,21],[5,19],[6,17],[7,16],[8,14],[8,12],[6,10],null,[7,24],[6,22],[6,20],[7,18],[8,17],[9,15],[9,13],[8,11],[4,9],[8,7],[9,5],[9,3],[8,1],[7,0],[6,-2],[6,-4],[7,-6],null,[6,8],[8,6],[8,4],[7,2],[6,1],[5,-1],[5,-3],[6,-5],[7,-6],[9,-7]]},"|":{width:8,points:[[4,25],[4,-7]]},"}":{width:14,points:[[5,25],[7,24],[8,23],[9,21],[9,19],[8,17],[7,16],[6,14],[6,12],[8,10],null,[7,24],[8,22],[8,20],[7,18],[6,17],[5,15],[5,13],[6,11],[10,9],[6,7],[5,5],[5,3],[6,1],[7,0],[8,-2],[8,-4],[7,-6],null,[8,8],[6,6],[6,4],[7,2],[8,1],[9,-1],[9,-3],[8,-5],[7,-6],[5,-7]]},"~":{width:24,points:[[3,6],[3,8],[4,11],[6,12],[8,12],[10,11],[14,8],[16,7],[18,7],[20,8],[21,10],null,[3,8],[4,10],[6,11],[8,11],[10,10],[14,7],[16,6],[18,6],[20,7],[21,10],[21,12]]},"�":{diacritic:"`",letter:"a"},"�":{diacritic:"�",letter:"a"},"�":{diacritic:"^",letter:"a"},"�":{diacritic:"�",letter:"a"},"�":{diacritic:"~",letter:"a"},"�":{diacritic:"`",letter:"e"},"�":{diacritic:"�",letter:"e"},"�":{diacritic:"^",letter:"e"},"�":{diacritic:"�",letter:"e"},"�":{diacritic:"`",letter:"i"},"�":{diacritic:"�",letter:"i"},"�":{diacritic:"^",letter:"i"},"�":{diacritic:"�",letter:"i"},"�":{diacritic:"`",letter:"o"},"�":{diacritic:"�",letter:"o"},"�":{diacritic:"^",letter:"o"},"�":{diacritic:"�",letter:"o"},"�":{diacritic:"~",letter:"o"},"�":{diacritic:"`",letter:"u"},"�":{diacritic:"�",letter:"u"},"�":{diacritic:"^",letter:"u"},"�":{diacritic:"�",letter:"u"},"�":{diacritic:"�",letter:"y"},"�":{diacritic:"�",letter:"y"},"�":{diacritic:"�",letter:"c"},"�":{diacritic:"~",letter:"n"},"�":{diacritic:"`",letter:"A"},"�":{diacritic:"�",letter:"A"},"�":{diacritic:"^",letter:"A"},"�":{diacritic:"�",letter:"A"},"�":{diacritic:"~",letter:"A"},"�":{diacritic:"`",letter:"E"},"�":{diacritic:"�",letter:"E"},"�":{diacritic:"^",letter:"E"},"�":{diacritic:"�",letter:"E"},"�":{diacritic:"`",letter:"I"},"�":{diacritic:"�",letter:"I"},"�":{diacritic:"^",letter:"I"},"�":{diacritic:"�",letter:"I"},"�":{diacritic:"`",letter:"O"},"�":{diacritic:"�",letter:"O"},"�":{diacritic:"^",letter:"O"},"�":{diacritic:"�",letter:"O"},"�":{diacritic:"~",letter:"O"},"�":{diacritic:"`",letter:"U"},"�":{diacritic:"�",letter:"U"},"�":{diacritic:"^",letter:"U"},"�":{diacritic:"�",letter:"U"},"�":{diacritic:"�",letter:"Y"},"�":{diacritic:"�",letter:"C"},"�":{diacritic:"~",letter:"N"}},specialchars:{pi:{width:19,points:[[6,14],[6,0],null,[14,14],[14,0],null,[2,13],[6,16],[13,13],[17,16]]}},diacritics:{"�":{entity:"cedil",points:[[6,-4],[4,-6],[2,-7],[1,-7]]},"�":{entity:"acute",points:[[8,19],[13,22]]},"`":{entity:"grave",points:[[7,22],[12,19]]},"^":{entity:"circ",points:[[5.5,19],[9.5,23],[12.5,19]]},"�":{entity:"trema",points:[[5,21],[6,20],[7,21],[6,22],[5,21],null,[12,21],[13,20],[14,21],[13,22],[12,21]]},"~":{entity:"tilde",points:[[4,18],[7,22],[10,18],[13,22]]}},style:{size:8,font:null,color:"#000000",weight:1,textAlign:"left",textBaseline:"bottom",adjustAlign:!1,angle:0,tracking:1,boundingBoxColor:"#ff0000",originPointColor:"#000000"},debug:!1,_bufferLexemes:{},extend:function(a,b){for(var c in b){if(c in a)continue;a[c]=b[c]}return a},letter:function(a){return CanvasText.letters[a]},parseLexemes:function(a){if(CanvasText._bufferLexemes[a])return CanvasText._bufferLexemes[a];var b,c,d=a.match(/&[A-Za-z]{2,5};|\s|./g),e=[],f=[];for(b=0;b<d.length;b++){c=d[b];if(c.length==1)f.push(c);else{var g=c.substring(1,c.length-1);CanvasText.specialchars[g]?f.push(g):f=f.concat(c.toArray())}}for(b=0;b<f.length;b++)c=f[b],(c=CanvasText.letters[c]||CanvasText.specialchars[c])&&e.push(c);for(b=0;b<e.length;b++)(e===null||typeof e=="undefined")&&delete e[b];return CanvasText._bufferLexemes[a]=e},ascent:function(a){return a=a||CanvasText.style,a.size||CanvasText.style.size},descent:function(a){return a=a||CanvasText.style,7*(a.size||CanvasText.style.size)/25},measure:function(a,b){if(!a)return;b=b||CanvasText.style;var d,e,f=CanvasText.parseLexemes(a),g=0;for(d=f.length-1;d>-1;--d)c=f[d],e=c.diacritic?CanvasText.letter(c.letter).width:c.width,g+=e*(b.tracking||CanvasText.style.tracking)*(b.size||CanvasText.style.size)/25;return g},getDimensions:function(a,b){b=b||CanvasText.style;var c=CanvasText.measure(a,b),d=b.size||CanvasText.style.size,e=b.angle||CanvasText.style.angle;return b.angle==0?{width:c,height:d}:{width:Math.abs(Math.cos(e)*c)+Math.abs(Math.sin(e)*d),height:Math.abs(Math.sin(e)*c)+Math.abs(Math.cos(e)*d)}},drawPoints:function(a,b,c,d,e,f){var g,h,i=!0,j=0;f=f||{x:0,y:0},a.beginPath();for(g=0;g<b.length;g++){h=b[g];if(!h){i=!0;continue}i?(a.moveTo(c+h[0]*e+f.x,d-h[1]*e+f.y),i=!1):a.lineTo(c+h[0]*e+f.x,d-h[1]*e+f.y)}a.stroke(),a.closePath()},draw:function(a,b,c,d){if(!a)return;CanvasText.extend(d,CanvasText.style);var e,f,g=0,h=d.size/25,i=0,j=0,k=CanvasText.parseLexemes(a),l={x:0,y:0},m=CanvasText.measure(a,d),n;d.adjustAlign&&(n=CanvasText.getBestAlign(d.angle,d),CanvasText.extend(d,n));switch(d.textAlign){case"left":break;case"center":l.x=-m/2;break;case"right":l.x=-m}switch(d.textBaseline){case"bottom":break;case"middle":l.y=d.size/2;break;case"top":l.y=d.size}this.save(),this.translate(b,c),this.rotate(d.angle),this.lineCap="round",this.lineWidth=2*h*(d.weight||CanvasText.style.weight),this.strokeStyle=d.color||CanvasText.style.color;for(e=0;e<k.length;e++){f=k[e];if(f.width==-1){i=0,j=d.size*1.4;continue}var o=f.points,p=f.width;if(f.diacritic){var q=CanvasText.diacritics[f.diacritic],r=CanvasText.letter(f.letter);CanvasText.drawPoints(this,q.points,i,j-(f.letter.toUpperCase()==f.letter?3:0),h,l),o=r.points,p=r.width}CanvasText.drawPoints(this,o,i,j,h,l),CanvasText.debug&&(this.save(),this.lineJoin="miter",this.lineWidth=.5,this.strokeStyle=d.boundingBoxColor||CanvasText.style.boundingBoxColor,this.strokeRect(i+l.x,j+l.y,p*h,-d.size),this.fillStyle=d.originPointColor||CanvasText.style.originPointColor,this.beginPath(),this.arc(0,0,1.5,0,Math.PI*2,!0),this.fill(),this.closePath(),this.restore()),i+=p*h*(d.tracking||CanvasText.style.tracking)}return this.restore(),g}};CanvasText.proto=window.CanvasRenderingContext2D?window.CanvasRenderingContext2D.prototype:document.createElement("canvas").getContext("2d").__proto__,CanvasText.proto&&(CanvasText.proto.drawText=CanvasText.draw,CanvasText.proto.measure=CanvasText.measure,CanvasText.proto.getTextBounds=CanvasText.getDimensions,CanvasText.proto.fontAscent=CanvasText.ascent,CanvasText.proto.fontDescent=CanvasText.descent)
1894\ No newline at end of file
1895
1896=== removed file 'addons/web_graph/static/lib/flotr2/flotr2.js'
1897--- addons/web_graph/static/lib/flotr2/flotr2.js 2012-05-07 08:19:08 +0000
1898+++ addons/web_graph/static/lib/flotr2/flotr2.js 1970-01-01 00:00:00 +0000
1899@@ -1,6865 +0,0 @@
1900-/*!
1901- * bean.js - copyright Jacob Thornton 2011
1902- * https://github.com/fat/bean
1903- * MIT License
1904- * special thanks to:
1905- * dean edwards: http://dean.edwards.name/
1906- * dperini: https://github.com/dperini/nwevents
1907- * the entire mootools team: github.com/mootools/mootools-core
1908- */
1909-/*global module:true, define:true*/
1910-!function (name, context, definition) {
1911- if (typeof module !== 'undefined') module.exports = definition(name, context);
1912- else if (typeof define === 'function' && typeof define.amd === 'object') define(definition);
1913- else context[name] = definition(name, context);
1914-}('bean', this, function (name, context) {
1915- var win = window
1916- , old = context[name]
1917- , overOut = /over|out/
1918- , namespaceRegex = /[^\.]*(?=\..*)\.|.*/
1919- , nameRegex = /\..*/
1920- , addEvent = 'addEventListener'
1921- , attachEvent = 'attachEvent'
1922- , removeEvent = 'removeEventListener'
1923- , detachEvent = 'detachEvent'
1924- , doc = document || {}
1925- , root = doc.documentElement || {}
1926- , W3C_MODEL = root[addEvent]
1927- , eventSupport = W3C_MODEL ? addEvent : attachEvent
1928- , slice = Array.prototype.slice
1929- , mouseTypeRegex = /click|mouse|menu|drag|drop/i
1930- , touchTypeRegex = /^touch|^gesture/i
1931- , ONE = { one: 1 } // singleton for quick matching making add() do one()
1932-
1933- , nativeEvents = (function (hash, events, i) {
1934- for (i = 0; i < events.length; i++)
1935- hash[events[i]] = 1
1936- return hash
1937- })({}, (
1938- 'click dblclick mouseup mousedown contextmenu ' + // mouse buttons
1939- 'mousewheel DOMMouseScroll ' + // mouse wheel
1940- 'mouseover mouseout mousemove selectstart selectend ' + // mouse movement
1941- 'keydown keypress keyup ' + // keyboard
1942- 'orientationchange ' + // mobile
1943- 'focus blur change reset select submit ' + // form elements
1944- 'load unload beforeunload resize move DOMContentLoaded readystatechange ' + // window
1945- 'error abort scroll ' + // misc
1946- (W3C_MODEL ? // element.fireEvent('onXYZ'... is not forgiving if we try to fire an event
1947- // that doesn't actually exist, so make sure we only do these on newer browsers
1948- 'show ' + // mouse buttons
1949- 'input invalid ' + // form elements
1950- 'touchstart touchmove touchend touchcancel ' + // touch
1951- 'gesturestart gesturechange gestureend ' + // gesture
1952- 'message readystatechange pageshow pagehide popstate ' + // window
1953- 'hashchange offline online ' + // window
1954- 'afterprint beforeprint ' + // printing
1955- 'dragstart dragenter dragover dragleave drag drop dragend ' + // dnd
1956- 'loadstart progress suspend emptied stalled loadmetadata ' + // media
1957- 'loadeddata canplay canplaythrough playing waiting seeking ' + // media
1958- 'seeked ended durationchange timeupdate play pause ratechange ' + // media
1959- 'volumechange cuechange ' + // media
1960- 'checking noupdate downloading cached updateready obsolete ' + // appcache
1961- '' : '')
1962- ).split(' ')
1963- )
1964-
1965- , customEvents = (function () {
1966- function isDescendant(parent, node) {
1967- while ((node = node.parentNode) !== null) {
1968- if (node === parent) return true
1969- }
1970- return false
1971- }
1972-
1973- function check(event) {
1974- var related = event.relatedTarget
1975- if (!related) return related === null
1976- return (related !== this && related.prefix !== 'xul' && !/document/.test(this.toString()) && !isDescendant(this, related))
1977- }
1978-
1979- return {
1980- mouseenter: { base: 'mouseover', condition: check }
1981- , mouseleave: { base: 'mouseout', condition: check }
1982- , mousewheel: { base: /Firefox/.test(navigator.userAgent) ? 'DOMMouseScroll' : 'mousewheel' }
1983- }
1984- })()
1985-
1986- , fixEvent = (function () {
1987- var commonProps = 'altKey attrChange attrName bubbles cancelable ctrlKey currentTarget detail eventPhase getModifierState isTrusted metaKey relatedNode relatedTarget shiftKey srcElement target timeStamp type view which'.split(' ')
1988- , mouseProps = commonProps.concat('button buttons clientX clientY dataTransfer fromElement offsetX offsetY pageX pageY screenX screenY toElement'.split(' '))
1989- , keyProps = commonProps.concat('char charCode key keyCode'.split(' '))
1990- , touchProps = commonProps.concat('touches targetTouches changedTouches scale rotation'.split(' '))
1991- , preventDefault = 'preventDefault'
1992- , createPreventDefault = function (event) {
1993- return function () {
1994- if (event[preventDefault])
1995- event[preventDefault]()
1996- else
1997- event.returnValue = false
1998- }
1999- }
2000- , stopPropagation = 'stopPropagation'
2001- , createStopPropagation = function (event) {
2002- return function () {
2003- if (event[stopPropagation])
2004- event[stopPropagation]()
2005- else
2006- event.cancelBubble = true
2007- }
2008- }
2009- , createStop = function (synEvent) {
2010- return function () {
2011- synEvent[preventDefault]()
2012- synEvent[stopPropagation]()
2013- synEvent.stopped = true
2014- }
2015- }
2016- , copyProps = function (event, result, props) {
2017- var i, p
2018- for (i = props.length; i--;) {
2019- p = props[i]
2020- if (!(p in result) && p in event) result[p] = event[p]
2021- }
2022- }
2023-
2024- return function (event, isNative) {
2025- var result = { originalEvent: event, isNative: isNative }
2026- if (!event)
2027- return result
2028-
2029- var props
2030- , type = event.type
2031- , target = event.target || event.srcElement
2032-
2033- result[preventDefault] = createPreventDefault(event)
2034- result[stopPropagation] = createStopPropagation(event)
2035- result.stop = createStop(result)
2036- result.target = target && target.nodeType === 3 ? target.parentNode : target
2037-
2038- if (isNative) { // we only need basic augmentation on custom events, the rest is too expensive
2039- if (type.indexOf('key') !== -1) {
2040- props = keyProps
2041- result.keyCode = event.which || event.keyCode
2042- } else if (mouseTypeRegex.test(type)) {
2043- props = mouseProps
2044- result.rightClick = event.which === 3 || event.button === 2
2045- result.pos = { x: 0, y: 0 }
2046- if (event.pageX || event.pageY) {
2047- result.clientX = event.pageX
2048- result.clientY = event.pageY
2049- } else if (event.clientX || event.clientY) {
2050- result.clientX = event.clientX + doc.body.scrollLeft + root.scrollLeft
2051- result.clientY = event.clientY + doc.body.scrollTop + root.scrollTop
2052- }
2053- if (overOut.test(type))
2054- result.relatedTarget = event.relatedTarget || event[(type === 'mouseover' ? 'from' : 'to') + 'Element']
2055- } else if (touchTypeRegex.test(type)) {
2056- props = touchProps
2057- }
2058- copyProps(event, result, props || commonProps)
2059- }
2060- return result
2061- }
2062- })()
2063-
2064- // if we're in old IE we can't do onpropertychange on doc or win so we use doc.documentElement for both
2065- , targetElement = function (element, isNative) {
2066- return !W3C_MODEL && !isNative && (element === doc || element === win) ? root : element
2067- }
2068-
2069- // we use one of these per listener, of any type
2070- , RegEntry = (function () {
2071- function entry(element, type, handler, original, namespaces) {
2072- this.element = element
2073- this.type = type
2074- this.handler = handler
2075- this.original = original
2076- this.namespaces = namespaces
2077- this.custom = customEvents[type]
2078- this.isNative = nativeEvents[type] && element[eventSupport]
2079- this.eventType = W3C_MODEL || this.isNative ? type : 'propertychange'
2080- this.customType = !W3C_MODEL && !this.isNative && type
2081- this.target = targetElement(element, this.isNative)
2082- this.eventSupport = this.target[eventSupport]
2083- }
2084-
2085- entry.prototype = {
2086- // given a list of namespaces, is our entry in any of them?
2087- inNamespaces: function (checkNamespaces) {
2088- var i, j
2089- if (!checkNamespaces)
2090- return true
2091- if (!this.namespaces)
2092- return false
2093- for (i = checkNamespaces.length; i--;) {
2094- for (j = this.namespaces.length; j--;) {
2095- if (checkNamespaces[i] === this.namespaces[j])
2096- return true
2097- }
2098- }
2099- return false
2100- }
2101-
2102- // match by element, original fn (opt), handler fn (opt)
2103- , matches: function (checkElement, checkOriginal, checkHandler) {
2104- return this.element === checkElement &&
2105- (!checkOriginal || this.original === checkOriginal) &&
2106- (!checkHandler || this.handler === checkHandler)
2107- }
2108- }
2109-
2110- return entry
2111- })()
2112-
2113- , registry = (function () {
2114- // our map stores arrays by event type, just because it's better than storing
2115- // everything in a single array. uses '$' as a prefix for the keys for safety
2116- var map = {}
2117-
2118- // generic functional search of our registry for matching listeners,
2119- // `fn` returns false to break out of the loop
2120- , forAll = function (element, type, original, handler, fn) {
2121- if (!type || type === '*') {
2122- // search the whole registry
2123- for (var t in map) {
2124- if (t.charAt(0) === '$')
2125- forAll(element, t.substr(1), original, handler, fn)
2126- }
2127- } else {
2128- var i = 0, l, list = map['$' + type], all = element === '*'
2129- if (!list)
2130- return
2131- for (l = list.length; i < l; i++) {
2132- if (all || list[i].matches(element, original, handler))
2133- if (!fn(list[i], list, i, type))
2134- return
2135- }
2136- }
2137- }
2138-
2139- , has = function (element, type, original) {
2140- // we're not using forAll here simply because it's a bit slower and this
2141- // needs to be fast
2142- var i, list = map['$' + type]
2143- if (list) {
2144- for (i = list.length; i--;) {
2145- if (list[i].matches(element, original, null))
2146- return true
2147- }
2148- }
2149- return false
2150- }
2151-
2152- , get = function (element, type, original) {
2153- var entries = []
2154- forAll(element, type, original, null, function (entry) { return entries.push(entry) })
2155- return entries
2156- }
2157-
2158- , put = function (entry) {
2159- (map['$' + entry.type] || (map['$' + entry.type] = [])).push(entry)
2160- return entry
2161- }
2162-
2163- , del = function (entry) {
2164- forAll(entry.element, entry.type, null, entry.handler, function (entry, list, i) {
2165- list.splice(i, 1)
2166- if (list.length === 0)
2167- delete map['$' + entry.type]
2168- return false
2169- })
2170- }
2171-
2172- // dump all entries, used for onunload
2173- , entries = function () {
2174- var t, entries = []
2175- for (t in map) {
2176- if (t.charAt(0) === '$')
2177- entries = entries.concat(map[t])
2178- }
2179- return entries
2180- }
2181-
2182- return { has: has, get: get, put: put, del: del, entries: entries }
2183- })()
2184-
2185- // add and remove listeners to DOM elements
2186- , listener = W3C_MODEL ? function (element, type, fn, add) {
2187- element[add ? addEvent : removeEvent](type, fn, false)
2188- } : function (element, type, fn, add, custom) {
2189- if (custom && add && element['_on' + custom] === null)
2190- element['_on' + custom] = 0
2191- element[add ? attachEvent : detachEvent]('on' + type, fn)
2192- }
2193-
2194- , nativeHandler = function (element, fn, args) {
2195- return function (event) {
2196- event = fixEvent(event || ((this.ownerDocument || this.document || this).parentWindow || win).event, true)
2197- return fn.apply(element, [event].concat(args))
2198- }
2199- }
2200-
2201- , customHandler = function (element, fn, type, condition, args, isNative) {
2202- return function (event) {
2203- if (condition ? condition.apply(this, arguments) : W3C_MODEL ? true : event && event.propertyName === '_on' + type || !event) {
2204- if (event)
2205- event = fixEvent(event || ((this.ownerDocument || this.document || this).parentWindow || win).event, isNative)
2206- fn.apply(element, event && (!args || args.length === 0) ? arguments : slice.call(arguments, event ? 0 : 1).concat(args))
2207- }
2208- }
2209- }
2210-
2211- , once = function (rm, element, type, fn, originalFn) {
2212- // wrap the handler in a handler that does a remove as well
2213- return function () {
2214- rm(element, type, originalFn)
2215- fn.apply(this, arguments)
2216- }
2217- }
2218-
2219- , removeListener = function (element, orgType, handler, namespaces) {
2220- var i, l, entry
2221- , type = (orgType && orgType.replace(nameRegex, ''))
2222- , handlers = registry.get(element, type, handler)
2223-
2224- for (i = 0, l = handlers.length; i < l; i++) {
2225- if (handlers[i].inNamespaces(namespaces)) {
2226- if ((entry = handlers[i]).eventSupport)
2227- listener(entry.target, entry.eventType, entry.handler, false, entry.type)
2228- // TODO: this is problematic, we have a registry.get() and registry.del() that
2229- // both do registry searches so we waste cycles doing this. Needs to be rolled into
2230- // a single registry.forAll(fn) that removes while finding, but the catch is that
2231- // we'll be splicing the arrays that we're iterating over. Needs extra tests to
2232- // make sure we don't screw it up. @rvagg
2233- registry.del(entry)
2234- }
2235- }
2236- }
2237-
2238- , addListener = function (element, orgType, fn, originalFn, args) {
2239- var entry
2240- , type = orgType.replace(nameRegex, '')
2241- , namespaces = orgType.replace(namespaceRegex, '').split('.')
2242-
2243- if (registry.has(element, type, fn))
2244- return element // no dupe
2245- if (type === 'unload')
2246- fn = once(removeListener, element, type, fn, originalFn) // self clean-up
2247- if (customEvents[type]) {
2248- if (customEvents[type].condition)
2249- fn = customHandler(element, fn, type, customEvents[type].condition, true)
2250- type = customEvents[type].base || type
2251- }
2252- entry = registry.put(new RegEntry(element, type, fn, originalFn, namespaces[0] && namespaces))
2253- entry.handler = entry.isNative ?
2254- nativeHandler(element, entry.handler, args) :
2255- customHandler(element, entry.handler, type, false, args, false)
2256- if (entry.eventSupport)
2257- listener(entry.target, entry.eventType, entry.handler, true, entry.customType)
2258- }
2259-
2260- , del = function (selector, fn, $) {
2261- return function (e) {
2262- var target, i, array = typeof selector === 'string' ? $(selector, this) : selector
2263- for (target = e.target; target && target !== this; target = target.parentNode) {
2264- for (i = array.length; i--;) {
2265- if (array[i] === target) {
2266- return fn.apply(target, arguments)
2267- }
2268- }
2269- }
2270- }
2271- }
2272-
2273- , remove = function (element, typeSpec, fn) {
2274- var k, m, type, namespaces, i
2275- , rm = removeListener
2276- , isString = typeSpec && typeof typeSpec === 'string'
2277-
2278- if (isString && typeSpec.indexOf(' ') > 0) {
2279- // remove(el, 't1 t2 t3', fn) or remove(el, 't1 t2 t3')
2280- typeSpec = typeSpec.split(' ')
2281- for (i = typeSpec.length; i--;)
2282- remove(element, typeSpec[i], fn)
2283- return element
2284- }
2285- type = isString && typeSpec.replace(nameRegex, '')
2286- if (type && customEvents[type])
2287- type = customEvents[type].type
2288- if (!typeSpec || isString) {
2289- // remove(el) or remove(el, t1.ns) or remove(el, .ns) or remove(el, .ns1.ns2.ns3)
2290- if (namespaces = isString && typeSpec.replace(namespaceRegex, ''))
2291- namespaces = namespaces.split('.')
2292- rm(element, type, fn, namespaces)
2293- } else if (typeof typeSpec === 'function') {
2294- // remove(el, fn)
2295- rm(element, null, typeSpec)
2296- } else {
2297- // remove(el, { t1: fn1, t2, fn2 })
2298- for (k in typeSpec) {
2299- if (typeSpec.hasOwnProperty(k))
2300- remove(element, k, typeSpec[k])
2301- }
2302- }
2303- return element
2304- }
2305-
2306- , add = function (element, events, fn, delfn, $) {
2307- var type, types, i, args
2308- , originalFn = fn
2309- , isDel = fn && typeof fn === 'string'
2310-
2311- if (events && !fn && typeof events === 'object') {
2312- for (type in events) {
2313- if (events.hasOwnProperty(type))
2314- add.apply(this, [ element, type, events[type] ])
2315- }
2316- } else {
2317- args = arguments.length > 3 ? slice.call(arguments, 3) : []
2318- types = (isDel ? fn : events).split(' ')
2319- isDel && (fn = del(events, (originalFn = delfn), $)) && (args = slice.call(args, 1))
2320- // special case for one()
2321- this === ONE && (fn = once(remove, element, events, fn, originalFn))
2322- for (i = types.length; i--;) addListener(element, types[i], fn, originalFn, args)
2323- }
2324- return element
2325- }
2326-
2327- , one = function () {
2328- return add.apply(ONE, arguments)
2329- }
2330-
2331- , fireListener = W3C_MODEL ? function (isNative, type, element) {
2332- var evt = doc.createEvent(isNative ? 'HTMLEvents' : 'UIEvents')
2333- evt[isNative ? 'initEvent' : 'initUIEvent'](type, true, true, win, 1)
2334- element.dispatchEvent(evt)
2335- } : function (isNative, type, element) {
2336- element = targetElement(element, isNative)
2337- // if not-native then we're using onpropertychange so we just increment a custom property
2338- isNative ? element.fireEvent('on' + type, doc.createEventObject()) : element['_on' + type]++
2339- }
2340-
2341- , fire = function (element, type, args) {
2342- var i, j, l, names, handlers
2343- , types = type.split(' ')
2344-
2345- for (i = types.length; i--;) {
2346- type = types[i].replace(nameRegex, '')
2347- if (names = types[i].replace(namespaceRegex, ''))
2348- names = names.split('.')
2349- if (!names && !args && element[eventSupport]) {
2350- fireListener(nativeEvents[type], type, element)
2351- } else {
2352- // non-native event, either because of a namespace, arguments or a non DOM element
2353- // iterate over all listeners and manually 'fire'
2354- handlers = registry.get(element, type)
2355- args = [false].concat(args)
2356- for (j = 0, l = handlers.length; j < l; j++) {
2357- if (handlers[j].inNamespaces(names))
2358- handlers[j].handler.apply(element, args)
2359- }
2360- }
2361- }
2362- return element
2363- }
2364-
2365- , clone = function (element, from, type) {
2366- var i = 0
2367- , handlers = registry.get(from, type)
2368- , l = handlers.length
2369-
2370- for (;i < l; i++)
2371- handlers[i].original && add(element, handlers[i].type, handlers[i].original)
2372- return element
2373- }
2374-
2375- , bean = {
2376- add: add
2377- , one: one
2378- , remove: remove
2379- , clone: clone
2380- , fire: fire
2381- , noConflict: function () {
2382- context[name] = old
2383- return this
2384- }
2385- }
2386-
2387- if (win[attachEvent]) {
2388- // for IE, clean up on unload to avoid leaks
2389- var cleanup = function () {
2390- var i, entries = registry.entries()
2391- for (i in entries) {
2392- if (entries[i].type && entries[i].type !== 'unload')
2393- remove(entries[i].element, entries[i].type)
2394- }
2395- win[detachEvent]('onunload', cleanup)
2396- win.CollectGarbage && win.CollectGarbage()
2397- }
2398- win[attachEvent]('onunload', cleanup)
2399- }
2400-
2401- return bean
2402-});
2403-// Underscore.js 1.1.7
2404-// (c) 2011 Jeremy Ashkenas, DocumentCloud Inc.
2405-// Underscore is freely distributable under the MIT license.
2406-// Portions of Underscore are inspired or borrowed from Prototype,
2407-// Oliver Steele's Functional, and John Resig's Micro-Templating.
2408-// For all details and documentation:
2409-// http://documentcloud.github.com/underscore
2410-
2411-(function() {
2412-
2413- // Baseline setup
2414- // --------------
2415-
2416- // Establish the root object, `window` in the browser, or `global` on the server.
2417- var root = this;
2418-
2419- // Save the previous value of the `_` variable.
2420- var previousUnderscore = root._;
2421-
2422- // Establish the object that gets returned to break out of a loop iteration.
2423- var breaker = {};
2424-
2425- // Save bytes in the minified (but not gzipped) version:
2426- var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
2427-
2428- // Create quick reference variables for speed access to core prototypes.
2429- var slice = ArrayProto.slice,
2430- unshift = ArrayProto.unshift,
2431- toString = ObjProto.toString,
2432- hasOwnProperty = ObjProto.hasOwnProperty;
2433-
2434- // All **ECMAScript 5** native function implementations that we hope to use
2435- // are declared here.
2436- var
2437- nativeForEach = ArrayProto.forEach,
2438- nativeMap = ArrayProto.map,
2439- nativeReduce = ArrayProto.reduce,
2440- nativeReduceRight = ArrayProto.reduceRight,
2441- nativeFilter = ArrayProto.filter,
2442- nativeEvery = ArrayProto.every,
2443- nativeSome = ArrayProto.some,
2444- nativeIndexOf = ArrayProto.indexOf,
2445- nativeLastIndexOf = ArrayProto.lastIndexOf,
2446- nativeIsArray = Array.isArray,
2447- nativeKeys = Object.keys,
2448- nativeBind = FuncProto.bind;
2449-
2450- // Create a safe reference to the Underscore object for use below.
2451- var _ = function(obj) { return new wrapper(obj); };
2452-
2453- // Export the Underscore object for **CommonJS**, with backwards-compatibility
2454- // for the old `require()` API. If we're not in CommonJS, add `_` to the
2455- // global object.
2456- if (typeof module !== 'undefined' && module.exports) {
2457- module.exports = _;
2458- _._ = _;
2459- } else {
2460- // Exported as a string, for Closure Compiler "advanced" mode.
2461- root['_'] = _;
2462- }
2463-
2464- // Current version.
2465- _.VERSION = '1.1.7';
2466-
2467- // Collection Functions
2468- // --------------------
2469-
2470- // The cornerstone, an `each` implementation, aka `forEach`.
2471- // Handles objects with the built-in `forEach`, arrays, and raw objects.
2472- // Delegates to **ECMAScript 5**'s native `forEach` if available.
2473- var each = _.each = _.forEach = function(obj, iterator, context) {
2474- if (obj == null) return;
2475- if (nativeForEach && obj.forEach === nativeForEach) {
2476- obj.forEach(iterator, context);
2477- } else if (obj.length === +obj.length) {
2478- for (var i = 0, l = obj.length; i < l; i++) {
2479- if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;
2480- }
2481- } else {
2482- for (var key in obj) {
2483- if (hasOwnProperty.call(obj, key)) {
2484- if (iterator.call(context, obj[key], key, obj) === breaker) return;
2485- }
2486- }
2487- }
2488- };
2489-
2490- // Return the results of applying the iterator to each element.
2491- // Delegates to **ECMAScript 5**'s native `map` if available.
2492- _.map = function(obj, iterator, context) {
2493- var results = [];
2494- if (obj == null) return results;
2495- if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
2496- each(obj, function(value, index, list) {
2497- results[results.length] = iterator.call(context, value, index, list);
2498- });
2499- return results;
2500- };
2501-
2502- // **Reduce** builds up a single result from a list of values, aka `inject`,
2503- // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
2504- _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
2505- var initial = memo !== void 0;
2506- if (obj == null) obj = [];
2507- if (nativeReduce && obj.reduce === nativeReduce) {
2508- if (context) iterator = _.bind(iterator, context);
2509- return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
2510- }
2511- each(obj, function(value, index, list) {
2512- if (!initial) {
2513- memo = value;
2514- initial = true;
2515- } else {
2516- memo = iterator.call(context, memo, value, index, list);
2517- }
2518- });
2519- if (!initial) throw new TypeError("Reduce of empty array with no initial value");
2520- return memo;
2521- };
2522-
2523- // The right-associative version of reduce, also known as `foldr`.
2524- // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
2525- _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
2526- if (obj == null) obj = [];
2527- if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
2528- if (context) iterator = _.bind(iterator, context);
2529- return memo !== void 0 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
2530- }
2531- var reversed = (_.isArray(obj) ? obj.slice() : _.toArray(obj)).reverse();
2532- return _.reduce(reversed, iterator, memo, context);
2533- };
2534-
2535- // Return the first value which passes a truth test. Aliased as `detect`.
2536- _.find = _.detect = function(obj, iterator, context) {
2537- var result;
2538- any(obj, function(value, index, list) {
2539- if (iterator.call(context, value, index, list)) {
2540- result = value;
2541- return true;
2542- }
2543- });
2544- return result;
2545- };
2546-
2547- // Return all the elements that pass a truth test.
2548- // Delegates to **ECMAScript 5**'s native `filter` if available.
2549- // Aliased as `select`.
2550- _.filter = _.select = function(obj, iterator, context) {
2551- var results = [];
2552- if (obj == null) return results;
2553- if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
2554- each(obj, function(value, index, list) {
2555- if (iterator.call(context, value, index, list)) results[results.length] = value;
2556- });
2557- return results;
2558- };
2559-
2560- // Return all the elements for which a truth test fails.
2561- _.reject = function(obj, iterator, context) {
2562- var results = [];
2563- if (obj == null) return results;
2564- each(obj, function(value, index, list) {
2565- if (!iterator.call(context, value, index, list)) results[results.length] = value;
2566- });
2567- return results;
2568- };
2569-
2570- // Determine whether all of the elements match a truth test.
2571- // Delegates to **ECMAScript 5**'s native `every` if available.
2572- // Aliased as `all`.
2573- _.every = _.all = function(obj, iterator, context) {
2574- var result = true;
2575- if (obj == null) return result;
2576- if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
2577- each(obj, function(value, index, list) {
2578- if (!(result = result && iterator.call(context, value, index, list))) return breaker;
2579- });
2580- return result;
2581- };
2582-
2583- // Determine if at least one element in the object matches a truth test.
2584- // Delegates to **ECMAScript 5**'s native `some` if available.
2585- // Aliased as `any`.
2586- var any = _.some = _.any = function(obj, iterator, context) {
2587- iterator = iterator || _.identity;
2588- var result = false;
2589- if (obj == null) return result;
2590- if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
2591- each(obj, function(value, index, list) {
2592- if (result |= iterator.call(context, value, index, list)) return breaker;
2593- });
2594- return !!result;
2595- };
2596-
2597- // Determine if a given value is included in the array or object using `===`.
2598- // Aliased as `contains`.
2599- _.include = _.contains = function(obj, target) {
2600- var found = false;
2601- if (obj == null) return found;
2602- if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
2603- any(obj, function(value) {
2604- if (found = value === target) return true;
2605- });
2606- return found;
2607- };
2608-
2609- // Invoke a method (with arguments) on every item in a collection.
2610- _.invoke = function(obj, method) {
2611- var args = slice.call(arguments, 2);
2612- return _.map(obj, function(value) {
2613- return (method.call ? method || value : value[method]).apply(value, args);
2614- });
2615- };
2616-
2617- // Convenience version of a common use case of `map`: fetching a property.
2618- _.pluck = function(obj, key) {
2619- return _.map(obj, function(value){ return value[key]; });
2620- };
2621-
2622- // Return the maximum element or (element-based computation).
2623- _.max = function(obj, iterator, context) {
2624- if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);
2625- var result = {computed : -Infinity};
2626- each(obj, function(value, index, list) {
2627- var computed = iterator ? iterator.call(context, value, index, list) : value;
2628- computed >= result.computed && (result = {value : value, computed : computed});
2629- });
2630- return result.value;
2631- };
2632-
2633- // Return the minimum element (or element-based computation).
2634- _.min = function(obj, iterator, context) {
2635- if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);
2636- var result = {computed : Infinity};
2637- each(obj, function(value, index, list) {
2638- var computed = iterator ? iterator.call(context, value, index, list) : value;
2639- computed < result.computed && (result = {value : value, computed : computed});
2640- });
2641- return result.value;
2642- };
2643-
2644- // Sort the object's values by a criterion produced by an iterator.
2645- _.sortBy = function(obj, iterator, context) {
2646- return _.pluck(_.map(obj, function(value, index, list) {
2647- return {
2648- value : value,
2649- criteria : iterator.call(context, value, index, list)
2650- };
2651- }).sort(function(left, right) {
2652- var a = left.criteria, b = right.criteria;
2653- return a < b ? -1 : a > b ? 1 : 0;
2654- }), 'value');
2655- };
2656-
2657- // Groups the object's values by a criterion produced by an iterator
2658- _.groupBy = function(obj, iterator) {
2659- var result = {};
2660- each(obj, function(value, index) {
2661- var key = iterator(value, index);
2662- (result[key] || (result[key] = [])).push(value);
2663- });
2664- return result;
2665- };
2666-
2667- // Use a comparator function to figure out at what index an object should
2668- // be inserted so as to maintain order. Uses binary search.
2669- _.sortedIndex = function(array, obj, iterator) {
2670- iterator || (iterator = _.identity);
2671- var low = 0, high = array.length;
2672- while (low < high) {
2673- var mid = (low + high) >> 1;
2674- iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;
2675- }
2676- return low;
2677- };
2678-
2679- // Safely convert anything iterable into a real, live array.
2680- _.toArray = function(iterable) {
2681- if (!iterable) return [];
2682- if (iterable.toArray) return iterable.toArray();
2683- if (_.isArray(iterable)) return slice.call(iterable);
2684- if (_.isArguments(iterable)) return slice.call(iterable);
2685- return _.values(iterable);
2686- };
2687-
2688- // Return the number of elements in an object.
2689- _.size = function(obj) {
2690- return _.toArray(obj).length;
2691- };
2692-
2693- // Array Functions
2694- // ---------------
2695-
2696- // Get the first element of an array. Passing **n** will return the first N
2697- // values in the array. Aliased as `head`. The **guard** check allows it to work
2698- // with `_.map`.
2699- _.first = _.head = function(array, n, guard) {
2700- return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
2701- };
2702-
2703- // Returns everything but the first entry of the array. Aliased as `tail`.
2704- // Especially useful on the arguments object. Passing an **index** will return
2705- // the rest of the values in the array from that index onward. The **guard**
2706- // check allows it to work with `_.map`.
2707- _.rest = _.tail = function(array, index, guard) {
2708- return slice.call(array, (index == null) || guard ? 1 : index);
2709- };
2710-
2711- // Get the last element of an array.
2712- _.last = function(array) {
2713- return array[array.length - 1];
2714- };
2715-
2716- // Trim out all falsy values from an array.
2717- _.compact = function(array) {
2718- return _.filter(array, function(value){ return !!value; });
2719- };
2720-
2721- // Return a completely flattened version of an array.
2722- _.flatten = function(array) {
2723- return _.reduce(array, function(memo, value) {
2724- if (_.isArray(value)) return memo.concat(_.flatten(value));
2725- memo[memo.length] = value;
2726- return memo;
2727- }, []);
2728- };
2729-
2730- // Return a version of the array that does not contain the specified value(s).
2731- _.without = function(array) {
2732- return _.difference(array, slice.call(arguments, 1));
2733- };
2734-
2735- // Produce a duplicate-free version of the array. If the array has already
2736- // been sorted, you have the option of using a faster algorithm.
2737- // Aliased as `unique`.
2738- _.uniq = _.unique = function(array, isSorted) {
2739- return _.reduce(array, function(memo, el, i) {
2740- if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) memo[memo.length] = el;
2741- return memo;
2742- }, []);
2743- };
2744-
2745- // Produce an array that contains the union: each distinct element from all of
2746- // the passed-in arrays.
2747- _.union = function() {
2748- return _.uniq(_.flatten(arguments));
2749- };
2750-
2751- // Produce an array that contains every item shared between all the
2752- // passed-in arrays. (Aliased as "intersect" for back-compat.)
2753- _.intersection = _.intersect = function(array) {
2754- var rest = slice.call(arguments, 1);
2755- return _.filter(_.uniq(array), function(item) {
2756- return _.every(rest, function(other) {
2757- return _.indexOf(other, item) >= 0;
2758- });
2759- });
2760- };
2761-
2762- // Take the difference between one array and another.
2763- // Only the elements present in just the first array will remain.
2764- _.difference = function(array, other) {
2765- return _.filter(array, function(value){ return !_.include(other, value); });
2766- };
2767-
2768- // Zip together multiple lists into a single array -- elements that share
2769- // an index go together.
2770- _.zip = function() {
2771- var args = slice.call(arguments);
2772- var length = _.max(_.pluck(args, 'length'));
2773- var results = new Array(length);
2774- for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i);
2775- return results;
2776- };
2777-
2778- // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
2779- // we need this function. Return the position of the first occurrence of an
2780- // item in an array, or -1 if the item is not included in the array.
2781- // Delegates to **ECMAScript 5**'s native `indexOf` if available.
2782- // If the array is large and already in sort order, pass `true`
2783- // for **isSorted** to use binary search.
2784- _.indexOf = function(array, item, isSorted) {
2785- if (array == null) return -1;
2786- var i, l;
2787- if (isSorted) {
2788- i = _.sortedIndex(array, item);
2789- return array[i] === item ? i : -1;
2790- }
2791- if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
2792- for (i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
2793- return -1;
2794- };
2795-
2796-
2797- // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
2798- _.lastIndexOf = function(array, item) {
2799- if (array == null) return -1;
2800- if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
2801- var i = array.length;
2802- while (i--) if (array[i] === item) return i;
2803- return -1;
2804- };
2805-
2806- // Generate an integer Array containing an arithmetic progression. A port of
2807- // the native Python `range()` function. See
2808- // [the Python documentation](http://docs.python.org/library/functions.html#range).
2809- _.range = function(start, stop, step) {
2810- if (arguments.length <= 1) {
2811- stop = start || 0;
2812- start = 0;
2813- }
2814- step = arguments[2] || 1;
2815-
2816- var len = Math.max(Math.ceil((stop - start) / step), 0);
2817- var idx = 0;
2818- var range = new Array(len);
2819-
2820- while(idx < len) {
2821- range[idx++] = start;
2822- start += step;
2823- }
2824-
2825- return range;
2826- };
2827-
2828- // Function (ahem) Functions
2829- // ------------------
2830-
2831- // Create a function bound to a given object (assigning `this`, and arguments,
2832- // optionally). Binding with arguments is also known as `curry`.
2833- // Delegates to **ECMAScript 5**'s native `Function.bind` if available.
2834- // We check for `func.bind` first, to fail fast when `func` is undefined.
2835- _.bind = function(func, obj) {
2836- if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
2837- var args = slice.call(arguments, 2);
2838- return function() {
2839- return func.apply(obj, args.concat(slice.call(arguments)));
2840- };
2841- };
2842-
2843- // Bind all of an object's methods to that object. Useful for ensuring that
2844- // all callbacks defined on an object belong to it.
2845- _.bindAll = function(obj) {
2846- var funcs = slice.call(arguments, 1);
2847- if (funcs.length == 0) funcs = _.functions(obj);
2848- each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
2849- return obj;
2850- };
2851-
2852- // Memoize an expensive function by storing its results.
2853- _.memoize = function(func, hasher) {
2854- var memo = {};
2855- hasher || (hasher = _.identity);
2856- return function() {
2857- var key = hasher.apply(this, arguments);
2858- return hasOwnProperty.call(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
2859- };
2860- };
2861-
2862- // Delays a function for the given number of milliseconds, and then calls
2863- // it with the arguments supplied.
2864- _.delay = function(func, wait) {
2865- var args = slice.call(arguments, 2);
2866- return setTimeout(function(){ return func.apply(func, args); }, wait);
2867- };
2868-
2869- // Defers a function, scheduling it to run after the current call stack has
2870- // cleared.
2871- _.defer = function(func) {
2872- return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
2873- };
2874-
2875- // Internal function used to implement `_.throttle` and `_.debounce`.
2876- var limit = function(func, wait, debounce) {
2877- var timeout;
2878- return function() {
2879- var context = this, args = arguments;
2880- var throttler = function() {
2881- timeout = null;
2882- func.apply(context, args);
2883- };
2884- if (debounce) clearTimeout(timeout);
2885- if (debounce || !timeout) timeout = setTimeout(throttler, wait);
2886- };
2887- };
2888-
2889- // Returns a function, that, when invoked, will only be triggered at most once
2890- // during a given window of time.
2891- _.throttle = function(func, wait) {
2892- return limit(func, wait, false);
2893- };
2894-
2895- // Returns a function, that, as long as it continues to be invoked, will not
2896- // be triggered. The function will be called after it stops being called for
2897- // N milliseconds.
2898- _.debounce = function(func, wait) {
2899- return limit(func, wait, true);
2900- };
2901-
2902- // Returns a function that will be executed at most one time, no matter how
2903- // often you call it. Useful for lazy initialization.
2904- _.once = function(func) {
2905- var ran = false, memo;
2906- return function() {
2907- if (ran) return memo;
2908- ran = true;
2909- return memo = func.apply(this, arguments);
2910- };
2911- };
2912-
2913- // Returns the first function passed as an argument to the second,
2914- // allowing you to adjust arguments, run code before and after, and
2915- // conditionally execute the original function.
2916- _.wrap = function(func, wrapper) {
2917- return function() {
2918- var args = [func].concat(slice.call(arguments));
2919- return wrapper.apply(this, args);
2920- };
2921- };
2922-
2923- // Returns a function that is the composition of a list of functions, each
2924- // consuming the return value of the function that follows.
2925- _.compose = function() {
2926- var funcs = slice.call(arguments);
2927- return function() {
2928- var args = slice.call(arguments);
2929- for (var i = funcs.length - 1; i >= 0; i--) {
2930- args = [funcs[i].apply(this, args)];
2931- }
2932- return args[0];
2933- };
2934- };
2935-
2936- // Returns a function that will only be executed after being called N times.
2937- _.after = function(times, func) {
2938- return function() {
2939- if (--times < 1) { return func.apply(this, arguments); }
2940- };
2941- };
2942-
2943-
2944- // Object Functions
2945- // ----------------
2946-
2947- // Retrieve the names of an object's properties.
2948- // Delegates to **ECMAScript 5**'s native `Object.keys`
2949- _.keys = nativeKeys || function(obj) {
2950- if (obj !== Object(obj)) throw new TypeError('Invalid object');
2951- var keys = [];
2952- for (var key in obj) if (hasOwnProperty.call(obj, key)) keys[keys.length] = key;
2953- return keys;
2954- };
2955-
2956- // Retrieve the values of an object's properties.
2957- _.values = function(obj) {
2958- return _.map(obj, _.identity);
2959- };
2960-
2961- // Return a sorted list of the function names available on the object.
2962- // Aliased as `methods`
2963- _.functions = _.methods = function(obj) {
2964- var names = [];
2965- for (var key in obj) {
2966- if (_.isFunction(obj[key])) names.push(key);
2967- }
2968- return names.sort();
2969- };
2970-
2971- // Extend a given object with all the properties in passed-in object(s).
2972- _.extend = function(obj) {
2973- each(slice.call(arguments, 1), function(source) {
2974- for (var prop in source) {
2975- if (source[prop] !== void 0) obj[prop] = source[prop];
2976- }
2977- });
2978- return obj;
2979- };
2980-
2981- // Fill in a given object with default properties.
2982- _.defaults = function(obj) {
2983- each(slice.call(arguments, 1), function(source) {
2984- for (var prop in source) {
2985- if (obj[prop] == null) obj[prop] = source[prop];
2986- }
2987- });
2988- return obj;
2989- };
2990-
2991- // Create a (shallow-cloned) duplicate of an object.
2992- _.clone = function(obj) {
2993- return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
2994- };
2995-
2996- // Invokes interceptor with the obj, and then returns obj.
2997- // The primary purpose of this method is to "tap into" a method chain, in
2998- // order to perform operations on intermediate results within the chain.
2999- _.tap = function(obj, interceptor) {
3000- interceptor(obj);
3001- return obj;
3002- };
3003-
3004- // Perform a deep comparison to check if two objects are equal.
3005- _.isEqual = function(a, b) {
3006- // Check object identity.
3007- if (a === b) return true;
3008- // Different types?
3009- var atype = typeof(a), btype = typeof(b);
3010- if (atype != btype) return false;
3011- // Basic equality test (watch out for coercions).
3012- if (a == b) return true;
3013- // One is falsy and the other truthy.
3014- if ((!a && b) || (a && !b)) return false;
3015- // Unwrap any wrapped objects.
3016- if (a._chain) a = a._wrapped;
3017- if (b._chain) b = b._wrapped;
3018- // One of them implements an isEqual()?
3019- if (a.isEqual) return a.isEqual(b);
3020- if (b.isEqual) return b.isEqual(a);
3021- // Check dates' integer values.
3022- if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime();
3023- // Both are NaN?
3024- if (_.isNaN(a) && _.isNaN(b)) return false;
3025- // Compare regular expressions.
3026- if (_.isRegExp(a) && _.isRegExp(b))
3027- return a.source === b.source &&
3028- a.global === b.global &&
3029- a.ignoreCase === b.ignoreCase &&
3030- a.multiline === b.multiline;
3031- // If a is not an object by this point, we can't handle it.
3032- if (atype !== 'object') return false;
3033- // Check for different array lengths before comparing contents.
3034- if (a.length && (a.length !== b.length)) return false;
3035- // Nothing else worked, deep compare the contents.
3036- var aKeys = _.keys(a), bKeys = _.keys(b);
3037- // Different object sizes?
3038- if (aKeys.length != bKeys.length) return false;
3039- // Recursive comparison of contents.
3040- for (var key in a) if (!(key in b) || !_.isEqual(a[key], b[key])) return false;
3041- return true;
3042- };
3043-
3044- // Is a given array or object empty?
3045- _.isEmpty = function(obj) {
3046- if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
3047- for (var key in obj) if (hasOwnProperty.call(obj, key)) return false;
3048- return true;
3049- };
3050-
3051- // Is a given value a DOM element?
3052- _.isElement = function(obj) {
3053- return !!(obj && obj.nodeType == 1);
3054- };
3055-
3056- // Is a given value an array?
3057- // Delegates to ECMA5's native Array.isArray
3058- _.isArray = nativeIsArray || function(obj) {
3059- return toString.call(obj) === '[object Array]';
3060- };
3061-
3062- // Is a given variable an object?
3063- _.isObject = function(obj) {
3064- return obj === Object(obj);
3065- };
3066-
3067- // Is a given variable an arguments object?
3068- _.isArguments = function(obj) {
3069- return !!(obj && hasOwnProperty.call(obj, 'callee'));
3070- };
3071-
3072- // Is a given value a function?
3073- _.isFunction = function(obj) {
3074- return !!(obj && obj.constructor && obj.call && obj.apply);
3075- };
3076-
3077- // Is a given value a string?
3078- _.isString = function(obj) {
3079- return !!(obj === '' || (obj && obj.charCodeAt && obj.substr));
3080- };
3081-
3082- // Is a given value a number?
3083- _.isNumber = function(obj) {
3084- return !!(obj === 0 || (obj && obj.toExponential && obj.toFixed));
3085- };
3086-
3087- // Is the given value `NaN`? `NaN` happens to be the only value in JavaScript
3088- // that does not equal itself.
3089- _.isNaN = function(obj) {
3090- return obj !== obj;
3091- };
3092-
3093- // Is a given value a boolean?
3094- _.isBoolean = function(obj) {
3095- return obj === true || obj === false;
3096- };
3097-
3098- // Is a given value a date?
3099- _.isDate = function(obj) {
3100- return !!(obj && obj.getTimezoneOffset && obj.setUTCFullYear);
3101- };
3102-
3103- // Is the given value a regular expression?
3104- _.isRegExp = function(obj) {
3105- return !!(obj && obj.test && obj.exec && (obj.ignoreCase || obj.ignoreCase === false));
3106- };
3107-
3108- // Is a given value equal to null?
3109- _.isNull = function(obj) {
3110- return obj === null;
3111- };
3112-
3113- // Is a given variable undefined?
3114- _.isUndefined = function(obj) {
3115- return obj === void 0;
3116- };
3117-
3118- // Utility Functions
3119- // -----------------
3120-
3121- // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
3122- // previous owner. Returns a reference to the Underscore object.
3123- _.noConflict = function() {
3124- root._ = previousUnderscore;
3125- return this;
3126- };
3127-
3128- // Keep the identity function around for default iterators.
3129- _.identity = function(value) {
3130- return value;
3131- };
3132-
3133- // Run a function **n** times.
3134- _.times = function (n, iterator, context) {
3135- for (var i = 0; i < n; i++) iterator.call(context, i);
3136- };
3137-
3138- // Add your own custom functions to the Underscore object, ensuring that
3139- // they're correctly added to the OOP wrapper as well.
3140- _.mixin = function(obj) {
3141- each(_.functions(obj), function(name){
3142- addToWrapper(name, _[name] = obj[name]);
3143- });
3144- };
3145-
3146- // Generate a unique integer id (unique within the entire client session).
3147- // Useful for temporary DOM ids.
3148- var idCounter = 0;
3149- _.uniqueId = function(prefix) {
3150- var id = idCounter++;
3151- return prefix ? prefix + id : id;
3152- };
3153-
3154- // By default, Underscore uses ERB-style template delimiters, change the
3155- // following template settings to use alternative delimiters.
3156- _.templateSettings = {
3157- evaluate : /<%([\s\S]+?)%>/g,
3158- interpolate : /<%=([\s\S]+?)%>/g
3159- };
3160-
3161- // JavaScript micro-templating, similar to John Resig's implementation.
3162- // Underscore templating handles arbitrary delimiters, preserves whitespace,
3163- // and correctly escapes quotes within interpolated code.
3164- _.template = function(str, data) {
3165- var c = _.templateSettings;
3166- var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' +
3167- 'with(obj||{}){__p.push(\'' +
3168- str.replace(/\\/g, '\\\\')
3169- .replace(/'/g, "\\'")
3170- .replace(c.interpolate, function(match, code) {
3171- return "'," + code.replace(/\\'/g, "'") + ",'";
3172- })
3173- .replace(c.evaluate || null, function(match, code) {
3174- return "');" + code.replace(/\\'/g, "'")
3175- .replace(/[\r\n\t]/g, ' ') + "__p.push('";
3176- })
3177- .replace(/\r/g, '\\r')
3178- .replace(/\n/g, '\\n')
3179- .replace(/\t/g, '\\t')
3180- + "');}return __p.join('');";
3181- var func = new Function('obj', tmpl);
3182- return data ? func(data) : func;
3183- };
3184-
3185- // The OOP Wrapper
3186- // ---------------
3187-
3188- // If Underscore is called as a function, it returns a wrapped object that
3189- // can be used OO-style. This wrapper holds altered versions of all the
3190- // underscore functions. Wrapped objects may be chained.
3191- var wrapper = function(obj) { this._wrapped = obj; };
3192-
3193- // Expose `wrapper.prototype` as `_.prototype`
3194- _.prototype = wrapper.prototype;
3195-
3196- // Helper function to continue chaining intermediate results.
3197- var result = function(obj, chain) {
3198- return chain ? _(obj).chain() : obj;
3199- };
3200-
3201- // A method to easily add functions to the OOP wrapper.
3202- var addToWrapper = function(name, func) {
3203- wrapper.prototype[name] = function() {
3204- var args = slice.call(arguments);
3205- unshift.call(args, this._wrapped);
3206- return result(func.apply(_, args), this._chain);
3207- };
3208- };
3209-
3210- // Add all of the Underscore functions to the wrapper object.
3211- _.mixin(_);
3212-
3213- // Add all mutator Array functions to the wrapper.
3214- each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
3215- var method = ArrayProto[name];
3216- wrapper.prototype[name] = function() {
3217- method.apply(this._wrapped, arguments);
3218- return result(this._wrapped, this._chain);
3219- };
3220- });
3221-
3222- // Add all accessor Array functions to the wrapper.
3223- each(['concat', 'join', 'slice'], function(name) {
3224- var method = ArrayProto[name];
3225- wrapper.prototype[name] = function() {
3226- return result(method.apply(this._wrapped, arguments), this._chain);
3227- };
3228- });
3229-
3230- // Start chaining a wrapped Underscore object.
3231- wrapper.prototype.chain = function() {
3232- this._chain = true;
3233- return this;
3234- };
3235-
3236- // Extracts the result from a wrapped and chained object.
3237- wrapper.prototype.value = function() {
3238- return this._wrapped;
3239- };
3240-
3241-})();
3242-/**
3243- * Flotr2 (c) 2012 Carl Sutherland
3244- * MIT License
3245- * Special thanks to:
3246- * Flotr: http://code.google.com/p/flotr/ (fork)
3247- * Flot: https://github.com/flot/flot (original fork)
3248- */
3249-(function () {
3250-
3251-var
3252- global = this,
3253- previousFlotr = this.Flotr,
3254- Flotr;
3255-
3256-Flotr = {
3257- _: _,
3258- bean: bean,
3259- isIphone: /iphone/i.test(navigator.userAgent),
3260- isIE: (navigator.appVersion.indexOf("MSIE") != -1 ? parseFloat(navigator.appVersion.split("MSIE")[1]) : false),
3261-
3262- /**
3263- * An object of the registered graph types. Use Flotr.addType(type, object)
3264- * to add your own type.
3265- */
3266- graphTypes: {},
3267-
3268- /**
3269- * The list of the registered plugins
3270- */
3271- plugins: {},
3272-
3273- /**
3274- * Can be used to add your own chart type.
3275- * @param {String} name - Type of chart, like 'pies', 'bars' etc.
3276- * @param {String} graphType - The object containing the basic drawing functions (draw, etc)
3277- */
3278- addType: function(name, graphType){
3279- Flotr.graphTypes[name] = graphType;
3280- Flotr.defaultOptions[name] = graphType.options || {};
3281- Flotr.defaultOptions.defaultType = Flotr.defaultOptions.defaultType || name;
3282- },
3283-
3284- /**
3285- * Can be used to add a plugin
3286- * @param {String} name - The name of the plugin
3287- * @param {String} plugin - The object containing the plugin's data (callbacks, options, function1, function2, ...)
3288- */
3289- addPlugin: function(name, plugin){
3290- Flotr.plugins[name] = plugin;
3291- Flotr.defaultOptions[name] = plugin.options || {};
3292- },
3293-
3294- /**
3295- * Draws the graph. This function is here for backwards compatibility with Flotr version 0.1.0alpha.
3296- * You could also draw graphs by directly calling Flotr.Graph(element, data, options).
3297- * @param {Element} el - element to insert the graph into
3298- * @param {Object} data - an array or object of dataseries
3299- * @param {Object} options - an object containing options
3300- * @param {Class} _GraphKlass_ - (optional) Class to pass the arguments to, defaults to Flotr.Graph
3301- * @return {Object} returns a new graph object and of course draws the graph.
3302- */
3303- draw: function(el, data, options, GraphKlass){
3304- GraphKlass = GraphKlass || Flotr.Graph;
3305- return new GraphKlass(el, data, options);
3306- },
3307-
3308- /**
3309- * Recursively merges two objects.
3310- * @param {Object} src - source object (likely the object with the least properties)
3311- * @param {Object} dest - destination object (optional, object with the most properties)
3312- * @return {Object} recursively merged Object
3313- * @TODO See if we can't remove this.
3314- */
3315- merge: function(src, dest){
3316- var i, v, result = dest || {};
3317-
3318- for (i in src) {
3319- v = src[i];
3320- if (v && typeof(v) === 'object') {
3321- if (v.constructor === Array) {
3322- result[i] = this._.clone(v);
3323- } else if (v.constructor !== RegExp && !this._.isElement(v)) {
3324- result[i] = Flotr.merge(v, (dest ? dest[i] : undefined));
3325- } else {
3326- result[i] = v;
3327- }
3328- } else {
3329- result[i] = v;
3330- }
3331- }
3332-
3333- return result;
3334- },
3335-
3336- /**
3337- * Recursively clones an object.
3338- * @param {Object} object - The object to clone
3339- * @return {Object} the clone
3340- * @TODO See if we can't remove this.
3341- */
3342- clone: function(object){
3343- return Flotr.merge(object, {});
3344- },
3345-
3346- /**
3347- * Function calculates the ticksize and returns it.
3348- * @param {Integer} noTicks - number of ticks
3349- * @param {Integer} min - lower bound integer value for the current axis
3350- * @param {Integer} max - upper bound integer value for the current axis
3351- * @param {Integer} decimals - number of decimals for the ticks
3352- * @return {Integer} returns the ticksize in pixels
3353- */
3354- getTickSize: function(noTicks, min, max, decimals){
3355- var delta = (max - min) / noTicks,
3356- magn = Flotr.getMagnitude(delta),
3357- tickSize = 10,
3358- norm = delta / magn; // Norm is between 1.0 and 10.0.
3359-
3360- if(norm < 1.5) tickSize = 1;
3361- else if(norm < 2.25) tickSize = 2;
3362- else if(norm < 3) tickSize = ((decimals === 0) ? 2 : 2.5);
3363- else if(norm < 7.5) tickSize = 5;
3364-
3365- return tickSize * magn;
3366- },
3367-
3368- /**
3369- * Default tick formatter.
3370- * @param {String, Integer} val - tick value integer
3371- * @param {Object} axisOpts - the axis' options
3372- * @return {String} formatted tick string
3373- */
3374- defaultTickFormatter: function(val, axisOpts){
3375- return val+'';
3376- },
3377-
3378- /**
3379- * Formats the mouse tracker values.
3380- * @param {Object} obj - Track value Object {x:..,y:..}
3381- * @return {String} Formatted track string
3382- */
3383- defaultTrackFormatter: function(obj){
3384- return '('+obj.x+', '+obj.y+')';
3385- },
3386-
3387- /**
3388- * Utility function to convert file size values in bytes to kB, MB, ...
3389- * @param value {Number} - The value to convert
3390- * @param precision {Number} - The number of digits after the comma (default: 2)
3391- * @param base {Number} - The base (default: 1000)
3392- */
3393- engineeringNotation: function(value, precision, base){
3394- var sizes = ['Y','Z','E','P','T','G','M','k',''],
3395- fractionSizes = ['y','z','a','f','p','n','µ','m',''],
3396- total = sizes.length;
3397-
3398- base = base || 1000;
3399- precision = Math.pow(10, precision || 2);
3400-
3401- if (value === 0) return 0;
3402-
3403- if (value > 1) {
3404- while (total-- && (value >= base)) value /= base;
3405- }
3406- else {
3407- sizes = fractionSizes;
3408- total = sizes.length;
3409- while (total-- && (value < 1)) value *= base;
3410- }
3411-
3412- return (Math.round(value * precision) / precision) + sizes[total];
3413- },
3414-
3415- /**
3416- * Returns the magnitude of the input value.
3417- * @param {Integer, Float} x - integer or float value
3418- * @return {Integer, Float} returns the magnitude of the input value
3419- */
3420- getMagnitude: function(x){
3421- return Math.pow(10, Math.floor(Math.log(x) / Math.LN10));
3422- },
3423- toPixel: function(val){
3424- return Math.floor(val)+0.5;//((val-Math.round(val) < 0.4) ? (Math.floor(val)-0.5) : val);
3425- },
3426- toRad: function(angle){
3427- return -angle * (Math.PI/180);
3428- },
3429- floorInBase: function(n, base) {
3430- return base * Math.floor(n / base);
3431- },
3432- drawText: function(ctx, text, x, y, style) {
3433- if (!ctx.fillText) {
3434- ctx.drawText(text, x, y, style);
3435- return;
3436- }
3437-
3438- style = this._.extend({
3439- size: Flotr.defaultOptions.fontSize,
3440- color: '#000000',
3441- textAlign: 'left',
3442- textBaseline: 'bottom',
3443- weight: 1,
3444- angle: 0
3445- }, style);
3446-
3447- ctx.save();
3448- ctx.translate(x, y);
3449- ctx.rotate(style.angle);
3450- ctx.fillStyle = style.color;
3451- ctx.font = (style.weight > 1 ? "bold " : "") + (style.size*1.3) + "px sans-serif";
3452- ctx.textAlign = style.textAlign;
3453- ctx.textBaseline = style.textBaseline;
3454- ctx.fillText(text, 0, 0);
3455- ctx.restore();
3456- },
3457- getBestTextAlign: function(angle, style) {
3458- style = style || {textAlign: 'center', textBaseline: 'middle'};
3459- angle += Flotr.getTextAngleFromAlign(style);
3460-
3461- if (Math.abs(Math.cos(angle)) > 10e-3)
3462- style.textAlign = (Math.cos(angle) > 0 ? 'right' : 'left');
3463-
3464- if (Math.abs(Math.sin(angle)) > 10e-3)
3465- style.textBaseline = (Math.sin(angle) > 0 ? 'top' : 'bottom');
3466-
3467- return style;
3468- },
3469- alignTable: {
3470- 'right middle' : 0,
3471- 'right top' : Math.PI/4,
3472- 'center top' : Math.PI/2,
3473- 'left top' : 3*(Math.PI/4),
3474- 'left middle' : Math.PI,
3475- 'left bottom' : -3*(Math.PI/4),
3476- 'center bottom': -Math.PI/2,
3477- 'right bottom' : -Math.PI/4,
3478- 'center middle': 0
3479- },
3480- getTextAngleFromAlign: function(style) {
3481- return Flotr.alignTable[style.textAlign+' '+style.textBaseline] || 0;
3482- },
3483- noConflict : function () {
3484- global.Flotr = previousFlotr;
3485- return this;
3486- }
3487-};
3488-
3489-global.Flotr = Flotr;
3490-
3491-})();
3492-
3493-/**
3494- * Flotr Defaults
3495- */
3496-Flotr.defaultOptions = {
3497- colors: ['#00A8F0', '#C0D800', '#CB4B4B', '#4DA74D', '#9440ED'], //=> The default colorscheme. When there are > 5 series, additional colors are generated.
3498- ieBackgroundColor: '#FFFFFF', // Background color for excanvas clipping
3499- title: null, // => The graph's title
3500- subtitle: null, // => The graph's subtitle
3501- shadowSize: 4, // => size of the 'fake' shadow
3502- defaultType: null, // => default series type
3503- HtmlText: true, // => wether to draw the text using HTML or on the canvas
3504- fontColor: '#545454', // => default font color
3505- fontSize: 7.5, // => canvas' text font size
3506- resolution: 1, // => resolution of the graph, to have printer-friendly graphs !
3507- parseFloat: true, // => whether to preprocess data for floats (ie. if input is string)
3508- xaxis: {
3509- ticks: null, // => format: either [1, 3] or [[1, 'a'], 3]
3510- minorTicks: null, // => format: either [1, 3] or [[1, 'a'], 3]
3511- showLabels: true, // => setting to true will show the axis ticks labels, hide otherwise
3512- showMinorLabels: false,// => true to show the axis minor ticks labels, false to hide
3513- labelsAngle: 0, // => labels' angle, in degrees
3514- title: null, // => axis title
3515- titleAngle: 0, // => axis title's angle, in degrees
3516- noTicks: 5, // => number of ticks for automagically generated ticks
3517- minorTickFreq: null, // => number of minor ticks between major ticks for autogenerated ticks
3518- tickFormatter: Flotr.defaultTickFormatter, // => fn: number, Object -> string
3519- tickDecimals: null, // => no. of decimals, null means auto
3520- min: null, // => min. value to show, null means set automatically
3521- max: null, // => max. value to show, null means set automatically
3522- autoscale: false, // => Turns autoscaling on with true
3523- autoscaleMargin: 0, // => margin in % to add if auto-setting min/max
3524- color: null, // => color of the ticks
3525- mode: 'normal', // => can be 'time' or 'normal'
3526- timeFormat: null,
3527- timeMode:'UTC', // => For UTC time ('local' for local time).
3528- timeUnit:'millisecond',// => Unit for time (millisecond, second, minute, hour, day, month, year)
3529- scaling: 'linear', // => Scaling, can be 'linear' or 'logarithmic'
3530- base: Math.E,
3531- titleAlign: 'center',
3532- margin: true // => Turn off margins with false
3533- },
3534- x2axis: {},
3535- yaxis: {
3536- ticks: null, // => format: either [1, 3] or [[1, 'a'], 3]
3537- minorTicks: null, // => format: either [1, 3] or [[1, 'a'], 3]
3538- showLabels: true, // => setting to true will show the axis ticks labels, hide otherwise
3539- showMinorLabels: false,// => true to show the axis minor ticks labels, false to hide
3540- labelsAngle: 0, // => labels' angle, in degrees
3541- title: null, // => axis title
3542- titleAngle: 90, // => axis title's angle, in degrees
3543- noTicks: 5, // => number of ticks for automagically generated ticks
3544- minorTickFreq: null, // => number of minor ticks between major ticks for autogenerated ticks
3545- tickFormatter: Flotr.defaultTickFormatter, // => fn: number, Object -> string
3546- tickDecimals: null, // => no. of decimals, null means auto
3547- min: null, // => min. value to show, null means set automatically
3548- max: null, // => max. value to show, null means set automatically
3549- autoscale: false, // => Turns autoscaling on with true
3550- autoscaleMargin: 0, // => margin in % to add if auto-setting min/max
3551- color: null, // => The color of the ticks
3552- scaling: 'linear', // => Scaling, can be 'linear' or 'logarithmic'
3553- base: Math.E,
3554- titleAlign: 'center',
3555- margin: true // => Turn off margins with false
3556- },
3557- y2axis: {
3558- titleAngle: 270
3559- },
3560- grid: {
3561- color: '#545454', // => primary color used for outline and labels
3562- backgroundColor: null, // => null for transparent, else color
3563- backgroundImage: null, // => background image. String or object with src, left and top
3564- watermarkAlpha: 0.4, // =>
3565- tickColor: '#DDDDDD', // => color used for the ticks
3566- labelMargin: 3, // => margin in pixels
3567- verticalLines: true, // => whether to show gridlines in vertical direction
3568- minorVerticalLines: null, // => whether to show gridlines for minor ticks in vertical dir.
3569- horizontalLines: true, // => whether to show gridlines in horizontal direction
3570- minorHorizontalLines: null, // => whether to show gridlines for minor ticks in horizontal dir.
3571- outlineWidth: 1, // => width of the grid outline/border in pixels
3572- outline : 'nsew', // => walls of the outline to display
3573- circular: false // => if set to true, the grid will be circular, must be used when radars are drawn
3574- },
3575- mouse: {
3576- track: false, // => true to track the mouse, no tracking otherwise
3577- trackAll: false,
3578- position: 'se', // => position of the value box (default south-east)
3579- relative: false, // => next to the mouse cursor
3580- trackFormatter: Flotr.defaultTrackFormatter, // => formats the values in the value box
3581- margin: 5, // => margin in pixels of the valuebox
3582- lineColor: '#FF3F19', // => line color of points that are drawn when mouse comes near a value of a series
3583- trackDecimals: 1, // => decimals for the track values
3584- sensibility: 2, // => the lower this number, the more precise you have to aim to show a value
3585- trackY: true, // => whether or not to track the mouse in the y axis
3586- radius: 3, // => radius of the track point
3587- fillColor: null, // => color to fill our select bar with only applies to bar and similar graphs (only bars for now)
3588- fillOpacity: 0.4 // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill
3589- }
3590-};
3591-
3592-/**
3593- * Flotr Color
3594- */
3595-
3596-(function () {
3597-
3598-var
3599- _ = Flotr._;
3600-
3601-// Constructor
3602-function Color (r, g, b, a) {
3603- this.rgba = ['r','g','b','a'];
3604- var x = 4;
3605- while(-1<--x){
3606- this[this.rgba[x]] = arguments[x] || ((x==3) ? 1.0 : 0);
3607- }
3608- this.normalize();
3609-}
3610-
3611-// Constants
3612-var COLOR_NAMES = {
3613- aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],
3614- brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],
3615- darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],
3616- darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],
3617- darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],
3618- khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],
3619- lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],
3620- maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],
3621- violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]
3622-};
3623-
3624-Color.prototype = {
3625- scale: function(rf, gf, bf, af){
3626- var x = 4;
3627- while (-1 < --x) {
3628- if (!_.isUndefined(arguments[x])) this[this.rgba[x]] *= arguments[x];
3629- }
3630- return this.normalize();
3631- },
3632- alpha: function(alpha) {
3633- if (!_.isUndefined(alpha) && !_.isNull(alpha)) {
3634- this.a = alpha;
3635- }
3636- return this.normalize();
3637- },
3638- clone: function(){
3639- return new Color(this.r, this.b, this.g, this.a);
3640- },
3641- limit: function(val,minVal,maxVal){
3642- return Math.max(Math.min(val, maxVal), minVal);
3643- },
3644- normalize: function(){
3645- var limit = this.limit;
3646- this.r = limit(parseInt(this.r, 10), 0, 255);
3647- this.g = limit(parseInt(this.g, 10), 0, 255);
3648- this.b = limit(parseInt(this.b, 10), 0, 255);
3649- this.a = limit(this.a, 0, 1);
3650- return this;
3651- },
3652- distance: function(color){
3653- if (!color) return;
3654- color = new Color.parse(color);
3655- var dist = 0, x = 3;
3656- while(-1<--x){
3657- dist += Math.abs(this[this.rgba[x]] - color[this.rgba[x]]);
3658- }
3659- return dist;
3660- },
3661- toString: function(){
3662- return (this.a >= 1.0) ? 'rgb('+[this.r,this.g,this.b].join(',')+')' : 'rgba('+[this.r,this.g,this.b,this.a].join(',')+')';
3663- },
3664- contrast: function () {
3665- var
3666- test = 1 - ( 0.299 * this.r + 0.587 * this.g + 0.114 * this.b) / 255;
3667- return (test < 0.5 ? '#000000' : '#ffffff');
3668- }
3669-};
3670-
3671-_.extend(Color, {
3672- /**
3673- * Parses a color string and returns a corresponding Color.
3674- * The different tests are in order of probability to improve speed.
3675- * @param {String, Color} str - string thats representing a color
3676- * @return {Color} returns a Color object or false
3677- */
3678- parse: function(color){
3679- if (color instanceof Color) return color;
3680-
3681- var result;
3682-
3683- // #a0b1c2
3684- if((result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color)))
3685- return new Color(parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16));
3686-
3687- // rgb(num,num,num)
3688- if((result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color)))
3689- return new Color(parseInt(result[1], 10), parseInt(result[2], 10), parseInt(result[3], 10));
3690-
3691- // #fff
3692- if((result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color)))
3693- return new Color(parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16));
3694-
3695- // rgba(num,num,num,num)
3696- if((result = /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(color)))
3697- return new Color(parseInt(result[1], 10), parseInt(result[2], 10), parseInt(result[3], 10), parseFloat(result[4]));
3698-
3699- // rgb(num%,num%,num%)
3700- if((result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color)))
3701- return new Color(parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55);
3702-
3703- // rgba(num%,num%,num%,num)
3704- if((result = /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(color)))
3705- return new Color(parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55, parseFloat(result[4]));
3706-
3707- // Otherwise, we're most likely dealing with a named color.
3708- var name = (color+'').replace(/^\s*([\S\s]*?)\s*$/, '$1').toLowerCase();
3709- if(name == 'transparent'){
3710- return new Color(255, 255, 255, 0);
3711- }
3712- return (result = COLOR_NAMES[name]) ? new Color(result[0], result[1], result[2]) : new Color(0, 0, 0, 0);
3713- },
3714-
3715- /**
3716- * Process color and options into color style.
3717- */
3718- processColor: function(color, options) {
3719-
3720- var opacity = options.opacity;
3721- if (!color) return 'rgba(0, 0, 0, 0)';
3722- if (color instanceof Color) return color.alpha(opacity).toString();
3723- if (_.isString(color)) return Color.parse(color).alpha(opacity).toString();
3724-
3725- var grad = color.colors ? color : {colors: color};
3726-
3727- if (!options.ctx) {
3728- if (!_.isArray(grad.colors)) return 'rgba(0, 0, 0, 0)';
3729- return Color.parse(_.isArray(grad.colors[0]) ? grad.colors[0][1] : grad.colors[0]).alpha(opacity).toString();
3730- }
3731- grad = _.extend({start: 'top', end: 'bottom'}, grad);
3732-
3733- if (/top/i.test(grad.start)) options.x1 = 0;
3734- if (/left/i.test(grad.start)) options.y1 = 0;
3735- if (/bottom/i.test(grad.end)) options.x2 = 0;
3736- if (/right/i.test(grad.end)) options.y2 = 0;
3737-
3738- var i, c, stop, gradient = options.ctx.createLinearGradient(options.x1, options.y1, options.x2, options.y2);
3739- for (i = 0; i < grad.colors.length; i++) {
3740- c = grad.colors[i];
3741- if (_.isArray(c)) {
3742- stop = c[0];
3743- c = c[1];
3744- }
3745- else stop = i / (grad.colors.length-1);
3746- gradient.addColorStop(stop, Color.parse(c).alpha(opacity));
3747- }
3748- return gradient;
3749- }
3750-});
3751-
3752-Flotr.Color = Color;
3753-
3754-})();
3755-
3756-/**
3757- * Flotr Date
3758- */
3759-Flotr.Date = {
3760-
3761- set : function (date, name, mode, value) {
3762- mode = mode || 'UTC';
3763- name = 'set' + (mode === 'UTC' ? 'UTC' : '') + name;
3764- date[name](value);
3765- },
3766-
3767- get : function (date, name, mode) {
3768- mode = mode || 'UTC';
3769- name = 'get' + (mode === 'UTC' ? 'UTC' : '') + name;
3770- return date[name]();
3771- },
3772-
3773- format: function(d, format, mode) {
3774- if (!d) return;
3775-
3776- // We should maybe use an "official" date format spec, like PHP date() or ColdFusion
3777- // http://fr.php.net/manual/en/function.date.php
3778- // http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=functions_c-d_29.html
3779- var
3780- get = this.get,
3781- tokens = {
3782- h: get(d, 'Hours', mode).toString(),
3783- H: leftPad(get(d, 'Hours', mode)),
3784- M: leftPad(get(d, 'Minutes', mode)),
3785- S: leftPad(get(d, 'Seconds', mode)),
3786- s: get(d, 'Milliseconds', mode),
3787- d: get(d, 'Date', mode).toString(),
3788- m: (get(d, 'Month') + 1).toString(),
3789- y: get(d, 'FullYear').toString(),
3790- b: Flotr.Date.monthNames[get(d, 'Month', mode)]
3791- };
3792-
3793- function leftPad(n){
3794- n += '';
3795- return n.length == 1 ? "0" + n : n;
3796- }
3797-
3798- var r = [], c,
3799- escape = false;
3800-
3801- for (var i = 0; i < format.length; ++i) {
3802- c = format.charAt(i);
3803-
3804- if (escape) {
3805- r.push(tokens[c] || c);
3806- escape = false;
3807- }
3808- else if (c == "%")
3809- escape = true;
3810- else
3811- r.push(c);
3812- }
3813- return r.join('');
3814- },
3815- getFormat: function(time, span) {
3816- var tu = Flotr.Date.timeUnits;
3817- if (time < tu.second) return "%h:%M:%S.%s";
3818- else if (time < tu.minute) return "%h:%M:%S";
3819- else if (time < tu.day) return (span < 2 * tu.day) ? "%h:%M" : "%b %d %h:%M";
3820- else if (time < tu.month) return "%b %d";
3821- else if (time < tu.year) return (span < tu.year) ? "%b" : "%b %y";
3822- else return "%y";
3823- },
3824- formatter: function (v, axis) {
3825- var
3826- options = axis.options,
3827- scale = Flotr.Date.timeUnits[options.timeUnit],
3828- d = new Date(v * scale);
3829-
3830- // first check global format
3831- if (axis.options.timeFormat)
3832- return Flotr.Date.format(d, options.timeFormat, options.timeMode);
3833-
3834- var span = (axis.max - axis.min) * scale,
3835- t = axis.tickSize * Flotr.Date.timeUnits[axis.tickUnit];
3836-
3837- return Flotr.Date.format(d, Flotr.Date.getFormat(t, span), options.timeMode);
3838- },
3839- generator: function(axis) {
3840-
3841- var
3842- set = this.set,
3843- get = this.get,
3844- timeUnits = this.timeUnits,
3845- spec = this.spec,
3846- options = axis.options,
3847- mode = options.timeMode,
3848- scale = timeUnits[options.timeUnit],
3849- min = axis.min * scale,
3850- max = axis.max * scale,
3851- delta = (max - min) / options.noTicks,
3852- ticks = [],
3853- tickSize = axis.tickSize,
3854- tickUnit,
3855- formatter, i;
3856-
3857- // Use custom formatter or time tick formatter
3858- formatter = (options.tickFormatter === Flotr.defaultTickFormatter ?
3859- this.formatter : options.tickFormatter
3860- );
3861-
3862- for (i = 0; i < spec.length - 1; ++i) {
3863- var d = spec[i][0] * timeUnits[spec[i][1]];
3864- if (delta < (d + spec[i+1][0] * timeUnits[spec[i+1][1]]) / 2 && d >= tickSize)
3865- break;
3866- }
3867- tickSize = spec[i][0];
3868- tickUnit = spec[i][1];
3869-
3870- // special-case the possibility of several years
3871- if (tickUnit == "year") {
3872- tickSize = Flotr.getTickSize(options.noTicks*timeUnits.year, min, max, 0);
3873-
3874- // Fix for 0.5 year case
3875- if (tickSize == 0.5) {
3876- tickUnit = "month";
3877- tickSize = 6;
3878- }
3879- }
3880-
3881- axis.tickUnit = tickUnit;
3882- axis.tickSize = tickSize;
3883-
3884- var
3885- d = new Date(min);
3886-
3887- var step = tickSize * timeUnits[tickUnit];
3888-
3889- function setTick (name) {
3890- set(d, name, mode, Flotr.floorInBase(
3891- get(d, name, mode), tickSize
3892- ));
3893- }
3894-
3895- switch (tickUnit) {
3896- case "millisecond": setTick('Milliseconds'); break;
3897- case "second": setTick('Seconds'); break;
3898- case "minute": setTick('Minutes'); break;
3899- case "hour": setTick('Hours'); break;
3900- case "month": setTick('Month'); break;
3901- case "year": setTick('FullYear'); break;
3902- }
3903-
3904- // reset smaller components
3905- if (step >= timeUnits.second) set(d, 'Milliseconds', mode, 0);
3906- if (step >= timeUnits.minute) set(d, 'Seconds', mode, 0);
3907- if (step >= timeUnits.hour) set(d, 'Minutes', mode, 0);
3908- if (step >= timeUnits.day) set(d, 'Hours', mode, 0);
3909- if (step >= timeUnits.day * 4) set(d, 'Date', mode, 1);
3910- if (step >= timeUnits.year) set(d, 'Month', mode, 0);
3911-
3912- var carry = 0, v = NaN, prev;
3913- do {
3914- prev = v;
3915- v = d.getTime();
3916- ticks.push({ v: v / scale, label: formatter(v / scale, axis) });
3917- if (tickUnit == "month") {
3918- if (tickSize < 1) {
3919- /* a bit complicated - we'll divide the month up but we need to take care of fractions
3920- so we don't end up in the middle of a day */
3921- set(d, 'Date', mode, 1);
3922- var start = d.getTime();
3923- set(d, 'Month', mode, get(d, 'Month', mode) + 1)
3924- var end = d.getTime();
3925- d.setTime(v + carry * timeUnits.hour + (end - start) * tickSize);
3926- carry = get(d, 'Hours', mode)
3927- set(d, 'Hours', mode, 0);
3928- }
3929- else
3930- set(d, 'Month', mode, get(d, 'Month', mode) + tickSize);
3931- }
3932- else if (tickUnit == "year") {
3933- set(d, 'FullYear', mode, get(d, 'FullYear', mode) + tickSize);
3934- }
3935- else
3936- d.setTime(v + step);
3937-
3938- } while (v < max && v != prev);
3939-
3940- return ticks;
3941- },
3942- timeUnits: {
3943- millisecond: 1,
3944- second: 1000,
3945- minute: 1000 * 60,
3946- hour: 1000 * 60 * 60,
3947- day: 1000 * 60 * 60 * 24,
3948- month: 1000 * 60 * 60 * 24 * 30,
3949- year: 1000 * 60 * 60 * 24 * 365.2425
3950- },
3951- // the allowed tick sizes, after 1 year we use an integer algorithm
3952- spec: [
3953- [1, "millisecond"], [20, "millisecond"], [50, "millisecond"], [100, "millisecond"], [200, "millisecond"], [500, "millisecond"],
3954- [1, "second"], [2, "second"], [5, "second"], [10, "second"], [30, "second"],
3955- [1, "minute"], [2, "minute"], [5, "minute"], [10, "minute"], [30, "minute"],
3956- [1, "hour"], [2, "hour"], [4, "hour"], [8, "hour"], [12, "hour"],
3957- [1, "day"], [2, "day"], [3, "day"],
3958- [0.25, "month"], [0.5, "month"], [1, "month"], [2, "month"], [3, "month"], [6, "month"],
3959- [1, "year"]
3960- ],
3961- monthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
3962-};
3963-
3964-(function () {
3965-
3966-var _ = Flotr._;
3967-
3968-Flotr.DOM = {
3969- addClass: function(element, name){
3970- var classList = (element.className ? element.className : '');
3971- if (_.include(classList.split(/\s+/g), name)) return;
3972- element.className = (classList ? classList + ' ' : '') + name;
3973- },
3974- /**
3975- * Create an element.
3976- */
3977- create: function(tag){
3978- return document.createElement(tag);
3979- },
3980- node: function(html) {
3981- var div = Flotr.DOM.create('div'), n;
3982- div.innerHTML = html;
3983- n = div.children[0];
3984- div.innerHTML = '';
3985- return n;
3986- },
3987- /**
3988- * Remove all children.
3989- */
3990- empty: function(element){
3991- element.innerHTML = '';
3992- /*
3993- if (!element) return;
3994- _.each(element.childNodes, function (e) {
3995- Flotr.DOM.empty(e);
3996- element.removeChild(e);
3997- });
3998- */
3999- },
4000- hide: function(element){
4001- Flotr.DOM.setStyles(element, {display:'none'});
4002- },
4003- /**
4004- * Insert a child.
4005- * @param {Element} element
4006- * @param {Element|String} Element or string to be appended.
4007- */
4008- insert: function(element, child){
4009- if(_.isString(child))
4010- element.innerHTML += child;
4011- else if (_.isElement(child))
4012- element.appendChild(child);
4013- },
4014- // @TODO find xbrowser implementation
4015- opacity: function(element, opacity) {
4016- element.style.opacity = opacity;
4017- },
4018- position: function(element, p){
4019- if (!element.offsetParent)
4020- return {left: (element.offsetLeft || 0), top: (element.offsetTop || 0)};
4021-
4022- p = this.position(element.offsetParent);
4023- p.left += element.offsetLeft;
4024- p.top += element.offsetTop;
4025- return p;
4026- },
4027- removeClass: function(element, name) {
4028- var classList = (element.className ? element.className : '');
4029- element.className = _.filter(classList.split(/\s+/g), function (c) {
4030- if (c != name) return true; }
4031- ).join(' ');
4032- },
4033- setStyles: function(element, o) {
4034- _.each(o, function (value, key) {
4035- element.style[key] = value;
4036- });
4037- },
4038- show: function(element){
4039- Flotr.DOM.setStyles(element, {display:''});
4040- },
4041- /**
4042- * Return element size.
4043- */
4044- size: function(element){
4045- return {
4046- height : element.offsetHeight,
4047- width : element.offsetWidth };
4048- }
4049-};
4050-
4051-})();
4052-
4053-/**
4054- * Flotr Event Adapter
4055- */
4056-(function () {
4057-var
4058- F = Flotr,
4059- bean = F.bean;
4060-F.EventAdapter = {
4061- observe: function(object, name, callback) {
4062- bean.add(object, name, callback);
4063- return this;
4064- },
4065- fire: function(object, name, args) {
4066- bean.fire(object, name, args);
4067- if (typeof(Prototype) != 'undefined')
4068- Event.fire(object, name, args);
4069- // @TODO Someone who uses mootools, add mootools adapter for existing applciations.
4070- return this;
4071- },
4072- stopObserving: function(object, name, callback) {
4073- bean.remove(object, name, callback);
4074- return this;
4075- },
4076- eventPointer: function(e) {
4077- if (!F._.isUndefined(e.touches) && e.touches.length > 0) {
4078- return {
4079- x : e.touches[0].pageX,
4080- y : e.touches[0].pageY
4081- };
4082- } else if (!F._.isUndefined(e.changedTouches) && e.changedTouches.length > 0) {
4083- return {
4084- x : e.changedTouches[0].pageX,
4085- y : e.changedTouches[0].pageY
4086- };
4087- } else if (e.pageX || e.pageY) {
4088- return {
4089- x : e.pageX,
4090- y : e.pageY
4091- };
4092- } else if (e.clientX || e.clientY) {
4093- var
4094- d = document,
4095- b = d.body,
4096- de = d.documentElement;
4097- return {
4098- x: e.clientX + b.scrollLeft + de.scrollLeft,
4099- y: e.clientY + b.scrollTop + de.scrollTop
4100- };
4101- }
4102- }
4103-};
4104-})();
4105-
4106-/**
4107- * Text Utilities
4108- */
4109-(function () {
4110-
4111-var
4112- F = Flotr,
4113- D = F.DOM,
4114- _ = F._,
4115-
4116-Text = function (o) {
4117- this.o = o;
4118-};
4119-
4120-Text.prototype = {
4121-
4122- dimensions : function (text, canvasStyle, htmlStyle, className) {
4123-
4124- if (!text) return { width : 0, height : 0 };
4125-
4126- return (this.o.html) ?
4127- this.html(text, this.o.element, htmlStyle, className) :
4128- this.canvas(text, canvasStyle);
4129- },
4130-
4131- canvas : function (text, style) {
4132-
4133- if (!this.o.textEnabled) return;
4134- style = style || {};
4135-
4136- var
4137- metrics = this.measureText(text, style),
4138- width = metrics.width,
4139- height = style.size || F.defaultOptions.fontSize,
4140- angle = style.angle || 0,
4141- cosAngle = Math.cos(angle),
4142- sinAngle = Math.sin(angle),
4143- widthPadding = 2,
4144- heightPadding = 6,
4145- bounds;
4146-
4147- bounds = {
4148- width: Math.abs(cosAngle * width) + Math.abs(sinAngle * height) + widthPadding,
4149- height: Math.abs(sinAngle * width) + Math.abs(cosAngle * height) + heightPadding
4150- };
4151-
4152- return bounds;
4153- },
4154-
4155- html : function (text, element, style, className) {
4156-
4157- var div = D.create('div');
4158-
4159- D.setStyles(div, { 'position' : 'absolute', 'top' : '-10000px' });
4160- D.insert(div, '<div style="'+style+'" class="'+className+' flotr-dummy-div">' + text + '</div>');
4161- D.insert(this.o.element, div);
4162-
4163- return D.size(div);
4164- },
4165-
4166- measureText : function (text, style) {
4167-
4168- var
4169- context = this.o.ctx,
4170- metrics;
4171-
4172- if (!context.fillText || (F.isIphone && context.measure)) {
4173- return { width : context.measure(text, style)};
4174- }
4175-
4176- style = _.extend({
4177- size: F.defaultOptions.fontSize,
4178- weight: 1,
4179- angle: 0
4180- }, style);
4181-
4182- context.save();
4183- context.font = (style.weight > 1 ? "bold " : "") + (style.size*1.3) + "px sans-serif";
4184- metrics = context.measureText(text);
4185- context.restore();
4186-
4187- return metrics;
4188- }
4189-};
4190-
4191-Flotr.Text = Text;
4192-
4193-})();
4194-
4195-/**
4196- * Flotr Graph class that plots a graph on creation.
4197- */
4198-(function () {
4199-
4200-var
4201- D = Flotr.DOM,
4202- E = Flotr.EventAdapter,
4203- _ = Flotr._,
4204- flotr = Flotr;
4205-/**
4206- * Flotr Graph constructor.
4207- * @param {Element} el - element to insert the graph into
4208- * @param {Object} data - an array or object of dataseries
4209- * @param {Object} options - an object containing options
4210- */
4211-Graph = function(el, data, options){
4212-// Let's see if we can get away with out this [JS]
4213-// try {
4214- this._setEl(el);
4215- this._initMembers();
4216- this._initPlugins();
4217-
4218- E.fire(this.el, 'flotr:beforeinit', [this]);
4219-
4220- this.data = data;
4221- this.series = flotr.Series.getSeries(data);
4222- this._initOptions(options);
4223- this._initGraphTypes();
4224- this._initCanvas();
4225- this._text = new flotr.Text({
4226- element : this.el,
4227- ctx : this.ctx,
4228- html : this.options.HtmlText,
4229- textEnabled : this.textEnabled
4230- });
4231- E.fire(this.el, 'flotr:afterconstruct', [this]);
4232- this._initEvents();
4233-
4234- this.findDataRanges();
4235- this.calculateSpacing();
4236-
4237- this.draw(_.bind(function() {
4238- E.fire(this.el, 'flotr:afterinit', [this]);
4239- }, this));
4240-/*
4241- try {
4242- } catch (e) {
4243- try {
4244- console.error(e);
4245- } catch (e2) {}
4246- }*/
4247-};
4248-
4249-function observe (object, name, callback) {
4250- E.observe.apply(this, arguments);
4251- this._handles.push(arguments);
4252- return this;
4253-}
4254-
4255-Graph.prototype = {
4256-
4257- destroy: function () {
4258- E.fire(this.el, 'flotr:destroy');
4259- _.each(this._handles, function (handle) {
4260- E.stopObserving.apply(this, handle);
4261- });
4262- this._handles = [];
4263- this.el.graph = null;
4264- },
4265-
4266- observe : observe,
4267-
4268- /**
4269- * @deprecated
4270- */
4271- _observe : observe,
4272-
4273- processColor: function(color, options){
4274- var o = { x1: 0, y1: 0, x2: this.plotWidth, y2: this.plotHeight, opacity: 1, ctx: this.ctx };
4275- _.extend(o, options);
4276- return flotr.Color.processColor(color, o);
4277- },
4278- /**
4279- * Function determines the min and max values for the xaxis and yaxis.
4280- *
4281- * TODO logarithmic range validation (consideration of 0)
4282- */
4283- findDataRanges: function(){
4284- var a = this.axes,
4285- xaxis, yaxis, range;
4286-
4287- _.each(this.series, function (series) {
4288- range = series.getRange();
4289- if (range) {
4290- xaxis = series.xaxis;
4291- yaxis = series.yaxis;
4292- xaxis.datamin = Math.min(range.xmin, xaxis.datamin);
4293- xaxis.datamax = Math.max(range.xmax, xaxis.datamax);
4294- yaxis.datamin = Math.min(range.ymin, yaxis.datamin);
4295- yaxis.datamax = Math.max(range.ymax, yaxis.datamax);
4296- xaxis.used = (xaxis.used || range.xused);
4297- yaxis.used = (yaxis.used || range.yused);
4298- }
4299- }, this);
4300-
4301- // Check for empty data, no data case (none used)
4302- if (!a.x.used && !a.x2.used) a.x.used = true;
4303- if (!a.y.used && !a.y2.used) a.y.used = true;
4304-
4305- _.each(a, function (axis) {
4306- axis.calculateRange();
4307- });
4308-
4309- var
4310- types = _.keys(flotr.graphTypes),
4311- drawn = false;
4312-
4313- _.each(this.series, function (series) {
4314- if (series.hide) return;
4315- _.each(types, function (type) {
4316- if (series[type] && series[type].show) {
4317- this.extendRange(type, series);
4318- drawn = true;
4319- }
4320- }, this);
4321- if (!drawn) {
4322- this.extendRange(this.options.defaultType, series);
4323- }
4324- }, this);
4325- },
4326-
4327- extendRange : function (type, series) {
4328- if (this[type].extendRange) this[type].extendRange(series, series.data, series[type], this[type]);
4329- if (this[type].extendYRange) this[type].extendYRange(series.yaxis, series.data, series[type], this[type]);
4330- if (this[type].extendXRange) this[type].extendXRange(series.xaxis, series.data, series[type], this[type]);
4331- },
4332-
4333- /**
4334- * Calculates axis label sizes.
4335- */
4336- calculateSpacing: function(){
4337-
4338- var a = this.axes,
4339- options = this.options,
4340- series = this.series,
4341- margin = options.grid.labelMargin,
4342- T = this._text,
4343- x = a.x,
4344- x2 = a.x2,
4345- y = a.y,
4346- y2 = a.y2,
4347- maxOutset = options.grid.outlineWidth,
4348- i, j, l, dim;
4349-
4350- // TODO post refactor, fix this
4351- _.each(a, function (axis) {
4352- axis.calculateTicks();
4353- axis.calculateTextDimensions(T, options);
4354- });
4355-
4356- // Title height
4357- dim = T.dimensions(
4358- options.title,
4359- {size: options.fontSize*1.5},
4360- 'font-size:1em;font-weight:bold;',
4361- 'flotr-title'
4362- );
4363- this.titleHeight = dim.height;
4364-
4365- // Subtitle height
4366- dim = T.dimensions(
4367- options.subtitle,
4368- {size: options.fontSize},
4369- 'font-size:smaller;',
4370- 'flotr-subtitle'
4371- );
4372- this.subtitleHeight = dim.height;
4373-
4374- for(j = 0; j < options.length; ++j){
4375- if (series[j].points.show){
4376- maxOutset = Math.max(maxOutset, series[j].points.radius + series[j].points.lineWidth/2);
4377- }
4378- }
4379-
4380- var p = this.plotOffset;
4381- if (x.options.margin === false) {
4382- p.bottom = 0;
4383- p.top = 0;
4384- } else {
4385- p.bottom += (options.grid.circular ? 0 : (x.used && x.options.showLabels ? (x.maxLabel.height + margin) : 0)) +
4386- (x.used && x.options.title ? (x.titleSize.height + margin) : 0) + maxOutset;
4387-
4388- p.top += (options.grid.circular ? 0 : (x2.used && x2.options.showLabels ? (x2.maxLabel.height + margin) : 0)) +
4389- (x2.used && x2.options.title ? (x2.titleSize.height + margin) : 0) + this.subtitleHeight + this.titleHeight + maxOutset;
4390- }
4391- if (y.options.margin === false) {
4392- p.left = 0;
4393- p.right = 0;
4394- } else {
4395- p.left += (options.grid.circular ? 0 : (y.used && y.options.showLabels ? (y.maxLabel.width + margin) : 0)) +
4396- (y.used && y.options.title ? (y.titleSize.width + margin) : 0) + maxOutset;
4397-
4398- p.right += (options.grid.circular ? 0 : (y2.used && y2.options.showLabels ? (y2.maxLabel.width + margin) : 0)) +
4399- (y2.used && y2.options.title ? (y2.titleSize.width + margin) : 0) + maxOutset;
4400- }
4401-
4402- p.top = Math.floor(p.top); // In order the outline not to be blured
4403-
4404- this.plotWidth = this.canvasWidth - p.left - p.right;
4405- this.plotHeight = this.canvasHeight - p.bottom - p.top;
4406-
4407- // TODO post refactor, fix this
4408- x.length = x2.length = this.plotWidth;
4409- y.length = y2.length = this.plotHeight;
4410- y.offset = y2.offset = this.plotHeight;
4411- x.setScale();
4412- x2.setScale();
4413- y.setScale();
4414- y2.setScale();
4415- },
4416- /**
4417- * Draws grid, labels, series and outline.
4418- */
4419- draw: function(after) {
4420-
4421- var
4422- context = this.ctx,
4423- i;
4424-
4425- E.fire(this.el, 'flotr:beforedraw', [this.series, this]);
4426-
4427- if (this.series.length) {
4428-
4429- context.save();
4430- context.translate(this.plotOffset.left, this.plotOffset.top);
4431-
4432- for (i = 0; i < this.series.length; i++) {
4433- if (!this.series[i].hide) this.drawSeries(this.series[i]);
4434- }
4435-
4436- context.restore();
4437- this.clip();
4438- }
4439-
4440- E.fire(this.el, 'flotr:afterdraw', [this.series, this]);
4441- if (after) after();
4442- },
4443- /**
4444- * Actually draws the graph.
4445- * @param {Object} series - series to draw
4446- */
4447- drawSeries: function(series){
4448-
4449- function drawChart (series, typeKey) {
4450- var options = this.getOptions(series, typeKey);
4451- this[typeKey].draw(options);
4452- }
4453-
4454- var drawn = false;
4455- series = series || this.series;
4456-
4457- _.each(flotr.graphTypes, function (type, typeKey) {
4458- if (series[typeKey] && series[typeKey].show && this[typeKey]) {
4459- drawn = true;
4460- drawChart.call(this, series, typeKey);
4461- }
4462- }, this);
4463-
4464- if (!drawn) drawChart.call(this, series, this.options.defaultType);
4465- },
4466-
4467- getOptions : function (series, typeKey) {
4468- var
4469- type = series[typeKey],
4470- graphType = this[typeKey],
4471- options = {
4472- context : this.ctx,
4473- width : this.plotWidth,
4474- height : this.plotHeight,
4475- fontSize : this.options.fontSize,
4476- fontColor : this.options.fontColor,
4477- textEnabled : this.textEnabled,
4478- htmlText : this.options.HtmlText,
4479- text : this._text, // TODO Is this necessary?
4480- element : this.el,
4481- data : series.data,
4482- color : series.color,
4483- shadowSize : series.shadowSize,
4484- xScale : _.bind(series.xaxis.d2p, series.xaxis),
4485- yScale : _.bind(series.yaxis.d2p, series.yaxis)
4486- };
4487-
4488- options = flotr.merge(type, options);
4489-
4490- // Fill
4491- options.fillStyle = this.processColor(
4492- type.fillColor || series.color,
4493- {opacity: type.fillOpacity}
4494- );
4495-
4496- return options;
4497- },
4498- /**
4499- * Calculates the coordinates from a mouse event object.
4500- * @param {Event} event - Mouse Event object.
4501- * @return {Object} Object with coordinates of the mouse.
4502- */
4503- getEventPosition: function (e){
4504-
4505- var
4506- d = document,
4507- b = d.body,
4508- de = d.documentElement,
4509- axes = this.axes,
4510- plotOffset = this.plotOffset,
4511- lastMousePos = this.lastMousePos,
4512- pointer = E.eventPointer(e),
4513- dx = pointer.x - lastMousePos.pageX,
4514- dy = pointer.y - lastMousePos.pageY,
4515- r, rx, ry;
4516-
4517- if ('ontouchstart' in this.el) {
4518- r = D.position(this.overlay);
4519- rx = pointer.x - r.left - plotOffset.left;
4520- ry = pointer.y - r.top - plotOffset.top;
4521- } else {
4522- r = this.overlay.getBoundingClientRect();
4523- rx = e.clientX - r.left - plotOffset.left - b.scrollLeft - de.scrollLeft;
4524- ry = e.clientY - r.top - plotOffset.top - b.scrollTop - de.scrollTop;
4525- }
4526-
4527- return {
4528- x: axes.x.p2d(rx),
4529- x2: axes.x2.p2d(rx),
4530- y: axes.y.p2d(ry),
4531- y2: axes.y2.p2d(ry),
4532- relX: rx,
4533- relY: ry,
4534- dX: dx,
4535- dY: dy,
4536- absX: pointer.x,
4537- absY: pointer.y,
4538- pageX: pointer.x,
4539- pageY: pointer.y
4540- };
4541- },
4542- /**
4543- * Observes the 'click' event and fires the 'flotr:click' event.
4544- * @param {Event} event - 'click' Event object.
4545- */
4546- clickHandler: function(event){
4547- if(this.ignoreClick){
4548- this.ignoreClick = false;
4549- return this.ignoreClick;
4550- }
4551- E.fire(this.el, 'flotr:click', [this.getEventPosition(event), this]);
4552- },
4553- /**
4554- * Observes mouse movement over the graph area. Fires the 'flotr:mousemove' event.
4555- * @param {Event} event - 'mousemove' Event object.
4556- */
4557- mouseMoveHandler: function(event){
4558- if (this.mouseDownMoveHandler) return;
4559- var pos = this.getEventPosition(event);
4560- E.fire(this.el, 'flotr:mousemove', [event, pos, this]);
4561- this.lastMousePos = pos;
4562- },
4563- /**
4564- * Observes the 'mousedown' event.
4565- * @param {Event} event - 'mousedown' Event object.
4566- */
4567- mouseDownHandler: function (event){
4568-
4569- /*
4570- // @TODO Context menu?
4571- if(event.isRightClick()) {
4572- event.stop();
4573-
4574- var overlay = this.overlay;
4575- overlay.hide();
4576-
4577- function cancelContextMenu () {
4578- overlay.show();
4579- E.stopObserving(document, 'mousemove', cancelContextMenu);
4580- }
4581- E.observe(document, 'mousemove', cancelContextMenu);
4582- return;
4583- }
4584- */
4585-
4586- if (this.mouseUpHandler) return;
4587- this.mouseUpHandler = _.bind(function (e) {
4588- E.stopObserving(document, 'mouseup', this.mouseUpHandler);
4589- E.stopObserving(document, 'mousemove', this.mouseDownMoveHandler);
4590- this.mouseDownMoveHandler = null;
4591- this.mouseUpHandler = null;
4592- // @TODO why?
4593- //e.stop();
4594- E.fire(this.el, 'flotr:mouseup', [e, this]);
4595- }, this);
4596- this.mouseDownMoveHandler = _.bind(function (e) {
4597- var pos = this.getEventPosition(e);
4598- E.fire(this.el, 'flotr:mousemove', [event, pos, this]);
4599- this.lastMousePos = pos;
4600- }, this);
4601- E.observe(document, 'mouseup', this.mouseUpHandler);
4602- E.observe(document, 'mousemove', this.mouseDownMoveHandler);
4603- E.fire(this.el, 'flotr:mousedown', [event, this]);
4604- this.ignoreClick = false;
4605- },
4606- drawTooltip: function(content, x, y, options) {
4607- var mt = this.getMouseTrack(),
4608- style = 'opacity:0.7;background-color:#000;color:#fff;display:none;position:absolute;padding:2px 8px;-moz-border-radius:4px;border-radius:4px;white-space:nowrap;',
4609- p = options.position,
4610- m = options.margin,
4611- plotOffset = this.plotOffset;
4612-
4613- if(x !== null && y !== null){
4614- if (!options.relative) { // absolute to the canvas
4615- if(p.charAt(0) == 'n') style += 'top:' + (m + plotOffset.top) + 'px;bottom:auto;';
4616- else if(p.charAt(0) == 's') style += 'bottom:' + (m + plotOffset.bottom) + 'px;top:auto;';
4617- if(p.charAt(1) == 'e') style += 'right:' + (m + plotOffset.right) + 'px;left:auto;';
4618- else if(p.charAt(1) == 'w') style += 'left:' + (m + plotOffset.left) + 'px;right:auto;';
4619- }
4620- else { // relative to the mouse
4621- if(p.charAt(0) == 'n') style += 'bottom:' + (m - plotOffset.top - y + this.canvasHeight) + 'px;top:auto;';
4622- else if(p.charAt(0) == 's') style += 'top:' + (m + plotOffset.top + y) + 'px;bottom:auto;';
4623- if(p.charAt(1) == 'e') style += 'left:' + (m + plotOffset.left + x) + 'px;right:auto;';
4624- else if(p.charAt(1) == 'w') style += 'right:' + (m - plotOffset.left - x + this.canvasWidth) + 'px;left:auto;';
4625- }
4626-
4627- mt.style.cssText = style;
4628- D.empty(mt);
4629- D.insert(mt, content);
4630- D.show(mt);
4631- }
4632- else {
4633- D.hide(mt);
4634- }
4635- },
4636-
4637- clip: function () {
4638-
4639- var
4640- ctx = this.ctx,
4641- o = this.plotOffset,
4642- w = this.canvasWidth,
4643- h = this.canvasHeight;
4644-
4645- if (flotr.isIE && flotr.isIE < 9) {
4646- // Clipping for excanvas :-(
4647- ctx.save();
4648- ctx.fillStyle = this.processColor(this.options.ieBackgroundColor);
4649- ctx.fillRect(0, 0, w, o.top);
4650- ctx.fillRect(0, 0, o.left, h);
4651- ctx.fillRect(0, h - o.bottom, w, o.bottom);
4652- ctx.fillRect(w - o.right, 0, o.right,h);
4653- ctx.restore();
4654- } else {
4655- ctx.clearRect(0, 0, w, o.top);
4656- ctx.clearRect(0, 0, o.left, h);
4657- ctx.clearRect(0, h - o.bottom, w, o.bottom);
4658- ctx.clearRect(w - o.right, 0, o.right,h);
4659- }
4660- },
4661-
4662- _initMembers: function() {
4663- this._handles = [];
4664- this.lastMousePos = {pageX: null, pageY: null };
4665- this.plotOffset = {left: 0, right: 0, top: 0, bottom: 0};
4666- this.ignoreClick = true;
4667- this.prevHit = null;
4668- },
4669-
4670- _initGraphTypes: function() {
4671- _.each(flotr.graphTypes, function(handler, graphType){
4672- this[graphType] = flotr.clone(handler);
4673- }, this);
4674- },
4675-
4676- _initEvents: function () {
4677-
4678- var
4679- el = this.el,
4680- touchendHandler, movement, touchend;
4681-
4682- if ('ontouchstart' in el) {
4683-
4684- touchendHandler = _.bind(function (e) {
4685- touchend = true;
4686- E.stopObserving(document, 'touchend', touchendHandler);
4687- E.fire(el, 'flotr:mouseup', [event, this]);
4688- this.multitouches = null;
4689-
4690- if (!movement) {
4691- this.clickHandler(e);
4692- }
4693- }, this);
4694-
4695- this.observe(this.overlay, 'touchstart', _.bind(function (e) {
4696- movement = false;
4697- touchend = false;
4698- this.ignoreClick = false;
4699-
4700- if (e.touches && e.touches.length > 1) {
4701- this.multitouches = e.touches;
4702- }
4703-
4704- E.fire(el, 'flotr:mousedown', [event, this]);
4705- this.observe(document, 'touchend', touchendHandler);
4706- }, this));
4707-
4708- this.observe(this.overlay, 'touchmove', _.bind(function (e) {
4709-
4710- var pos = this.getEventPosition(e);
4711-
4712- e.preventDefault();
4713-
4714- movement = true;
4715-
4716- if (this.multitouches || (e.touches && e.touches.length > 1)) {
4717- this.multitouches = e.touches;
4718- } else {
4719- if (!touchend) {
4720- E.fire(el, 'flotr:mousemove', [event, pos, this]);
4721- }
4722- }
4723- this.lastMousePos = pos;
4724- }, this));
4725-
4726- } else {
4727- this.
4728- observe(this.overlay, 'mousedown', _.bind(this.mouseDownHandler, this)).
4729- observe(el, 'mousemove', _.bind(this.mouseMoveHandler, this)).
4730- observe(this.overlay, 'click', _.bind(this.clickHandler, this)).
4731- observe(el, 'mouseout', function () {
4732- E.fire(el, 'flotr:mouseout');
4733- });
4734- }
4735- },
4736-
4737- /**
4738- * Initializes the canvas and it's overlay canvas element. When the browser is IE, this makes use
4739- * of excanvas. The overlay canvas is inserted for displaying interactions. After the canvas elements
4740- * are created, the elements are inserted into the container element.
4741- */
4742- _initCanvas: function(){
4743- var el = this.el,
4744- o = this.options,
4745- children = el.children,
4746- removedChildren = [],
4747- child, i,
4748- size, style;
4749-
4750- // Empty the el
4751- for (i = children.length; i--;) {
4752- child = children[i];
4753- if (!this.canvas && child.className === 'flotr-canvas') {
4754- this.canvas = child;
4755- } else if (!this.overlay && child.className === 'flotr-overlay') {
4756- this.overlay = child;
4757- } else {
4758- removedChildren.push(child);
4759- }
4760- }
4761- for (i = removedChildren.length; i--;) {
4762- el.removeChild(removedChildren[i]);
4763- }
4764-
4765- D.setStyles(el, {position: 'relative'}); // For positioning labels and overlay.
4766- size = {};
4767- size.width = el.clientWidth;
4768- size.height = el.clientHeight;
4769-
4770- if(size.width <= 0 || size.height <= 0 || o.resolution <= 0){
4771- throw 'Invalid dimensions for plot, width = ' + size.width + ', height = ' + size.height + ', resolution = ' + o.resolution;
4772- }
4773-
4774- // Main canvas for drawing graph types
4775- this.canvas = getCanvas(this.canvas, 'canvas');
4776- // Overlay canvas for interactive features
4777- this.overlay = getCanvas(this.overlay, 'overlay');
4778- this.ctx = getContext(this.canvas);
4779- this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
4780- this.octx = getContext(this.overlay);
4781- this.octx.clearRect(0, 0, this.overlay.width, this.overlay.height);
4782- this.canvasHeight = size.height;
4783- this.canvasWidth = size.width;
4784- this.textEnabled = !!this.ctx.drawText || !!this.ctx.fillText; // Enable text functions
4785-
4786- function getCanvas(canvas, name){
4787- if(!canvas){
4788- canvas = D.create('canvas');
4789- if (typeof FlashCanvas != "undefined" && typeof canvas.getContext === 'function') {
4790- FlashCanvas.initElement(canvas);
4791- }
4792- canvas.className = 'flotr-'+name;
4793- canvas.style.cssText = 'position:absolute;left:0px;top:0px;';
4794- D.insert(el, canvas);
4795- }
4796- _.each(size, function(size, attribute){
4797- D.show(canvas);
4798- if (name == 'canvas' && canvas.getAttribute(attribute) === size) {
4799- return;
4800- }
4801- canvas.setAttribute(attribute, size * o.resolution);
4802- canvas.style[attribute] = size + 'px';
4803- });
4804- canvas.context_ = null; // Reset the ExCanvas context
4805- return canvas;
4806- }
4807-
4808- function getContext(canvas){
4809- if(window.G_vmlCanvasManager) window.G_vmlCanvasManager.initElement(canvas); // For ExCanvas
4810- var context = canvas.getContext('2d');
4811- if(!window.G_vmlCanvasManager) context.scale(o.resolution, o.resolution);
4812- return context;
4813- }
4814- },
4815-
4816- _initPlugins: function(){
4817- // TODO Should be moved to flotr and mixed in.
4818- _.each(flotr.plugins, function(plugin, name){
4819- _.each(plugin.callbacks, function(fn, c){
4820- this.observe(this.el, c, _.bind(fn, this));
4821- }, this);
4822- this[name] = flotr.clone(plugin);
4823- _.each(this[name], function(fn, p){
4824- if (_.isFunction(fn))
4825- this[name][p] = _.bind(fn, this);
4826- }, this);
4827- }, this);
4828- },
4829-
4830- /**
4831- * Sets options and initializes some variables and color specific values, used by the constructor.
4832- * @param {Object} opts - options object
4833- */
4834- _initOptions: function(opts){
4835- var options = flotr.clone(flotr.defaultOptions);
4836- options.x2axis = _.extend(_.clone(options.xaxis), options.x2axis);
4837- options.y2axis = _.extend(_.clone(options.yaxis), options.y2axis);
4838- this.options = flotr.merge(opts || {}, options);
4839-
4840- if (this.options.grid.minorVerticalLines === null &&
4841- this.options.xaxis.scaling === 'logarithmic') {
4842- this.options.grid.minorVerticalLines = true;
4843- }
4844- if (this.options.grid.minorHorizontalLines === null &&
4845- this.options.yaxis.scaling === 'logarithmic') {
4846- this.options.grid.minorHorizontalLines = true;
4847- }
4848-
4849- E.fire(this.el, 'flotr:afterinitoptions', [this]);
4850-
4851- this.axes = flotr.Axis.getAxes(this.options);
4852-
4853- // Initialize some variables used throughout this function.
4854- var assignedColors = [],
4855- colors = [],
4856- ln = this.series.length,
4857- neededColors = this.series.length,
4858- oc = this.options.colors,
4859- usedColors = [],
4860- variation = 0,
4861- c, i, j, s;
4862-
4863- // Collect user-defined colors from series.
4864- for(i = neededColors - 1; i > -1; --i){
4865- c = this.series[i].color;
4866- if(c){
4867- --neededColors;
4868- if(_.isNumber(c)) assignedColors.push(c);
4869- else usedColors.push(flotr.Color.parse(c));
4870- }
4871- }
4872-
4873- // Calculate the number of colors that need to be generated.
4874- for(i = assignedColors.length - 1; i > -1; --i)
4875- neededColors = Math.max(neededColors, assignedColors[i] + 1);
4876-
4877- // Generate needed number of colors.
4878- for(i = 0; colors.length < neededColors;){
4879- c = (oc.length == i) ? new flotr.Color(100, 100, 100) : flotr.Color.parse(oc[i]);
4880-
4881- // Make sure each serie gets a different color.
4882- var sign = variation % 2 == 1 ? -1 : 1,
4883- factor = 1 + sign * Math.ceil(variation / 2) * 0.2;
4884- c.scale(factor, factor, factor);
4885-
4886- /**
4887- * @todo if we're getting too close to something else, we should probably skip this one
4888- */
4889- colors.push(c);
4890-
4891- if(++i >= oc.length){
4892- i = 0;
4893- ++variation;
4894- }
4895- }
4896-
4897- // Fill the options with the generated colors.
4898- for(i = 0, j = 0; i < ln; ++i){
4899- s = this.series[i];
4900-
4901- // Assign the color.
4902- if (!s.color){
4903- s.color = colors[j++].toString();
4904- }else if(_.isNumber(s.color)){
4905- s.color = colors[s.color].toString();
4906- }
4907-
4908- // Every series needs an axis
4909- if (!s.xaxis) s.xaxis = this.axes.x;
4910- if (s.xaxis == 1) s.xaxis = this.axes.x;
4911- else if (s.xaxis == 2) s.xaxis = this.axes.x2;
4912-
4913- if (!s.yaxis) s.yaxis = this.axes.y;
4914- if (s.yaxis == 1) s.yaxis = this.axes.y;
4915- else if (s.yaxis == 2) s.yaxis = this.axes.y2;
4916-
4917- // Apply missing options to the series.
4918- for (var t in flotr.graphTypes){
4919- s[t] = _.extend(_.clone(this.options[t]), s[t]);
4920- }
4921- s.mouse = _.extend(_.clone(this.options.mouse), s.mouse);
4922-
4923- if (_.isUndefined(s.shadowSize)) s.shadowSize = this.options.shadowSize;
4924- }
4925- },
4926-
4927- _setEl: function(el) {
4928- if (!el) throw 'The target container doesn\'t exist';
4929- else if (el.graph instanceof Graph) el.graph.destroy();
4930- else if (!el.clientWidth) throw 'The target container must be visible';
4931-
4932- el.graph = this;
4933- this.el = el;
4934- }
4935-};
4936-
4937-Flotr.Graph = Graph;
4938-
4939-})();
4940-
4941-/**
4942- * Flotr Axis Library
4943- */
4944-
4945-(function () {
4946-
4947-var
4948- _ = Flotr._,
4949- LOGARITHMIC = 'logarithmic';
4950-
4951-function Axis (o) {
4952-
4953- this.orientation = 1;
4954- this.offset = 0;
4955- this.datamin = Number.MAX_VALUE;
4956- this.datamax = -Number.MAX_VALUE;
4957-
4958- _.extend(this, o);
4959-
4960- this._setTranslations();
4961-}
4962-
4963-
4964-// Prototype
4965-Axis.prototype = {
4966-
4967- setScale : function () {
4968- var length = this.length;
4969- if (this.options.scaling == LOGARITHMIC) {
4970- this.scale = length / (log(this.max, this.options.base) - log(this.min, this.options.base));
4971- } else {
4972- this.scale = length / (this.max - this.min);
4973- }
4974- },
4975-
4976- calculateTicks : function () {
4977- var options = this.options;
4978-
4979- this.ticks = [];
4980- this.minorTicks = [];
4981-
4982- // User Ticks
4983- if(options.ticks){
4984- this._cleanUserTicks(options.ticks, this.ticks);
4985- this._cleanUserTicks(options.minorTicks || [], this.minorTicks);
4986- }
4987- else {
4988- if (options.mode == 'time') {
4989- this._calculateTimeTicks();
4990- } else if (options.scaling === 'logarithmic') {
4991- this._calculateLogTicks();
4992- } else {
4993- this._calculateTicks();
4994- }
4995- }
4996- },
4997-
4998- /**
4999- * Calculates the range of an axis to apply autoscaling.
5000- */
The diff has been truncated for viewing.